{ "openapi": "3.1.0", "info": { "title": "", "version": "" }, "paths": { "/ai/codex/auth/device-code": { "post": { "operationId": "start_codex_device_login", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CodexDeviceLogin" } } } } } } }, "/ai/codex/auth/session": { "delete": { "operationId": "delete_codex_session", "responses": { "204": { "description": "" } } } }, "/ai/codex/auth/status": { "get": { "operationId": "get_codex_auth_status", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CodexAuthStatus" } } } } } } }, "/ai/codex/images": { "post": { "operationId": "start_codex_image_generation", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CodexImageGenerationOptions" } } }, "required": true }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CodexImageGenerationResponse" } } } } } } }, "/blobs/{hash}": { "get": { "operationId": "get_blob", "parameters": [ { "name": "hash", "in": "path", "description": "Blake3 hash of the blob", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/octet-stream": {} } } } } }, "/config": { "get": { "operationId": "get_config", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AppConfig" } } } } } }, "patch": { "operationId": "patch_config", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigPatch" } } }, "required": true }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AppConfig" } } } } } } }, "/config/providers/{id}/secret": { "put": { "summary": "Save (or overwrite) the keyring secret for a provider. Creates the\nprovider entry in `config.providers` if it didn't exist. `PUT` because\nsetting the secret is idempotent for the same body.", "operationId": "set_provider_secret", "parameters": [ { "name": "id", "in": "path", "description": "Provider id", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderSecretRequest" } } }, "required": true }, "responses": { "204": { "description": "" } } }, "delete": { "summary": "Clear a provider's keyring secret. The provider entry itself is kept.", "operationId": "clear_provider_secret", "parameters": [ { "name": "id", "in": "path", "description": "Provider id", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "" } } } }, "/downloads": { "get": { "operationId": "list_downloads", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListDownloadsResponse" } } } } } }, "post": { "operationId": "start_download", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StartDownloadRequest" } } }, "required": true }, "responses": { "202": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StartDownloadResponse" } } } } } } }, "/engines": { "get": { "operationId": "get_engine_catalog", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EngineCatalog" } } } } } } }, "/events": { "get": { "operationId": "events", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AppEvent" } } } } } } }, "/fonts": { "get": { "operationId": "list_fonts", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/FontFaceInfo" } } } } } } } }, "/google-fonts": { "get": { "operationId": "get_google_fonts_catalog", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GoogleFontCatalog" } } } } } } }, "/google-fonts/{family}/fetch": { "post": { "operationId": "fetch_google_font", "parameters": [ { "name": "family", "in": "path", "description": "Google Fonts family name", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "" } } } }, "/google-fonts/{family}/{file}": { "get": { "operationId": "get_google_font_file", "parameters": [ { "name": "family", "in": "path", "description": "Google Fonts family name", "required": true, "schema": { "type": "string" } }, { "name": "file", "in": "path", "description": "Font filename", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "", "content": { "font/ttf": {} } } } } }, "/history/apply": { "post": { "operationId": "apply_command", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Op" } } }, "required": true }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HistoryResult" } } } } } } }, "/history/redo": { "post": { "operationId": "redo", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HistoryResult" } } } } } } }, "/history/undo": { "post": { "operationId": "undo", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HistoryResult" } } } } } } }, "/llm/catalog": { "get": { "operationId": "get_catalog", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LlmCatalog" } } } } } } }, "/llm/current": { "get": { "operationId": "get_current_llm", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LlmState" } } } } } }, "put": { "operationId": "put_current_llm", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LlmLoadRequest" } } }, "required": true }, "responses": { "204": { "description": "" } } }, "delete": { "operationId": "delete_current_llm", "responses": { "204": { "description": "" } } } }, "/meta": { "get": { "operationId": "get_meta", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MetaInfo" } } } } } } }, "/operations": { "get": { "operationId": "list_operations", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListOperationsResponse" } } } } } } }, "/operations/{id}": { "delete": { "operationId": "cancel_operation", "parameters": [ { "name": "id", "in": "path", "description": "Operation id", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "" } } } }, "/pages": { "post": { "operationId": "create_pages", "requestBody": { "content": { "multipart/form-data": {} } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatePagesResponse" } } } } } } }, "/pages/from-paths": { "post": { "summary": "Create pages by reading image files from absolute paths on the server's\nfilesystem. This is the Tauri desktop import path — the webview picker\nreturns paths, and the backend reads + decodes + hashes them in parallel\nwithout a round-trip through JS memory or a multipart upload body.", "description": "Web clients should keep using `POST /pages` with multipart.", "operationId": "create_pages_from_paths", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatePagesFromPathsRequest" } } }, "required": true }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatePagesResponse" } } } } } } }, "/pages/{id}/image-layers": { "post": { "operationId": "add_image_layer", "parameters": [ { "name": "id", "in": "path", "description": "Page id", "required": true, "schema": { "$ref": "#/components/schemas/PageId" } } ], "requestBody": { "content": { "multipart/form-data": {} } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddImageLayerResponse" } } } } } } }, "/pages/{id}/masks/{role}": { "put": { "summary": "Upsert the `Mask { role }` node on a page with the raw image bytes in\nthe body. Emits `Op::UpdateNode` if a mask of that role exists, else\n`Op::AddNode`. Used by the repair-brush / segment-edit flow; the\nfollow-up localized inpaint is a separate `POST /pipelines` call.", "operationId": "put_mask", "parameters": [ { "name": "id", "in": "path", "description": "Page id", "required": true, "schema": { "$ref": "#/components/schemas/PageId" } }, { "name": "role", "in": "path", "description": "Mask role (segment|brushInpaint)", "required": true, "schema": { "$ref": "#/components/schemas/MaskRole" } } ], "requestBody": { "content": { "image/png": {} } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PutMaskResponse" } } } } } } }, "/pages/{id}/thumbnail": { "get": { "operationId": "get_page_thumbnail", "parameters": [ { "name": "id", "in": "path", "description": "Page id", "required": true, "schema": { "$ref": "#/components/schemas/PageId" } } ], "responses": { "200": { "description": "", "content": { "image/webp": {} } } } } }, "/pipelines": { "post": { "operationId": "start_pipeline", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StartPipelineRequest" } } }, "required": true }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StartPipelineResponse" } } } } } } }, "/projects": { "get": { "operationId": "list_projects", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListProjectsResponse" } } } } } }, "post": { "operationId": "create_project", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateProjectRequest" } } }, "required": true }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectSummary" } } } } } } }, "/projects/current": { "put": { "operationId": "put_current_project", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OpenProjectRequest" } } }, "required": true }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectSummary" } } } } } }, "delete": { "operationId": "delete_current_project", "responses": { "204": { "description": "" } } } }, "/projects/current/export": { "post": { "operationId": "export_current_project", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExportProjectRequest" } } }, "required": true }, "responses": { "200": { "description": "Export bytes. Content-Type is `application/zip` when the format produces multiple files.", "content": { "application/octet-stream": {} } } } } }, "/projects/import": { "post": { "operationId": "import_project", "requestBody": { "content": { "application/zip": {} } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectSummary" } } } } } } }, "/scene.bin": { "get": { "operationId": "get_scene_bin", "responses": { "200": { "description": "", "content": { "application/octet-stream": {} } } } } }, "/scene.json": { "get": { "operationId": "get_scene_json", "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SceneSnapshot" } } } } } } } }, "components": { "schemas": { "AddImageLayerResponse": { "type": "object", "required": ["node"], "properties": { "node": { "$ref": "#/components/schemas/NodeId" } } }, "AppConfig": { "type": "object", "properties": { "data": { "oneOf": [ { "$ref": "#/components/schemas/DataConfig" } ], "default": { "path": "C:\\Users\\Mayo\\AppData\\Local\\Koharu" } }, "http": { "oneOf": [ { "$ref": "#/components/schemas/HttpConfig" } ], "default": { "connect_timeout": 20, "max_retries": 3, "read_timeout": 300 } }, "pipeline": { "oneOf": [ { "$ref": "#/components/schemas/PipelineConfig" } ], "default": { "bubble_segmenter": "speech-bubble-segmentation", "detector": "pp-doclayout-v3", "font_detector": "yuzumarker-font-detection", "inpainter": "lama-manga", "ocr": "paddle-ocr-vl-1.5", "renderer": "koharu-renderer", "segmenter": "comic-text-detector-seg", "translator": "llm" } }, "providers": { "type": "array", "items": { "$ref": "#/components/schemas/ProviderConfig" }, "default": [] } } }, "AppEvent": { "oneOf": [ { "type": "object", "required": ["id", "kind", "event"], "properties": { "event": { "type": "string", "enum": ["jobStarted"] }, "id": { "type": "string" }, "kind": { "type": "string" } } }, { "allOf": [ { "$ref": "#/components/schemas/PipelineProgress" }, { "type": "object", "required": ["event"], "properties": { "event": { "type": "string", "enum": ["jobProgress"] } } } ] }, { "allOf": [ { "$ref": "#/components/schemas/JobWarningEvent", "description": "A single step on one page failed but the pipeline kept running.\nEmitted per failed step so clients can show a non-fatal warning while\nthe job continues with the next page." }, { "type": "object", "required": ["event"], "properties": { "event": { "type": "string", "enum": ["jobWarning"] } } } ], "description": "A single step on one page failed but the pipeline kept running.\nEmitted per failed step so clients can show a non-fatal warning while\nthe job continues with the next page." }, { "allOf": [ { "$ref": "#/components/schemas/JobFinishedEvent" }, { "type": "object", "required": ["event"], "properties": { "event": { "type": "string", "enum": ["jobFinished"] } } } ] }, { "allOf": [ { "$ref": "#/components/schemas/DownloadProgress" }, { "type": "object", "required": ["event"], "properties": { "event": { "type": "string", "enum": ["downloadProgress"] } } } ] }, { "type": "object", "required": ["target", "event"], "properties": { "event": { "type": "string", "enum": ["llmLoading"] }, "target": { "$ref": "#/components/schemas/LlmTarget" } } }, { "type": "object", "required": ["target", "event"], "properties": { "event": { "type": "string", "enum": ["llmLoaded"] }, "target": { "$ref": "#/components/schemas/LlmTarget" } } }, { "type": "object", "required": ["event"], "properties": { "event": { "type": "string", "enum": ["llmFailed"] }, "target": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/LlmTarget" } ] } } }, { "type": "object", "required": ["event"], "properties": { "event": { "type": "string", "enum": ["llmUnloaded"] } } }, { "allOf": [ { "$ref": "#/components/schemas/SnapshotEvent" }, { "type": "object", "required": ["event"], "properties": { "event": { "type": "string", "enum": ["snapshot"] } } } ] } ] }, "BlobRef": { "type": "string", "description": "Hex-encoded blake3 hash of an immutable blob." }, "CodexAuthAttemptStatus": { "type": "string", "enum": ["pending", "succeeded", "failed"] }, "CodexAuthStatus": { "type": "object", "required": ["signedIn"], "properties": { "accountId": { "type": ["string", "null"] }, "login": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CodexDeviceLoginStatus" } ] }, "signedIn": { "type": "boolean" } } }, "CodexDeviceLogin": { "type": "object", "required": ["loginId", "verificationUrl", "userCode", "intervalSeconds", "timeoutSeconds"], "properties": { "intervalSeconds": { "type": "integer", "format": "int64", "minimum": 0 }, "loginId": { "type": "string" }, "timeoutSeconds": { "type": "integer", "format": "int64", "minimum": 0 }, "userCode": { "type": "string" }, "verificationUrl": { "type": "string" } } }, "CodexDeviceLoginStatus": { "type": "object", "required": ["loginId", "status"], "properties": { "accountId": { "type": ["string", "null"] }, "error": { "type": ["string", "null"] }, "loginId": { "type": "string" }, "status": { "$ref": "#/components/schemas/CodexAuthAttemptStatus" } } }, "CodexImageGenerationOptions": { "type": "object", "required": ["pageId", "prompt"], "properties": { "instructions": { "type": ["string", "null"] }, "model": { "type": ["string", "null"] }, "pageId": { "$ref": "#/components/schemas/PageId" }, "prompt": { "type": "string" }, "quality": { "type": ["string", "null"] }, "size": { "type": ["string", "null"] } } }, "CodexImageGenerationResponse": { "type": "object", "required": ["operationId"], "properties": { "operationId": { "type": "string" } } }, "ConfigPatch": { "type": "object", "description": "Sparse patch for `koharu_app::AppConfig`. Missing fields mean \"leave\nas-is\". The `providers` field, if present, replaces the whole provider\nlist — we do not merge by id because ordering is meaningful.", "properties": { "data": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/DataConfigPatch" } ] }, "http": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/HttpConfigPatch" } ] }, "pipeline": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/PipelineConfigPatch" } ] }, "providers": { "type": ["array", "null"], "items": { "$ref": "#/components/schemas/ProviderPatch" }, "description": "If present, replaces the entire list. Api_key values of `\"[REDACTED]\"`\nare interpreted as \"leave the existing secret alone\"." } } }, "CreatePagesFromPathsRequest": { "type": "object", "required": ["paths"], "properties": { "paths": { "type": "array", "items": { "type": "string" } }, "replace": { "type": "boolean" } } }, "CreatePagesResponse": { "type": "object", "required": ["pages"], "properties": { "pages": { "type": "array", "items": { "$ref": "#/components/schemas/PageId" } } } }, "CreateProjectRequest": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" } } }, "DataConfig": { "type": "object", "required": ["path"], "properties": { "path": { "type": "string" } } }, "DataConfigPatch": { "type": "object", "properties": { "path": { "type": ["string", "null"] } } }, "DownloadProgress": { "type": "object", "required": ["id", "filename", "downloaded", "status"], "properties": { "downloaded": { "type": "integer", "format": "int64", "minimum": 0 }, "filename": { "type": "string" }, "id": { "type": "string" }, "status": { "$ref": "#/components/schemas/DownloadStatus" }, "total": { "type": ["integer", "null"], "format": "int64", "minimum": 0 } } }, "DownloadStatus": { "oneOf": [ { "type": "object", "required": ["status"], "properties": { "status": { "type": "string", "enum": ["started"] } } }, { "type": "object", "required": ["status"], "properties": { "status": { "type": "string", "enum": ["downloading"] } } }, { "type": "object", "required": ["status"], "properties": { "status": { "type": "string", "enum": ["completed"] } } }, { "type": "object", "required": ["reason", "status"], "properties": { "reason": { "type": "string" }, "status": { "type": "string", "enum": ["failed"] } } } ] }, "EngineCatalog": { "type": "object", "required": [ "detectors", "fontDetectors", "segmenters", "bubbleSegmenters", "ocr", "translators", "inpainters", "renderers" ], "properties": { "bubbleSegmenters": { "type": "array", "items": { "$ref": "#/components/schemas/EngineCatalogEntry" } }, "detectors": { "type": "array", "items": { "$ref": "#/components/schemas/EngineCatalogEntry" } }, "fontDetectors": { "type": "array", "items": { "$ref": "#/components/schemas/EngineCatalogEntry" } }, "inpainters": { "type": "array", "items": { "$ref": "#/components/schemas/EngineCatalogEntry" } }, "ocr": { "type": "array", "items": { "$ref": "#/components/schemas/EngineCatalogEntry" } }, "renderers": { "type": "array", "items": { "$ref": "#/components/schemas/EngineCatalogEntry" } }, "segmenters": { "type": "array", "items": { "$ref": "#/components/schemas/EngineCatalogEntry" } }, "translators": { "type": "array", "items": { "$ref": "#/components/schemas/EngineCatalogEntry" } } } }, "EngineCatalogEntry": { "type": "object", "required": ["id", "name", "produces"], "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "produces": { "type": "array", "items": { "type": "string" } } } }, "ExportFormat": { "type": "string", "enum": ["khr", "psd", "rendered", "inpainted"] }, "ExportProjectRequest": { "type": "object", "required": ["format"], "properties": { "format": { "$ref": "#/components/schemas/ExportFormat" }, "pages": { "type": ["array", "null"], "items": { "$ref": "#/components/schemas/PageId" }, "description": "Optional subset of pages; defaults to every page." } } }, "FontFaceInfo": { "type": "object", "required": ["familyName", "postScriptName", "source", "cached"], "properties": { "cached": { "type": "boolean" }, "category": { "type": ["string", "null"] }, "familyName": { "type": "string" }, "postScriptName": { "type": "string" }, "source": { "$ref": "#/components/schemas/FontSource" } } }, "FontPrediction": { "type": "object", "required": [ "topFonts", "namedFonts", "direction", "textColor", "strokeColor", "fontSizePx", "strokeWidthPx", "lineHeight", "angleDeg" ], "properties": { "angleDeg": { "type": "number", "format": "float" }, "direction": { "$ref": "#/components/schemas/TextDirection" }, "fontSizePx": { "type": "number", "format": "float" }, "lineHeight": { "type": "number", "format": "float" }, "namedFonts": { "type": "array", "items": { "$ref": "#/components/schemas/NamedFontPrediction" } }, "strokeColor": { "type": "array", "items": { "type": "integer", "format": "int32", "minimum": 0 } }, "strokeWidthPx": { "type": "number", "format": "float" }, "textColor": { "type": "array", "items": { "type": "integer", "format": "int32", "minimum": 0 } }, "topFonts": { "type": "array", "items": { "$ref": "#/components/schemas/TopFont" } } } }, "FontSource": { "type": "string", "enum": ["system", "google"] }, "GoogleFontCatalog": { "type": "object", "required": ["fonts"], "properties": { "fonts": { "type": "array", "items": { "$ref": "#/components/schemas/GoogleFontEntry" } } } }, "GoogleFontEntry": { "type": "object", "required": ["family", "category", "subsets", "variants"], "properties": { "category": { "type": "string" }, "family": { "type": "string" }, "subsets": { "type": "array", "items": { "type": "string" } }, "variants": { "type": "array", "items": { "$ref": "#/components/schemas/GoogleFontVariant" } } } }, "GoogleFontVariant": { "type": "object", "required": ["style", "weight", "filename"], "properties": { "filename": { "type": "string" }, "style": { "type": "string" }, "weight": { "type": "integer", "format": "int32", "minimum": 0 } } }, "HistoryResult": { "type": "object", "properties": { "epoch": { "type": ["integer", "null"], "format": "int64", "description": "New epoch. `None` only for a no-op undo/redo at the stack boundary.", "minimum": 0 } } }, "HttpConfig": { "type": "object", "properties": { "connect_timeout": { "type": "integer", "format": "int64", "default": 20, "minimum": 0 }, "max_retries": { "type": "integer", "format": "int32", "default": 3, "minimum": 0 }, "read_timeout": { "type": "integer", "format": "int64", "default": 300, "minimum": 0 } } }, "HttpConfigPatch": { "type": "object", "properties": { "connectTimeout": { "type": ["integer", "null"], "format": "int64", "minimum": 0 }, "maxRetries": { "type": ["integer", "null"], "format": "int32", "minimum": 0 }, "readTimeout": { "type": ["integer", "null"], "format": "int64", "minimum": 0 } } }, "ImageData": { "type": "object", "required": ["role", "blob", "naturalWidth", "naturalHeight"], "properties": { "blob": { "$ref": "#/components/schemas/BlobRef" }, "name": { "type": ["string", "null"] }, "naturalHeight": { "type": "integer", "format": "int32", "minimum": 0 }, "naturalWidth": { "type": "integer", "format": "int32", "minimum": 0 }, "opacity": { "type": "number", "format": "float" }, "role": { "$ref": "#/components/schemas/ImageRole", "description": "Role tags differentiate source / inpainted / rendered / user-imported images.\nRole is immutable on an existing node — switching roles = delete + add." } } }, "ImageDataPatch": { "type": "object", "properties": { "blob": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/BlobRef" } ] }, "name": { "type": ["string", "null"] }, "naturalHeight": { "type": ["integer", "null"], "format": "int32", "minimum": 0 }, "naturalWidth": { "type": ["integer", "null"], "format": "int32", "minimum": 0 }, "opacity": { "type": ["number", "null"], "format": "float" } } }, "ImageRole": { "type": "string", "enum": ["source", "inpainted", "rendered", "custom"] }, "JobFinishedEvent": { "type": "object", "required": ["id", "status"], "properties": { "error": { "type": ["string", "null"] }, "id": { "type": "string" }, "status": { "$ref": "#/components/schemas/JobStatus" } } }, "JobStatus": { "type": "string", "enum": ["running", "completed", "completed_with_errors", "cancelled", "failed"] }, "JobSummary": { "type": "object", "required": ["id", "kind", "status"], "properties": { "error": { "type": ["string", "null"] }, "id": { "type": "string" }, "kind": { "type": "string" }, "status": { "$ref": "#/components/schemas/JobStatus" } } }, "JobWarningEvent": { "type": "object", "description": "A non-fatal step failure during a pipeline run. The pipeline recovers by\nskipping the rest of the current page's steps and moving on to the next\npage; the UI accumulates these into a list during the job.", "required": ["jobId", "pageIndex", "totalPages", "stepId", "message"], "properties": { "jobId": { "type": "string" }, "message": { "type": "string" }, "pageIndex": { "type": "integer", "description": "0-based page index where the failure happened.", "minimum": 0 }, "stepId": { "type": "string", "description": "Engine id (e.g. `\"lama-manga\"`) of the step that failed." }, "totalPages": { "type": "integer", "minimum": 0 } } }, "ListDownloadsResponse": { "type": "object", "required": ["downloads"], "properties": { "downloads": { "type": "array", "items": { "$ref": "#/components/schemas/DownloadProgress" } } } }, "ListOperationsResponse": { "type": "object", "required": ["operations"], "properties": { "operations": { "type": "array", "items": { "$ref": "#/components/schemas/JobSummary" } } } }, "ListProjectsResponse": { "type": "object", "required": ["projects"], "properties": { "projects": { "type": "array", "items": { "$ref": "#/components/schemas/ProjectSummary" } } } }, "LlmCatalog": { "type": "object", "required": ["localModels", "providers"], "properties": { "localModels": { "type": "array", "items": { "$ref": "#/components/schemas/LlmCatalogModel" } }, "providers": { "type": "array", "items": { "$ref": "#/components/schemas/LlmProviderCatalog" } } } }, "LlmCatalogModel": { "type": "object", "required": ["target", "name", "languages"], "properties": { "languages": { "type": "array", "items": { "type": "string" } }, "name": { "type": "string" }, "target": { "$ref": "#/components/schemas/LlmTarget" } } }, "LlmGenerationOptions": { "type": "object", "properties": { "customSystemPrompt": { "type": ["string", "null"] }, "maxTokens": { "type": ["integer", "null"], "format": "int32", "minimum": 0 }, "temperature": { "type": ["number", "null"], "format": "double" } } }, "LlmLoadRequest": { "type": "object", "required": ["target"], "properties": { "options": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/LlmGenerationOptions" } ] }, "target": { "$ref": "#/components/schemas/LlmTarget" } } }, "LlmProviderCatalog": { "type": "object", "required": [ "id", "name", "requiresApiKey", "requiresBaseUrl", "hasApiKey", "status", "models" ], "properties": { "baseUrl": { "type": ["string", "null"] }, "error": { "type": ["string", "null"] }, "hasApiKey": { "type": "boolean" }, "id": { "type": "string" }, "models": { "type": "array", "items": { "$ref": "#/components/schemas/LlmCatalogModel" } }, "name": { "type": "string" }, "requiresApiKey": { "type": "boolean" }, "requiresBaseUrl": { "type": "boolean" }, "status": { "$ref": "#/components/schemas/LlmProviderCatalogStatus" } } }, "LlmProviderCatalogStatus": { "type": "string", "enum": ["ready", "missing_configuration", "discovery_failed"] }, "LlmState": { "type": "object", "required": ["status"], "properties": { "error": { "type": ["string", "null"] }, "status": { "$ref": "#/components/schemas/LlmStateStatus" }, "target": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/LlmTarget" } ] } } }, "LlmStateStatus": { "type": "string", "enum": ["empty", "loading", "ready", "failed"] }, "LlmTarget": { "type": "object", "required": ["kind", "modelId"], "properties": { "kind": { "$ref": "#/components/schemas/LlmTargetKind" }, "modelId": { "type": "string" }, "providerId": { "type": ["string", "null"] } } }, "LlmTargetKind": { "type": "string", "enum": ["local", "provider"] }, "MaskData": { "type": "object", "required": ["role", "blob"], "properties": { "blob": { "$ref": "#/components/schemas/BlobRef" }, "role": { "$ref": "#/components/schemas/MaskRole" } } }, "MaskDataPatch": { "type": "object", "properties": { "blob": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/BlobRef" } ] } } }, "MaskRole": { "type": "string", "enum": ["brushInpaint", "segment", "bubble"] }, "MetaInfo": { "type": "object", "required": ["version", "mlDevice"], "properties": { "mlDevice": { "type": "string" }, "version": { "type": "string" } } }, "NamedFontPrediction": { "type": "object", "required": ["index", "name", "probability", "serif"], "properties": { "index": { "type": "integer", "minimum": 0 }, "language": { "type": ["string", "null"] }, "name": { "type": "string" }, "probability": { "type": "number", "format": "float" }, "serif": { "type": "boolean" } } }, "Node": { "type": "object", "required": ["id", "visible", "kind"], "properties": { "id": { "$ref": "#/components/schemas/NodeId" }, "kind": { "$ref": "#/components/schemas/NodeKind" }, "transform": { "$ref": "#/components/schemas/Transform" }, "visible": { "type": "boolean" } } }, "NodeDataPatch": { "oneOf": [ { "type": "object", "required": ["text"], "properties": { "text": { "$ref": "#/components/schemas/TextDataPatch" } } }, { "type": "object", "required": ["image"], "properties": { "image": { "$ref": "#/components/schemas/ImageDataPatch" } } }, { "type": "object", "required": ["mask"], "properties": { "mask": { "$ref": "#/components/schemas/MaskDataPatch" } } } ] }, "NodeId": { "type": "string", "format": "uuid" }, "NodeKind": { "oneOf": [ { "type": "object", "required": ["image"], "properties": { "image": { "$ref": "#/components/schemas/ImageData" } } }, { "type": "object", "required": ["text"], "properties": { "text": { "$ref": "#/components/schemas/TextData" } } }, { "type": "object", "required": ["mask"], "properties": { "mask": { "$ref": "#/components/schemas/MaskData" } } } ] }, "NodePatch": { "type": "object", "properties": { "data": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/NodeDataPatch" } ] }, "transform": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/Transform" } ] }, "visible": { "type": ["boolean", "null"] } } }, "Op": { "oneOf": [ { "type": "object", "required": ["updateProjectMeta"], "properties": { "updateProjectMeta": { "type": "object", "required": ["patch"], "properties": { "patch": { "$ref": "#/components/schemas/ProjectMetaPatch" }, "prev": { "$ref": "#/components/schemas/ProjectMetaPatch" } } } } }, { "type": "object", "required": ["addPage"], "properties": { "addPage": { "type": "object", "required": ["page", "at"], "properties": { "at": { "type": "integer", "minimum": 0 }, "page": { "$ref": "#/components/schemas/Page" } } } } }, { "type": "object", "required": ["removePage"], "properties": { "removePage": { "type": "object", "required": ["id", "prev_page", "prev_index"], "properties": { "id": { "$ref": "#/components/schemas/PageId" }, "prev_index": { "type": "integer", "minimum": 0 }, "prev_page": { "$ref": "#/components/schemas/Page" } } } } }, { "type": "object", "required": ["updatePage"], "properties": { "updatePage": { "type": "object", "required": ["id", "patch"], "properties": { "id": { "$ref": "#/components/schemas/PageId" }, "patch": { "$ref": "#/components/schemas/PagePatch" }, "prev": { "$ref": "#/components/schemas/PagePatch" } } } } }, { "type": "object", "required": ["reorderPages"], "properties": { "reorderPages": { "type": "object", "required": ["order", "prev_order"], "properties": { "order": { "type": "array", "items": { "$ref": "#/components/schemas/PageId" } }, "prev_order": { "type": "array", "items": { "$ref": "#/components/schemas/PageId" } } } } } }, { "type": "object", "required": ["addNode"], "properties": { "addNode": { "type": "object", "required": ["page", "node", "at"], "properties": { "at": { "type": "integer", "minimum": 0 }, "node": { "$ref": "#/components/schemas/Node" }, "page": { "$ref": "#/components/schemas/PageId" } } } } }, { "type": "object", "required": ["removeNode"], "properties": { "removeNode": { "type": "object", "required": ["page", "id", "prev_node", "prev_index"], "properties": { "id": { "$ref": "#/components/schemas/NodeId" }, "page": { "$ref": "#/components/schemas/PageId" }, "prev_index": { "type": "integer", "minimum": 0 }, "prev_node": { "$ref": "#/components/schemas/Node" } } } } }, { "type": "object", "required": ["updateNode"], "properties": { "updateNode": { "type": "object", "required": ["page", "id", "patch"], "properties": { "id": { "$ref": "#/components/schemas/NodeId" }, "page": { "$ref": "#/components/schemas/PageId" }, "patch": { "$ref": "#/components/schemas/NodePatch" }, "prev": { "$ref": "#/components/schemas/NodePatch" } } } } }, { "type": "object", "required": ["reorderNodes"], "properties": { "reorderNodes": { "type": "object", "required": ["page", "order", "prev_order"], "properties": { "order": { "type": "array", "items": { "$ref": "#/components/schemas/NodeId" } }, "page": { "$ref": "#/components/schemas/PageId" }, "prev_order": { "type": "array", "items": { "$ref": "#/components/schemas/NodeId" } } } } } }, { "type": "object", "required": ["batch"], "properties": { "batch": { "type": "object", "required": ["ops", "label"], "properties": { "label": { "type": "string" }, "ops": { "type": "array", "items": { "$ref": "#/components/schemas/Op" } } } } } } ] }, "OpenProjectRequest": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string", "description": "`.khrproj/` directory basename (no extension). Must exist under the\nmanaged projects directory." } } }, "Page": { "type": "object", "required": ["id", "name", "width", "height", "nodes"], "properties": { "height": { "type": "integer", "format": "int32", "minimum": 0 }, "id": { "$ref": "#/components/schemas/PageId" }, "name": { "type": "string" }, "nodes": { "type": "object", "description": "Stacking = insertion order. Bottom-first: `source` is typically first,\n`rendered` typically last.", "additionalProperties": { "$ref": "#/components/schemas/Node" }, "propertyNames": { "type": "string", "format": "uuid" } }, "width": { "type": "integer", "format": "int32", "minimum": 0 } } }, "PageId": { "type": "string", "format": "uuid" }, "PagePatch": { "type": "object", "properties": { "height": { "type": ["integer", "null"], "format": "int32", "minimum": 0 }, "name": { "type": ["string", "null"] }, "width": { "type": ["integer", "null"], "format": "int32", "minimum": 0 } } }, "PipelineConfig": { "type": "object", "description": "Engine selection for each pipeline stage.\nValues are engine IDs (e.g. \"pp-doclayout-v3\", \"comic-text-detector\").\nEmpty string means use default.", "properties": { "bubble_segmenter": { "type": "string", "default": "speech-bubble-segmentation" }, "detector": { "type": "string", "default": "pp-doclayout-v3" }, "font_detector": { "type": "string", "default": "yuzumarker-font-detection" }, "inpainter": { "type": "string", "default": "lama-manga" }, "ocr": { "type": "string", "default": "paddle-ocr-vl-1.5" }, "renderer": { "type": "string", "default": "koharu-renderer" }, "segmenter": { "type": "string", "default": "comic-text-detector-seg" }, "translator": { "type": "string", "default": "llm" } } }, "PipelineConfigPatch": { "type": "object", "properties": { "bubbleSegmenter": { "type": ["string", "null"] }, "detector": { "type": ["string", "null"] }, "fontDetector": { "type": ["string", "null"] }, "inpainter": { "type": ["string", "null"] }, "ocr": { "type": ["string", "null"] }, "renderer": { "type": ["string", "null"] }, "segmenter": { "type": ["string", "null"] }, "translator": { "type": ["string", "null"] } } }, "PipelineProgress": { "type": "object", "required": [ "jobId", "status", "currentPage", "totalPages", "currentStepIndex", "totalSteps", "overallPercent" ], "properties": { "currentPage": { "type": "integer", "minimum": 0 }, "currentStepIndex": { "type": "integer", "minimum": 0 }, "jobId": { "type": "string" }, "overallPercent": { "type": "integer", "format": "int32", "minimum": 0 }, "status": { "$ref": "#/components/schemas/PipelineStatus" }, "step": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/PipelineStep" } ] }, "totalPages": { "type": "integer", "minimum": 0 }, "totalSteps": { "type": "integer", "minimum": 0 } } }, "PipelineStatus": { "oneOf": [ { "type": "object", "required": ["status"], "properties": { "status": { "type": "string", "enum": ["running"] } } }, { "type": "object", "required": ["status"], "properties": { "status": { "type": "string", "enum": ["completed"] } } }, { "type": "object", "required": ["status"], "properties": { "status": { "type": "string", "enum": ["cancelled"] } } }, { "type": "object", "required": ["reason", "status"], "properties": { "reason": { "type": "string" }, "status": { "type": "string", "enum": ["failed"] } } } ] }, "PipelineStep": { "type": "string", "enum": ["detect", "ocr", "inpaint", "llmGenerate", "render"] }, "ProjectMeta": { "type": "object", "required": ["name", "createdAt", "updatedAt"], "properties": { "createdAt": { "type": "string", "format": "date-time" }, "name": { "type": "string" }, "style": { "$ref": "#/components/schemas/ProjectStyle" }, "updatedAt": { "type": "string", "format": "date-time" } } }, "ProjectMetaPatch": { "type": "object", "properties": { "name": { "type": ["string", "null"] }, "style": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ProjectStyle" } ] }, "updatedAt": { "type": ["string", "null"], "format": "date-time" } } }, "ProjectStyle": { "type": "object", "properties": { "defaultFont": { "type": ["string", "null"] } } }, "ProjectSummary": { "type": "object", "required": ["id", "name", "path"], "properties": { "id": { "type": "string", "description": "Stable identifier — the `.khrproj` directory basename (without the\nextension). Clients address projects by this." }, "name": { "type": "string" }, "path": { "type": "string", "description": "Absolute filesystem path. Informational; clients never need to pass\nit back in — they use `id`." }, "updatedAtMs": { "type": "integer", "format": "int64", "description": "Last modification time of the project directory on disk (ms since\nUNIX epoch). Used for \"recent projects\" ordering.", "minimum": 0 } } }, "ProviderConfig": { "type": "object", "required": ["id"], "properties": { "api_key": { "type": ["string", "null"], "description": "Populated from credential storage on `load()`, never written to config.toml.\nSerializes as `\"[REDACTED]\"` in API responses." }, "base_url": { "type": ["string", "null"] }, "id": { "type": "string" } } }, "ProviderPatch": { "type": "object", "required": ["id"], "properties": { "apiKey": { "type": ["string", "null"], "description": "`\"[REDACTED]\"` → keep existing keyring secret; empty → clear; otherwise save." }, "baseUrl": { "type": ["string", "null"] }, "id": { "type": "string" } } }, "ProviderSecretRequest": { "type": "object", "required": ["secret"], "properties": { "secret": { "type": "string" } } }, "PutMaskResponse": { "type": "object", "required": ["node", "blob"], "properties": { "blob": { "$ref": "#/components/schemas/BlobRef" }, "node": { "$ref": "#/components/schemas/NodeId" } } }, "Region": { "type": "object", "required": ["x", "y", "width", "height"], "properties": { "height": { "type": "integer", "format": "int32", "minimum": 0 }, "width": { "type": "integer", "format": "int32", "minimum": 0 }, "x": { "type": "integer", "format": "int32", "minimum": 0 }, "y": { "type": "integer", "format": "int32", "minimum": 0 } } }, "Scene": { "type": "object", "required": ["project", "pages"], "properties": { "pages": { "type": "object", "description": "Pages in insertion order; `IndexMap` ordering *is* the page order.", "additionalProperties": { "$ref": "#/components/schemas/Page" }, "propertyNames": { "type": "string", "format": "uuid" } }, "project": { "$ref": "#/components/schemas/ProjectMeta" } } }, "SceneSnapshot": { "type": "object", "description": "JSON-shaped scene snapshot for the UI (no postcard decoder in JS).", "required": ["epoch", "scene"], "properties": { "epoch": { "type": "integer", "format": "int64", "minimum": 0 }, "scene": { "$ref": "#/components/schemas/Scene" } } }, "SnapshotEvent": { "type": "object", "required": ["jobs", "downloads"], "properties": { "downloads": { "type": "array", "items": { "$ref": "#/components/schemas/DownloadProgress" } }, "jobs": { "type": "array", "items": { "$ref": "#/components/schemas/JobSummary" } } } }, "StartDownloadRequest": { "type": "object", "required": ["modelId"], "properties": { "modelId": { "type": "string", "description": "Package id, as declared via `declare_hf_model_package!`\n(e.g. `\"model:comic-text-detector:yolo-v5\"`)." } } }, "StartDownloadResponse": { "type": "object", "required": ["operationId"], "properties": { "operationId": { "type": "string", "description": "Operation id. Reusing the package id keeps ids meaningful for clients\nwatching progress events." } } }, "StartPipelineRequest": { "type": "object", "required": ["steps"], "properties": { "defaultFont": { "type": ["string", "null"] }, "pages": { "type": ["array", "null"], "items": { "$ref": "#/components/schemas/PageId" }, "description": "`None` → whole project, `Some(pages)` → just those pages." }, "region": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/Region", "description": "Optional bounding-box hint for inpainter engines (repair-brush)." } ] }, "steps": { "type": "array", "items": { "type": "string" }, "description": "Engine ids (`inventory::submit!` ids) to run in order." }, "systemPrompt": { "type": ["string", "null"] }, "targetLanguage": { "type": ["string", "null"] }, "textNodeIds": { "type": ["array", "null"], "items": { "$ref": "#/components/schemas/NodeId" }, "description": "Optional text-node ids for engines that can operate on individual blocks." } } }, "StartPipelineResponse": { "type": "object", "required": ["operationId"], "properties": { "operationId": { "type": "string" } } }, "TextAlign": { "type": "string", "enum": ["left", "center", "right"] }, "TextData": { "type": "object", "properties": { "confidence": { "type": "number", "format": "float" }, "detectedFontSizePx": { "type": ["number", "null"], "format": "float" }, "detector": { "type": ["string", "null"] }, "fontPrediction": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/FontPrediction" } ] }, "linePolygons": { "type": ["array", "null"], "items": { "type": "array", "items": { "type": "array", "items": { "type": "number", "format": "float" } } } }, "lockLayoutBox": { "type": "boolean" }, "renderedDirection": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TextDirection" } ] }, "rotationDeg": { "type": ["number", "null"], "format": "float" }, "sourceDirection": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TextDirection" } ] }, "sourceLang": { "type": ["string", "null"] }, "sprite": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/BlobRef", "description": "Renderer-produced sprite for this block." } ] }, "spriteTransform": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/Transform", "description": "Sprite placement when the renderer expands past the bubble geometry." } ] }, "style": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TextStyle" } ] }, "text": { "type": ["string", "null"] }, "translation": { "type": ["string", "null"] } } }, "TextDataPatch": { "type": "object", "description": "For fields where \"set to None\" is meaningful (e.g. clearing a translation),\nthe outer `Option` is \"patch present\", the inner is \"value present\".", "properties": { "confidence": { "type": ["number", "null"], "format": "float" }, "detectedFontSizePx": { "type": ["number", "null"], "format": "float" }, "detector": { "type": ["string", "null"] }, "fontPrediction": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/FontPrediction" } ] }, "linePolygons": { "type": ["array", "null"], "items": { "type": "array", "items": { "type": "array", "items": { "type": "number", "format": "float" } } } }, "lockLayoutBox": { "type": ["boolean", "null"] }, "renderedDirection": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TextDirection" } ] }, "rotationDeg": { "type": ["number", "null"], "format": "float" }, "sourceDirection": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TextDirection" } ] }, "sourceLang": { "type": ["string", "null"] }, "sprite": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/BlobRef" } ] }, "spriteTransform": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/Transform" } ] }, "style": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TextStyle" } ] }, "text": { "type": ["string", "null"] }, "translation": { "type": ["string", "null"] } } }, "TextDirection": { "type": "string", "description": "Reading axis of a text block.", "enum": ["horizontal", "vertical"] }, "TextShaderEffect": { "type": "object", "properties": { "bold": { "type": "boolean" }, "italic": { "type": "boolean" } } }, "TextStrokeStyle": { "type": "object", "properties": { "color": { "type": "array", "items": { "type": "integer", "format": "int32", "minimum": 0 } }, "enabled": { "type": "boolean" }, "widthPx": { "type": ["number", "null"], "format": "float" } } }, "TextStyle": { "type": "object", "required": ["fontFamilies", "color"], "properties": { "color": { "type": "array", "items": { "type": "integer", "format": "int32", "minimum": 0 } }, "effect": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TextShaderEffect" } ] }, "fontFamilies": { "type": "array", "items": { "type": "string" } }, "fontSize": { "type": ["number", "null"], "format": "float" }, "stroke": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TextStrokeStyle" } ] }, "textAlign": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/TextAlign" } ] } } }, "TopFont": { "type": "object", "required": ["index", "score"], "properties": { "index": { "type": "integer", "minimum": 0 }, "score": { "type": "number", "format": "float" } } }, "Transform": { "type": "object", "required": ["x", "y", "width", "height"], "properties": { "height": { "type": "number", "format": "float" }, "rotationDeg": { "type": "number", "format": "float" }, "width": { "type": "number", "format": "float" }, "x": { "type": "number", "format": "float" }, "y": { "type": "number", "format": "float" } } } } } }