This document describes the API surface that is currently wired in the codebase.
- REST base URL:
http://localhost:8080/api - WebSocket base:
ws://localhost:8080/ws
- Login:
POST /api/auth/login - Logout:
POST /api/auth/logout - Use bearer token in
Authorization: Bearer <token>
Guest fallback is still supported for many scene-related routes. If the token is missing or invalid, the backend often falls back to console_user instead of failing hard.
Important exceptions:
/api/users/:user_id/...requires authenticated ownership./api/scripts/*requires authenticated access.- Some write operations explicitly use stricter auth middleware.
Most endpoints return the unified response envelope:
{
"success": true,
"data": {},
"message": "...",
"timestamp": "...",
"request_id": "..."
}Many generation and analysis flows are asynchronous:
- start a job
- receive
task_id - subscribe to
GET /api/progress/:taskID - fetch the final artifact/result through its
GETendpoint
SSE endpoint:
GET /api/progress/:taskID
The /api group is rate-limited globally. Chat/interactions and analysis/upload paths use stricter rate limits than ordinary routes.
GET /api/settingsPOST /api/settingsPOST /api/settings/test-connection
Notes:
GET /api/settingsis the main frontend source of truth forllm_provider,vision_provider,video_provider,vision_models, andvideo_models.POST /api/settings/test-connectioncurrently validates LLM connectivity only.
GET /api/llm/statusGET /api/llm/models?provider=<provider>PUT /api/llm/config
Current backend-supported LLM provider names:
openaianthropicgoogledeepseekqwenmistralgrokglmgithubmodelsopenrouternvidia
POST /api/auth/loginPOST /api/auth/logout
GET /api/scenesPOST /api/scenesPOST /api/scenes/shellGET /api/scenes/:idDELETE /api/scenes/:idGET /api/scenes/:id/charactersGET /api/scenes/:id/conversationsGET /api/scenes/:id/nodes/:node_id/contentGET /api/scenes/:id/aggregate
GET /api/scenes/:id/itemsPOST /api/scenes/:id/itemsGET /api/scenes/:id/items/:item_idPUT /api/scenes/:id/items/:item_idDELETE /api/scenes/:id/items/:item_id
GET /api/scenes/:id/storyPOST /api/scenes/:id/story/choicePOST /api/scenes/:id/story/advancePOST /api/scenes/:id/story/commandPOST /api/scenes/:id/story/nodes/:node_id/insertPOST /api/scenes/:id/story/rewindGET /api/scenes/:id/story/branchesGET /api/scenes/:id/story/choicesPOST /api/scenes/:id/story/batchPOST /api/scenes/:id/story/tasks/:task_id/objectives/:objective_id/completePOST /api/scenes/:id/story/locations/:location_id/unlockPOST /api/scenes/:id/story/locations/:location_id/explore
Base group: /api/scenes/:id/comic
GET /api/scenes/:id/comicDELETE /api/scenes/:id/comicGET /api/scenes/:id/comic/export?format=zip|htmlPOST /api/scenes/:id/comic/analysisGET /api/scenes/:id/comic/analysisPUT /api/scenes/:id/comic/analysisPOST /api/scenes/:id/comic/promptsGET /api/scenes/:id/comic/promptsPUT /api/scenes/:id/comic/prompts/:frameIDPOST /api/scenes/:id/comic/key_elementsGET /api/scenes/:id/comic/key_elementsPUT /api/scenes/:id/comic/key_elementsPOST /api/scenes/:id/comic/referencesGET /api/scenes/:id/comic/referencesGET /api/scenes/:id/comic/references/:elementID/imageDELETE /api/scenes/:id/comic/references/:elementIDPOST /api/scenes/:id/comic/generatePOST /api/scenes/:id/comic/frames/generatePOST /api/scenes/:id/comic/frames/:frameID/regenerateGET /api/scenes/:id/comic/images/:frameID
Base group: /api/scenes/:id/comic/video
POST /api/scenes/:id/comic/video/timelineGET /api/scenes/:id/comic/video/timelinePUT /api/scenes/:id/comic/video/frames/:frameIDPOST /api/scenes/:id/comic/video/generatePOST /api/scenes/:id/comic/video/frames/:frameID/regenerateGET /api/scenes/:id/comic/videoDELETE /api/scenes/:id/comic/videoGET /api/scenes/:id/comic/video/clips/:frameID/assetGET /api/scenes/:id/comic/video/renderGET /api/scenes/:id/comic/video/export?format=zip|html
Important runtime note:
- Some providers need a reachable image URL for reference input. In deployment,
video_config.public_base_urlis usually required.
Base group: /api/scripts
GET /api/scriptsPOST /api/scriptsPUT /api/scripts/:idDELETE /api/scripts/:idGET /api/scripts/:idGET /api/scripts/:id/charactersPUT /api/scripts/:id/charactersGET /api/scripts/:id/itemsPUT /api/scripts/:id/itemsPUT /api/scripts/:id/chapter_draftPUT /api/scripts/:id/draftPOST /api/scripts/:id/generatePOST /api/scripts/:id/commandPOST /api/scripts/:id/rewindGET /api/scripts/:id/export?format=json|markdown|txt|html
POST /api/chatPOST /api/chat/emotionPOST /api/interactions/triggerPOST /api/interactions/simulatePOST /api/interactions/aggregateGET /api/interactions/:scene_idGET /api/interactions/:scene_id/:character1_id/:character2_id
POST /api/uploadPOST /api/analyzeGET /api/progress/:taskIDPOST /api/cancel/:taskID
GET /api/scenes/:id/export/sceneGET /api/scenes/:id/export/interactionsGET /api/scenes/:id/export/story
Base group: /api/users/:user_id
GET /api/users/:user_idPUT /api/users/:user_idGET /api/users/:user_id/preferencesPUT /api/users/:user_id/preferencesGET /api/users/:user_id/itemsPOST /api/users/:user_id/itemsGET /api/users/:user_id/items/:item_idPUT /api/users/:user_id/items/:item_idDELETE /api/users/:user_id/items/:item_idGET /api/users/:user_id/skillsPOST /api/users/:user_id/skillsGET /api/users/:user_id/skills/:skill_idPUT /api/users/:user_id/skills/:skill_idDELETE /api/users/:user_id/skills/:skill_id
GET /api/config/healthGET /api/config/metricsGET /api/ws/statusPOST /api/ws/cleanup
GET /ws/scene/:idGET /ws/user/status
The backend uses plain Gorilla WebSocket, not Socket.IO.
curl -sS http://localhost:8080/api/settingscurl -sS -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
http://localhost:8080/api/scenes/<scene_id>/comic/analysis \
-d '{"source_text":"A detective enters the station.","target_frames":6}'curl -N -H "Accept: text/event-stream" \
http://localhost:8080/api/progress/<task_id>{
"llm_provider": "nvidia",
"llm_config": {
"api_key": "***",
"base_url": "https://integrate.api.nvidia.com/v1",
"default_model": "moonshotai/kimi-k2.5"
},
"vision_provider": "glm",
"vision_default_model": "glm-image",
"vision_config": {
"endpoint": "https://open.bigmodel.cn/api/paas/v4",
"api_key": "***"
},
"video_provider": "dashscope",
"video_default_model": "wan2.6-i2v-flash",
"video_config": {
"endpoint": "https://dashscope.aliyuncs.com/api/v1",
"api_key": "***",
"public_base_url": "https://your-domain.example"
}
}Fetch results:
curl -sS http://localhost:8080/api/scenes/<scene_id>/comic/analysis
curl -sS http://localhost:8080/api/scenes/<scene_id>/comic/prompts
curl -sS http://localhost:8080/api/scenes/<scene_id>/comic/key_elementsStart prompts / key elements (both return 202 + task_id; subscribe via /api/progress/<task_id>):
curl -sS -X POST -H "Content-Type: application/json" \
http://localhost:8080/api/scenes/<scene_id>/comic/prompts -d '{}'
curl -sS -X POST -H "Content-Type: application/json" \
http://localhost:8080/api/scenes/<scene_id>/comic/key_elements -d '{}'Upload reference images (multipart; PNG/JPEG/WEBP; <= 5MB each):
Single upload (element_id + file):
curl -sS -X POST \
-F "element_id=<element_id>" \
-F "file=@./reference.png" \
http://localhost:8080/api/scenes/<scene_id>/comic/referencesBatch upload (file_<element_id> parts):
curl -sS -X POST \
-F "file_<element_id_1>=@./ref1.png" \
-F "file_<element_id_2>=@./ref2.jpg" \
http://localhost:8080/api/scenes/<scene_id>/comic/referencesGenerate images / regenerate one frame (both return 202 + task_id):
curl -sS -X POST -H "Content-Type: application/json" \
http://localhost:8080/api/scenes/<scene_id>/comic/generate -d '{}'
curl -sS -X POST -H "Content-Type: application/json" \
http://localhost:8080/api/scenes/<scene_id>/comic/frames/<frame_id>/regenerate -d '{}'Overview:
curl -sS http://localhost:8080/api/scenes/<scene_id>/comicExport (ZIP/HTML):
curl -fSL -o comic_<scene_id>.zip \
"http://localhost:8080/api/scenes/<scene_id>/comic/export?format=zip"
curl -fSL -o comic_<scene_id>.html \
"http://localhost:8080/api/scenes/<scene_id>/comic/export?format=html"Start analysis:
POST /api/scenes/<scene_id>/comic/analysis
Content-Type: application/json
{}Standalone analysis example:
POST /api/scenes/<scene_id>/comic/analysis
Content-Type: application/json
{
"source_text": "A detective enters the abandoned station and finds a broken clock...",
"target_frames": 6
}Create a standalone comic scene shell:
POST /api/scenes/shell
Content-Type: application/json
Authorization: Bearer <token>
{
"title": "My Comic",
"description": "Standalone comic workspace"
}Response (202):
{
"success": true,
"data": { "task_id": "comic_analyze_<scene_id>_..." },
"message": "分镜分析任务已受理",
"timestamp": "..."
}Fetch analysis:
GET /api/scenes/<scene_id>/comic/analysisResponse (200):
{
"success": true,
"data": {
"scene_id": "<scene_id>",
"target_frames": 8,
"frames": [
{ "id": "frame_1", "order": 1, "description": "..." }
]
},
"message": "分镜分析结果获取成功",
"timestamp": "..."
}Common error codes:
LLM_NOT_READY: LLM is not configured or not ready (503)COMIC_SERVICE_NOT_READY: ComicService/Repo is not initialized (503)COMIC_ANALYSIS_NOT_FOUND: analysis is missing (404)COMIC_PROMPTS_NOT_FOUND: prompts are missing (404)COMIC_KEY_ELEMENTS_NOT_FOUND: key elements are missing (404)
Export comic:
GET /api/scenes/<scene_id>/comic/export?format=zipResponse (200): file download
Content-Type:application/zip/text/html; charset=utf-8Content-Disposition:attachment; filename="comic_<scene_id>_<timestamp>.<ext>"
GET /api/scripts— List scriptsPOST /api/scripts— Create a new script project (New Script). This endpoint creates the project and initializes draft-related files; to start generation explicitly, callPOST /api/scripts/:id/generate(returns atask_idfor SSE progress).GET /api/scripts/:id— Get script details (project metadata, active draft, outline, memory, chapter summaries, workflow items)POST /api/scripts/:id/generate— Start (or restart) initial generation for the script (asynchronous). Returns{ "task_id": "..." }. Subscribe to/api/progress/:task_id(SSE) for progress updates.POST /api/scripts/:id/command— Execute a command (e.g.,assist_mode:inspiration,completion,polish) to expand or edit a chapter/scene; may return draft/workflow ids and output.PUT /api/scripts/:id/chapter_draft— Update per-chapteruser_draft(best-effort persist tochapter_draft.json).PUT /api/scripts/:id/draft— Save/replace a draft (creates new draft version and updates active draft).POST /api/scripts/:id/rewind— Rewind to a previous draft (body:{ "draft_id": "draft_xxx" }).GET /api/scripts/:id/export— Export script in formats:json|markdown|txt|html(e.g.,?format=markdown|txt|html&include_meta=true).
GET /api/scenes/:id/itemsPOST /api/scenes/:id/itemsGET /api/scenes/:id/items/:item_idPUT /api/scenes/:id/items/:item_idDELETE /api/scenes/:id/items/:item_id
GET /api/scenes/:id/storyPOST /api/scenes/:id/story/choicePOST /api/scenes/:id/story/advancePOST /api/scenes/:id/story/commandPOST /api/scenes/:id/story/nodes/:node_id/insertPOST /api/scenes/:id/story/rewindGET /api/scenes/:id/story/branchesGET /api/scenes/:id/story/choicesPOST /api/scenes/:id/story/batchPOST /api/scenes/:id/story/tasks/:task_id/objectives/:objective_id/completePOST /api/scenes/:id/story/locations/:location_id/unlockPOST /api/scenes/:id/story/locations/:location_id/explore
All export endpoints accept ?format= (commonly json, markdown, txt, html, and some exports also support csv depending on handler).
GET /api/scenes/:id/export/sceneGET /api/scenes/:id/export/interactionsGET /api/scenes/:id/export/story
POST /api/chatPOST /api/chat/emotion
POST /api/interactions/triggerPOST /api/interactions/simulatePOST /api/interactions/aggregateGET /api/interactions/:scene_idGET /api/interactions/:scene_id/:character1_id/:character2_id
POST /api/uploadPOST /api/analyzeGET /api/progress/:taskID(SSE)POST /api/cancel/:taskID
Subscribe to task progress updates via Server-Sent Events.
GET /api/progress/<taskID>
Accept: text/event-streamSSE events:
event: connected(sent once on connect)event: progress(JSON payload)event: heartbeat(keep-alive)
progress event payload schema:
{
"progress": 42,
"message": "...",
"status": "running"
}status is one of: running / completed / failed. When completed or failed, the server closes the SSE stream.
If the task does not exist, the endpoint returns a normal JSON error response (not SSE):
{
"success": false,
"error": { "code": "TASK_NOT_FOUND", "message": "任务不存在" },
"timestamp": "..."
}If the client requests SSE (e.g. Accept: text/event-stream), the server emits a single event: progress with status="failed" and then closes the stream.
Common reasons include:
- The server restarted (progress trackers are in-memory).
- The task was cleaned up after completion/failure.
- The task ID is invalid.
Cancel a task by its task ID:
POST /api/cancel/<taskID>
Authorization: Bearer <token>- If a running job exists in the JobQueue, cancellation will be propagated to it.
- The progress tracker is marked as failed with a "用户取消" reason so SSE subscribers can converge.
GET /api/config/healthGET /api/config/metrics
All user endpoints are under /api/users/:user_id and require that :user_id matches the authenticated user.
GET /api/users/:user_idPUT /api/users/:user_idGET /api/users/:user_id/preferencesPUT /api/users/:user_id/preferencesGET /api/users/:user_id/itemsPOST /api/users/:user_id/itemsGET /api/users/:user_id/items/:item_idPUT /api/users/:user_id/items/:item_idDELETE /api/users/:user_id/items/:item_idGET /api/users/:user_id/skillsPOST /api/users/:user_id/skillsGET /api/users/:user_id/skills/:skill_idPUT /api/users/:user_id/skills/:skill_idDELETE /api/users/:user_id/skills/:skill_id
GET /api/ws/statusPOST /api/ws/cleanup
POST /api/scenes
Content-Type: application/json
Authorization: Bearer <token>
{
"title": "My Scene",
"text": "...source text..."
}POST /api/scripts
Content-Type: application/json
Authorization: Bearer <token>
{
"title": "My Novel",
"type": "novel",
"framework": {
"genre": "mystery",
"chapter_count": 12,
"notes": "slow-burn mystery with 12 chapters"
}
}Response (201)
{
"success": true,
"data": {
"id": "script_12345",
"title": "My Novel",
"state": { "active_draft_id": "", "cursor": { "chapter": 1, "scene": 1 } }
},
"message": "Script created"
}Start generation explicitly
POST /api/scripts/{id}/generate
Content-Type: application/json
Authorization: Bearer <token>
{}Response (202)
{
"success": true,
"data": { "task_id": "task_abc123" },
"message": "Generation started; subscribe to /api/progress/{task_id} for progress (SSE)"
}Note: The generation process posts progress events to
/api/progress/:taskID(SSE). UseGET /api/progress/<taskID>withAccept: text/event-streamto receiveprogressevents.
- Start analysis:
POST /api/analyze
Content-Type: application/json
Authorization: Bearer <token>
{
"title": "My Scene",
"text": "...source text..."
}- Subscribe progress (Server-Sent Events):
GET /api/progress/<taskID>
Accept: text/event-streamSSE events:
event: connectedevent: progressevent: heartbeat
GET /ws/scene/:id?user_id=<optional>GET /ws/user/status?user_id=<required>
This backend uses plain WebSocket (Gorilla WebSocket), not Socket.IO.
Messages are JSON objects with a type field.
Client → server supported types:
character_interactionstory_choiceuser_status_updateping
Server → client examples:
connectedconversation:newstory:choice_confirmeduser:presencepongheartbeaterror
Example send (client → server):
{
"type": "ping"
}