Skip to content

AI App Installation and Service Deployment Progress API ​

This document describes manual AI App installation, device-side service deployment, streaming progress, and the API interface to query the latest deployment status using serviceId.

For integration and testing workflows, refer to the deployment progress testing documentation in the project repository.

1. Basic Conventions ​

  • AI Pod external domain: https://<subdomain>.<box-domain>
  • subdomain is derived from the app's lzc-manifest.yml; currently defaults to ai
  • box-domain is prioritized by fetching from lzc-cli box default; if unavailable, defaults to 13gxg.heiyu.space

Platform-side API base path:

  • https://<subdomain>.<box-domain>/backend/aiapps
  • https://<subdomain>.<box-domain>/backend/services

Device-side API base path:

  • http://<device-ip>:<device-port>/v1/service

2. Manual AI App Installation ​

2.1 POST /backend/aiapps/install/stream ​

Purpose:

  • Upload an AI App ZIP file
  • Complete registration
  • If the package includes deployable services, continue triggering device deployment. The new resource export service paths are agxorin/docker-compose.yml, thor/docker-compose.yml. Fallback to legacy ai-pod-service/docker-compose.yml if missing.
  • Return installation progress via SSE.

Request:

  • Method: POST
  • Content-Type: multipart/form-data
  • Required fields: file

Response:

  • Content-Type: text/event-stream
  • Event name: progress

Event structure:

json
{
  "stage": "pulling",
  "status": "downloading",
  "progress": 37,
  "message": "registry.lazycat.cloud/demo/app:latest: Downloading",
  "pkgId": "demo-app",
  "serviceId": "demo-app",
  "currentImage": "registry.lazycat.cloud/demo/app:latest",
  "currentLayer": "sha256:abcd",
  "current": 5242880,
  "total": 10485760,
  "error": ""
}

Note:

  • During the local package processing phase, status messages such as upload_saved, unzipping, validating, and registering are still sent.
  • The progress token in these phases is fixed to 0 and is not counted in the installation progress bar.
  • Actual progress in installation occurs during the service deployment phase:
    • pulling: 0-80
    • starting: 85
    • waiting: 95
    • completed: 100
    • failed: retain progress prior to failure
  • If the AI App has no deployable services, it directly returns:
    • stage=completed
    • progress=100
    • message=installed without deployable service

Typical return:

text
event:progress
data:{"stage":"registering","progress":0,"message":"registering ai app","pkgId":"demo-app"}

event:progress
data:{"stage":"pulling","status":"downloading","progress":31,"message":"registry.lazycat.cloud/demo/app:latest: Downloading","pkgId":"demo-app","serviceId":"demo-app","currentImage":"registry.lazycat.cloud/demo/app:latest","currentLayer":"sha256:abcd","current":5242880,"total":10485760}

event:progress
data:{"stage":"starting","status":"starting","progress":85,"message":"starting service","pkgId":"demo-app","serviceId":"demo-app"}

event:progress
data:{"stage":"waiting","status":"waiting","progress":95,"message":"waiting for service health","pkgId":"demo-app","serviceId":"demo-app"}

event:progress
data:{"stage":"completed","status":"complete","progress":100,"message":"service deployed","pkgId":"demo-app","serviceId":"demo-app"}

Failure example:

text
event:progress
data:{"stage":"failed","status":"error","progress":42,"message":"pull images failed","pkgId":"demo-app","serviceId":"demo-app","error":"pull access denied"}

2.2 DELETE /backend/aiapps/apps/:pkgId ​

Purpose:

  • Delete a manually installed AI App
  • Remove the corresponding service directory, cache directory, and container image

Return:

json
{"removed":true,"pkgId":"demo-app"}

2.3 GET /backend/aiapps/apps ​

Purpose:

  • List the current AI App entries

2.4 GET /backend/aiapps/installed/:pkgId ​

Purpose:

  • Check if a specified pkgId has been registered to the AI App store

Return:

json
{"installed":true}

3. Platform-side Service Interfaces ​

3.1 GET /backend/services/progress?serialNumber=<sn>&serviceId=<serviceId> ​

Purpose:

  • Query the most recent deployment progress of a specified service on a device
  • Suitable for automatic deployment scenarios, or for manual installation with interruption and subsequent recovery

Return structure:

json
{
  "serviceId": "demo-app",
  "stage": "pulling",
  "status": "extracting",
  "progress": 56,
  "message": "registry.lazycat.cloud/demo/app:latest: Extracting",
  "currentImage": "registry.lazycat.cloud/demo/app:latest",
  "currentLayer": "sha256:abcd",
  "current": 7340032,
  "total": 10485760,
  "startedAt": 1742880000,
  "updatedAt": 1742880012,
  "finishedAt": 0,
  "error": ""
}

Idle state return:

json
{
  "serviceId": "demo-app",
  "stage": "idle",
  "progress": 0,
  "message": "deployment not started"
}

3.2 Existing Platform-side Interfaces ​

  • GET /backend/services/list?serialNumber=<sn>
  • GET /backend/services/start?serialNumber=<sn>&serviceId=<serviceId>
  • GET /backend/services/stop?serialNumber=<sn>&serviceId=<serviceId>
  • GET /backend/services/delete?serialNumber=<sn>&serviceId=<serviceId>
  • GET /backend/services/log?serialNumber=<sn>&serviceId=<serviceId>

Note:

  • start is a synchronous trigger and does not return streaming progress.
  • Automatic deployment and start both continuously update the latest deployment status of serviceId.
  • For real-time progress, prefer using the AI App installation stream or the device-side /service/start/stream.

4. Device-side Service Interfaces ​

4.1 POST /v1/service/start ​

Purpose:

  • Triggers a one-time synchronous deployment.
  • The system internally updates the latest deployment status.

Request Fields:

  • file: service zip
  • serviceId
  • dirOverWrite: true|false
  • forceRecreate: true|false
  • extraEnv[KEY]=VALUE: optional

4.2 POST /v1/service/start/stream ​

Purpose:

  • Trigger a streaming deployment
  • Shares the same underlying deployment logic as /v1/service/start
  • Adds SSE-based progress feedback

Response:

  • Content-Type: text/event-stream
  • Event name: progress
  • Data structure matches backend.ServiceDeployStatus

4.3 GET /v1/service/progress?serviceId=<serviceId> ​

Purpose:

  • Query the latest deployment status of the service

4.4 GET /v1/service/log?serviceId=<serviceId> ​

Purpose:

  • Continuously monitor service logs

4.5 GET /v1/service/installed ​

Purpose:

  • View the currently installed services on the device along with docker-compose.yml summary information

5. Semantic Meaning of Deployment Progress ​

Unified status fields:

  • stage: High-level stage
  • status: Fine-grained status
  • progress: 0–100
  • message: Human-readable message

Current stage definitions:

stageprogressMeaning
idle0No deployment records available
prepare0Start deployment: prepare directory, unzip, write .env
pulling0-80Pull the compose container image
starting85Execute docker-compose up -d --wait
waiting95Container has been started, waiting for health check or --wait to complete
completed100Deployment successful
failedKeep current valueDeployment failed. Error details see error.

pulling.status Currently possible:

  • prepare
  • preparing
  • waiting
  • downloading
  • download_complete
  • extracting
  • verifying
  • already_exists
  • complete

Explanation:

  • The percentage for pulling comes from the structured byte progress of Docker Engine ImagePull, no longer relying on docker-compose pull PTY text.
  • In multi-image scenarios, the overall 0-80 progress is calculated by averaging the weights of individual images.
  • starting and waiting are currently phase-based progress indicators and are not precise container-level percentages.
  • The system retains only the most recent deployment status for each serviceId.

6. Call Examples ​

6.1 Manually installing an AI App and monitoring streaming progress ​

bash
curl --no-buffer \
  -F "file=@./demo-app.zip" \
  "https://ai.13gxg.heiyu.space/backend/aiapps/install/stream"

6.2 Query the recent deployment status of a specific service ​

bash
curl \
  "https://ai.13gxg.heiyu.space/backend/services/progress?serialNumber=<sn>&serviceId=demo-app"

6.3 Directly Call Device-Side Stream Deployment Interface ​

bash
curl --no-buffer \
  -F "file=@./demo-app-service.zip" \
  -F "serviceId=demo-app" \
  -F "dirOverWrite=true" \
  "http://<device-ip>:<device-port>/v1/service/start/stream"

6.4 Directly Call the Device-side Deployment Status Query Interface ​

bash
curl "http://<device-ip>:<device-port>/v1/service/progress?serviceId=demo-app"

7. ZIP Structure Requirements ​

AI App ZIP supports both resource export structure and legacy manual installation structure.

7.1 Resource Export Structure ​

Recommended structure:

text
demo-app/
└── resources/
    └── aipod/
        └── demo-app/
            ├── package.yml
            ├── lzc-manifest.yml
            ├── icon.png
            ├── config/
            │   └── aipod.yml
            ├── agxorin/
            │   └── docker-compose.yml
            ├── thor/
            │   └── docker-compose.yml
            └── extensions/
                └── extension.zip

After platform installation, the AIApp resource is expanded to:

text
/lzcapp/run/resources/aipod/<package-id>/

Service selection rules:

  • Thor devices prioritize thor/docker-compose.yml
  • All other devices default to agxorin/docker-compose.yml
  • When model-specific compose is missing, fallback to legacy ai-pod-service/docker-compose.yml

Plugin selection rules:

  • Prefer extensions/*.zip|*.crx
  • Fall back to legacy browser-extensions/extension.zip if missing

7.2 Legacy Manual Installation Structure ​

Legacy manual installation ZIP remains compatible:

text
demo-app/
└── pkg/
    ├── manifest.yml
    ├── icon.png
    ├── extension.zip
    └── ai-pod-service/
        └── docker-compose.yml

Device-side service zip structure:

text
demo-app/
├── docker-compose.yml
└── ...

AI App Rules:

  • The ZIP file containing resource export must contain exactly one AIApp resource root directory and be parsable to extract only one such root.
  • Legacy manual installation ZIP files must contain exactly one pkg/manifest.yml.
  • The legacy manual installation service path is pkg/ai-pod-service/docker-compose.yml.
  • The new resource export service paths are agxorin/docker-compose.yml, thor/docker-compose.yml, or fallback to ai-pod-service/docker-compose.yml.
  • The compose file must include a resolvable Traefik Host(...) label for platform identification of AI host and startup loading status.

8. Compatibility Notes ​

  • Automatic deployment, manual installation with streaming deployment, and platform-side start interface all share the same underlying deployment logic and the same state repository.
  • During manual installation, the AI App SSE directly passes through the device-side deployment progress.
  • During automatic deployment, no SSE is returned; the caller should query the latest deployment status via serviceId.
  • The pkg/ai-pod-service/docker-compose.yml in legacy ZIP files is only used as a compatibility path for manual installation and is not the sole service format for the new resource export.