Skip to content

Add new sample application - Agent Predictive Maintenance Pipeline#2479

Draft
madhuri-rai07 wants to merge 18 commits into
open-edge-platform:mainfrom
madhuri-rai07:agent-predictive-maintenance-bp
Draft

Add new sample application - Agent Predictive Maintenance Pipeline#2479
madhuri-rai07 wants to merge 18 commits into
open-edge-platform:mainfrom
madhuri-rai07:agent-predictive-maintenance-bp

Conversation

@madhuri-rai07

Copy link
Copy Markdown
Contributor

Description

Please include a summary of the changes and the related issue. List any dependencies that are required for this change.

Fixes # (issue)

Any Newly Introduced Dependencies

Please describe any newly introduced 3rd party dependencies in this change. List their name, license information and how they are used in the project.

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

Checklist:

  • I agree to use the APACHE-2.0 license for my code changes.
  • I have not introduced any 3rd party components incompatible with APACHE-2.0.
  • I have not included any company confidential information, trade secret, password or security token.
  • I have performed a self-review of my code.

madhuri-rai07 and others added 18 commits May 31, 2026 17:52
Blueprint SA for multi-agent industrial defect detection pipeline.
Config-driven: new use case = 4 files, no code changes.

Services (new):
- storage-service: SQLite REST API with WAL mode, Prometheus metrics
- agent-service: LangGraph 4-agent pipeline (policy/analysis/evidence/ticketing)
  with MQTT subscriber, fallback/LLM modes, FastAPI REST wrapper
- ui-service: FastAPI web dashboard with Jinja2 templates

Reused microservices:
- dlstreamer-pipeline-server, vlm-openvino-serving, model-download, metrics-manager

Infrastructure:
- 5 Docker Compose files (base/agents/llm/ui/telemetry)
- nginx, mosquitto, prometheus configs
- setup.sh one-command launcher with --use-case, --stop, --clean-data

Use case: pipeline-defect-detection
- agents.yaml, policy_fallback.json, pipeline-server-config.json
- Prompt file with SYSTEM/POLICY/ANALYSIS/EVIDENCE/TICKETING sections
- .env file for deployment config

Tests: 31 unit tests (18 storage + 9 agent + 4 ui), all passing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
agent-service:
  - fastapi 0.115.12 → 0.136.3
  - uvicorn 0.34.3 → 0.49.0
  - pydantic 2.11.4 → 2.13.4
  - langgraph 0.4.8 → 1.2.4
  - openai 1.84.0 → 2.41.1
  - pyyaml 6.0.2 → 6.0.3
  - requests 2.32.3 → 2.34.2
  - paho-mqtt 2.1.0 (unchanged, already latest)
  - REMOVED: langchain-openai (not directly imported)
  - REMOVED: langchain-core (transitive dep of langgraph)
  - REMOVED: jinja2 (only used in ui-service)

storage-service:
  - fastapi 0.115.12 → 0.136.3
  - uvicorn 0.34.3 → 0.49.0
  - pydantic 2.11.4 → 2.13.4

ui-service:
  - fastapi 0.115.12 → 0.136.3
  - uvicorn 0.34.3 → 0.49.0
  - pydantic 2.11.4 → 2.13.4
  - jinja2 3.1.6, httpx 0.28.1 (unchanged, already latest)

All 31 tests pass with updated deps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
python:3.12-slim does not include curl, causing all three new services
(apm-storage, apm-agent, apm-ui) to fail their Docker healthchecks and
be marked unhealthy immediately after startup.

Replace curl with Python stdlib urllib.request.urlopen() which is always
available in the Python base image and needs no extra packages:

  compose.base.yaml  (apm-storage :5001)
  compose.agents.yaml (apm-agent  :5002)
  compose.ui.yaml     (apm-ui     :5003)

compose.llm.yaml left unchanged — vlm-openvino-serving is a reused
Intel image that ships with curl.

Fixes: container apm-storage is unhealthy / dependency failed to start.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Three mismatches between the compose environment block and what the
agent-service Python modules actually read via os.environ.get():

  PROMPTS_DIR          → USE_CASE_PROMPTS_DIR  (prompt_loader.py, main.py)
  POLICY_FALLBACK_PATH → FALLBACK_POLICY_PATH  (llm_client.py)
  (missing)            + USE_CASE_CONFIGS_DIR   (config_loader.py, llm_client.py)

These caused the runtime error:
  'Prompt file not found: /configs/prompts/pipeline-defect-detection.txt'
because USE_CASE_PROMPTS_DIR was unset so prompt_loader.py fell back
to the /configs/prompts default path instead of /app/prompts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…oot volume

- Rewrite pipeline-server-config.json to match DL Streamer Pipeline Server
  2026.x format: {"config": {"pipelines": [...]}} with GStreamer pipeline
  strings instead of the incorrect flat config[] array with shell vars
- Remove ${VAR} shell substitution that DL Streamer does not evaluate
- Add CPU (auto_start=true), GPU, and NPU pipeline variants matching
  IEI-Vision reference pattern
- Specify model path directly in gvadetect element
- Add apm_pipeline_root named volume in compose.base.yaml to fix
  PermissionError on /var/cache/pipeline_root at container startup
- Mount USE_CASE_RESOURCES_DIR to /home/pipeline-server/resources so
  sample video is accessible inside the container
- Export USE_CASE_RESOURCES_DIR in setup.sh alongside other USE_CASE_* vars
- Add resources/videos/README.md with instructions for placing sample video

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adapted from intel/predictive-maintenance-pipeline with blueprint-specific
integration:

- scripts/download_and_prep_data.py
  * Downloads dataset from URL (e.g. Kaggle pipeline-defect-dataset)
  * Splits into 90/10 train/val in YOLO format under datasets/<use_case>/
  * Creates sample.mp4 from val images directly at
    apps/<use-case>/resources/videos/sample.mp4 (the path DL Streamer reads)
  * Supports --use-case flag matching our blueprint naming convention
  * Supports gas-detection use case via stratified class split
  * Supports --train-ratio, --seed, --keep-download options

- setup.sh
  * Warns if sample.mp4 is missing and prints the prep command to run
  * Points to LLM_MODE=fallback as the no-video alternative

- README.md
  * Added step 2 documenting the data prep workflow with Kaggle URL
  * Added DISCLAIMER notice for dataset licensing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sionError

Named Docker volumes are created root-owned; DL Streamer runs as uid 1999
and cannot mkdir /var/cache/pipeline_root/user_defined_pipelines.

Replace the named volume with a tmpfs mount (uid=1999,gid=1999,mode=0755)
so the directory is writable by the pipeline-server process on startup.
Pipeline root only holds ephemeral runtime pipeline state so tmpfs is correct.

Verified: apm-dlstreamer container starts healthy, all 3 pipelines load.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- .env_pipeline-defect-detection: fix LLM_MODEL_NAME from bare
  'Phi-4-mini-instruct' to full HF repo ID 'microsoft/Phi-4-mini-instruct'
  (bare name causes 401 RepositoryNotFoundError from HuggingFace Hub)
- Add clear HUGGINGFACEHUB_API_TOKEN comment with instructions to accept
  model license before generating a token
- setup.sh: skip compose.llm.yaml entirely when LLM_MODE=fallback so the
  VLM container is never started in rule-based mode (saves memory/GPU)
- setup.sh: relax validation — LLM_MODEL_NAME/LLM_DEVICE are only required
  when LLM_MODE != fallback
- Print active mode (LLM model+device or fallback) at startup

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- pipeline-server-config.json: set auto_start=false for default CPU pipeline
  to avoid gst-resource-error at startup when sample.mp4 hasn't been
  downloaded yet. Pipeline server starts cleanly; pipeline is started via
  REST API once the video is available.

- compose.base.yaml: expose DL Streamer REST port to host using
  PIPELINE_SERVER_PORT env var (default 8554); pass same value as
  REST_SERVER_PORT inside the container so host curl calls work.

- setup.sh: after stack start, check if sample.mp4 exists and auto-start
  the DL Streamer pipeline via REST API (with 30s timeout waiting for
  Tornado server). If video is missing, print the prep command instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- setup.sh: rewrite stop_containers() to stop by fixed container names
  (apm-nginx, apm-ui, etc.) instead of 'docker compose down', which
  requires USE_CASE_* env vars to be set and fails when --down is called
  standalone. No env vars needed for teardown.

- compose.agents.yaml: add ':-/tmp/apm-placeholder' defaults to
  USE_CASE_CONFIGS_DIR and USE_CASE_PROMPTS_DIR volume mounts so compose
  config parsing succeeds even when vars are unset (e.g. during --down).

- compose.base.yaml: same fix for USE_CASE_CONFIGS_DIR volume mount on
  the dlstreamer-pipeline-server service.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When user runs 'LLM_MODE=fallback source setup.sh ...', the .env file
was sourced after and overwrote LLM_MODE=fallback with LLM_MODE=llm,
causing VLM to be started despite the fallback override.

Fix: capture caller-supplied vars before sourcing the env file, restore
them after. Currently preserves LLM_MODE; pattern can be extended to
other override vars as needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
proxy_pass http://agent_backend/ stripped '/api/agents/' from the path,
sending '/runs' instead of '/agents/runs' to the agent service → 404.

Fix: proxy_pass http://agent_backend/agents/ so /api/agents/runs maps
correctly to /agents/runs on the agent service.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
cv2.VideoWriter with mp4v codec writes the moov atom at the end of the
file. GStreamer's qtdemux only scans the first 10 MB, causing:
  'no moov atom within the first 10 MB'

Run ffmpeg -movflags +faststart after cv2 writes the file to move moov
to immediately after ftyp, making the file streamable from the start.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…download touchpoints, labels sync

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Agent service:
- Fix MQTT subscriber to parse DL Streamer message format
  (unwrap metadata.objects[] instead of treating payload as flat dict)
- Add DL Streamer watchdog (dlstreamer_client.py) that auto-starts and
  restarts the pipeline when it completes
- Fix proxy bypass for all internal Docker service calls (storage, LLM,
  DL Streamer) using trust_env=False / proxies={http:None}
- Add optional ?id= filter to GET /agents/runs
- Tune LLM max_tokens per agent: policy=512, analysis=800, evidence=600,
  ticket=300 (was 2048 for all)
- Analysis agent: send compact deduplicated stats instead of 50 raw records
- Evidence agent: use summary + top-5 per class instead of fetching all records
- storage_client: add default limit=500 to prevent unbounded fetches

App config:
- pipeline-server-config.json: auto_start=true with MQTT payload destination
  so CPU pipeline starts automatically on container start
- compose.agents.yaml: add DLSTREAMER_URL, DLSTREAMER_PIPELINE_NAME env vars

UI service:
- Fix empty min_confidence string causing 422 validation error
- Dashboard: auto-refresh when a run is in progress, active nav state
- Dashboard: move Clear Detections to detections page (Danger Zone)
- Detections: limit selector (50/100/250/500), show total count
- Results: per-agent status breakdown on error, Run Again button
- Run history: full run ID on hover (title attribute)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant