From 5f863b662eb9aed8a3f57e9fc01bc5e8bf497005 Mon Sep 17 00:00:00 2001 From: extreme Date: Fri, 17 Apr 2026 17:19:39 +0800 Subject: [PATCH] =?UTF-8?q?[feat]=20=E6=B7=BB=E5=8A=A0=E9=95=9C=E5=A4=B4?= =?UTF-8?q?=E8=AF=AD=E4=B9=89=E5=BB=BA=E8=AE=AE=E5=92=8C=E5=8A=A8=E4=BD=9C?= =?UTF-8?q?=E6=8B=8D=E7=82=B9=E6=94=AF=E6=8C=81=EF=BC=8C=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=A8=A1=E5=9E=8B=E5=92=8C=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E4=BB=A5=E5=A2=9E=E5=BC=BA=E9=95=9C=E5=A4=B4=E7=94=9F=E6=88=90?= =?UTF-8?q?=E7=9A=84=E8=BF=9E=E8=B4=AF=E6=80=A7=E4=B8=8E=E5=87=86=E7=A1=AE?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/api/v1/routes/film/generated_video.py | 6 +- .../app/api/v1/routes/script_processing.py | 11 + .../app/api/v1/routes/studio/image_tasks.py | 54 +- .../chains/agents/element_extractor_agent.py | 11 +- .../chains/agents/shot_frame_prompt_agents.py | 63 +- backend/app/models/studio_shots.py | 6 + .../app/schemas/skills/script_processing.py | 19 +- .../app/schemas/skills/shot_frame_prompt.py | 15 + backend/app/schemas/studio/shots.py | 33 ++ backend/app/services/film/generated_video.py | 8 +- .../services/film/shot_frame_prompt_tasks.py | 496 ++++++++++++++++ .../app/services/script_processing_tasks.py | 99 ++-- .../app/services/script_processing_worker.py | 4 + backend/app/services/studio/action_beats.py | 147 +++++ .../studio/generation/frame/build_base.py | 17 +- .../generation/frame/build_submission.py | 4 + .../studio/generation/frame/derive_preview.py | 294 ++++++++- .../studio/generation/video/derive_preview.py | 12 +- .../services/studio/shot_extraction_draft.py | 9 + .../services/studio/shot_preparation_state.py | 24 +- .../services/studio/shot_semantic_defaults.py | 124 ++++ .../services/studio/shot_video_prompt_pack.py | 295 ++++++++- backend/sql/008-add-shot-action-beats.sql | 43 ++ .../test_generated_video_api_responses.py | 28 +- backend/tests/test_generated_video_service.py | 147 ++++- backend/tests/test_image_task_services.py | 86 +++ .../tests/test_image_tasks_api_responses.py | 67 +++ backend/tests/test_script_extract_cache.py | 2 + ...shot_extracted_candidates_api_responses.py | 13 + .../test_shot_frame_prompt_tasks_service.py | 140 +++++ .../test_shot_semantic_defaults_service.py | 181 ++++++ front/openapi.json | 2 +- .../pages/aiStudio/chapter/ChapterStudio.tsx | 560 +++++++++++++++++- .../aiStudio/shots/ChapterShotEditPage.tsx | 105 +++- .../ChapterShotBasicInfoSection.tsx | 173 +++++- front/src/services/generated/index.ts | 3 + .../generated/models/ActionBeatPhaseRead.ts | 18 + .../models/FrameGuidanceDecisionRead.ts | 26 + .../models/RenderedShotFramePromptRead.ts | 17 + .../generated/models/ShotDetailCreate.ts | 4 + .../generated/models/ShotDetailRead.ts | 4 + .../generated/models/ShotDetailUpdate.ts | 1 + .../models/ShotPreparationStateRead.ts | 21 + .../models/ShotSemanticSuggestion.ts | 37 ++ .../models/ShotVideoPromptPackRead.ts | 25 + .../generated/models/StudioShotDraft.ts | 5 + .../models/VideoPromptPreviewResponse.ts | 5 + .../docs/architecture/generation-workspace.md | 70 +++ .../shot-frame-prompt-generation.md | 65 ++ .../docs/architecture/shot-page-boundary.md | 28 + 50 files changed, 3522 insertions(+), 105 deletions(-) create mode 100644 backend/app/services/studio/action_beats.py create mode 100644 backend/app/services/studio/shot_semantic_defaults.py create mode 100644 backend/sql/008-add-shot-action-beats.sql create mode 100644 backend/tests/test_shot_semantic_defaults_service.py create mode 100644 front/src/services/generated/models/ActionBeatPhaseRead.ts create mode 100644 front/src/services/generated/models/FrameGuidanceDecisionRead.ts create mode 100644 front/src/services/generated/models/ShotSemanticSuggestion.ts diff --git a/backend/app/api/v1/routes/film/generated_video.py b/backend/app/api/v1/routes/film/generated_video.py index 94a0f62..82d8009 100644 --- a/backend/app/api/v1/routes/film/generated_video.py +++ b/backend/app/api/v1/routes/film/generated_video.py @@ -7,6 +7,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.core.task_manager import DeliveryMode, SqlAlchemyTaskStore, TaskManager from app.dependencies import get_db from app.models.task_links import GenerationTaskLink +from app.schemas.studio.shots import ShotVideoPromptPackRead from app.services.film.generated_video import build_run_args, preview_prompt_and_images from app.services.studio.shot_status import mark_shot_generating from app.tasks.execute_task import enqueue_task_execution @@ -21,6 +22,7 @@ router = APIRouter() class VideoPromptPreviewResponse(BaseModel): prompt: str = Field(..., description="最终用于视频生成的提示词") images: list[str] = Field(default_factory=list, description="关联参考图 file_id 列表") + pack: ShotVideoPromptPackRead | None = Field(None, description="视频提示词预览上下文包") @@ -35,14 +37,14 @@ async def preview_video_generation_prompt( db: AsyncSession = Depends(get_db), ) -> ApiResponse[VideoPromptPreviewResponse]: """预览视频生成的提示词与自动关联参考图。""" - prompt, images, _shot_detail = await preview_prompt_and_images( + prompt, images, pack = await preview_prompt_and_images( db, shot_id=body.shot_id, reference_mode=body.reference_mode, prompt=body.prompt, images=body.images, ) - return success_response(VideoPromptPreviewResponse(prompt=prompt, images=images)) + return success_response(VideoPromptPreviewResponse(prompt=prompt, images=images, pack=pack)) @router.post( diff --git a/backend/app/api/v1/routes/script_processing.py b/backend/app/api/v1/routes/script_processing.py index 84dfa37..09b660b 100644 --- a/backend/app/api/v1/routes/script_processing.py +++ b/backend/app/api/v1/routes/script_processing.py @@ -78,6 +78,7 @@ from app.services.studio import ( sync_shot_extracted_candidates_from_draft, sync_shot_extracted_dialogue_candidates_from_draft, ) +from app.services.studio.shot_semantic_defaults import apply_shot_semantic_defaults_from_draft from app.api.v1.routes.film.common import AsyncTaskCreateRead logger = logging.getLogger(__name__) @@ -999,6 +1000,11 @@ async def extract_script( chapter_id=request.chapter_id, draft=cached, ) + await apply_shot_semantic_defaults_from_draft( + db, + chapter_id=request.chapter_id, + draft=cached, + ) await db.commit() return success_response(data=cached, meta={"from_cache": True}) @@ -1020,6 +1026,11 @@ async def extract_script( chapter_id=request.chapter_id, draft=result, ) + await apply_shot_semantic_defaults_from_draft( + db, + chapter_id=request.chapter_id, + draft=result, + ) await db.commit() return success_response(data=result, meta={"from_cache": False}) except Exception as e: diff --git a/backend/app/api/v1/routes/studio/image_tasks.py b/backend/app/api/v1/routes/studio/image_tasks.py index 620db2a..ea5feea 100644 --- a/backend/app/api/v1/routes/studio/image_tasks.py +++ b/backend/app/api/v1/routes/studio/image_tasks.py @@ -40,6 +40,7 @@ from app.services.studio.generation.frame import ( build_frame_submission_payload as _build_frame_submission_payload_service, derive_frame_preview as _derive_frame_preview_service, ) +from app.services.film.shot_frame_prompt_tasks import build_run_args as _build_shot_frame_prompt_run_args_service from app.services.studio.generation.frame.derive_preview import ( to_rendered_shot_frame_prompt_read as _to_rendered_shot_frame_prompt_read_service, ) @@ -135,6 +136,38 @@ class RenderedPromptResponse(BaseModel): ) +async def _load_frame_render_guidance( + *, + db: AsyncSession, + shot_id: str, + frame_type: ShotFrameType, +) -> dict[str, str]: + """读取最终图片提示词需要保留的高优先级镜头约束。""" + try: + run_args = await _build_shot_frame_prompt_run_args_service( + db, + shot_id=shot_id, + frame_type=frame_type.value if hasattr(frame_type, "value") else str(frame_type), + ) + except HTTPException: + return { + "director_command_summary": "", + "continuity_guidance": "", + "frame_specific_guidance": "", + "composition_anchor": "", + "screen_direction_guidance": "", + } + + input_dict = dict(run_args.get("input") or {}) + return { + "director_command_summary": str(input_dict.get("director_command_summary") or "").strip(), + "continuity_guidance": str(input_dict.get("continuity_guidance") or "").strip(), + "frame_specific_guidance": str(input_dict.get("frame_specific_guidance") or "").strip(), + "composition_anchor": str(input_dict.get("composition_anchor") or "").strip(), + "screen_direction_guidance": str(input_dict.get("screen_direction_guidance") or "").strip(), + } + + @router.post( "/actors/{actor_id}/image-tasks", @@ -345,10 +378,20 @@ async def create_shot_frame_image_generation_task( shot_detail = await db.get(ShotDetail, shot_id) if shot_detail is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="ShotDetail not found") + render_guidance = await _load_frame_render_guidance( + db=db, + shot_id=shot_id, + frame_type=body.frame_type, + ) base = _build_frame_base_draft_service( shot_id=shot_id, frame_type=body.frame_type, prompt=prompt, + director_command_summary=render_guidance["director_command_summary"], + continuity_guidance=render_guidance["continuity_guidance"], + frame_specific_guidance=render_guidance["frame_specific_guidance"], + composition_anchor=render_guidance["composition_anchor"], + screen_direction_guidance=render_guidance["screen_direction_guidance"], ) context = _build_frame_context_service( shot_id=shot_id, @@ -414,17 +457,26 @@ async def render_shot_frame_prompt( body: ShotFramePromptRenderRequest, db: AsyncSession = Depends(get_db), ) -> ApiResponse[RenderedShotFramePromptRead]: - _ = shot_id, db prompt = (body.prompt or "").strip() if not prompt: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="prompt is required for shot frame render", ) + render_guidance = await _load_frame_render_guidance( + db=db, + shot_id=shot_id, + frame_type=body.frame_type, + ) base = _build_frame_base_draft_service( shot_id=shot_id, frame_type=body.frame_type, prompt=prompt, + director_command_summary=render_guidance["director_command_summary"], + continuity_guidance=render_guidance["continuity_guidance"], + frame_specific_guidance=render_guidance["frame_specific_guidance"], + composition_anchor=render_guidance["composition_anchor"], + screen_direction_guidance=render_guidance["screen_direction_guidance"], ) context = _build_frame_context_service( shot_id=shot_id, diff --git a/backend/app/chains/agents/element_extractor_agent.py b/backend/app/chains/agents/element_extractor_agent.py index 68461fe..cfc4a1b 100644 --- a/backend/app/chains/agents/element_extractor_agent.py +++ b/backend/app/chains/agents/element_extractor_agent.py @@ -17,8 +17,9 @@ _SCRIPT_EXTRACTOR_SYSTEM_PROMPT = """\ - chapter_id(必填) - characters: [{name, description, costume_name?, prop_names[], tags[]}] - scenes/props/costumes: [{name, description, tags[], prompt_template_id?, view_count}] -- shots: [{index, title, script_excerpt, scene_name?, character_names[], prop_names[], costume_names[], dialogue_lines[], actions[]}] +- shots: [{index, title, script_excerpt, scene_name?, character_names[], prop_names[], costume_names[], dialogue_lines[], actions[], semantic_suggestion?}] - dialogue_lines: [{index, text, line_mode, speaker_name?, target_name?}] + - semantic_suggestion: {camera_shot?, angle?, movement?, duration?, action_beats[], notes?} 强约束: - 同名实体在输出中只出现一次(全局去重);shots 中引用必须使用同一名称 @@ -34,6 +35,13 @@ _SCRIPT_EXTRACTOR_SYSTEM_PROMPT = """\ - 输出 shots 之前,必须做“全集校验”并补齐缺失:所有 shots[*] 中出现的 character_names/prop_names/costume_names/scene_name 的名字集合,必须都能在对应全局列表(characters/props/costumes/scenes)的 name 中找到;如果有缺失,必须在全局列表中补齐对应条目(描述可最小化,但 name 必须完全一致),禁止用别名替换来绕过。 - 角色名/场景名必须原样保留字符细节:包括全角/半角括号、空格、标点,不要自动做任何规范化或替换(例如不能把「女子(群)」改成「女子(群)」或「女子 (群)」)。 - 严格区分:shots[*].title 是“镜头标题”(一句话描述该镜头画面/动作),不要拿它当作 scenes 的 scene 名;shots[*].scene_name 才是场景名称,必须来自 scenes 全局列表的 name。 +- 除实体与对白外,还必须尽量补充镜头语言默认建议:`camera_shot` / `angle` / `movement` / `duration`。 +- `camera_shot` 只能输出:ECU / CU / MCU / MS / MLS / LS / ELS。 +- `angle` 只能输出:EYE_LEVEL / HIGH_ANGLE / LOW_ANGLE / BIRD_EYE / DUTCH / OVER_SHOULDER。 +- `movement` 只能输出:STATIC / PAN / TILT / DOLLY_IN / DOLLY_OUT / TRACK / CRANE / HANDHELD / STEADICAM / ZOOM_IN / ZOOM_OUT。 +- `duration` 必须输出正整数秒数;若无法判断,可省略。 +- `action_beats` 需要输出 2-4 条按镜头内部时间顺序排列的动作拍点;每一条只描述一个主要动作或状态变化,不要写成长段文学描述。 +- `semantic_suggestion` 是“镜头默认语义建议”,不是最终生成提示词,不要输出提示词式修饰文本。 输入: - project_id @@ -80,4 +88,3 @@ class ElementExtractorAgent(AgentBase[StudioScriptExtractionDraft]): if k not in data or not isinstance(data[k], list): data[k] = [] return data - diff --git a/backend/app/chains/agents/shot_frame_prompt_agents.py b/backend/app/chains/agents/shot_frame_prompt_agents.py index 49f8232..df9f3fc 100644 --- a/backend/app/chains/agents/shot_frame_prompt_agents.py +++ b/backend/app/chains/agents/shot_frame_prompt_agents.py @@ -18,6 +18,10 @@ def _prepare_shot_frame_input(input_dict: dict[str, Any]) -> dict[str, Any]: out["mood_tags"] = ", ".join(str(t) for t in out["mood_tags"]) else: out.setdefault("mood_tags", "") + if "action_beats" in out and isinstance(out["action_beats"], list): + out["action_beats"] = ";".join(str(item) for item in out["action_beats"] if str(item).strip()) + else: + out.setdefault("action_beats", "") for key in ( "visual_style", "style", @@ -32,11 +36,26 @@ def _prepare_shot_frame_input(input_dict: dict[str, Any]) -> dict[str, Any]: "duration", "scene_id", "dialog_summary", + "action_beats", + "action_beat_phases", + "selected_action_beat_phase", + "selected_action_beat_text", "character_context", "scene_context", "prop_context", "costume_context", "subject_priority", + "previous_shot_title", + "previous_shot_script_excerpt", + "previous_shot_end_state", + "next_shot_title", + "next_shot_script_excerpt", + "next_shot_start_goal", + "continuity_guidance", + "composition_anchor", + "screen_direction_guidance", + "frame_specific_guidance", + "director_command_summary", "retry_guidance", ): if key not in out or out[key] is None: @@ -64,16 +83,31 @@ _SHOT_FRAME_INPUT_VARS = [ "duration", "scene_id", "dialog_summary", + "action_beats", + "action_beat_phases", + "selected_action_beat_phase", + "selected_action_beat_text", "character_context", "scene_context", "prop_context", "costume_context", "subject_priority", + "previous_shot_title", + "previous_shot_script_excerpt", + "previous_shot_end_state", + "next_shot_title", + "next_shot_script_excerpt", + "next_shot_start_goal", + "continuity_guidance", + "composition_anchor", + "screen_direction_guidance", + "frame_specific_guidance", + "director_command_summary", "retry_guidance", ] _FRAME_FOCUS = { - "首帧": "优先描述镜头开始时最先看到的画面建立信息,强调开场定场、主体初始状态与进入情境的第一印象。", + "首帧": "优先描述镜头开始时最先看到的画面建立信息,强调开场定场、主体初始状态与进入情境的第一印象;只表现触发瞬间或最初反应,不要直接写成后续完成动作、最终姿态或情绪爆发完成态。", "尾帧": "优先描述镜头结束时最终停留的画面状态,强调动作收束、人物结束姿态、视线落点或情绪余韵。", "关键帧": "优先捕捉镜头中最具代表性、最有戏剧张力或信息密度最高的瞬间,不必平均描述整个过程。", } @@ -95,6 +129,15 @@ _SHOT_FRAME_TEMPLATE = """你是一名专业影视分镜提示词设计师,需 10. 主体优先级建议:{subject_priority} 11. 不要为了“写全信息”而平均罗列所有角色、道具、服装;优先突出主角色、主场景和主动作,其余元素仅在能强化当前画面时再进入提示词 12. 如果下面提供了“修正要求”,必须逐条满足后再输出最终结果 +13. 若存在上一镜头信息,当前画面应尽量承接上一镜头的动作、空间方向、视线或情绪,不要像全新场景重新开局 +14. 若存在下一镜头信息,当前画面应为下一镜头留下自然的动作或情绪收束,避免硬切 +15. 尽量明确主体在画面中的相对位置、朝向与动作峰值,减少构图和轴线突变 +16. 若提供了构图与空间锚点建议,应尽量落实到画面描述中,让主体位置、环境重心和空间方向更稳定 +17. 若提供了朝向与视线建议,应保持人物左右关系、视线落点与反打轴线稳定,不要无故翻转 +18. 若提供了当前帧专项建议,应优先满足该建议,确保首帧/关键帧/尾帧各自承担清晰职责 +19. 若提供了导演指令摘要,应将其视为最高优先级的镜头执行约束,优先体现到最终画面描述中 +20. 若当前为首帧,只能表现事件触发瞬间或最初反应,不要直接把后续完成动作、最终姿态或情绪爆发结果写进画面 +21. 若当前为首帧且镜头存在连续动作链,应优先使用“刚开始 / 尚未完成 / 被打断”的未完成态表达,而不是结果态表达 ## 镜头信息 剧本摘录:{script_excerpt} @@ -108,12 +151,30 @@ _SHOT_FRAME_TEMPLATE = """你是一名专业影视分镜提示词设计师,需 视效:{vfx_type} - {vfx_note} 时长:{duration}秒 对白摘要:{dialog_summary} +动作拍点:{action_beats} +动作拍点阶段:{action_beat_phases} +当前帧优先消费阶段:{selected_action_beat_phase} +当前帧主拍点:{selected_action_beat_text} ## 已确认实体上下文 角色:{character_context} 场景:{scene_context} 道具:{prop_context} 服装:{costume_context} + +## 相邻镜头承接信息 +上一镜头标题:{previous_shot_title} +上一镜头剧本摘录:{previous_shot_script_excerpt} +上一镜头结尾状态:{previous_shot_end_state} +下一镜头标题:{next_shot_title} +下一镜头剧本摘录:{next_shot_script_excerpt} +下一镜头起始目标:{next_shot_start_goal} +连续性建议:{continuity_guidance} +构图与空间锚点:{composition_anchor} +朝向与视线建议:{screen_direction_guidance} +当前帧专项建议:{frame_specific_guidance} +导演指令摘要:{director_command_summary} + 修正要求:{retry_guidance} ## 输出(仅 {frame_name} 基础提示词,JSON:{{"prompt": "..."}}) diff --git a/backend/app/models/studio_shots.py b/backend/app/models/studio_shots.py index 137097f..8e71855 100644 --- a/backend/app/models/studio_shots.py +++ b/backend/app/models/studio_shots.py @@ -194,6 +194,12 @@ class ShotDetail(Base,TimestampMixin): default="", comment="分镜整体描述(用于提示词补充)", ) + action_beats: Mapped[list[str]] = mapped_column( + JSON, + nullable=False, + default=list, + comment="镜头动作拍点(按时间顺序排列,用于关键帧与视频生成)", + ) prompt_template_id: Mapped[str | None] = mapped_column( String(64), ForeignKey("prompt_templates.id", ondelete="SET NULL"), diff --git a/backend/app/schemas/skills/script_processing.py b/backend/app/schemas/skills/script_processing.py index 77455a7..6383675 100644 --- a/backend/app/schemas/skills/script_processing.py +++ b/backend/app/schemas/skills/script_processing.py @@ -6,6 +6,7 @@ from typing import Any, Dict, List, Literal, Optional from pydantic import BaseModel, ConfigDict, Field +from app.models.studio import CameraAngle, CameraMovement, CameraShotType from app.schemas.skills.common import DialogueLine, DialogueLineMode, EvidenceSpan from app.schemas.skills.film import Character, Location, Prop, Scene, ProjectCinematicBreakdown @@ -320,6 +321,19 @@ class StudioShotDraftDialogueLine(BaseModel): target_name: Optional[str] = Field(None, description="听者角色名称(可空)") +class ShotSemanticSuggestion(BaseModel): + """镜头语义默认建议:用于准备阶段初始化镜头语言与动作拍点。""" + + model_config = ConfigDict(extra="forbid") + + camera_shot: Optional[CameraShotType] = Field(None, description="建议景别") + angle: Optional[CameraAngle] = Field(None, description="建议机位") + movement: Optional[CameraMovement] = Field(None, description="建议运镜") + duration: Optional[int] = Field(None, ge=1, description="建议时长(秒)") + action_beats: List[str] = Field(default_factory=list, description="按时间顺序排列的动作拍点") + notes: Optional[str] = Field(None, description="不确定项说明") + + class StudioShotDraft(BaseModel): """镜头草稿:不含 shot_id,由导入 API 生成;引用实体用 name。""" @@ -336,6 +350,10 @@ class StudioShotDraft(BaseModel): dialogue_lines: List[StudioShotDraftDialogueLine] = Field(default_factory=list, description="对白列表") actions: List[str] = Field(default_factory=list, description="动作/场景描述") + semantic_suggestion: Optional[ShotSemanticSuggestion] = Field( + None, + description="镜头语言默认建议与动作拍点候选", + ) class StudioScriptExtractionDraft(BaseModel): @@ -483,4 +501,3 @@ __all__ = [ "TableData", "OutputCompileResult", ] - diff --git a/backend/app/schemas/skills/shot_frame_prompt.py b/backend/app/schemas/skills/shot_frame_prompt.py index d6d8f11..c7e1e31 100644 --- a/backend/app/schemas/skills/shot_frame_prompt.py +++ b/backend/app/schemas/skills/shot_frame_prompt.py @@ -26,11 +26,26 @@ class ShotFramePromptInput(BaseModel): duration: Optional[int] = Field(None, description="时长(秒)") scene_id: Optional[str] = Field(None, description="关联场景 ID") dialog_summary: Optional[str] = Field(None, description="对白摘要") + action_beats: Optional[List[str]] = Field(None, description="按时间顺序排列的动作拍点") + action_beat_phases: Optional[str] = Field(None, description="动作拍点的阶段摘要,如 trigger / peak / aftermath") + selected_action_beat_phase: Optional[str] = Field(None, description="当前帧优先消费的动作阶段") + selected_action_beat_text: Optional[str] = Field(None, description="当前帧优先消费的动作拍点原文") character_context: Optional[str] = Field(None, description="镜头已确认角色及描述") scene_context: Optional[str] = Field(None, description="镜头已确认场景及描述") prop_context: Optional[str] = Field(None, description="镜头已确认道具及描述") costume_context: Optional[str] = Field(None, description="镜头已确认服装及描述") subject_priority: Optional[str] = Field(None, description="主体优先级建议,说明本镜头应优先写谁、先写哪个场景") + previous_shot_title: Optional[str] = Field(None, description="上一镜头标题,用于连续性承接") + previous_shot_script_excerpt: Optional[str] = Field(None, description="上一镜头剧本摘录,用于连续性承接") + previous_shot_end_state: Optional[str] = Field(None, description="上一镜头结尾状态摘要") + next_shot_title: Optional[str] = Field(None, description="下一镜头标题,用于连续性承接") + next_shot_script_excerpt: Optional[str] = Field(None, description="下一镜头剧本摘录,用于连续性承接") + next_shot_start_goal: Optional[str] = Field(None, description="下一镜头起始目标摘要") + continuity_guidance: Optional[str] = Field(None, description="当前镜头与相邻镜头的承接建议") + composition_anchor: Optional[str] = Field(None, description="画面构图与空间锚点建议") + screen_direction_guidance: Optional[str] = Field(None, description="人物朝向、视线与左右轴线建议") + frame_specific_guidance: Optional[str] = Field(None, description="按首帧/关键帧/尾帧区分的专项生成建议") + director_command_summary: Optional[str] = Field(None, description="汇总后的导演指令摘要,高优先级约束") retry_guidance: Optional[str] = Field(None, description="自动重试时附加的修正要求") diff --git a/backend/app/schemas/studio/shots.py b/backend/app/schemas/studio/shots.py index 5691e6e..0aab495 100644 --- a/backend/app/schemas/studio/shots.py +++ b/backend/app/schemas/studio/shots.py @@ -139,6 +139,7 @@ class ShotDetailBase(BaseModel): has_bgm: bool = Field(False, description="是否包含 BGM") vfx_type: VFXType = Field(VFXType.none, description="视效类型") vfx_note: str = Field("", description="视效说明") + action_beats: list[str] = Field(default_factory=list, description="动作拍点(按时间顺序排列)") first_frame_prompt: str = Field( "", description="镜头分镜首帧提示词", @@ -170,6 +171,7 @@ class ShotDetailUpdate(BaseModel): has_bgm: bool | None = None vfx_type: VFXType | None = None vfx_note: str | None = None + action_beats: list[str] | None = None first_frame_prompt: str | None = None last_frame_prompt: str | None = None key_frame_prompt: str | None = None @@ -319,11 +321,24 @@ class ShotFramePromptMappingRead(BaseModel): file_id: str = Field(..., description="本次渲染与生成使用的文件 ID") +class FrameGuidanceDecisionRead(BaseModel): + """分镜帧 guidance 的保留/压缩决策结果。""" + + text: str = Field(..., description="guidance 原文") + category: str = Field(..., description="guidance 分类,如 summary / continuity / composition / screen") + reason_tag: str = Field("", description="简短原因标签,如 首帧保空间 / 关键帧保轴线") + reason: str = Field(..., description="该 guidance 被保留或压缩的原因说明") + + class RenderedShotFramePromptRead(BaseModel): """关键帧最终生成提示词渲染结果。""" base_prompt: str = Field(..., description="原始基础提示词(不含图片映射说明)") rendered_prompt: str = Field(..., description="最终提交给模型的提示词(含图片映射说明)") + selected_guidance: list[str] = Field(default_factory=list, description="最终 prompt 实际保留的 guidance 列表") + dropped_guidance: list[str] = Field(default_factory=list, description="本次渲染中被压缩掉的 guidance 列表") + selected_guidance_details: list[FrameGuidanceDecisionRead] = Field(default_factory=list, description="最终保留 guidance 的决策详情") + dropped_guidance_details: list[FrameGuidanceDecisionRead] = Field(default_factory=list, description="被压缩 guidance 的决策详情") images: list[str] = Field(default_factory=list, description="最终参考图 file_id 列表,顺序与 mappings 一致") mappings: list[ShotFramePromptMappingRead] = Field( default_factory=list, @@ -382,6 +397,13 @@ class ShotPreparationLinkRequest(BaseModel): linked_entity_id: str = Field(..., description="要关联的实体 ID") +class ActionBeatPhaseRead(BaseModel): + """动作拍点的轻量阶段推断结果。""" + + text: str = Field(..., description="动作拍点原文") + phase: Literal["trigger", "peak", "aftermath"] = Field(..., description="推断阶段:触发 / 峰值 / 收束") + + class ShotPreparationStateRead(BaseModel): """分镜准备页聚合状态。""" @@ -396,6 +418,11 @@ class ShotPreparationStateRead(BaseModel): description="当前已保存的对白行", ) pending_confirm_count: int = Field(..., description="当前仍待确认的总数量(资产 + 对白)") + basic_info_ready: bool = Field(..., description="标题与剧本摘录是否已补齐") + semantic_defaults_ready: bool = Field(..., description="镜头语言默认值是否已确认") + action_beats_ready: bool = Field(..., description="动作拍点是否已确认") + action_beats_count: int = Field(0, description="当前已确认动作拍点数量") + action_beat_phases: list[ActionBeatPhaseRead] = Field(default_factory=list, description="当前动作拍点的阶段推断结果") ready_for_generation: bool = Field(..., description="当前镜头是否已完成准备,可进入后续生成") @@ -441,6 +468,12 @@ class ShotVideoPromptPackRead(BaseModel): title: str = Field("", description="镜头标题") script_excerpt: str = Field("", description="剧本摘录") action_beats: list[str] = Field(default_factory=list, description="动作/场景要点") + action_beat_phases: list[ActionBeatPhaseRead] = Field(default_factory=list, description="动作拍点的阶段推断结果") + previous_shot_summary: str = Field("", description="上一镜头摘要,用于提示词连续性约束") + next_shot_goal: str = Field("", description="下一镜头目标,用于提示词连续性约束") + continuity_guidance: str = Field("", description="当前镜头与相邻镜头的承接建议") + composition_anchor: str = Field("", description="当前镜头的构图与空间锚点建议") + screen_direction_guidance: str = Field("", description="当前镜头的人物朝向、视线与左右轴线建议") dialogue_summary: str = Field("", description="对白摘要") characters: list[ShotPromptAssetRef] = Field(default_factory=list, description="角色引用") scene: ShotPromptAssetRef | None = Field(None, description="场景引用") diff --git a/backend/app/services/film/generated_video.py b/backend/app/services/film/generated_video.py index c5618bb..481a648 100644 --- a/backend/app/services/film/generated_video.py +++ b/backend/app/services/film/generated_video.py @@ -80,7 +80,7 @@ async def preview_prompt_and_images( reference_mode: str, prompt: str | None, images: list[str] | None = None, -) -> tuple[str, list[str], ShotDetail]: +) -> tuple[str, list[str], dict | None]: shot_detail = await validate_shot_and_duration(db, shot_id) base = build_video_base_draft(shot_id=shot_id, prompt=prompt) context = await build_video_context( @@ -92,7 +92,11 @@ async def preview_prompt_and_images( submission = await build_video_submission_payload(db, base=base, context=context) if not submission.prompt: raise HTTPException(status_code=400, detail="prompt is required") - return submission.prompt, submission.images, shot_detail + prompt_preview_payload = submission.extra.get("prompt_preview") + if isinstance(prompt_preview_payload, dict): + pack = prompt_preview_payload.get("pack") + return submission.prompt, submission.images, pack if isinstance(pack, dict) else None + return submission.prompt, submission.images, None async def resolve_default_video_model(db: AsyncSession) -> Model: diff --git a/backend/app/services/film/shot_frame_prompt_tasks.py b/backend/app/services/film/shot_frame_prompt_tasks.py index 6064f71..69053a8 100644 --- a/backend/app/services/film/shot_frame_prompt_tasks.py +++ b/backend/app/services/film/shot_frame_prompt_tasks.py @@ -30,6 +30,7 @@ from app.models.studio import ( ) from app.services.llm.runtime import build_default_text_llm_sync from app.services.common import entity_not_found, invalid_choice +from app.services.studio.action_beats import infer_action_beat_sequence, pick_action_beat_for_frame from app.services.studio.shot_status import recompute_shot_status from app.services.worker.async_task_support import cancel_if_requested_async from app.services.worker.task_logging import log_task_event, log_task_failure @@ -126,6 +127,432 @@ def _build_subject_priority( return ";".join(parts) if parts else "优先根据镜头信息突出主角色和主场景,不必平均铺陈所有元素" +def _truncate_for_prompt(value: str | None, *, limit: int = 80) -> str: + text = _compact_text(value) + if len(text) <= limit: + return text + return f"{text[:limit].rstrip()}..." + + +def _summarize_neighbor_shot(shot: Shot | None) -> tuple[str, str, str]: + """生成相邻镜头的标题、摘录和状态摘要,供连续性提示词使用。""" + if shot is None: + return "", "", "" + detail = getattr(shot, "detail", None) + scene_name = _compact_text(getattr(getattr(detail, "scene", None), "name", None)) + camera_parts = [ + _enum_value(getattr(detail, "camera_shot", None)), + _enum_value(getattr(detail, "angle", None)), + _enum_value(getattr(detail, "movement", None)), + ] + camera_text = " / ".join(part for part in camera_parts if part) + description = _truncate_for_prompt(getattr(detail, "description", None), limit=60) + summary_parts = [ + f"场景:{scene_name}" if scene_name else "", + f"镜头语言:{camera_text}" if camera_text else "", + f"画面状态:{description}" if description else "", + ] + return ( + _compact_text(getattr(shot, "title", None)), + _truncate_for_prompt(getattr(shot, "script_excerpt", None), limit=80), + ";".join(part for part in summary_parts if part), + ) + + +def _build_continuity_guidance( + *, + previous_shot: Shot | None, + current_shot: Shot, + next_shot: Shot | None, +) -> str: + """基于相邻镜头关系生成简明连续性约束。""" + guidance: list[str] = [] + current_detail = getattr(current_shot, "detail", None) + current_scene_id = str(getattr(current_detail, "scene_id", "") or "") + previous_detail = getattr(previous_shot, "detail", None) if previous_shot else None + next_detail = getattr(next_shot, "detail", None) if next_shot else None + previous_scene_id = str(getattr(previous_detail, "scene_id", "") or "") + next_scene_id = str(getattr(next_detail, "scene_id", "") or "") + + if previous_shot is not None: + guidance.append("当前镜头应承接上一镜头的动作与情绪,不要像全新场面重新开局") + if current_scene_id and previous_scene_id and current_scene_id == previous_scene_id: + guidance.append("上一镜头与当前镜头处于同一场景,优先保持空间轴线和主体朝向稳定") + if _enum_value(getattr(previous_detail, "movement", None)) and _enum_value(getattr(current_detail, "movement", None)): + guidance.append("若镜头语言未明显变化,应视为同一动作链条中的推进或延续") + + if next_shot is not None: + guidance.append("当前镜头应形成自然收束,为下一镜头预留动作或情绪落点,避免硬切") + if current_scene_id and next_scene_id and current_scene_id == next_scene_id: + guidance.append("下一镜头与当前镜头处于同一场景,尽量保持视觉重心与空间关系可连续延展") + + return ";".join(guidance) + + +def _build_composition_anchor( + *, + detail: ShotDetail, + previous_shot: Shot | None, + next_shot: Shot | None, + characters: list[Character], + scenes: list[Scene], +) -> str: + """根据镜头语言和相邻镜头关系生成构图锚点建议。""" + anchors: list[str] = [] + camera_shot = _enum_value(detail.camera_shot) + movement = _enum_value(detail.movement) + + if camera_shot in {"ECU", "CU"}: + anchors.append("以主角色面部或关键动作作为画面重心,弱化环境干扰") + elif camera_shot in {"MS", "FS"}: + anchors.append("保持人物与环境同时可读,避免只剩情绪特写或只剩空场") + else: + anchors.append("优先建立空间关系,再突出主角色动作") + + if movement in {"DOLLY_IN", "ZOOM_IN"}: + anchors.append("构图应体现向主体推进的视觉趋势,焦点逐步收束到主角色") + elif movement in {"DOLLY_OUT", "ZOOM_OUT"}: + anchors.append("构图应体现从主体向环境退开的趋势,保留更多空间信息") + elif movement == "STATIC": + anchors.append("保持构图稳定,不要无故改变主体在画面中的重心位置") + + if scenes: + anchors.append(f"以场景 {scenes[0].name} 作为空间锚点,保证主体与环境关系清晰") + if characters: + anchors.append(f"优先锁定角色 {characters[0].name} 的朝向和视线,不要无故翻转左右关系") + + if previous_shot is not None and str(getattr(getattr(previous_shot, 'detail', None), 'scene_id', '') or '') == str(detail.scene_id or ''): + anchors.append("与上一镜头同场景时,尽量延续同一空间轴线和主体朝向") + if next_shot is not None and str(getattr(getattr(next_shot, 'detail', None), 'scene_id', '') or '') == str(detail.scene_id or ''): + anchors.append("与下一镜头同场景时,为后续镜头保留稳定的视觉落点与空间方向") + + return ";".join(anchors) + + +def _build_screen_direction_guidance( + *, + detail: ShotDetail, + previous_shot: Shot | None, + next_shot: Shot | None, + dialogue_summary: str, + character_names: list[str], +) -> str: + """生成人物朝向、视线与左右轴线建议。""" + guidance: list[str] = [] + angle = _enum_value(detail.angle) + + if angle == "OVER_SHOULDER": + guidance.append("当前镜头为过肩视角,应保持前景肩部与被看对象的左右关系稳定") + elif angle == "EYE_LEVEL": + guidance.append("优先保持人物视线水平和对视方向稳定,避免无故翻转左右朝向") + else: + guidance.append("明确主体朝向和视线落点,避免人物突然改向或跳轴") + + if dialogue_summary.strip(): + guidance.append("存在对白时,优先保证说话者与受话者的视线关系连续") + if len(character_names) >= 2: + guidance.append(f"角色 {character_names[0]} 与 {character_names[1]} 的左右站位和对视方向应保持一致") + elif character_names: + guidance.append(f"角色 {character_names[0]} 的朝向与视线落点应在相邻镜头中保持延续") + + current_scene_id = str(detail.scene_id or "") + previous_scene_id = str(getattr(getattr(previous_shot, "detail", None), "scene_id", "") or "") + next_scene_id = str(getattr(getattr(next_shot, "detail", None), "scene_id", "") or "") + if previous_shot is not None and current_scene_id and current_scene_id == previous_scene_id: + guidance.append("与上一镜头同场景时,不要无故翻转人物面向和左右轴线") + if next_shot is not None and current_scene_id and current_scene_id == next_scene_id: + guidance.append("与下一镜头同场景时,当前镜头结尾应保留可延续的视线方向") + + return ";".join(guidance) + + +_SEQUENTIAL_REACTION_KEYWORDS = ( + "听到", + "闻声", + "忽然", + "突然", + "下意识", + "立刻", + "随即", + "紧接着", + "随后", + "脱手", + "掉在地上", + "捂住耳朵", + "捂住", + "蹲下", + "跪下", + "跌坐", + "转身", + "回头", +) + + +def _has_sequential_reaction_chain(*values: str | None) -> bool: + """判断文本是否包含明显的连续反应链,供首帧时间切片加权使用。""" + text = " ".join(_compact_text(value) for value in values if _compact_text(value)) + if not text: + return False + keyword_hits = sum(1 for keyword in _SEQUENTIAL_REACTION_KEYWORDS if keyword in text) + punctuation_hits = text.count(",") + text.count("。") + text.count(";") + text.count("、") + return keyword_hits >= 2 or (keyword_hits >= 1 and punctuation_hits >= 2) + + +def _build_frame_specific_guidance( + *, + frame_type: str, + previous_shot: Shot | None, + next_shot: Shot | None, + detail: ShotDetail, + script_excerpt: str, + action_beats: list[str], +) -> str: + """按首帧/关键帧/尾帧生成专项提示,拉开三类帧职责差异。""" + guidance: list[str] = [] + if frame_type == "first": + guidance.append("首帧应优先建立空间、主体初始站位和第一眼视觉印象,不要直接跳到动作尾声") + guidance.append("首帧只表现事件触发瞬间或最初反应的起始状态,不要直接写成后续完成动作、最终姿态或情绪爆发结果") + guidance.append("若剧本存在连续反应链,优先写成动作刚开始、尚未完成或被打断的状态,例如手刚松脱、身体骤然僵住、人物尚未完全蹲下") + if _has_sequential_reaction_chain(script_excerpt, detail.description): + guidance.append("当前镜头存在明显连续反应链,首帧必须截取触发后最早的可见瞬间,禁止直接落到捂耳、蹲下、倒地或转身完成态") + if previous_shot is not None: + guidance.append("首帧要承接上一镜头结束状态,但仍应让观众迅速看清当前空间与主体起始状态") + if _enum_value(detail.camera_shot) in {"LS", "ELS", "MLS"}: + guidance.append("当前景别较大时,优先把环境、人物位置关系和进入方向交代清楚") + elif frame_type == "last": + guidance.append("尾帧应强调动作收束、情绪余韵或视线停留点,不要重新铺开新的动作起点") + if next_shot is not None: + guidance.append("尾帧应为下一镜头留下自然衔接的姿态、视线或情绪落点") + guidance.append("尾帧中的主体姿态应更稳定,便于后续镜头承接") + else: + guidance.append("关键帧应锁定镜头内最有戏剧张力或信息密度最高的瞬间,不要平均描述整个过程") + guidance.append("优先选择动作峰值、情绪爆点或构图最有代表性的瞬间") + if _enum_value(detail.movement) in {"DOLLY_IN", "ZOOM_IN", "TRACK"}: + guidance.append("若镜头存在推进或跟拍,关键帧应体现运动过程中最集中、最有压迫感的画面") + beat_item = pick_action_beat_for_frame(frame_type, action_beats) + if beat_item is not None: + phase_label = { + "trigger": "触发阶段", + "peak": "峰值阶段", + "aftermath": "收束阶段", + }.get(beat_item.phase, "当前阶段") + guidance.append(f"当前帧优先围绕动作拍点“{beat_item.text}”组织画面({phase_label}),不要越级跳到其他阶段") + return ";".join(guidance) + + +def _format_action_beat_phase_summary(action_beats: list[str]) -> str: + """格式化动作拍点阶段摘要,供 agent 输入与调试预览复用。""" + sequence = infer_action_beat_sequence(action_beats) + phase_labels = { + "trigger": "触发", + "peak": "峰值", + "aftermath": "收束", + } + return ";".join( + f"{index + 1}. {phase_labels.get(item.phase, item.phase)} · {item.text}" + for index, item in enumerate(sequence) + ) + + +def _same_scene(shot: Shot | None, current_scene_id: str) -> bool: + """判断相邻镜头是否与当前镜头处于同一场景。""" + return bool( + shot is not None + and current_scene_id + and str(getattr(getattr(shot, "detail", None), "scene_id", "") or "") == current_scene_id + ) + + +def _score_director_guidance_item( + *, + category: str, + text: str, + frame_type: str, + has_dialogue: bool, + character_count: int, + same_scene_with_previous: bool, + same_scene_with_next: bool, + movement: str, +) -> int: + """为 guidance 句子打分,优先保留更能稳定镜头连续性的约束。""" + score = 0 + if category == "frame": + score += 10 + if frame_type == "first" and ("建立空间" in text or "起始状态" in text): + score += 5 + if frame_type == "first" and ("触发瞬间" in text or "后续完成动作" in text or "尚未完成" in text): + score += 6 + if frame_type == "first" and ("连续反应链" in text or "最早的可见瞬间" in text or "完成态" in text): + score += 8 + if frame_type == "key" and ("动作峰值" in text or "戏剧张力" in text or "情绪爆点" in text): + score += 5 + if frame_type == "last" and ("动作收束" in text or "情绪余韵" in text or "停留点" in text): + score += 5 + elif category == "continuity": + score += 8 + if "承接上一镜头" in text: + score += 3 + if same_scene_with_previous: + score += 4 + if "下一镜头" in text or "收束" in text: + score += 3 + if same_scene_with_next: + score += 4 + if "空间轴线" in text or "主体朝向稳定" in text or "视觉重心" in text: + score += 3 + elif category == "composition": + score += 7 + if frame_type == "first" and ("空间锚点" in text or "建立空间" in text): + score += 5 + if frame_type == "key" and ("画面重心" in text or "推进" in text or "焦点" in text): + score += 4 + if frame_type == "last" and ("视觉落点" in text or "空间方向" in text): + score += 4 + if "锁定角色" in text or "重心位置" in text: + score += 2 + elif category == "screen": + score += 6 + if "不要无故翻转" in text or "跳轴" in text: + score += 5 + if has_dialogue and ("视线关系连续" in text or "对视方向" in text): + score += 5 + if character_count >= 2 and ("左右站位" in text or "对视方向" in text): + score += 4 + if same_scene_with_previous or same_scene_with_next: + if "同场景" in text or "视线方向" in text or "左右轴线" in text: + score += 4 + if frame_type == "last" and "视线方向" in text: + score += 2 + if movement in {"DOLLY_IN", "ZOOM_IN", "TRACK"} and category == "composition" and "推进" in text: + score += 3 + return score + + +def _build_director_must_categories( + *, + frame_type: str, + has_dialogue: bool, + character_count: int, + same_scene_with_previous: bool, + same_scene_with_next: bool, + movement: str, +) -> list[str]: + """按镜头风险动态决定哪些 guidance 应提升为必须项。""" + if frame_type == "first": + must_categories = ["frame", "continuity", "composition"] + elif frame_type == "key": + must_categories = ["frame", "composition", "continuity"] + else: + must_categories = ["frame", "continuity", "screen"] + + if movement in {"DOLLY_IN", "ZOOM_IN", "TRACK"} and "composition" in must_categories: + must_categories = ["composition" if item == "composition" else item for item in must_categories] + must_categories.insert(0, must_categories.pop(must_categories.index("composition"))) + + if has_dialogue or character_count >= 2 or same_scene_with_previous or same_scene_with_next: + if "screen" not in must_categories: + insert_at = 2 if frame_type == "key" else 1 + must_categories.insert(min(insert_at, len(must_categories)), "screen") + elif frame_type == "last": + must_categories.insert(1, must_categories.pop(must_categories.index("screen"))) + + deduped: list[str] = [] + for category in must_categories: + if category not in deduped: + deduped.append(category) + return deduped[:4] + + +def _build_director_command_summary( + *, + frame_type: str, + frame_specific_guidance: str, + continuity_guidance: str, + composition_anchor: str, + screen_direction_guidance: str, + has_dialogue: bool, + character_count: int, + same_scene_with_previous: bool, + same_scene_with_next: bool, + movement: str, +) -> str: + """将多类 guidance 压缩成高优先级导演指令摘要。""" + seen: set[str] = set() + + def _split_bucket(category: str, block: str) -> list[str]: + bucket: list[str] = [] + for piece in str(block or "").split(";"): + text = piece.strip() + if not text or text in seen: + continue + seen.add(text) + bucket.append(text) + return sorted( + bucket, + key=lambda item: _score_director_guidance_item( + category=category, + text=item, + frame_type=frame_type, + has_dialogue=has_dialogue, + character_count=character_count, + same_scene_with_previous=same_scene_with_previous, + same_scene_with_next=same_scene_with_next, + movement=movement, + ), + reverse=True, + ) + + buckets = { + "frame": _split_bucket("frame", frame_specific_guidance), + "continuity": _split_bucket("continuity", continuity_guidance), + "composition": _split_bucket("composition", composition_anchor), + "screen": _split_bucket("screen", screen_direction_guidance), + } + must_categories = _build_director_must_categories( + frame_type=frame_type, + has_dialogue=has_dialogue, + character_count=character_count, + same_scene_with_previous=same_scene_with_previous, + same_scene_with_next=same_scene_with_next, + movement=movement, + ) + + must_items: list[str] = [] + prefer_items: list[str] = [] + consumed_must_items: set[str] = set() + + for category in must_categories: + bucket = buckets.get(category) or [] + if bucket: + must_items.append(bucket[0]) + consumed_must_items.add(bucket[0]) + + frame_bucket = buckets.get("frame") or [] + if frame_type == "first" and len(frame_bucket) > 1: + primary_frame_item = frame_bucket[0] + if any(keyword in primary_frame_item for keyword in ("连续反应链", "触发瞬间", "尚未完成", "完成态")): + secondary_frame_item = frame_bucket[1] + if secondary_frame_item not in consumed_must_items: + must_items.append(secondary_frame_item) + consumed_must_items.add(secondary_frame_item) + + for category in ("frame", "continuity", "composition", "screen"): + bucket = buckets.get(category) or [] + if category in must_categories and bucket: + prefer_items.extend(item for item in bucket[1:] if item not in consumed_must_items) + continue + prefer_items.extend(item for item in bucket if item not in consumed_must_items) + if category not in must_categories and bucket: + head = bucket[0] + if head not in consumed_must_items: + prefer_items.insert(0, head) + + items = [*(f"必须:{item}" for item in must_items[:4]), *(f"优先:{item}" for item in prefer_items[:4])] + if not items: + return "" + return ";".join(items[:8]) + + def _extract_context_names(context_text: str | None) -> list[str]: names: list[str] = [] for raw_line in str(context_text or "").splitlines(): @@ -212,6 +639,19 @@ async def build_run_args( raise HTTPException(status_code=404, detail=entity_not_found("ShotDetail")) detail = shot.detail + neighbors_stmt = ( + select(Shot) + .options(selectinload(Shot.detail).selectinload(ShotDetail.scene)) + .where( + Shot.chapter_id == shot.chapter_id, + Shot.index.in_([shot.index - 1, shot.index + 1]), + ) + ) + neighbor_rows = (await db.execute(neighbors_stmt)).scalars().all() + previous_shot = next((item for item in neighbor_rows if item.index == shot.index - 1), None) + next_shot = next((item for item in neighbor_rows if item.index == shot.index + 1), None) + previous_title, previous_excerpt, previous_state = _summarize_neighbor_shot(previous_shot) + next_title, next_excerpt, next_goal = _summarize_neighbor_shot(next_shot) dialog_summary = "\n".join(line.text for line in (detail.dialog_lines or []) if line.text) project = getattr(getattr(shot, "chapter", None), "project", None) visual_style = _enum_value(getattr(project, "visual_style", None)) @@ -243,6 +683,36 @@ async def build_run_args( ] scenes = list(scenes_by_id.values()) + continuity_guidance = _build_continuity_guidance( + previous_shot=previous_shot, + current_shot=shot, + next_shot=next_shot, + ) + action_beats = [str(item).strip() for item in list(getattr(detail, "action_beats", []) or []) if str(item).strip()] + selected_action_beat = pick_action_beat_for_frame(normalized_frame_type, action_beats) + action_beat_phases = _format_action_beat_phase_summary(action_beats) + composition_anchor = _build_composition_anchor( + detail=detail, + previous_shot=previous_shot, + next_shot=next_shot, + characters=characters, + scenes=scenes, + ) + screen_direction_guidance = _build_screen_direction_guidance( + detail=detail, + previous_shot=previous_shot, + next_shot=next_shot, + dialogue_summary=dialog_summary, + character_names=[character.name for character in characters], + ) + frame_specific_guidance = _build_frame_specific_guidance( + frame_type=normalized_frame_type, + previous_shot=previous_shot, + next_shot=next_shot, + detail=detail, + script_excerpt=shot.script_excerpt or "", + action_beats=action_beats, + ) return { "shot_id": shot_id, "frame_type": normalized_frame_type, @@ -263,6 +733,10 @@ async def build_run_args( "duration": detail.duration, "scene_id": detail.scene_id, "dialog_summary": dialog_summary, + "action_beats": action_beats, + "action_beat_phases": action_beat_phases, + "selected_action_beat_phase": getattr(selected_action_beat, "phase", ""), + "selected_action_beat_text": getattr(selected_action_beat, "text", ""), "character_context": _build_character_context(characters), "scene_context": _build_named_asset_context(scenes), "prop_context": _build_named_asset_context(props), @@ -273,6 +747,28 @@ async def build_run_args( props=props, costumes=costumes, ), + "previous_shot_title": previous_title, + "previous_shot_script_excerpt": previous_excerpt, + "previous_shot_end_state": previous_state, + "next_shot_title": next_title, + "next_shot_script_excerpt": next_excerpt, + "next_shot_start_goal": next_goal, + "continuity_guidance": continuity_guidance, + "composition_anchor": composition_anchor, + "screen_direction_guidance": screen_direction_guidance, + "frame_specific_guidance": frame_specific_guidance, + "director_command_summary": _build_director_command_summary( + frame_type=normalized_frame_type, + frame_specific_guidance=frame_specific_guidance, + continuity_guidance=continuity_guidance, + composition_anchor=composition_anchor, + screen_direction_guidance=screen_direction_guidance, + has_dialogue=bool(dialog_summary.strip()), + character_count=len(characters), + same_scene_with_previous=_same_scene(previous_shot, str(detail.scene_id or "")), + same_scene_with_next=_same_scene(next_shot, str(detail.scene_id or "")), + movement=_enum_value(detail.movement), + ), }, } diff --git a/backend/app/services/script_processing_tasks.py b/backend/app/services/script_processing_tasks.py index d149747..d25d4bb 100644 --- a/backend/app/services/script_processing_tasks.py +++ b/backend/app/services/script_processing_tasks.py @@ -97,15 +97,33 @@ async def find_active_divide_task( *, chapter_id: str, ) -> GenerationTask | None: + return await _find_active_task( + db, + relation_type=CHAPTER_DIVISION_RELATION_TYPE, + relation_entity_id=chapter_id, + ) + + +async def _find_active_task( + db: AsyncSession, + *, + relation_type: str, + relation_entity_id: str, +) -> GenerationTask | None: + """按业务关联查询任意活动任务。 + + 这里的目标只是“是否已有运行中的同类任务”,不需要挑出“最新”那一条。 + 因此直接从 relation link 侧过滤,再按活动状态做一次连接,并去掉排序, + 避免在任务量大时触发 MySQL 的大排序与 sort buffer 压力。 + """ stmt = ( select(GenerationTask) .join(GenerationTaskLink, GenerationTaskLink.task_id == GenerationTask.id) .where( - GenerationTaskLink.relation_type == CHAPTER_DIVISION_RELATION_TYPE, - GenerationTaskLink.relation_entity_id == chapter_id, + GenerationTaskLink.relation_type == relation_type, + GenerationTaskLink.relation_entity_id == relation_entity_id, GenerationTask.status.in_(_ACTIVE_TASK_STATUSES), ) - .order_by(GenerationTask.updated_at.desc(), GenerationTask.id.desc()) .limit(1) ) return (await db.execute(stmt)).scalars().first() @@ -171,18 +189,11 @@ async def find_active_extract_task( *, chapter_id: str, ) -> GenerationTask | None: - stmt = ( - select(GenerationTask) - .join(GenerationTaskLink, GenerationTaskLink.task_id == GenerationTask.id) - .where( - GenerationTaskLink.relation_type == SCRIPT_EXTRACTION_RELATION_TYPE, - GenerationTaskLink.relation_entity_id == chapter_id, - GenerationTask.status.in_(_ACTIVE_TASK_STATUSES), - ) - .order_by(GenerationTask.updated_at.desc(), GenerationTask.id.desc()) - .limit(1) + return await _find_active_task( + db, + relation_type=SCRIPT_EXTRACTION_RELATION_TYPE, + relation_entity_id=chapter_id, ) - return (await db.execute(stmt)).scalars().first() async def find_active_merge_task( @@ -190,18 +201,11 @@ async def find_active_merge_task( *, relation_entity_id: str, ) -> GenerationTask | None: - stmt = ( - select(GenerationTask) - .join(GenerationTaskLink, GenerationTaskLink.task_id == GenerationTask.id) - .where( - GenerationTaskLink.relation_type == ENTITY_MERGE_RELATION_TYPE, - GenerationTaskLink.relation_entity_id == relation_entity_id, - GenerationTask.status.in_(_ACTIVE_TASK_STATUSES), - ) - .order_by(GenerationTask.updated_at.desc(), GenerationTask.id.desc()) - .limit(1) + return await _find_active_task( + db, + relation_type=ENTITY_MERGE_RELATION_TYPE, + relation_entity_id=relation_entity_id, ) - return (await db.execute(stmt)).scalars().first() async def find_active_consistency_task( @@ -209,18 +213,11 @@ async def find_active_consistency_task( *, relation_entity_id: str, ) -> GenerationTask | None: - stmt = ( - select(GenerationTask) - .join(GenerationTaskLink, GenerationTaskLink.task_id == GenerationTask.id) - .where( - GenerationTaskLink.relation_type == CONSISTENCY_CHECK_RELATION_TYPE, - GenerationTaskLink.relation_entity_id == relation_entity_id, - GenerationTask.status.in_(_ACTIVE_TASK_STATUSES), - ) - .order_by(GenerationTask.updated_at.desc(), GenerationTask.id.desc()) - .limit(1) + return await _find_active_task( + db, + relation_type=CONSISTENCY_CHECK_RELATION_TYPE, + relation_entity_id=relation_entity_id, ) - return (await db.execute(stmt)).scalars().first() async def find_active_variant_task( @@ -228,18 +225,11 @@ async def find_active_variant_task( *, relation_entity_id: str, ) -> GenerationTask | None: - stmt = ( - select(GenerationTask) - .join(GenerationTaskLink, GenerationTaskLink.task_id == GenerationTask.id) - .where( - GenerationTaskLink.relation_type == VARIANT_ANALYSIS_RELATION_TYPE, - GenerationTaskLink.relation_entity_id == relation_entity_id, - GenerationTask.status.in_(_ACTIVE_TASK_STATUSES), - ) - .order_by(GenerationTask.updated_at.desc(), GenerationTask.id.desc()) - .limit(1) + return await _find_active_task( + db, + relation_type=VARIANT_ANALYSIS_RELATION_TYPE, + relation_entity_id=relation_entity_id, ) - return (await db.execute(stmt)).scalars().first() async def _find_active_analysis_task( @@ -248,18 +238,11 @@ async def _find_active_analysis_task( relation_type: str, relation_entity_id: str, ) -> GenerationTask | None: - stmt = ( - select(GenerationTask) - .join(GenerationTaskLink, GenerationTaskLink.task_id == GenerationTask.id) - .where( - GenerationTaskLink.relation_type == relation_type, - GenerationTaskLink.relation_entity_id == relation_entity_id, - GenerationTask.status.in_(_ACTIVE_TASK_STATUSES), - ) - .order_by(GenerationTask.updated_at.desc(), GenerationTask.id.desc()) - .limit(1) + return await _find_active_task( + db, + relation_type=relation_type, + relation_entity_id=relation_entity_id, ) - return (await db.execute(stmt)).scalars().first() def pick_merge_relation_entity_id(*, chapter_id: str | None, project_id: str | None) -> str: diff --git a/backend/app/services/script_processing_worker.py b/backend/app/services/script_processing_worker.py index c06f7f3..a9d4f4e 100644 --- a/backend/app/services/script_processing_worker.py +++ b/backend/app/services/script_processing_worker.py @@ -39,6 +39,7 @@ from app.services.studio.shot_extracted_candidates import ( from app.services.studio.shot_extracted_dialogue_candidates import ( sync_from_extraction_draft_sync as sync_shot_extracted_dialogue_candidates_from_draft_sync, ) +from app.services.studio.shot_semantic_defaults import apply_shot_semantic_defaults_from_draft_sync from app.services.worker.task_executor import ( AbstractLLMResultGenerator, AbstractWorkerTaskExecutor, @@ -310,8 +311,11 @@ def apply_extraction_result( chapter_id: str, draft: Any, ) -> None: + """将提取草稿同步为候选与镜头语言默认值。""" + sync_shot_extracted_candidates_from_draft_sync(db, chapter_id=chapter_id, draft=draft) sync_shot_extracted_dialogue_candidates_from_draft_sync(db, chapter_id=chapter_id, draft=draft) + apply_shot_semantic_defaults_from_draft_sync(db, chapter_id=chapter_id, draft=draft) def run_divide_task_sync(task_id: str) -> None: diff --git a/backend/app/services/studio/action_beats.py b/backend/app/services/studio/action_beats.py new file mode 100644 index 0000000..05413cb --- /dev/null +++ b/backend/app/services/studio/action_beats.py @@ -0,0 +1,147 @@ +"""镜头动作拍点辅助服务。 + +该模块负责对 `ShotDetail.action_beats` 做轻量阶段推断,帮助关键帧与视频链 +在不引入复杂结构化模型的前提下,更稳定地区分: + +- trigger:触发 / 起始反应 +- peak:动作峰值 / 戏剧张力最高阶段 +- aftermath:结果态 / 收束阶段 +""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Literal + + +ActionBeatPhase = Literal["trigger", "peak", "aftermath"] + +_TRIGGER_KEYWORDS = ( + "听到", + "看到", + "看见", + "发现", + "察觉", + "突然", + "骤然", + "刚", + "开始", + "初次", + "异响", + "咔嚓", + "响起", + "推门", + "转头", + "回头", +) + +_AFTERMATH_KEYWORDS = ( + "呼吸急促", + "喘", + "余韵", + "停留", + "停住", + "站定", + "蹲着", + "倒在", + "保持", + "恢复", + "看向", + "余波", + "收束", +) + +_PEAK_KEYWORDS = ( + "脱手", + "下坠", + "落地", + "捂住", + "捂耳", + "蹲下", + "扑", + "冲", + "举起", + "挥", + "对峙", + "爆发", + "僵住", + "下沉", +) + + +@dataclass(frozen=True, slots=True) +class ActionBeatPhaseItem: + """单条动作拍点的阶段推断结果。""" + + text: str + phase: ActionBeatPhase + + +def _count_hits(text: str, keywords: tuple[str, ...]) -> int: + """统计一段文本中命中的阶段关键词数量。""" + return sum(1 for keyword in keywords if keyword in text) + + +def infer_action_beat_phase(*, text: str, index: int, total: int) -> ActionBeatPhase: + """为单条动作拍点推断阶段。 + + 规则优先级: + 1. 明显的 aftermath 关键词 + 2. 明显的 trigger 关键词 + 3. 明显的 peak 关键词 + 4. 按位置兜底: + - 首条默认 trigger + - 尾条默认 aftermath(总数 >= 3) + - 其余默认 peak + """ + + normalized = str(text or "").strip() + if not normalized: + return "peak" + + aftermath_hits = _count_hits(normalized, _AFTERMATH_KEYWORDS) + trigger_hits = _count_hits(normalized, _TRIGGER_KEYWORDS) + peak_hits = _count_hits(normalized, _PEAK_KEYWORDS) + + if aftermath_hits > 0 and aftermath_hits >= max(trigger_hits, peak_hits): + return "aftermath" + if trigger_hits > 0 and trigger_hits >= peak_hits: + return "trigger" + if peak_hits > 0: + return "peak" + + if index == 0: + return "trigger" + if total >= 3 and index == total - 1: + return "aftermath" + return "peak" + + +def infer_action_beat_sequence(action_beats: list[str] | None) -> list[ActionBeatPhaseItem]: + """将动作拍点列表转换为带阶段信息的序列。""" + beats = [str(item).strip() for item in list(action_beats or []) if str(item).strip()] + total = len(beats) + return [ + ActionBeatPhaseItem( + text=text, + phase=infer_action_beat_phase(text=text, index=index, total=total), + ) + for index, text in enumerate(beats) + ] + + +def pick_action_beat_for_frame(frame_type: str, action_beats: list[str] | None) -> ActionBeatPhaseItem | None: + """按帧类型挑选最适合作为当前帧主拍点的动作项。""" + sequence = infer_action_beat_sequence(action_beats) + if not sequence: + return None + + if frame_type == "first": + return next((item for item in sequence if item.phase == "trigger"), sequence[0]) + if frame_type == "last": + return next((item for item in sequence if item.phase == "aftermath"), sequence[-1]) + + peak_items = [item for item in sequence if item.phase == "peak"] + if peak_items: + return peak_items[-1] + return sequence[min(len(sequence) // 2, len(sequence) - 1)] diff --git a/backend/app/services/studio/generation/frame/build_base.py b/backend/app/services/studio/generation/frame/build_base.py index 402dd68..0f83825 100644 --- a/backend/app/services/studio/generation/frame/build_base.py +++ b/backend/app/services/studio/generation/frame/build_base.py @@ -11,6 +11,11 @@ class FrameBaseDraft(GenerationBaseDraft): shot_id: str frame_type: ShotFrameType prompt: str + director_command_summary: str = "" + continuity_guidance: str = "" + frame_specific_guidance: str = "" + composition_anchor: str = "" + screen_direction_guidance: str = "" def build_frame_base_draft( @@ -18,10 +23,20 @@ def build_frame_base_draft( shot_id: str, frame_type: ShotFrameType, prompt: str, + director_command_summary: str = "", + continuity_guidance: str = "", + frame_specific_guidance: str = "", + composition_anchor: str = "", + screen_direction_guidance: str = "", ) -> FrameBaseDraft: + """构造分镜帧基础草稿,并附带最终渲染阶段仍需保留的高优先级约束。""" return FrameBaseDraft( shot_id=shot_id, frame_type=frame_type, prompt=(prompt or "").strip(), + director_command_summary=(director_command_summary or "").strip(), + continuity_guidance=(continuity_guidance or "").strip(), + frame_specific_guidance=(frame_specific_guidance or "").strip(), + composition_anchor=(composition_anchor or "").strip(), + screen_direction_guidance=(screen_direction_guidance or "").strip(), ) - diff --git a/backend/app/services/studio/generation/frame/build_submission.py b/backend/app/services/studio/generation/frame/build_submission.py index 192ca13..56bf7e4 100644 --- a/backend/app/services/studio/generation/frame/build_submission.py +++ b/backend/app/services/studio/generation/frame/build_submission.py @@ -20,6 +20,10 @@ def build_frame_submission_payload( "render_context": { "base_prompt": derived.base_prompt, "rendered_prompt": derived.rendered_prompt, + "selected_guidance": derived.selected_guidance, + "dropped_guidance": derived.dropped_guidance, + "selected_guidance_details": [item.model_dump() for item in derived.selected_guidance_details], + "dropped_guidance_details": [item.model_dump() for item in derived.dropped_guidance_details], "images": derived.images, "mappings": [mapping.model_dump() for mapping in derived.mappings], } diff --git a/backend/app/services/studio/generation/frame/derive_preview.py b/backend/app/services/studio/generation/frame/derive_preview.py index d45a76f..986832e 100644 --- a/backend/app/services/studio/generation/frame/derive_preview.py +++ b/backend/app/services/studio/generation/frame/derive_preview.py @@ -1,6 +1,6 @@ from __future__ import annotations -from app.schemas.studio.shots import RenderedShotFramePromptRead, ShotFramePromptMappingRead +from app.schemas.studio.shots import FrameGuidanceDecisionRead, RenderedShotFramePromptRead, ShotFramePromptMappingRead from app.services.studio.generation.frame.build_base import FrameBaseDraft from app.services.studio.generation.frame.build_context import FrameGenerationContext from app.services.studio.generation.shared.types import GenerationDerivedPreview @@ -24,6 +24,265 @@ def replace_reference_names_in_prompt( return text +def _score_frame_guidance_line( + *, + frame_type: str, + category: str, + text: str, +) -> int: + """按帧类型和文本特征给图片 guidance 打分,控制最终 prompt 的收敛顺序。""" + score_by_category = { + "summary": 100, + "continuity": 80, + "frame": 70, + "screen": 65, + "composition": 60, + } + score = score_by_category.get(category, 0) + + if frame_type == "first" and category == "frame": + score += 18 + if frame_type == "first" and category == "composition": + score += 15 + if frame_type == "key" and category == "frame": + score += 6 + if frame_type == "last" and category == "frame": + score += 8 + if frame_type in {"key", "last"} and category == "screen": + score += 10 + if frame_type == "last" and category == "continuity": + score += 5 + + if category == "frame" and any(keyword in text for keyword in ("触发瞬间", "初始反应", "尚未完成", "动作峰值", "情绪余韵", "收束")): + score += 8 + if category == "screen" and any(keyword in text for keyword in ("视线", "对视", "左右", "朝向", "跳轴")): + score += 10 + if category == "composition" and any(keyword in text for keyword in ("空间", "重心", "环境", "锚点", "站位")): + score += 10 + if category == "continuity" and any(keyword in text for keyword in ("上一镜头", "下一镜头", "承接", "收束")): + score += 5 + + return score + + +def _build_frame_guidance_reason( + *, + frame_type: str, + category: str, + selected: bool, +) -> str: + """生成 guidance 被保留或压缩的可解释原因。""" + if selected: + if category == "frame": + if frame_type == "first": + return "当前是首帧,系统优先保留触发瞬间与未完成态约束,避免画面直接跳到后续完成动作。" + if frame_type == "key": + return "当前是关键帧,系统保留帧职责 guidance 来强化动作峰值或情绪爆点。" + if frame_type == "last": + return "当前是尾帧,系统保留帧职责 guidance 来强化动作收束与情绪落点。" + if frame_type == "first" and category == "composition": + return "当前是首帧,系统优先稳住空间建立与主体站位,所以保留构图锚点。" + if frame_type in {"key", "last"} and category == "screen": + return "当前镜头更看重视线与左右轴线稳定,因此优先保留朝向与视线 guidance。" + if category == "summary": + return "导演主指令始终属于最高优先级约束,因此会优先保留。" + if category == "continuity": + return "连续性 guidance 直接影响镜头承接稳定性,因此被保留。" + if category == "composition": + return "这条 guidance 对画面空间重心更关键,因此被保留。" + if category == "screen": + return "这条 guidance 对视线、朝向或轴线更关键,因此被保留。" + + if category == "frame": + if frame_type == "first": + return "当前已有更高优先级的首帧约束进入最终 prompt,因此这条帧职责 guidance 被压缩。" + if frame_type == "key": + return "当前已有更高优先级的关键帧约束进入最终 prompt,因此这条帧职责 guidance 被压缩。" + if frame_type == "last": + return "当前已有更高优先级的尾帧约束进入最终 prompt,因此这条帧职责 guidance 被压缩。" + if frame_type == "first" and category == "screen": + return "当前是首帧,系统更优先保空间建立与站位关系,因此将朝向与视线 guidance 降为次级。" + if frame_type in {"key", "last"} and category == "composition": + return "当前镜头更优先保视线与左右轴线稳定,因此构图锚点 guidance 被压缩。" + if category == "summary": + return "当前已有更高分的导演主指令进入最终 prompt,这条摘要未继续保留。" + if category == "continuity": + return "当前已有更高优先级的镜头约束进入最终 prompt,因此这条连续性 guidance 被压缩。" + if category == "composition": + return "当前已有更高优先级的空间或朝向约束进入最终 prompt,因此这条构图 guidance 被压缩。" + if category == "screen": + return "当前已有更高优先级的空间或连续性约束进入最终 prompt,因此这条朝向/视线 guidance 被压缩。" + return "当前已有更高优先级 guidance 进入最终 prompt,因此该条目未被保留。" + + +def _build_frame_guidance_reason_tag( + *, + frame_type: str, + category: str, + selected: bool, +) -> str: + """生成更适合前端快速阅读的短标签。""" + if category == "summary": + return "导演主指令" + if category == "frame": + if frame_type == "first": + return "首帧保时序" if selected else "首帧降时序" + if frame_type == "key": + return "关键帧保峰值" if selected else "关键帧降峰值" + if frame_type == "last": + return "尾帧保收束" if selected else "尾帧降收束" + if category == "continuity": + return "连续性优先" if selected else "连续性降级" + if frame_type == "first" and category == "composition": + return "首帧保空间" if selected else "首帧降构图" + if frame_type == "first" and category == "screen": + return "首帧降轴线" + if frame_type in {"key", "last"} and category == "screen": + return "关键帧保轴线" if frame_type == "key" and selected else ("尾帧保轴线" if selected else "轴线降级") + if frame_type in {"key", "last"} and category == "composition": + return "关键帧降构图" if frame_type == "key" else "尾帧降构图" + if category == "composition": + return "构图优先" if selected else "构图降级" + if category == "screen": + return "轴线优先" if selected else "轴线降级" + return "优先级调整" + + +def _collect_frame_guidance_lines( + *, + frame_type: str, + replaced_prompt: str, + director_command_summary: str, + continuity_guidance: str, + frame_specific_guidance: str, + composition_anchor: str, + screen_direction_guidance: str, +) -> tuple[list[str], list[str], list[FrameGuidanceDecisionRead], list[FrameGuidanceDecisionRead]]: + """收集最终保留与被压缩掉的 guidance,供渲染与前端展示共用。""" + text = (replaced_prompt or "").strip() + candidates: list[tuple[int, int, str, str]] = [] + normalized_summary = (director_command_summary or "").strip() + normalized_continuity = (continuity_guidance or "").strip() + normalized_frame = (frame_specific_guidance or "").strip() + normalized_composition = (composition_anchor or "").strip() + normalized_screen = (screen_direction_guidance or "").strip() + + if normalized_summary and normalized_summary not in text: + candidates.append( + ( + _score_frame_guidance_line(frame_type=frame_type, category="summary", text=normalized_summary), + 0, + "summary", + f"高优先级导演指令:{normalized_summary}", + ) + ) + if ( + normalized_continuity + and normalized_continuity not in text + and normalized_continuity not in normalized_summary + and "连续性要求:" not in text + ): + candidates.append( + ( + _score_frame_guidance_line(frame_type=frame_type, category="continuity", text=normalized_continuity), + 1, + "continuity", + f"连续性要求:{normalized_continuity}", + ) + ) + if ( + normalized_frame + and normalized_frame not in text + and normalized_frame not in normalized_summary + and "当前帧职责:" not in text + ): + candidates.append( + ( + _score_frame_guidance_line(frame_type=frame_type, category="frame", text=normalized_frame), + 2, + "frame", + f"当前帧职责:{normalized_frame}", + ) + ) + if ( + normalized_composition + and normalized_composition not in text + and "构图锚点:" not in text + ): + candidates.append( + ( + _score_frame_guidance_line(frame_type=frame_type, category="composition", text=normalized_composition), + 4, + "composition", + f"构图锚点:{normalized_composition}", + ) + ) + if ( + normalized_screen + and normalized_screen not in text + and "朝向与视线:" not in text + ): + candidates.append( + ( + _score_frame_guidance_line(frame_type=frame_type, category="screen", text=normalized_screen), + 3, + "screen", + f"朝向与视线:{normalized_screen}", + ) + ) + + ranked = sorted(candidates, key=lambda item: (-item[0], item[1])) + selected_rows = ranked[:3] + dropped_rows = ranked[3:] + selected = [line for _, _, _, line in selected_rows] + dropped = [line for _, _, _, line in dropped_rows] + selected_details = [ + FrameGuidanceDecisionRead( + text=line, + category=category, + reason_tag=_build_frame_guidance_reason_tag(frame_type=frame_type, category=category, selected=True), + reason=_build_frame_guidance_reason(frame_type=frame_type, category=category, selected=True), + ) + for _, _, category, line in selected_rows + ] + dropped_details = [ + FrameGuidanceDecisionRead( + text=line, + category=category, + reason_tag=_build_frame_guidance_reason_tag(frame_type=frame_type, category=category, selected=False), + reason=_build_frame_guidance_reason(frame_type=frame_type, category=category, selected=False), + ) + for _, _, category, line in dropped_rows + ] + return selected, dropped, selected_details, dropped_details + + +def enrich_frame_prompt_with_guidance( + *, + frame_type: str, + replaced_prompt: str, + director_command_summary: str, + continuity_guidance: str, + frame_specific_guidance: str, + composition_anchor: str, + screen_direction_guidance: str, +) -> str: + """将高优先级导演约束补入最终图片提示词,避免只停留在调试展示。""" + text = (replaced_prompt or "").strip() + guidance_lines, _, _, _ = _collect_frame_guidance_lines( + frame_type=frame_type, + replaced_prompt=text, + director_command_summary=director_command_summary, + continuity_guidance=continuity_guidance, + frame_specific_guidance=frame_specific_guidance, + composition_anchor=composition_anchor, + screen_direction_guidance=screen_direction_guidance, + ) + if not guidance_lines: + return text + return "\n".join([*guidance_lines, text]).strip() + + def compose_shot_frame_rendered_prompt( *, replaced_prompt: str, @@ -49,6 +308,10 @@ class FrameDerivedPreview(GenerationDerivedPreview): frame_type: str base_prompt: str rendered_prompt: str + selected_guidance: list[str] + dropped_guidance: list[str] + selected_guidance_details: list[FrameGuidanceDecisionRead] + dropped_guidance_details: list[FrameGuidanceDecisionRead] images: list[str] mappings: list[ShotFramePromptMappingRead] @@ -63,8 +326,26 @@ def derive_frame_preview( base_prompt=normalized_base_prompt, mappings=context.ordered_refs, ) - rendered_prompt = compose_shot_frame_rendered_prompt( + selected_guidance, dropped_guidance, selected_guidance_details, dropped_guidance_details = _collect_frame_guidance_lines( + frame_type=base.frame_type.value if hasattr(base.frame_type, "value") else str(base.frame_type), replaced_prompt=replaced_prompt, + director_command_summary=base.director_command_summary, + continuity_guidance=base.continuity_guidance, + frame_specific_guidance=base.frame_specific_guidance, + composition_anchor=base.composition_anchor, + screen_direction_guidance=base.screen_direction_guidance, + ) + enriched_prompt = enrich_frame_prompt_with_guidance( + frame_type=base.frame_type.value if hasattr(base.frame_type, "value") else str(base.frame_type), + replaced_prompt=replaced_prompt, + director_command_summary=base.director_command_summary, + continuity_guidance=base.continuity_guidance, + frame_specific_guidance=base.frame_specific_guidance, + composition_anchor=base.composition_anchor, + screen_direction_guidance=base.screen_direction_guidance, + ) + rendered_prompt = compose_shot_frame_rendered_prompt( + replaced_prompt=enriched_prompt, mappings=context.ordered_refs, ) return FrameDerivedPreview( @@ -72,6 +353,10 @@ def derive_frame_preview( frame_type=base.frame_type.value if hasattr(base.frame_type, "value") else str(base.frame_type), base_prompt=normalized_base_prompt, rendered_prompt=rendered_prompt, + selected_guidance=selected_guidance, + dropped_guidance=dropped_guidance, + selected_guidance_details=selected_guidance_details, + dropped_guidance_details=dropped_guidance_details, images=[mapping.file_id for mapping in context.ordered_refs], mappings=context.ordered_refs, ) @@ -84,7 +369,10 @@ def to_rendered_shot_frame_prompt_read( return RenderedShotFramePromptRead( base_prompt=derived.base_prompt, rendered_prompt=derived.rendered_prompt, + selected_guidance=derived.selected_guidance, + dropped_guidance=derived.dropped_guidance, + selected_guidance_details=derived.selected_guidance_details, + dropped_guidance_details=derived.dropped_guidance_details, images=derived.images, mappings=derived.mappings, ) - diff --git a/backend/app/services/studio/generation/video/derive_preview.py b/backend/app/services/studio/generation/video/derive_preview.py index fea0164..e57f6dc 100644 --- a/backend/app/services/studio/generation/video/derive_preview.py +++ b/backend/app/services/studio/generation/video/derive_preview.py @@ -10,6 +10,7 @@ from app.services.studio.shot_video_prompt_pack import ( _render_template, _resolve_video_prompt_template, build_shot_video_prompt_pack, + enrich_rendered_video_prompt, ) @@ -34,10 +35,14 @@ async def derive_video_preview( ) -> VideoDerivedPreview: pack = await build_shot_video_prompt_pack(db, shot_id=base.shot_id) if base.prompt: + rendered_prompt = enrich_rendered_video_prompt( + rendered_prompt=base.prompt, + pack=pack, + ) return VideoDerivedPreview( shot_id=base.shot_id, reference_mode=context.reference_mode, - rendered_prompt=base.prompt, + rendered_prompt=rendered_prompt, images=context.images, pack=pack, template_id=context.template_id, @@ -55,6 +60,11 @@ async def derive_video_preview( if not rendered_prompt: warnings.append("视频提示词模板渲染结果为空,已使用系统默认拼装提示词") rendered_prompt = _fallback_video_prompt(pack) + else: + rendered_prompt = enrich_rendered_video_prompt( + rendered_prompt=rendered_prompt, + pack=pack, + ) return VideoDerivedPreview( shot_id=base.shot_id, diff --git a/backend/app/services/studio/shot_extraction_draft.py b/backend/app/services/studio/shot_extraction_draft.py index 7b99ae3..270c0cc 100644 --- a/backend/app/services/studio/shot_extraction_draft.py +++ b/backend/app/services/studio/shot_extraction_draft.py @@ -33,6 +33,7 @@ from app.models.studio import ( from app.services.common import entity_not_found from app.services.studio.entity_thumbnails import resolve_thumbnail_infos from app.schemas.skills.script_processing import ( + ShotSemanticSuggestion, StudioAssetDraft, StudioCharacterDraft, StudioScriptExtractionDraft, @@ -364,6 +365,14 @@ async def build_script_extraction_draft_for_shot(db: AsyncSession, shot_id: str) costume_names=costume_names_shot, dialogue_lines=dialogue_lines, actions=actions, + semantic_suggestion=ShotSemanticSuggestion( + camera_shot=getattr(detail, "camera_shot", None) if detail is not None else None, + angle=getattr(detail, "angle", None) if detail is not None else None, + movement=getattr(detail, "movement", None) if detail is not None else None, + duration=getattr(detail, "duration", None) if detail is not None else None, + action_beats=list(getattr(detail, "action_beats", []) or []) if detail is not None else [], + notes=None, + ), ) return StudioScriptExtractionDraft( diff --git a/backend/app/services/studio/shot_preparation_state.py b/backend/app/services/studio/shot_preparation_state.py index 4b259ac..45c70cf 100644 --- a/backend/app/services/studio/shot_preparation_state.py +++ b/backend/app/services/studio/shot_preparation_state.py @@ -7,12 +7,15 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.schemas.studio.cast import ShotCharacterLinkCreate from app.schemas.studio.shots import ProjectAssetLinkCreate from app.schemas.studio.shots import ( + ActionBeatPhaseRead, ShotDialogLineRead, ShotExtractedDialogueCandidateRead, ShotPreparationLinkEntityType, ShotPreparationStateRead, ) +from app.services.studio.action_beats import infer_action_beat_sequence from app.services.studio.shot_assets import create_project_asset_link +from app.services.studio.shot_details import get as get_shot_detail from app.services.studio.shot_character_links import list_by_shot as list_shot_character_links, upsert as upsert_shot_character_link from app.services.studio.shot_assets_overview import get_shot_assets_overview from app.services.studio.shot_dialogs import list_by_shot as list_saved_dialog_lines_by_shot @@ -28,6 +31,7 @@ async def build_shot_preparation_state( """组装分镜准备页所需的统一聚合状态。""" shot = await get_shot(db, shot_id=shot_id) shot_read = await build_shot_read(db, shot=shot) + detail = await get_shot_detail(db, shot_id=shot_id) assets_overview = await get_shot_assets_overview(db, shot_id=shot_id) dialogue_candidates = [ ShotExtractedDialogueCandidateRead.model_validate(row) @@ -41,13 +45,31 @@ async def build_shot_preparation_state( int(assets_overview.summary.pending_count or 0) + int(shot_read.extraction.pending_dialogue_count or 0) ) - ready_for_generation = shot_read.status.value == "ready" + basic_info_ready = bool((shot_read.title or "").strip()) and bool((shot_read.script_excerpt or "").strip()) + semantic_defaults_ready = bool(detail.camera_shot) and bool(detail.angle) and bool(detail.movement) and int(detail.duration or 0) > 0 + action_beats_count = len([item for item in (detail.action_beats or []) if (item or "").strip()]) + action_beats_ready = action_beats_count > 0 + action_beat_phases = [ + ActionBeatPhaseRead(text=item.text, phase=item.phase) + for item in infer_action_beat_sequence(detail.action_beats) + ] + ready_for_generation = ( + shot_read.status.value == "ready" + and basic_info_ready + and semantic_defaults_ready + and action_beats_ready + ) return ShotPreparationStateRead( shot=shot_read, assets_overview=assets_overview, dialogue_candidates=dialogue_candidates, saved_dialogue_lines=saved_dialogue_lines, pending_confirm_count=pending_confirm_count, + basic_info_ready=basic_info_ready, + semantic_defaults_ready=semantic_defaults_ready, + action_beats_ready=action_beats_ready, + action_beats_count=action_beats_count, + action_beat_phases=action_beat_phases, ready_for_generation=ready_for_generation, ) diff --git a/backend/app/services/studio/shot_semantic_defaults.py b/backend/app/services/studio/shot_semantic_defaults.py new file mode 100644 index 0000000..5fcf4b6 --- /dev/null +++ b/backend/app/services/studio/shot_semantic_defaults.py @@ -0,0 +1,124 @@ +"""将提取草稿中的镜头语言默认建议回写到 ShotDetail。""" + +from __future__ import annotations + +from typing import Any + +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy.orm import Session + +from app.models.studio import CameraAngle, CameraMovement, CameraShotType, Shot, ShotDetail + + +def _get_value(obj: Any, key: str) -> Any: + """兼容 dict / Pydantic model / 普通对象的字段读取。""" + + if isinstance(obj, dict): + return obj.get(key) + return getattr(obj, key, None) + + +def _coerce_enum(enum_cls: type, value: Any) -> Any: + """将提取结果里的字符串安全转换为枚举;非法值直接忽略。""" + + if value in (None, ""): + return None + if isinstance(value, enum_cls): + return value + try: + return enum_cls(value) + except Exception: + return None + + +def _coerce_duration(value: Any) -> int | None: + """将提取结果里的时长安全转换为正整数秒数。""" + + if value in (None, ""): + return None + try: + duration = int(value) + except Exception: + return None + return duration if duration > 0 else None + + +def _apply_detail_defaults_from_shot_draft(detail: ShotDetail, shot_draft: Any) -> None: + """将单镜提取草稿中的默认镜头语言写入到现有 ShotDetail。""" + + semantic = _get_value(shot_draft, "semantic_suggestion") + source = semantic or shot_draft + + camera_shot = _coerce_enum(CameraShotType, _get_value(source, "camera_shot")) + angle = _coerce_enum(CameraAngle, _get_value(source, "angle")) + movement = _coerce_enum(CameraMovement, _get_value(source, "movement")) + duration = _coerce_duration(_get_value(source, "duration")) + action_beats = [ + str(item).strip() + for item in list(_get_value(source, "action_beats") or []) + if str(item).strip() + ] + + if camera_shot is not None: + detail.camera_shot = camera_shot + if angle is not None: + detail.angle = angle + if movement is not None: + detail.movement = movement + if duration is not None: + detail.duration = duration + if action_beats: + detail.action_beats = action_beats + + +async def apply_shot_semantic_defaults_from_draft( + db: AsyncSession, + *, + chapter_id: str, + draft: Any, +) -> None: + """按镜头序号匹配草稿,并将镜头语言默认建议回写到 ShotDetail。""" + + shot_rows = ( + await db.execute( + select(Shot.id, Shot.index).where(Shot.chapter_id == chapter_id) + ) + ).all() + shot_id_by_index = {int(row.index): str(row.id) for row in shot_rows} + + for shot_draft in list(_get_value(draft, "shots") or []): + shot_index = _coerce_duration(_get_value(shot_draft, "index")) + if shot_index is None: + continue + shot_id = shot_id_by_index.get(shot_index) + if not shot_id: + continue + detail = await db.get(ShotDetail, shot_id) + if detail is None: + continue + _apply_detail_defaults_from_shot_draft(detail, shot_draft) + + +def apply_shot_semantic_defaults_from_draft_sync( + db: Session, + *, + chapter_id: str, + draft: Any, +) -> None: + """同步任务执行器版本:将镜头语言默认建议回写到 ShotDetail。""" + + shot_rows = db.execute(select(Shot.id, Shot.index).where(Shot.chapter_id == chapter_id)).all() + shot_id_by_index = {int(row.index): str(row.id) for row in shot_rows} + + for shot_draft in list(_get_value(draft, "shots") or []): + shot_index = _coerce_duration(_get_value(shot_draft, "index")) + if shot_index is None: + continue + shot_id = shot_id_by_index.get(shot_index) + if not shot_id: + continue + detail = db.get(ShotDetail, shot_id) + if detail is None: + continue + _apply_detail_defaults_from_shot_draft(detail, shot_draft) diff --git a/backend/app/services/studio/shot_video_prompt_pack.py b/backend/app/services/studio/shot_video_prompt_pack.py index 37ee84e..b7e483c 100644 --- a/backend/app/services/studio/shot_video_prompt_pack.py +++ b/backend/app/services/studio/shot_video_prompt_pack.py @@ -11,6 +11,7 @@ from __future__ import annotations from typing import Any +import re from fastapi import HTTPException, status from langchain_core.prompts import PromptTemplate as LcPromptTemplate @@ -20,11 +21,13 @@ from sqlalchemy.orm import selectinload from app.models.studio import Chapter, PromptCategory, PromptTemplate, Shot, ShotDetail from app.schemas.studio.shots import ( + ActionBeatPhaseRead, ShotPromptAssetRef, ShotPromptCameraInfo, ShotVideoPromptPackRead, ) from app.services.common import entity_not_found +from app.services.studio.action_beats import infer_action_beat_sequence from app.services.studio.shot_assets_overview import get_shot_assets_overview @@ -64,6 +67,12 @@ def _pack_variables(pack: ShotVideoPromptPackRead) -> dict[str, Any]: "title": pack.title, "script_excerpt": pack.script_excerpt, "action_beats": "\n".join(pack.action_beats), + "action_beats_text": ";".join(pack.action_beats), + "previous_shot_summary": pack.previous_shot_summary, + "next_shot_goal": pack.next_shot_goal, + "continuity_guidance": pack.continuity_guidance, + "composition_anchor": pack.composition_anchor, + "screen_direction_guidance": pack.screen_direction_guidance, "dialogue_summary": pack.dialogue_summary, "characters": pack.characters, "character_names": "、".join(item.name for item in pack.characters), @@ -91,12 +100,247 @@ def _render_template(content: str, variables: dict[str, Any]) -> str: return template.format(**render_vars).strip() +def _build_guidance_suffix(pack: ShotVideoPromptPackRead) -> str: + """生成一段稳定的镜头执行约束,供模板渲染结果补强使用。""" + lines: list[str] = [] + if pack.action_beats: + lines.append(f"动作节拍:{';'.join(pack.action_beats)}") + if pack.previous_shot_summary: + lines.append(f"上一镜头承接:{pack.previous_shot_summary}") + if pack.next_shot_goal: + lines.append(f"下一镜头目标:{pack.next_shot_goal}") + if pack.continuity_guidance: + lines.append(f"连续性要求:{pack.continuity_guidance}") + if pack.composition_anchor: + lines.append(f"构图锚点:{pack.composition_anchor}") + if pack.screen_direction_guidance: + lines.append(f"朝向与视线:{pack.screen_direction_guidance}") + return "\n".join(lines).strip() + + +def enrich_rendered_video_prompt( + *, + rendered_prompt: str, + pack: ShotVideoPromptPackRead, +) -> str: + """为模板渲染结果补强关键执行约束。 + + 若模板未显式消费新的连续性/构图变量,则自动在末尾追加一段稳定约束, + 避免这类信息只停留在 preview pack 中却没有真正进入最终 prompt。 + """ + text = str(rendered_prompt or "").strip() + suffix = _build_guidance_suffix(pack) + if not suffix: + return text + + normalized = text.replace(" ", "") + if any( + marker in normalized + for marker in ( + "动作节拍:", + "上一镜头承接:", + "连续性要求:", + "构图锚点:", + "朝向与视线:", + ) + ): + return text + + if not text: + return suffix + return f"{text}\n\n{suffix}".strip() + + +def _split_beats(*values: str) -> list[str]: + """按常见中文断句规则拆分为动作节拍候选。""" + parts: list[str] = [] + for value in values: + text = str(value or "").strip() + if not text: + continue + for piece in re.split(r"[。!?;\n]+", text): + item = piece.strip(",,、 ").strip() + if len(item) >= 4: + parts.append(item) + return parts + + +def _dedupe_keep_order(items: list[str], *, limit: int = 4) -> list[str]: + seen: set[str] = set() + result: list[str] = [] + for item in items: + normalized = item.strip() + if not normalized or normalized in seen: + continue + seen.add(normalized) + result.append(normalized) + if len(result) >= limit: + break + return result + + +def _build_action_beats( + *, + confirmed_action_beats: list[str] | None, + script_excerpt: str, + shot_description: str, + dialogue_summary: str, +) -> list[str]: + """从剧本摘录、镜头描述与对白中提炼镜头内动作节拍。""" + confirmed = _dedupe_keep_order(list(confirmed_action_beats or []), limit=4) + if confirmed: + return confirmed + beat_candidates = _split_beats(shot_description, script_excerpt) + dialogue_candidates = [ + f"对白推进:{item}" + for item in _split_beats(dialogue_summary) + if len(item) <= 24 + ] + return _dedupe_keep_order(beat_candidates + dialogue_candidates, limit=4) + + +def _build_neighbor_prompt_summary(shot: Shot | None) -> tuple[str, str]: + """生成相邻镜头摘要与承接目标。""" + if shot is None: + return "", "" + detail = getattr(shot, "detail", None) + scene_name = str(getattr(getattr(detail, "scene", None), "name", "") or "").strip() + shot_description = str(getattr(detail, "description", "") or "").strip() + camera_parts = [ + _enum_value(getattr(detail, "camera_shot", None)), + _enum_value(getattr(detail, "angle", None)), + _enum_value(getattr(detail, "movement", None)), + ] + summary_parts = [ + f"标题:{str(shot.title or '').strip()}" if str(shot.title or '').strip() else "", + f"场景:{scene_name}" if scene_name else "", + f"镜头语言:{' / '.join(part for part in camera_parts if part)}" if any(camera_parts) else "", + f"画面状态:{shot_description}" if shot_description else "", + f"剧本摘录:{str(shot.script_excerpt or '').strip()}" if str(shot.script_excerpt or '').strip() else "", + ] + compact = ";".join(part for part in summary_parts if part) + goal_parts = [ + f"标题:{str(shot.title or '').strip()}" if str(shot.title or '').strip() else "", + shot_description or str(shot.script_excerpt or "").strip(), + ] + goal = ";".join(part for part in goal_parts if part) + return compact, goal + + +def _build_continuity_guidance( + *, + current_shot: Shot, + previous_shot: Shot | None, + next_shot: Shot | None, +) -> str: + """构造视频提示词的连续性建议。""" + detail = getattr(current_shot, "detail", None) + current_scene_id = str(getattr(detail, "scene_id", "") or "") + tips: list[str] = [] + if previous_shot is not None: + tips.append("承接上一镜头的动作、视线或情绪,不要像新场景重新开局") + previous_detail = getattr(previous_shot, "detail", None) + previous_scene_id = str(getattr(previous_detail, "scene_id", "") or "") + if current_scene_id and previous_scene_id and current_scene_id == previous_scene_id: + tips.append("与上一镜头同场景时保持空间轴线和人物朝向稳定") + if next_shot is not None: + tips.append("在本镜头结尾形成自然收束,为下一镜头留出动作或情绪落点") + next_detail = getattr(next_shot, "detail", None) + next_scene_id = str(getattr(next_detail, "scene_id", "") or "") + if current_scene_id and next_scene_id and current_scene_id == next_scene_id: + tips.append("与下一镜头同场景时保持视觉重心连续,避免突兀跳轴") + return ";".join(tips) + + +def _build_composition_anchor( + *, + shot: Shot, + previous_shot: Shot | None, + next_shot: Shot | None, + scene_name: str, + character_names: list[str], +) -> str: + """为视频提示词构造稳定的画面构图与空间锚点建议。""" + detail = getattr(shot, "detail", None) + camera_shot = _enum_value(getattr(detail, "camera_shot", None)) + movement = _enum_value(getattr(detail, "movement", None)) + anchors: list[str] = [] + + if camera_shot in {"ECU", "CU"}: + anchors.append("以人物表情或关键动作细节作为画面重心,环境只保留必要轮廓") + elif camera_shot in {"MS", "FS"}: + anchors.append("保持人物与环境的相对位置可读,避免主体漂在空场中") + else: + anchors.append("先建立环境纵深和主体站位,再推进动作表现") + + if movement in {"DOLLY_IN", "ZOOM_IN"}: + anchors.append("镜头重心应逐步向主体收束,形成推进感") + elif movement in {"DOLLY_OUT", "ZOOM_OUT"}: + anchors.append("镜头重心可从主体退向环境,强调空间扩展") + elif movement == "STATIC": + anchors.append("保持主体在画面中的位置稳定,避免重心突然跳变") + + if scene_name: + anchors.append(f"以场景 {scene_name} 作为主要空间锚点") + if character_names: + anchors.append(f"锁定角色 {'、'.join(character_names[:2])} 的朝向与视线逻辑") + + current_scene_id = str(getattr(detail, "scene_id", "") or "") + previous_scene_id = str(getattr(getattr(previous_shot, "detail", None), "scene_id", "") or "") + next_scene_id = str(getattr(getattr(next_shot, "detail", None), "scene_id", "") or "") + if previous_shot is not None and current_scene_id and current_scene_id == previous_scene_id: + anchors.append("与上一镜头同场景时,延续既有空间轴线和视觉方向") + if next_shot is not None and current_scene_id and current_scene_id == next_scene_id: + anchors.append("与下一镜头同场景时,保留可自然衔接的视觉落点") + + return ";".join(anchors) + + +def _build_screen_direction_guidance( + *, + shot: Shot, + previous_shot: Shot | None, + next_shot: Shot | None, + dialogue_summary: str, + character_names: list[str], +) -> str: + """构造视频镜头的人物朝向、视线与左右轴线建议。""" + detail = getattr(shot, "detail", None) + angle = _enum_value(getattr(detail, "angle", None)) + guidance: list[str] = [] + + if angle == "OVER_SHOULDER": + guidance.append("保持过肩镜头的前景肩部位置稳定,不要无故交换左右关系") + elif angle == "EYE_LEVEL": + guidance.append("保持人物平视方向和视线落点连续,避免镜头间突然翻面") + else: + guidance.append("明确人物朝向与视线落点,避免跳轴和朝向突变") + + if dialogue_summary.strip(): + guidance.append("对白驱动镜头应优先保持说话者与受话者的对视逻辑") + if len(character_names) >= 2: + guidance.append(f"角色 {character_names[0]} 与 {character_names[1]} 的左右站位和对视方向应保持稳定") + elif character_names: + guidance.append(f"角色 {character_names[0]} 的视线方向应在相邻镜头中保持延续") + + current_scene_id = str(getattr(detail, "scene_id", "") or "") + previous_scene_id = str(getattr(getattr(previous_shot, "detail", None), "scene_id", "") or "") + next_scene_id = str(getattr(getattr(next_shot, "detail", None), "scene_id", "") or "") + if previous_shot is not None and current_scene_id and current_scene_id == previous_scene_id: + guidance.append("与上一镜头同场景时,不要无故翻转人物左右面向") + if next_shot is not None and current_scene_id and current_scene_id == next_scene_id: + guidance.append("与下一镜头同场景时,为后续镜头保留可延续的视线方向") + + return ";".join(guidance) + + def _fallback_video_prompt(pack: ShotVideoPromptPackRead) -> str: style_text = ",".join(x for x in [pack.visual_style, pack.style] if x) camera_text = " / ".join(x for x in [pack.camera.camera_shot, pack.camera.angle, pack.camera.movement] if x) parts = [ f"镜头标题:{pack.title}", f"剧本摘录:{pack.script_excerpt}", + f"动作节拍:{';'.join(pack.action_beats)}" if pack.action_beats else "", f"画面风格:{style_text}", f"镜头语言:{camera_text}", f"时长:{pack.camera.duration} 秒" if pack.camera.duration else "", @@ -105,6 +349,11 @@ def _fallback_video_prompt(pack: ShotVideoPromptPackRead) -> str: f"道具:{'、'.join(item.name for item in pack.props)}", f"服装:{'、'.join(item.name for item in pack.costumes)}", f"对白摘要:{pack.dialogue_summary}", + f"上一镜头:{pack.previous_shot_summary}" if pack.previous_shot_summary else "", + f"下一镜头目标:{pack.next_shot_goal}" if pack.next_shot_goal else "", + f"连续性要求:{pack.continuity_guidance}" if pack.continuity_guidance else "", + f"构图锚点:{pack.composition_anchor}" if pack.composition_anchor else "", + f"朝向与视线:{pack.screen_direction_guidance}" if pack.screen_direction_guidance else "", f"氛围:{pack.atmosphere}", f"负面约束:{pack.negative_prompt}", ] @@ -153,6 +402,17 @@ async def build_shot_video_prompt_pack( detail = shot.detail project = getattr(getattr(shot, "chapter", None), "project", None) overview = await get_shot_assets_overview(db, shot_id=shot_id) + neighbors_stmt = ( + select(Shot) + .options(selectinload(Shot.detail).selectinload(ShotDetail.scene)) + .where( + Shot.chapter_id == shot.chapter_id, + Shot.index.in_([shot.index - 1, shot.index + 1]), + ) + ) + neighbor_rows = (await db.execute(neighbors_stmt)).scalars().all() + previous_shot = next((item for item in neighbor_rows if item.index == shot.index - 1), None) + next_shot = next((item for item in neighbor_rows if item.index == shot.index + 1), None) characters: list[ShotPromptAssetRef] = [] props: list[ShotPromptAssetRef] = [] @@ -177,12 +437,45 @@ async def build_shot_video_prompt_pack( for line in sorted(dialog_lines, key=lambda x: (x.index, x.id)) if line.text ) + previous_shot_summary, _ = _build_neighbor_prompt_summary(previous_shot) + _, next_shot_goal = _build_neighbor_prompt_summary(next_shot) + action_beats = _build_action_beats( + confirmed_action_beats=list(getattr(detail, "action_beats", []) or []), + script_excerpt=shot.script_excerpt or "", + shot_description=str(getattr(detail, "description", "") or ""), + dialogue_summary=dialogue_summary, + ) return ShotVideoPromptPackRead( shot_id=shot.id, title=shot.title or "", script_excerpt=shot.script_excerpt or "", - action_beats=[], + action_beats=action_beats, + action_beat_phases=[ + ActionBeatPhaseRead(text=item.text, phase=item.phase) + for item in infer_action_beat_sequence(action_beats) + ], + previous_shot_summary=previous_shot_summary, + next_shot_goal=next_shot_goal, + continuity_guidance=_build_continuity_guidance( + current_shot=shot, + previous_shot=previous_shot, + next_shot=next_shot, + ), + composition_anchor=_build_composition_anchor( + shot=shot, + previous_shot=previous_shot, + next_shot=next_shot, + scene_name=scene.name if scene else "", + character_names=[item.name for item in characters], + ), + screen_direction_guidance=_build_screen_direction_guidance( + shot=shot, + previous_shot=previous_shot, + next_shot=next_shot, + dialogue_summary=dialogue_summary, + character_names=[item.name for item in characters], + ), dialogue_summary=dialogue_summary, characters=characters, scene=scene, diff --git a/backend/sql/008-add-shot-action-beats.sql b/backend/sql/008-add-shot-action-beats.sql new file mode 100644 index 0000000..ce9e4bd --- /dev/null +++ b/backend/sql/008-add-shot-action-beats.sql @@ -0,0 +1,43 @@ +SET @has_shot_details_action_beats = ( + SELECT COUNT(*) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'shot_details' + AND COLUMN_NAME = 'action_beats' +); + +SET @add_shot_details_action_beats = IF( + @has_shot_details_action_beats = 0, + "ALTER TABLE shot_details ADD COLUMN action_beats JSON NULL COMMENT '镜头动作拍点(按时间顺序排列,用于关键帧与视频生成)'", + 'SELECT 1' +); +PREPARE stmt_add_shot_details_action_beats FROM @add_shot_details_action_beats; +EXECUTE stmt_add_shot_details_action_beats; +DEALLOCATE PREPARE stmt_add_shot_details_action_beats; + +SET @backfill_shot_details_action_beats = IF( + @has_shot_details_action_beats = 0, + "UPDATE shot_details SET action_beats = JSON_ARRAY() WHERE action_beats IS NULL", + 'SELECT 1' +); +PREPARE stmt_backfill_shot_details_action_beats FROM @backfill_shot_details_action_beats; +EXECUTE stmt_backfill_shot_details_action_beats; +DEALLOCATE PREPARE stmt_backfill_shot_details_action_beats; + +SET @normalize_shot_details_action_beats = ( + SELECT COUNT(*) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'shot_details' + AND COLUMN_NAME = 'action_beats' + AND IS_NULLABLE = 'YES' +); + +SET @alter_shot_details_action_beats = IF( + @normalize_shot_details_action_beats > 0, + "ALTER TABLE shot_details MODIFY COLUMN action_beats JSON NOT NULL COMMENT '镜头动作拍点(按时间顺序排列,用于关键帧与视频生成)'", + 'SELECT 1' +); +PREPARE stmt_alter_shot_details_action_beats FROM @alter_shot_details_action_beats; +EXECUTE stmt_alter_shot_details_action_beats; +DEALLOCATE PREPARE stmt_alter_shot_details_action_beats; diff --git a/backend/tests/test_generated_video_api_responses.py b/backend/tests/test_generated_video_api_responses.py index 74cd76b..290fdae 100644 --- a/backend/tests/test_generated_video_api_responses.py +++ b/backend/tests/test_generated_video_api_responses.py @@ -53,7 +53,31 @@ def test_preview_video_generation_prompt_returns_success_envelope(client: TestCl db = _FakeDB() async def _fake_preview(*_args, **_kwargs): - return "视频预览提示词", ["file-1", "file-2"], object() + return "视频预览提示词", ["file-1", "file-2"], { + "shot_id": "shot-1", + "title": "镜头一", + "script_excerpt": "主角转身看向门口。", + "action_beats": ["主角转身", "视线停在门口"], + "action_beat_phases": [ + {"text": "主角转身", "phase": "trigger"}, + {"text": "视线停在门口", "phase": "aftermath"}, + ], + "previous_shot_summary": "标题:镜头零;剧本摘录:主角推门进入走廊", + "next_shot_goal": "标题:镜头二;主角停住动作,保持警惕", + "continuity_guidance": "承接上一镜头动作,不要像全新场面重新开局", + "composition_anchor": "以走廊门口作为空间锚点", + "screen_direction_guidance": "保持主角朝向和视线落点连续", + "dialogue_summary": "", + "characters": [], + "scene": None, + "props": [], + "costumes": [], + "camera": {"camera_shot": "MS", "angle": "EYE_LEVEL", "movement": "STATIC", "duration": 4}, + "atmosphere": "紧张", + "visual_style": "现实", + "style": "真人都市", + "negative_prompt": "", + } monkeypatch.setattr(route, "preview_prompt_and_images", _fake_preview) app.dependency_overrides[get_db] = _override_db(db) @@ -77,6 +101,8 @@ def test_preview_video_generation_prompt_returns_success_envelope(client: TestCl assert body["message"] == "success" assert body["data"]["prompt"] == "视频预览提示词" assert body["data"]["images"] == ["file-1", "file-2"] + assert body["data"]["pack"]["previous_shot_summary"].startswith("标题:镜头零") + assert body["data"]["pack"]["next_shot_goal"].startswith("标题:镜头二") def test_preview_video_generation_prompt_not_found_returns_api_response( diff --git a/backend/tests/test_generated_video_service.py b/backend/tests/test_generated_video_service.py index df5705e..24cedbc 100644 --- a/backend/tests/test_generated_video_service.py +++ b/backend/tests/test_generated_video_service.py @@ -30,6 +30,9 @@ from app.services.film.generated_video import ( ) from app.bootstrap import bootstrap_all_registries from app.services.llm import resolve_provider_key_from_name +from app.services.studio.generation.video.derive_preview import derive_video_preview +from app.services.studio.generation.video.build_base import VideoBaseDraft +from app.services.studio.generation.video.build_context import VideoGenerationContext from app.services.studio import get_shot_video_readiness @@ -50,7 +53,17 @@ async def _seed_shot_graph(db: AsyncSession) -> None: visual_style=ProjectVisualStyle.live_action, ) chapter = Chapter(id="c1", project_id="p1", index=1, title="第一章") + prev_shot = Shot(id="s0", chapter_id="c1", index=0, title="镜头零", script_excerpt="角色沿着墙边逼近门口。") shot = Shot(id="s1", chapter_id="c1", index=1, title="镜头一", script_excerpt="角色推门而入。") + next_shot = Shot(id="s2", chapter_id="c1", index=2, title="镜头二", script_excerpt="角色停下脚步,盯向走廊尽头。") + prev_detail = ShotDetail( + id="s0", + camera_shot=CameraShotType.ms, + angle=CameraAngle.eye_level, + movement=CameraMovement.dolly_in, + duration=4, + description="主角贴墙缓慢逼近门口,视线紧盯前方。", + ) detail = ShotDetail( id="s1", camera_shot=CameraShotType.ms, @@ -59,11 +72,20 @@ async def _seed_shot_graph(db: AsyncSession) -> None: duration=6, follow_atmosphere=True, vfx_type=VFXType.none, + description="角色推门后微微停顿,确认走廊内部情况,再向前迈出一步。", first_frame_prompt="首帧提示词", last_frame_prompt="尾帧提示词", key_frame_prompt="关键帧提示词", ) - db.add_all([project, chapter, shot, detail]) + next_detail = ShotDetail( + id="s2", + camera_shot=CameraShotType.cu, + angle=CameraAngle.eye_level, + movement=CameraMovement.static, + duration=3, + description="角色停住动作,盯向走廊尽头,情绪绷紧。", + ) + db.add_all([project, chapter, prev_shot, shot, next_shot, prev_detail, detail, next_detail]) await db.commit() @@ -114,7 +136,7 @@ async def test_preview_prompt_and_images_uses_auto_frame_ids() -> None: ) await db.commit() - prompt, images, detail = await preview_prompt_and_images( + prompt, images, pack = await preview_prompt_and_images( db, shot_id="s1", reference_mode="first_last", @@ -123,8 +145,17 @@ async def test_preview_prompt_and_images_uses_auto_frame_ids() -> None: assert "镜头标题:镜头一" in prompt assert "剧本摘录:角色推门而入。" in prompt + assert "动作节拍:" in prompt + assert "上一镜头:" in prompt + assert "下一镜头目标:" in prompt + assert "构图锚点:" in prompt + assert "朝向与视线:" in prompt assert images == ["f1", "f2"] - assert detail.duration == 6 + assert pack is not None + assert pack["camera"]["duration"] == 6 + assert pack["action_beats"] + assert "镜头零" in pack["previous_shot_summary"] + assert "镜头二" in pack["next_shot_goal"] await engine.dispose() @@ -133,7 +164,7 @@ async def test_preview_prompt_and_images_prefers_request_images_when_provided() db, engine = await _build_session() async with db: await _seed_shot_graph(db) - prompt, images, detail = await preview_prompt_and_images( + prompt, images, pack = await preview_prompt_and_images( db, shot_id="s1", reference_mode="first_last", @@ -141,9 +172,12 @@ async def test_preview_prompt_and_images_prefers_request_images_when_provided() images=["manual-first", "manual-last"], ) - assert prompt == "自定义视频提示词" + assert "自定义视频提示词" in prompt + assert "动作节拍:" in prompt + assert "连续性要求:" in prompt assert images == ["manual-first", "manual-last"] - assert detail.duration == 6 + assert pack is not None + assert pack["camera"]["duration"] == 6 await engine.dispose() @@ -215,8 +249,109 @@ async def test_build_run_args_uses_prompt_pack_when_prompt_missing(monkeypatch: ) assert "镜头标题:镜头一" in run_args["input"]["prompt"] + assert "动作节拍:" in run_args["input"]["prompt"] assert run_args["input"]["ratio"] == "16:9" assert run_args["prompt_preview"]["shot_id"] == "s1" + assert run_args["prompt_preview"]["pack"]["action_beats"] + assert "镜头零" in run_args["prompt_preview"]["pack"]["previous_shot_summary"] + assert "镜头二" in run_args["prompt_preview"]["pack"]["next_shot_goal"] + assert run_args["prompt_preview"]["pack"]["composition_anchor"] + assert run_args["prompt_preview"]["pack"]["screen_direction_guidance"] + await engine.dispose() + + +@pytest.mark.asyncio +async def test_template_render_is_enriched_with_guidance_when_template_omits_it(monkeypatch: pytest.MonkeyPatch) -> None: + db, engine = await _build_session() + async with db: + await _seed_shot_graph(db) + + async def _fake_template(*_args, **_kwargs): + return type("Template", (), {"id": "tpl-1", "name": "simple", "content": "镜头标题:{{ title }}"})() + + monkeypatch.setattr( + "app.services.studio.generation.video.derive_preview._resolve_video_prompt_template", + _fake_template, + ) + + derived = await derive_video_preview( + db, + base=VideoBaseDraft(shot_id="s1", prompt=""), + context=VideoGenerationContext( + shot_id="s1", + reference_mode="text_only", + images=[], + template_id=None, + ), + ) + + assert "镜头标题:镜头一" in derived.rendered_prompt + assert "动作节拍:" in derived.rendered_prompt + assert "连续性要求:" in derived.rendered_prompt + assert "构图锚点:" in derived.rendered_prompt + assert "朝向与视线:" in derived.rendered_prompt + await engine.dispose() + + +@pytest.mark.asyncio +async def test_manual_video_prompt_is_also_enriched_with_guidance() -> None: + db, engine = await _build_session() + async with db: + await _seed_shot_graph(db) + + derived = await derive_video_preview( + db, + base=VideoBaseDraft(shot_id="s1", prompt="手动视频提示词"), + context=VideoGenerationContext( + shot_id="s1", + reference_mode="text_only", + images=[], + template_id=None, + ), + ) + + assert "手动视频提示词" in derived.rendered_prompt + assert "动作节拍:" in derived.rendered_prompt + assert "连续性要求:" in derived.rendered_prompt + assert "构图锚点:" in derived.rendered_prompt + assert "朝向与视线:" in derived.rendered_prompt + await engine.dispose() + + +@pytest.mark.asyncio +async def test_template_render_keeps_existing_guidance_without_duplicate_suffix(monkeypatch: pytest.MonkeyPatch) -> None: + db, engine = await _build_session() + async with db: + await _seed_shot_graph(db) + + async def _fake_template(*_args, **_kwargs): + return type( + "Template", + (), + { + "id": "tpl-2", + "name": "guided", + "content": "镜头标题:{{ title }}\n连续性要求:{{ continuity_guidance }}", + }, + )() + + monkeypatch.setattr( + "app.services.studio.generation.video.derive_preview._resolve_video_prompt_template", + _fake_template, + ) + + derived = await derive_video_preview( + db, + base=VideoBaseDraft(shot_id="s1", prompt=""), + context=VideoGenerationContext( + shot_id="s1", + reference_mode="text_only", + images=[], + template_id=None, + ), + ) + + assert derived.rendered_prompt.count("连续性要求:") == 1 await engine.dispose() diff --git a/backend/tests/test_image_task_services.py b/backend/tests/test_image_task_services.py index 3a23b96..37fdb99 100644 --- a/backend/tests/test_image_task_services.py +++ b/backend/tests/test_image_task_services.py @@ -290,6 +290,11 @@ def test_derive_frame_preview_replaces_reference_names_with_stable_order() -> No shot_id="shot-1", frame_type=ShotFrameType.first, prompt="张三在雨夜中逼近李四", + director_command_summary="必须:锁定主角视线方向;优先:保持同场景轴线稳定", + continuity_guidance="当前镜头应承接上一镜头的动作与情绪,不要像全新场面重新开局", + frame_specific_guidance="首帧只表现受惊瞬间,人物身体骤然僵住,动作尚未完成", + composition_anchor="以门口灯光和主角站位作为画面重心,保持环境与人物同时可读", + screen_direction_guidance="保持张三与李四的左右站位和对视方向稳定,避免无故翻转朝向", ) context = build_frame_context( shot_id="shot-1", @@ -305,4 +310,85 @@ def test_derive_frame_preview_replaces_reference_names_with_stable_order() -> No assert preview.images == ["char-1-front", "char-2-front"] assert preview.mappings[0].token == "图1" assert preview.mappings[1].token == "图2" + assert preview.selected_guidance == [ + "高优先级导演指令:必须:锁定主角视线方向;优先:保持同场景轴线稳定", + "当前帧职责:首帧只表现受惊瞬间,人物身体骤然僵住,动作尚未完成", + "连续性要求:当前镜头应承接上一镜头的动作与情绪,不要像全新场面重新开局", + ] + assert preview.dropped_guidance == [ + "构图锚点:以门口灯光和主角站位作为画面重心,保持环境与人物同时可读", + "朝向与视线:保持张三与李四的左右站位和对视方向稳定,避免无故翻转朝向", + ] + assert preview.selected_guidance_details[1].reason_tag == "首帧保时序" + assert preview.selected_guidance_details[1].reason == "当前是首帧,系统优先保留触发瞬间与未完成态约束,避免画面直接跳到后续完成动作。" + assert preview.dropped_guidance_details[0].reason_tag == "首帧降构图" + assert preview.dropped_guidance_details[1].reason_tag == "首帧降轴线" + assert "高优先级导演指令:必须:锁定主角视线方向;优先:保持同场景轴线稳定" in preview.rendered_prompt + assert "当前帧职责:首帧只表现受惊瞬间,人物身体骤然僵住,动作尚未完成" in preview.rendered_prompt + assert "连续性要求:当前镜头应承接上一镜头的动作与情绪,不要像全新场面重新开局" in preview.rendered_prompt + assert "构图锚点:以门口灯光和主角站位作为画面重心,保持环境与人物同时可读" not in preview.rendered_prompt + assert "朝向与视线:保持张三与李四的左右站位和对视方向稳定,避免无故翻转朝向" not in preview.rendered_prompt assert "图1在雨夜中逼近图2" in preview.rendered_prompt + + +def test_derive_frame_preview_prioritizes_composition_for_first_frame() -> None: + base = build_frame_base_draft( + shot_id="shot-2", + frame_type=ShotFrameType.first, + prompt="主角推门进入空旷大厅", + director_command_summary="必须:先建立空间", + continuity_guidance="当前镜头应承接上一镜头的动作与情绪", + frame_specific_guidance="首帧优先表现推门瞬间和人物尚未完全进入大厅的状态", + composition_anchor="以门框、人物站位和大厅纵深作为空间锚点,优先建立环境与人物关系", + screen_direction_guidance="保持人物朝向稳定", + ) + context = build_frame_context( + shot_id="shot-2", + frame_type=ShotFrameType.first, + items=[], + ) + + preview = derive_frame_preview(base=base, context=context) + + assert preview.selected_guidance[1] == "当前帧职责:首帧优先表现推门瞬间和人物尚未完全进入大厅的状态" + assert preview.dropped_guidance == [ + "构图锚点:以门框、人物站位和大厅纵深作为空间锚点,优先建立环境与人物关系", + "朝向与视线:保持人物朝向稳定", + ] + assert preview.selected_guidance_details[1].reason_tag == "首帧保时序" + assert preview.selected_guidance_details[1].reason == "当前是首帧,系统优先保留触发瞬间与未完成态约束,避免画面直接跳到后续完成动作。" + assert "当前帧职责:首帧优先表现推门瞬间和人物尚未完全进入大厅的状态" in preview.rendered_prompt + assert "构图锚点:以门框、人物站位和大厅纵深作为空间锚点,优先建立环境与人物关系" not in preview.rendered_prompt + assert "朝向与视线:保持人物朝向稳定" not in preview.rendered_prompt + + +def test_derive_frame_preview_prioritizes_screen_guidance_for_key_frame() -> None: + base = build_frame_base_draft( + shot_id="shot-3", + frame_type=ShotFrameType.key, + prompt="两人对峙,情绪到达顶点", + director_command_summary="必须:锁定对峙张力", + continuity_guidance="当前镜头应承接上一镜头的动作与情绪", + frame_specific_guidance="关键帧应锁定对峙动作的峰值瞬间", + composition_anchor="以走廊尽头和人物站位作为空间锚点,保持环境与人物同时可读", + screen_direction_guidance="保持两人的左右站位和对视方向稳定,避免跳轴", + ) + context = build_frame_context( + shot_id="shot-3", + frame_type=ShotFrameType.key, + items=[], + ) + + preview = derive_frame_preview(base=base, context=context) + + assert preview.selected_guidance[2] == "朝向与视线:保持两人的左右站位和对视方向稳定,避免跳轴" + assert preview.dropped_guidance == [ + "当前帧职责:关键帧应锁定对峙动作的峰值瞬间", + "构图锚点:以走廊尽头和人物站位作为空间锚点,保持环境与人物同时可读", + ] + assert preview.selected_guidance_details[2].reason_tag == "关键帧保轴线" + assert preview.selected_guidance_details[2].reason == "当前镜头更看重视线与左右轴线稳定,因此优先保留朝向与视线 guidance。" + assert preview.dropped_guidance_details[0].reason_tag == "关键帧降峰值" + assert "朝向与视线:保持两人的左右站位和对视方向稳定,避免跳轴" in preview.rendered_prompt + assert "构图锚点:以走廊尽头和人物站位作为空间锚点,保持环境与人物同时可读" not in preview.rendered_prompt + assert "当前帧职责:关键帧应锁定对峙动作的峰值瞬间" not in preview.rendered_prompt diff --git a/backend/tests/test_image_tasks_api_responses.py b/backend/tests/test_image_tasks_api_responses.py index baac944..4dd2bd9 100644 --- a/backend/tests/test_image_tasks_api_responses.py +++ b/backend/tests/test_image_tasks_api_responses.py @@ -125,6 +125,16 @@ def test_create_shot_frame_image_task_requires_prompt(client: TestClient) -> Non def test_render_shot_frame_prompt_returns_success_envelope_when_prompt_given(client: TestClient, monkeypatch) -> None: db = _DummyDB() + async def _fake_load_frame_render_guidance(**_kwargs): + return { + "director_command_summary": "必须:锁定主角视线方向", + "continuity_guidance": "当前镜头应承接上一镜头的动作与情绪,不要像全新场面重新开局", + "frame_specific_guidance": "首帧只表现惊响出现后的最初僵直反应,人物尚未完成捂耳和下蹲动作", + "composition_anchor": "以温室门框和人物站位作为空间锚点,保持环境与人物同时可读", + "screen_direction_guidance": "保持陆远与环境入口的视线方向稳定,避免无故翻转朝向", + } + + monkeypatch.setattr(route, "_load_frame_render_guidance", _fake_load_frame_render_guidance) app.dependency_overrides[get_db] = _override_db(db) try: response = client.post( @@ -146,11 +156,29 @@ def test_render_shot_frame_prompt_returns_success_envelope_when_prompt_given(cli assert body["code"] == 200 assert body["message"] == "success" assert body["data"]["base_prompt"] == "生成一个紧张的首帧画面" + assert body["data"]["selected_guidance"] == [ + "高优先级导演指令:必须:锁定主角视线方向", + "当前帧职责:首帧只表现惊响出现后的最初僵直反应,人物尚未完成捂耳和下蹲动作", + "连续性要求:当前镜头应承接上一镜头的动作与情绪,不要像全新场面重新开局", + ] + assert body["data"]["dropped_guidance"] == [ + "构图锚点:以温室门框和人物站位作为空间锚点,保持环境与人物同时可读", + "朝向与视线:保持陆远与环境入口的视线方向稳定,避免无故翻转朝向", + ] + assert body["data"]["selected_guidance_details"][1]["reason_tag"] == "首帧保时序" + assert body["data"]["selected_guidance_details"][1]["reason"] == "当前是首帧,系统优先保留触发瞬间与未完成态约束,避免画面直接跳到后续完成动作。" + assert body["data"]["dropped_guidance_details"][0]["reason_tag"] == "首帧降构图" + assert body["data"]["dropped_guidance_details"][1]["reason_tag"] == "首帧降轴线" assert body["data"]["images"] == ["file-1", "file-2"] assert body["data"]["mappings"] == [ {"token": "图1", "type": "character", "id": "char-1", "name": "陆远", "file_id": "file-1"}, {"token": "图2", "type": "scene", "id": "scene-1", "name": "温室", "file_id": "file-2"}, ] + assert "高优先级导演指令:必须:锁定主角视线方向" in body["data"]["rendered_prompt"] + assert "当前帧职责:首帧只表现惊响出现后的最初僵直反应,人物尚未完成捂耳和下蹲动作" in body["data"]["rendered_prompt"] + assert "连续性要求:当前镜头应承接上一镜头的动作与情绪,不要像全新场面重新开局" in body["data"]["rendered_prompt"] + assert "构图锚点:以温室门框和人物站位作为空间锚点,保持环境与人物同时可读" not in body["data"]["rendered_prompt"] + assert "朝向与视线:保持陆远与环境入口的视线方向稳定,避免无故翻转朝向" not in body["data"]["rendered_prompt"] assert "图1: 陆远" in body["data"]["rendered_prompt"] assert "图2: 温室" in body["data"]["rendered_prompt"] assert "生成一个紧张的首帧画面" in body["data"]["rendered_prompt"] @@ -186,8 +214,22 @@ def test_create_shot_frame_image_task_renders_prompt_before_submit(client: TestC async def _fake_resolve_image_refs(*_args, **_kwargs): return [{"image_url": "data:image/png;base64,abc"}] + async def _fake_load_frame_render_guidance(**_kwargs): + return { + "director_command_summary": "必须:锁定主角视线方向", + "continuity_guidance": "当前镜头应承接上一镜头的动作与情绪,不要像全新场面重新开局", + "frame_specific_guidance": "首帧只表现惊响出现后的最初僵直反应,人物尚未完成捂耳和下蹲动作", + "composition_anchor": "以温室门框和人物站位作为空间锚点,保持环境与人物同时可读", + "screen_direction_guidance": "保持陆远与环境入口的视线方向稳定,避免无故翻转朝向", + } + async def _fake_create_image_task_and_link(*_args, **kwargs): assert kwargs["prompt"].startswith("## 图片内容说明") + assert "高优先级导演指令:必须:锁定主角视线方向" in kwargs["prompt"] + assert "当前帧职责:首帧只表现惊响出现后的最初僵直反应,人物尚未完成捂耳和下蹲动作" in kwargs["prompt"] + assert "连续性要求:当前镜头应承接上一镜头的动作与情绪,不要像全新场面重新开局" in kwargs["prompt"] + assert "构图锚点:以温室门框和人物站位作为空间锚点,保持环境与人物同时可读" not in kwargs["prompt"] + assert "朝向与视线:保持陆远与环境入口的视线方向稳定,避免无故翻转朝向" not in kwargs["prompt"] assert "图1: 陆远" in kwargs["prompt"] assert kwargs["images"] == [{"image_url": "data:image/png;base64,abc"}] assert kwargs["target_ratio"] == "9:16" @@ -195,9 +237,14 @@ def test_create_shot_frame_image_task_renders_prompt_before_submit(client: TestC assert kwargs["purpose"] == "video_reference" assert kwargs["render_context"]["images"] == ["file-1"] assert kwargs["render_context"]["mappings"][0]["token"] == "图1" + assert kwargs["render_context"]["selected_guidance"][0] == "高优先级导演指令:必须:锁定主角视线方向" + assert kwargs["render_context"]["selected_guidance_details"][1]["reason_tag"] == "首帧保时序" + assert kwargs["render_context"]["dropped_guidance_details"][0]["reason_tag"] == "首帧降构图" + assert kwargs["render_context"]["dropped_guidance_details"][1]["reason_tag"] == "首帧降轴线" return "task-1" monkeypatch.setattr(route, "_resolve_reference_image_refs_by_file_ids_service", _fake_resolve_image_refs) + monkeypatch.setattr(route, "_load_frame_render_guidance", _fake_load_frame_render_guidance) monkeypatch.setattr(route, "_create_image_task_and_link_service", _fake_create_image_task_and_link) app.dependency_overrides[get_db] = _override_db(db) try: @@ -298,6 +345,24 @@ def test_run_image_generation_task_persists_render_context(monkeypatch) -> None: "render_context": { "images": ["file-1"], "mappings": [{"token": "图1", "name": "陆远", "file_id": "file-1"}], + "selected_guidance": ["高优先级导演指令:必须:锁定主角视线方向"], + "dropped_guidance": ["朝向与视线:保持陆远与环境入口的视线方向稳定,避免无故翻转朝向"], + "selected_guidance_details": [ + { + "text": "高优先级导演指令:必须:锁定主角视线方向", + "category": "summary", + "reason_tag": "导演主指令", + "reason": "导演主指令始终属于最高优先级约束,因此会优先保留。", + } + ], + "dropped_guidance_details": [ + { + "text": "朝向与视线:保持陆远与环境入口的视线方向稳定,避免无故翻转朝向", + "category": "screen", + "reason_tag": "首帧降轴线", + "reason": "当前是首帧,系统更优先保空间建立与站位关系,因此将朝向与视线 guidance 降为次级。", + } + ], }, "input": {"prompt": "## 图片内容说明\n图1: 陆远", "model": "gpt-image-1"}, }, @@ -305,3 +370,5 @@ def test_run_image_generation_task_persists_render_context(monkeypatch) -> None: ) assert calls["result_payload"]["render_context"]["images"] == ["file-1"] + assert calls["result_payload"]["render_context"]["selected_guidance_details"][0]["reason_tag"] == "导演主指令" + assert calls["result_payload"]["render_context"]["dropped_guidance_details"][0]["reason_tag"] == "首帧降轴线" diff --git a/backend/tests/test_script_extract_cache.py b/backend/tests/test_script_extract_cache.py index 36a582e..e83792f 100644 --- a/backend/tests/test_script_extract_cache.py +++ b/backend/tests/test_script_extract_cache.py @@ -54,6 +54,7 @@ async def test_extract_script_uses_cache_by_default(monkeypatch): monkeypatch.setattr(route, "ElementExtractorAgent", _FakeAgent) monkeypatch.setattr(route, "sync_shot_extracted_candidates_from_draft", _async_noop) monkeypatch.setattr(route, "sync_shot_extracted_dialogue_candidates_from_draft", _async_noop) + monkeypatch.setattr(route, "apply_shot_semantic_defaults_from_draft", _async_noop) request = route.ScriptExtractRequest( project_id="project-1", @@ -90,6 +91,7 @@ async def test_extract_script_refresh_cache_forces_recompute(monkeypatch): monkeypatch.setattr(route, "ElementExtractorAgent", _FakeAgent) monkeypatch.setattr(route, "sync_shot_extracted_candidates_from_draft", _async_noop) monkeypatch.setattr(route, "sync_shot_extracted_dialogue_candidates_from_draft", _async_noop) + monkeypatch.setattr(route, "apply_shot_semantic_defaults_from_draft", _async_noop) request = route.ScriptExtractRequest( project_id="project-1", diff --git a/backend/tests/test_shot_extracted_candidates_api_responses.py b/backend/tests/test_shot_extracted_candidates_api_responses.py index 85789dd..3abca4c 100644 --- a/backend/tests/test_shot_extracted_candidates_api_responses.py +++ b/backend/tests/test_shot_extracted_candidates_api_responses.py @@ -11,6 +11,7 @@ from app.dependencies import get_db from app.main import app from app.models.studio import ShotCandidateStatus, ShotCandidateType, ShotDialogueCandidateStatus, ShotStatus from app.schemas.studio.shots import ( + ActionBeatPhaseRead, ShotAssetsOverviewRead, ShotAssetsOverviewSummary, ShotExtractionSummaryRead, @@ -69,6 +70,15 @@ def _fake_preparation_state() -> ShotPreparationStateRead: dialogue_candidates=[], saved_dialogue_lines=[], pending_confirm_count=0, + basic_info_ready=True, + semantic_defaults_ready=True, + action_beats_ready=True, + action_beats_count=3, + action_beat_phases=[ + ActionBeatPhaseRead(text="听到异响骤然僵住", phase="trigger"), + ActionBeatPhaseRead(text="修枝剪脱手下坠", phase="peak"), + ActionBeatPhaseRead(text="蹲下后呼吸急促", phase="aftermath"), + ], ready_for_generation=True, ) @@ -143,6 +153,9 @@ def test_update_shot_skip_extraction_returns_success_envelope(client: TestClient assert body["code"] == 200 assert body["data"]["action"] == "skip_extraction" assert body["data"]["state"]["shot"]["status"] == "ready" + assert body["data"]["state"]["action_beats_ready"] is True + assert body["data"]["state"]["action_beats_count"] == 3 + assert body["data"]["state"]["action_beat_phases"][0]["phase"] == "trigger" assert body["data"]["state"]["ready_for_generation"] is True diff --git a/backend/tests/test_shot_frame_prompt_tasks_service.py b/backend/tests/test_shot_frame_prompt_tasks_service.py index a1a4228..5d42c35 100644 --- a/backend/tests/test_shot_frame_prompt_tasks_service.py +++ b/backend/tests/test_shot_frame_prompt_tasks_service.py @@ -33,6 +33,7 @@ from app.services.film.shot_frame_prompt_tasks import ( normalize_frame_type, relation_type_for_frame, ) +from app.services.studio.action_beats import infer_action_beat_sequence, pick_action_beat_for_frame async def _build_session() -> tuple[AsyncSession, object]: @@ -53,7 +54,9 @@ async def _seed_shot_graph(db: AsyncSession) -> None: unify_style=True, ) chapter = Chapter(id="c1", project_id="p1", index=1, title="第一章") + prev_shot = Shot(id="s0", chapter_id="c1", index=0, title="镜头零", script_excerpt="角色沿着墙边逼近门口。") shot = Shot(id="s1", chapter_id="c1", index=1, title="镜头一", script_excerpt="角色推门而入。") + next_shot = Shot(id="s2", chapter_id="c1", index=2, title="镜头二", script_excerpt="角色停下脚步,盯向走廊尽头。") actor = Actor( id="actor-1", name="演员甲", @@ -106,6 +109,24 @@ async def _seed_shot_graph(db: AsyncSession) -> None: vfx_note="无", description="狭长走廊里,主角谨慎前行并回头确认身后动静。", ) + prev_detail = ShotDetail( + id="s0", + camera_shot=CameraShotType.ms, + angle=CameraAngle.eye_level, + movement=CameraMovement.dolly_in, + scene_id="scene-1", + duration=4, + description="主角贴墙缓慢逼近门口,视线紧盯前方。", + ) + next_detail = ShotDetail( + id="s2", + camera_shot=CameraShotType.cu, + angle=CameraAngle.eye_level, + movement=CameraMovement.static, + scene_id="scene-1", + duration=3, + description="主角停住动作,神情绷紧,视线落向走廊尽头。", + ) line = ShotDialogLine( shot_detail_id="s1", index=0, @@ -121,13 +142,17 @@ async def _seed_shot_graph(db: AsyncSession) -> None: [ project, chapter, + prev_shot, shot, + next_shot, actor, costume, character, scene, prop, + prev_detail, detail, + next_detail, line, shot_character_link, scene_link, @@ -138,6 +163,46 @@ async def _seed_shot_graph(db: AsyncSession) -> None: await db.commit() +async def _seed_fear_reaction_shot_graph(db: AsyncSession) -> None: + project = Project( + id="fear-p1", + name="惊恐项目", + description="", + style=ProjectStyle.real_people_city, + visual_style=ProjectVisualStyle.live_action, + unify_style=True, + ) + chapter = Chapter(id="fear-c1", project_id="fear-p1", index=1, title="温室") + shot = Shot( + id="fear-s1", + chapter_id="fear-c1", + index=1, + title="惊恐镜头", + script_excerpt="“咔嚓。”剪刀咬合的声音在安静的温室里显得格外刺耳。陆远浑身一僵,手里的修枝剪脱手掉在地上。他下意识地捂住耳朵,蹲下身,呼吸变得急促。", + ) + detail = ShotDetail( + id="fear-s1", + camera_shot=CameraShotType.ms, + angle=CameraAngle.eye_level, + movement=CameraMovement.static, + duration=5, + action_beats=[ + "听到剪刀咬合声,陆远骤然僵住", + "修枝剪脱手下坠", + "陆远抬手捂耳,身体下沉", + "蹲下后呼吸急促", + ], + description="陆远在温室里修剪枝叶,忽然被刺耳剪刀声惊到,身体僵住,手中的修枝剪脱手下坠。", + atmosphere="压抑", + mood_tags=["惊恐"], + follow_atmosphere=True, + vfx_type=VFXType.none, + vfx_note="无", + ) + db.add_all([project, chapter, shot, detail]) + await db.commit() + + def test_normalize_frame_type_and_relation_type() -> None: assert normalize_frame_type(" First ") == "first" assert relation_type_for_frame("first") == "shot_first_frame_prompt" @@ -150,6 +215,25 @@ def test_normalize_frame_type_and_relation_type() -> None: assert exc_info.value.status_code == 400 +def test_action_beat_phase_inference_prefers_trigger_peak_and_aftermath() -> None: + beats = [ + "听到剪刀咬合声,陆远骤然僵住", + "修枝剪脱手下坠", + "陆远抬手捂耳,身体下沉", + "蹲下后呼吸急促", + ] + + sequence = infer_action_beat_sequence(beats) + first_item = pick_action_beat_for_frame("first", beats) + key_item = pick_action_beat_for_frame("key", beats) + last_item = pick_action_beat_for_frame("last", beats) + + assert [item.phase for item in sequence] == ["trigger", "peak", "peak", "aftermath"] + assert first_item is not None and first_item.text == "听到剪刀咬合声,陆远骤然僵住" + assert key_item is not None and key_item.text == "陆远抬手捂耳,身体下沉" + assert last_item is not None and last_item.text == "蹲下后呼吸急促" + + @pytest.mark.asyncio async def test_build_run_args_aggregates_dialog_and_project_style() -> None: db, engine = await _build_session() @@ -179,6 +263,46 @@ async def test_build_run_args_aggregates_dialog_and_project_style() -> None: assert "优先以角色 主角 作为画面主体" in run_args["input"]["subject_priority"] assert "优先建立场景 废弃走廊 的环境信息" in run_args["input"]["subject_priority"] assert "道具 手电筒 仅在进入主动作或构图焦点时重点写入" in run_args["input"]["subject_priority"] + assert run_args["input"]["previous_shot_title"] == "镜头零" + assert "角色沿着墙边逼近门口" in run_args["input"]["previous_shot_script_excerpt"] + assert "场景:废弃走廊" in run_args["input"]["previous_shot_end_state"] + assert run_args["input"]["next_shot_title"] == "镜头二" + assert "角色停下脚步" in run_args["input"]["next_shot_script_excerpt"] + assert "画面状态:主角停住动作" in run_args["input"]["next_shot_start_goal"] + assert "承接上一镜头的动作与情绪" in run_args["input"]["continuity_guidance"] + assert "为下一镜头预留动作或情绪落点" in run_args["input"]["continuity_guidance"] + assert "保持人物与环境同时可读" in run_args["input"]["composition_anchor"] + assert "以场景 废弃走廊 作为空间锚点" in run_args["input"]["composition_anchor"] + assert "锁定角色 主角 的朝向和视线" in run_args["input"]["composition_anchor"] + assert "优先保持人物视线水平和对视方向稳定" in run_args["input"]["screen_direction_guidance"] + assert "存在对白时,优先保证说话者与受话者的视线关系连续" in run_args["input"]["screen_direction_guidance"] + assert "角色 主角 的朝向与视线落点应在相邻镜头中保持延续" in run_args["input"]["screen_direction_guidance"] + assert "首帧应优先建立空间、主体初始站位和第一眼视觉印象" in run_args["input"]["frame_specific_guidance"] + assert "首帧只表现事件触发瞬间或最初反应的起始状态" in run_args["input"]["frame_specific_guidance"] + assert "若剧本存在连续反应链,优先写成动作刚开始、尚未完成或被打断的状态" in run_args["input"]["frame_specific_guidance"] + assert "首帧要承接上一镜头结束状态" in run_args["input"]["frame_specific_guidance"] + assert "必须:若剧本存在连续反应链,优先写成动作刚开始、尚未完成或被打断的状态,例如手刚松脱、身体骤然僵住、人物尚未完全蹲下" in run_args["input"]["director_command_summary"] + assert "必须:与上一镜头同场景时,不要无故翻转人物面向和左右轴线" in run_args["input"]["director_command_summary"] + assert "必须:下一镜头与当前镜头处于同一场景,尽量保持视觉重心与空间关系可连续延展" in run_args["input"]["director_command_summary"] + assert "必须:以场景 废弃走廊 作为空间锚点,保证主体与环境关系清晰" in run_args["input"]["director_command_summary"] + await engine.dispose() + + +@pytest.mark.asyncio +async def test_build_run_args_provides_different_guidance_for_key_and_last_frames() -> None: + db, engine = await _build_session() + async with db: + await _seed_shot_graph(db) + + key_args = await build_run_args(db, shot_id="s1", frame_type="key") + last_args = await build_run_args(db, shot_id="s1", frame_type="last") + + assert "关键帧应锁定镜头内最有戏剧张力或信息密度最高的瞬间" in key_args["input"]["frame_specific_guidance"] + assert "尾帧应强调动作收束、情绪余韵或视线停留点" in last_args["input"]["frame_specific_guidance"] + assert key_args["input"]["frame_specific_guidance"] != last_args["input"]["frame_specific_guidance"] + assert "必须:关键帧应锁定镜头内最有戏剧张力或信息密度最高的瞬间,不要平均描述整个过程" in key_args["input"]["director_command_summary"] + assert "必须:尾帧应强调动作收束、情绪余韵或视线停留点,不要重新铺开新的动作起点" in last_args["input"]["director_command_summary"] + assert "必须:与上一镜头同场景时,不要无故翻转人物面向和左右轴线" in last_args["input"]["director_command_summary"] await engine.dispose() @@ -204,3 +328,19 @@ async def test_build_run_args_requires_shot_detail() -> None: assert exc_info.value.status_code == 404 assert exc_info.value.detail == "ShotDetail not found" await engine.dispose() + + +@pytest.mark.asyncio +async def test_build_run_args_strengthens_first_frame_for_sequential_reaction_chain() -> None: + db, engine = await _build_session() + async with db: + await _seed_fear_reaction_shot_graph(db) + + run_args = await build_run_args(db, shot_id="fear-s1", frame_type="first") + + assert "当前镜头存在明显连续反应链" in run_args["input"]["frame_specific_guidance"] + assert "禁止直接落到捂耳、蹲下、倒地或转身完成态" in run_args["input"]["frame_specific_guidance"] + assert "当前帧优先围绕动作拍点“听到剪刀咬合声,陆远骤然僵住”组织画面(触发阶段)" in run_args["input"]["frame_specific_guidance"] + assert "必须:若剧本存在连续反应链,优先写成动作刚开始、尚未完成或被打断的状态,例如手刚松脱、身体骤然僵住、人物尚未完全蹲下" in run_args["input"]["director_command_summary"] + assert "当前镜头存在明显连续反应链,首帧必须截取触发后最早的可见瞬间,禁止直接落到捂耳、蹲下、倒地或转身完成态" in run_args["input"]["director_command_summary"] + await engine.dispose() diff --git a/backend/tests/test_shot_semantic_defaults_service.py b/backend/tests/test_shot_semantic_defaults_service.py new file mode 100644 index 0000000..d34d6a1 --- /dev/null +++ b/backend/tests/test_shot_semantic_defaults_service.py @@ -0,0 +1,181 @@ +from __future__ import annotations + +import pytest +from sqlalchemy import create_engine +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine +from sqlalchemy.orm import Session, sessionmaker + +from app.core.db import Base +from app.models.studio import ( + CameraAngle, + CameraMovement, + CameraShotType, + Chapter, + Project, + ProjectStyle, + ProjectVisualStyle, + Shot, + ShotDetail, +) +from app.schemas.skills.script_processing import ShotSemanticSuggestion, StudioScriptExtractionDraft, StudioShotDraft +from app.services.script_processing_worker import apply_extraction_result +from app.services.studio.shot_extraction_draft import build_script_extraction_draft_for_shot +from app.services.studio.shot_semantic_defaults import apply_shot_semantic_defaults_from_draft + + +async def _seed_async_graph(db: AsyncSession) -> str: + """构造最小项目/章节/镜头图,便于验证镜头语言默认值写回。""" + + project = Project( + id="project-1", + name="项目一", + style=ProjectStyle.guoman, + visual_style=ProjectVisualStyle.anime, + ) + chapter = Chapter(id="chapter-1", project_id=project.id, index=1, title="章节一") + shot = Shot(id="shot-1", chapter_id=chapter.id, index=1, title="镜头一", script_excerpt="原始摘录") + detail = ShotDetail( + id=shot.id, + camera_shot=CameraShotType.ms, + angle=CameraAngle.eye_level, + movement=CameraMovement.static, + duration=4, + ) + db.add_all([project, chapter, shot, detail]) + await db.flush() + return shot.id + + +def _seed_sync_graph(db: Session) -> str: + """同步版本的最小项目/章节/镜头图。""" + + project = Project( + id="project-1", + name="项目一", + style=ProjectStyle.guoman, + visual_style=ProjectVisualStyle.anime, + ) + chapter = Chapter(id="chapter-1", project_id=project.id, index=1, title="章节一") + shot = Shot(id="shot-1", chapter_id=chapter.id, index=1, title="镜头一", script_excerpt="原始摘录") + detail = ShotDetail( + id=shot.id, + camera_shot=CameraShotType.ms, + angle=CameraAngle.eye_level, + movement=CameraMovement.static, + duration=4, + ) + db.add_all([project, chapter, shot, detail]) + db.flush() + return shot.id + + +def _build_semantic_draft() -> StudioScriptExtractionDraft: + """构造带镜头语言默认建议的提取草稿。""" + + return StudioScriptExtractionDraft( + project_id="project-1", + chapter_id="chapter-1", + script_text="测试文本", + characters=[], + scenes=[], + props=[], + costumes=[], + shots=[ + StudioShotDraft( + index=1, + title="镜头一", + script_excerpt="摘录", + scene_name=None, + character_names=[], + prop_names=[], + costume_names=[], + dialogue_lines=[], + actions=["听到声音后僵住"], + semantic_suggestion=ShotSemanticSuggestion( + camera_shot=CameraShotType.cu, + angle=CameraAngle.low_angle, + movement=CameraMovement.track, + duration=6, + action_beats=["听到异响骤然僵住", "修枝剪脱手下坠"], + ), + ) + ], + ) + + +@pytest.mark.asyncio +async def test_apply_shot_semantic_defaults_from_draft_updates_shot_detail() -> None: + engine = create_async_engine("sqlite+aiosqlite:///:memory:", future=True) + session_local = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) + + import app.models.studio # noqa: F401 + + async with engine.begin() as conn: + await conn.run_sync(Base.metadata.create_all) + + async with session_local() as db: + shot_id = await _seed_async_graph(db) + draft = _build_semantic_draft() + + await apply_shot_semantic_defaults_from_draft(db, chapter_id="chapter-1", draft=draft) + detail = await db.get(ShotDetail, shot_id) + + assert detail is not None + assert detail.camera_shot == CameraShotType.cu + assert detail.angle == CameraAngle.low_angle + assert detail.movement == CameraMovement.track + assert detail.duration == 6 + assert detail.action_beats == ["听到异响骤然僵住", "修枝剪脱手下坠"] + + await engine.dispose() + + +@pytest.mark.asyncio +async def test_build_script_extraction_draft_for_shot_includes_semantic_suggestion() -> None: + engine = create_async_engine("sqlite+aiosqlite:///:memory:", future=True) + session_local = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) + + import app.models.studio # noqa: F401 + + async with engine.begin() as conn: + await conn.run_sync(Base.metadata.create_all) + + async with session_local() as db: + shot_id = await _seed_async_graph(db) + draft = await build_script_extraction_draft_for_shot(db, shot_id) + + assert len(draft.shots) == 1 + semantic = draft.shots[0].semantic_suggestion + assert semantic is not None + assert semantic.camera_shot == CameraShotType.ms + assert semantic.angle == CameraAngle.eye_level + assert semantic.movement == CameraMovement.static + assert semantic.duration == 4 + assert semantic.action_beats == [] + + await engine.dispose() + + +def test_apply_extraction_result_sync_updates_shot_detail() -> None: + engine = create_engine("sqlite:///:memory:", future=True) + session_local = sessionmaker(engine, class_=Session, expire_on_commit=False) + + import app.models.studio # noqa: F401 + + Base.metadata.create_all(engine) + + with session_local() as db: + shot_id = _seed_sync_graph(db) + draft = _build_semantic_draft() + + apply_extraction_result(db, chapter_id="chapter-1", draft=draft) + detail = db.get(ShotDetail, shot_id) + + assert detail is not None + assert detail.camera_shot == CameraShotType.cu + assert detail.angle == CameraAngle.low_angle + assert detail.movement == CameraMovement.track + assert detail.duration == 6 + assert detail.action_beats == ["听到异响骤然僵住", "修枝剪脱手下坠"] + + engine.dispose() diff --git a/front/openapi.json b/front/openapi.json index aed1462..4f29e89 100644 --- a/front/openapi.json +++ b/front/openapi.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"Jellyfish API","version":"0.1.0"},"paths":{"/api/v1/health":{"get":{"tags":["health"],"summary":"V1 Health","operationId":"v1_health_api_v1_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_"}}}}}}},"/api/v1/film/tasks/video/preview-prompt":{"post":{"tags":["film"],"summary":"视频提示词预览","description":"预览视频生成的提示词与自动关联参考图。","operationId":"preview_video_generation_prompt_api_v1_film_tasks_video_preview_prompt_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoGenerationTaskRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_VideoPromptPreviewResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/tasks/video":{"post":{"tags":["film"],"summary":"视频生成(任务版)","description":"创建视频生成任务并后台执行,结果通过 /tasks/{task_id}/result 获取。","operationId":"create_video_generation_task_api_v1_film_tasks_video_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoGenerationTaskRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/tasks/shot-frame-prompts":{"post":{"tags":["film"],"summary":"镜头分镜帧提示词生成(任务版)","operationId":"create_shot_frame_prompt_task_api_v1_film_tasks_shot_frame_prompts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotFramePromptRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/tasks":{"get":{"tags":["film"],"summary":"全局任务列表(任务中心)","operationId":"list_tasks_api_v1_film_tasks_get","parameters":[{"name":"statuses","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/TaskStatus"}},{"type":"null"}],"description":"按任务状态过滤,可多选","title":"Statuses"},"description":"按任务状态过滤,可多选"},{"name":"task_kind","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 task_kind 过滤","title":"Task Kind"},"description":"按 task_kind 过滤"},{"name":"relation_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 relation_type 过滤","title":"Relation Type"},"description":"按 relation_type 过滤"},{"name":"relation_entity_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 relation_entity_id 过滤","title":"Relation Entity Id"},"description":"按 relation_entity_id 过滤"},{"name":"recent_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":86400,"minimum":0,"description":"默认返回最近结束任务的时间窗口(秒)","default":300,"title":"Recent Seconds"},"description":"默认返回最近结束任务的时间窗口(秒)"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"页码","default":1,"title":"Page"},"description":"页码"},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"每页条数","default":20,"title":"Page Size"},"description":"每页条数"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_TaskListItemRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/tasks/{task_id}/status":{"get":{"tags":["film"],"summary":"查询任务状态/进度(轮询)","operationId":"get_task_status_api_v1_film_tasks__task_id__status_get","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskStatusRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/tasks/{task_id}/result":{"get":{"tags":["film"],"summary":"获取任务结果","operationId":"get_task_result_api_v1_film_tasks__task_id__result_get","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/tasks/{task_id}/cancel":{"post":{"tags":["film"],"summary":"请求取消任务","operationId":"cancel_task_api_v1_film_tasks__task_id__cancel_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCancelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCancelRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/task-links/adopt":{"patch":{"tags":["film"],"summary":"更新任务关联的采用状态(仅可正向变更)","description":"将指定任务链接的状态设为 accepted;已采用不可改为未采用。","operationId":"adopt_task_link_api_v1_film_task_links_adopt_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskLinkAdoptRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskLinkAdoptRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/task-links":{"get":{"tags":["film"],"summary":"生成任务关联列表(分页,支持多条件过滤)","operationId":"list_task_links_api_v1_film_task_links_get","parameters":[{"name":"resource_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 resource_type 过滤","title":"Resource Type"},"description":"按 resource_type 过滤"},{"name":"relation_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 relation_type 过滤","title":"Relation Type"},"description":"按 relation_type 过滤"},{"name":"relation_entity_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 relation_entity_id 过滤","title":"Relation Entity Id"},"description":"按 relation_entity_id 过滤"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按关联状态过滤(accepted/todo/rejected)","title":"Status"},"description":"按关联状态过滤(accepted/todo/rejected)"},{"name":"task_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 task_id 过滤","title":"Task Id"},"description":"按 task_id 过滤"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"排序字段:updated_at/created_at/id/status","title":"Order"},"description":"排序字段:updated_at/created_at/id/status"},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","description":"是否倒序;默认 true","default":true,"title":"Is Desc"},"description":"是否倒序;默认 true"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"页码","default":1,"title":"Page"},"description":"页码"},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"每页条数","default":10,"title":"Page Size"},"description":"每页条数"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_GenerationTaskLinkRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["film"],"summary":"创建生成任务关联","operationId":"create_task_link_api_v1_film_task_links_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationTaskLinkCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_GenerationTaskLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/task-links/{link_id}":{"get":{"tags":["film"],"summary":"获取生成任务关联详情","operationId":"get_task_link_api_v1_film_task_links__link_id__get","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_GenerationTaskLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["film"],"summary":"更新生成任务关联(不支持直接修改 is_adopted)","operationId":"update_task_link_api_v1_film_task_links__link_id__patch","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationTaskLinkUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_GenerationTaskLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["film"],"summary":"删除生成任务关联","operationId":"delete_task_link_api_v1_film_task_links__link_id__delete","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/llm/providers":{"get":{"tags":["llm"],"summary":"列出模型供应商(分页)","operationId":"list_providers_api_v1_llm_providers_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 name/description","title":"Q"},"description":"关键字,过滤 name/description"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"排序字段:name, created_at, updated_at","title":"Order"},"description":"排序字段:name, created_at, updated_at"},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","description":"是否倒序","default":false,"title":"Is Desc"},"description":"是否倒序"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"页码","default":1,"title":"Page"},"description":"页码"},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"每页条数","default":10,"title":"Page Size"},"description":"每页条数"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ProviderRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["llm"],"summary":"创建模型供应商","operationId":"create_provider_api_v1_llm_providers_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProviderRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/llm/providers/supported":{"get":{"tags":["llm"],"summary":"列出系统支持的供应商能力","operationId":"list_supported_providers_api_v1_llm_providers_supported_get","parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ModelCategoryKey"},{"type":"null"}],"description":"按模型类别过滤:text/image/video","title":"Category"},"description":"按模型类别过滤:text/image/video"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_list_ProviderSupportedRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/llm/image-generation-options":{"get":{"tags":["llm"],"summary":"获取当前默认图片模型的关键帧规格选项","operationId":"get_image_generation_options_api_v1_llm_image_generation_options_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ImageGenerationOptionsRead_"}}}}}}},"/api/v1/llm/video-generation-options":{"get":{"tags":["llm"],"summary":"获取当前默认视频模型的动态比例选项","operationId":"get_video_generation_options_api_v1_llm_video_generation_options_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_VideoGenerationOptionsRead_"}}}}}}},"/api/v1/llm/providers/{provider_id}":{"get":{"tags":["llm"],"summary":"获取单个模型供应商","operationId":"get_provider_api_v1_llm_providers__provider_id__get","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"string","title":"Provider Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProviderRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["llm"],"summary":"更新模型供应商","operationId":"update_provider_api_v1_llm_providers__provider_id__patch","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"string","title":"Provider Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProviderRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["llm"],"summary":"删除模型供应商","operationId":"delete_provider_api_v1_llm_providers__provider_id__delete","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"string","title":"Provider Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/llm/models":{"get":{"tags":["llm"],"summary":"列出模型(分页)","operationId":"list_models_api_v1_llm_models_get","parameters":[{"name":"provider_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按供应商过滤","title":"Provider Id"},"description":"按供应商过滤"},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ModelCategoryKey"},{"type":"null"}],"description":"按模型类别过滤","title":"Category"},"description":"按模型类别过滤"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 name/description","title":"Q"},"description":"关键字,过滤 name/description"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"排序字段:name, category, created_at, updated_at","title":"Order"},"description":"排序字段:name, category, created_at, updated_at"},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","description":"是否倒序","default":false,"title":"Is Desc"},"description":"是否倒序"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"页码","default":1,"title":"Page"},"description":"页码"},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"每页条数","default":10,"title":"Page Size"},"description":"每页条数"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ModelRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["llm"],"summary":"创建模型","operationId":"create_model_api_v1_llm_models_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ModelRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/llm/models/{model_id}":{"get":{"tags":["llm"],"summary":"获取单个模型","operationId":"get_model_api_v1_llm_models__model_id__get","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ModelRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["llm"],"summary":"更新模型","operationId":"update_model_api_v1_llm_models__model_id__patch","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ModelRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["llm"],"summary":"删除模型","operationId":"delete_model_api_v1_llm_models__model_id__delete","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/llm/model-settings":{"get":{"tags":["llm"],"summary":"获取模型全局设置(单例)","operationId":"get_model_settings_api_v1_llm_model_settings_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ModelSettingsRead_"}}}}}},"put":{"tags":["llm"],"summary":"更新模型全局设置(单例)","operationId":"update_model_settings_api_v1_llm_model_settings_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelSettingsUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ModelSettingsRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/projects/style-options":{"get":{"tags":["studio/projects"],"summary":"获取项目风格候选项","operationId":"get_project_style_options_api_v1_studio_projects_style_options_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectStyleOptionsRead_"}}}}}}},"/api/v1/studio/projects":{"get":{"tags":["studio/projects"],"summary":"项目列表(分页)","operationId":"list_projects_api_v1_studio_projects_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 name/description","title":"Q"},"description":"关键字,过滤 name/description"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"排序字段","title":"Order"},"description":"排序字段"},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","description":"是否倒序","default":false,"title":"Is Desc"},"description":"是否倒序"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ProjectRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/projects"],"summary":"创建项目","operationId":"create_project_api_v1_studio_projects_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/projects/{project_id}":{"get":{"tags":["studio/projects"],"summary":"获取项目","operationId":"get_project_api_v1_studio_projects__project_id__get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/projects"],"summary":"更新项目","operationId":"update_project_api_v1_studio_projects__project_id__patch","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/projects"],"summary":"删除项目","operationId":"delete_project_api_v1_studio_projects__project_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/chapters":{"get":{"tags":["studio/chapters"],"summary":"章节列表(分页)","operationId":"list_chapters_api_v1_studio_chapters_get","parameters":[{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按项目过滤","title":"Project Id"},"description":"按项目过滤"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 title/summary","title":"Q"},"description":"关键字,过滤 title/summary"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"排序字段","title":"Order"},"description":"排序字段"},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","description":"是否倒序","default":false,"title":"Is Desc"},"description":"是否倒序"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ChapterRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/chapters"],"summary":"创建章节","operationId":"create_chapter_api_v1_studio_chapters_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChapterCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ChapterRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/chapters/{chapter_id}":{"get":{"tags":["studio/chapters"],"summary":"获取章节","operationId":"get_chapter_api_v1_studio_chapters__chapter_id__get","parameters":[{"name":"chapter_id","in":"path","required":true,"schema":{"type":"string","title":"Chapter Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ChapterRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/chapters"],"summary":"更新章节","operationId":"update_chapter_api_v1_studio_chapters__chapter_id__patch","parameters":[{"name":"chapter_id","in":"path","required":true,"schema":{"type":"string","title":"Chapter Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChapterUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ChapterRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/chapters"],"summary":"删除章节","operationId":"delete_chapter_api_v1_studio_chapters__chapter_id__delete","parameters":[{"name":"chapter_id","in":"path","required":true,"schema":{"type":"string","title":"Chapter Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots":{"get":{"tags":["studio/shots"],"summary":"镜头列表(分页)","operationId":"list_shots_api_v1_studio_shots_get","parameters":[{"name":"chapter_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按章节过滤","title":"Chapter Id"},"description":"按章节过滤"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 title/script_excerpt","title":"Q"},"description":"关键字,过滤 title/script_excerpt"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ShotRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/shots"],"summary":"创建镜头","operationId":"create_shot_api_v1_studio_shots_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/runtime-summary":{"get":{"tags":["studio/shots"],"summary":"按章节获取镜头运行时任务态摘要","operationId":"list_shot_runtime_summary_api_v1_studio_shots_runtime_summary_get","parameters":[{"name":"chapter_id","in":"query","required":true,"schema":{"type":"string","description":"章节 ID","title":"Chapter Id"},"description":"章节 ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_list_ShotRuntimeSummaryRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/extraction-draft":{"get":{"tags":["studio/shots"],"summary":"分镜详情:按镜头关联拼装 StudioScriptExtractionDraft","operationId":"get_shot_extraction_draft_api_v1_studio_shots__shot_id__extraction_draft_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_StudioScriptExtractionDraft_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/extracted-candidates":{"get":{"tags":["studio/shots"],"summary":"获取镜头提取候选项","operationId":"get_shot_extracted_candidates_api_v1_studio_shots__shot_id__extracted_candidates_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_list_ShotExtractedCandidateRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/extracted-dialogue-candidates":{"get":{"tags":["studio/shots"],"summary":"获取镜头提取对白候选项","operationId":"get_shot_extracted_dialogue_candidates_api_v1_studio_shots__shot_id__extracted_dialogue_candidates_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_list_ShotExtractedDialogueCandidateRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/assets-overview":{"get":{"tags":["studio/shots"],"summary":"获取镜头资产总览(已关联资产 + 提取候选)","operationId":"get_shot_assets_overview_api_api_v1_studio_shots__shot_id__assets_overview_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotAssetsOverviewRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/preparation-state":{"get":{"tags":["studio/shots"],"summary":"获取镜头准备页聚合状态","operationId":"get_shot_preparation_state_api_api_v1_studio_shots__shot_id__preparation_state_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationStateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/preparation-link":{"post":{"tags":["studio/shots"],"summary":"准备页关联现有实体并返回最新聚合状态","operationId":"link_existing_asset_for_preparation_api_api_v1_studio_shots__shot_id__preparation_link_post","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotPreparationLinkRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationMutationResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/video-prompt-preview":{"get":{"tags":["studio/shots"],"summary":"预览镜头视频提示词","operationId":"preview_shot_video_prompt_api_v1_studio_shots__shot_id__video_prompt_preview_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}},{"name":"template_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"指定视频提示词模板 ID;不传则使用默认模板","title":"Template Id"},"description":"指定视频提示词模板 ID;不传则使用默认模板"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotVideoPromptPreviewRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/video-readiness":{"get":{"tags":["studio/shots"],"summary":"获取镜头视频生成准备度","operationId":"get_shot_video_readiness_api_api_v1_studio_shots__shot_id__video_readiness_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}},{"name":"reference_mode","in":"query","required":false,"schema":{"type":"string","description":"参考模式:first/last/key/first_last/first_last_key/text_only","default":"text_only","title":"Reference Mode"},"description":"参考模式:first/last/key/first_last/first_last_key/text_only"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotVideoReadinessRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/skip-extraction":{"patch":{"tags":["studio/shots"],"summary":"设置是否跳过镜头信息提取","operationId":"update_shot_skip_extraction_api_v1_studio_shots__shot_id__skip_extraction_patch","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotSkipExtractionUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationMutationResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/extracted-candidates/{candidate_id}/link":{"patch":{"tags":["studio/shots"],"summary":"确认并关联镜头提取候选项","operationId":"link_extracted_candidate_api_v1_studio_shots_extracted_candidates__candidate_id__link_patch","parameters":[{"name":"candidate_id","in":"path","required":true,"schema":{"type":"integer","title":"Candidate Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotExtractedCandidateLinkRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationMutationResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/extracted-candidates/{candidate_id}/ignore":{"patch":{"tags":["studio/shots"],"summary":"忽略镜头提取候选项","operationId":"ignore_extracted_candidate_api_v1_studio_shots_extracted_candidates__candidate_id__ignore_patch","parameters":[{"name":"candidate_id","in":"path","required":true,"schema":{"type":"integer","title":"Candidate Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationMutationResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/extracted-dialogue-candidates/{candidate_id}/accept":{"patch":{"tags":["studio/shots"],"summary":"接受镜头提取对白候选项","operationId":"accept_extracted_dialogue_candidate_api_v1_studio_shots_extracted_dialogue_candidates__candidate_id__accept_patch","parameters":[{"name":"candidate_id","in":"path","required":true,"schema":{"type":"integer","title":"Candidate Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ShotExtractedDialogueCandidateAcceptRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationMutationResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/extracted-dialogue-candidates/{candidate_id}/ignore":{"patch":{"tags":["studio/shots"],"summary":"忽略镜头提取对白候选项","operationId":"ignore_extracted_dialogue_candidate_api_v1_studio_shots_extracted_dialogue_candidates__candidate_id__ignore_patch","parameters":[{"name":"candidate_id","in":"path","required":true,"schema":{"type":"integer","title":"Candidate Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationMutationResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}":{"get":{"tags":["studio/shots"],"summary":"获取镜头","operationId":"get_shot_api_v1_studio_shots__shot_id__get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/shots"],"summary":"更新镜头","operationId":"update_shot_api_v1_studio_shots__shot_id__patch","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/shots"],"summary":"删除镜头","operationId":"delete_shot_api_v1_studio_shots__shot_id__delete","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/linked-assets":{"get":{"tags":["studio/shots"],"summary":"获取镜头关联的角色/道具/场景/服装(分页)","operationId":"list_shot_linked_assets_api_v1_studio_shots__shot_id__linked_assets_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ShotLinkedAssetItem__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-details":{"get":{"tags":["studio/shot-details"],"summary":"镜头细节列表(分页)","operationId":"list_shot_details_api_v1_studio_shot_details_get","parameters":[{"name":"shot_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按镜头过滤(id 同 shot_id)","title":"Shot Id"},"description":"按镜头过滤(id 同 shot_id)"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ShotDetailRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/shot-details"],"summary":"创建镜头细节","operationId":"create_shot_detail_api_v1_studio_shot_details_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotDetailCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotDetailRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-details/{shot_id}":{"get":{"tags":["studio/shot-details"],"summary":"获取镜头细节","operationId":"get_shot_detail_api_v1_studio_shot_details__shot_id__get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotDetailRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/shot-details"],"summary":"更新镜头细节","operationId":"update_shot_detail_api_v1_studio_shot_details__shot_id__patch","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotDetailUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotDetailRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/shot-details"],"summary":"删除镜头细节","operationId":"delete_shot_detail_api_v1_studio_shot_details__shot_id__delete","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-dialog-lines":{"get":{"tags":["studio/shot-dialog-lines"],"summary":"镜头对话行列表(分页)","operationId":"list_shot_dialog_lines_api_v1_studio_shot_dialog_lines_get","parameters":[{"name":"shot_detail_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按镜头细节过滤","title":"Shot Detail Id"},"description":"按镜头细节过滤"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 text","title":"Q"},"description":"关键字,过滤 text"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ShotDialogLineRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/shot-dialog-lines"],"summary":"创建镜头对话行","operationId":"create_shot_dialog_line_api_v1_studio_shot_dialog_lines_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotDialogLineCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotDialogLineRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-dialog-lines/{line_id}":{"patch":{"tags":["studio/shot-dialog-lines"],"summary":"更新镜头对话行","operationId":"update_shot_dialog_line_api_v1_studio_shot_dialog_lines__line_id__patch","parameters":[{"name":"line_id","in":"path","required":true,"schema":{"type":"integer","title":"Line Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotDialogLineUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotDialogLineRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/shot-dialog-lines"],"summary":"删除镜头对话行","operationId":"delete_shot_dialog_line_api_v1_studio_shot_dialog_lines__line_id__delete","parameters":[{"name":"line_id","in":"path","required":true,"schema":{"type":"integer","title":"Line Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/{entity_type}":{"get":{"tags":["studio/shot-links"],"summary":"项目-章节-镜头-实体关联列表(分页)","operationId":"list_project_entity_links_api_v1_studio_shot_links__entity_type__get","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"chapter_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id"}},{"name":"shot_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id"}},{"name":"asset_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Asset Id"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_Any__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/actor":{"post":{"tags":["studio/shot-links"],"summary":"创建项目-章节-镜头-演员关联","operationId":"create_project_actor_link_api_v1_studio_shot_links_actor_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAssetLinkCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectActorLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/actor/{link_id}":{"delete":{"tags":["studio/shot-links"],"summary":"删除项目-章节-镜头-演员关联","operationId":"delete_project_actor_link_api_v1_studio_shot_links_actor__link_id__delete","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/scene":{"post":{"tags":["studio/shot-links"],"summary":"创建项目-章节-镜头-场景关联","operationId":"create_project_scene_link_api_v1_studio_shot_links_scene_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAssetLinkCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectSceneLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/scene/{link_id}":{"delete":{"tags":["studio/shot-links"],"summary":"删除项目-章节-镜头-场景关联","operationId":"delete_project_scene_link_api_v1_studio_shot_links_scene__link_id__delete","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/prop":{"post":{"tags":["studio/shot-links"],"summary":"创建项目-章节-镜头-道具关联","operationId":"create_project_prop_link_api_v1_studio_shot_links_prop_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAssetLinkCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectPropLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/prop/{link_id}":{"delete":{"tags":["studio/shot-links"],"summary":"删除项目-章节-镜头-道具关联","operationId":"delete_project_prop_link_api_v1_studio_shot_links_prop__link_id__delete","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/costume":{"post":{"tags":["studio/shot-links"],"summary":"创建项目-章节-镜头-服装关联","operationId":"create_project_costume_link_api_v1_studio_shot_links_costume_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAssetLinkCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectCostumeLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/costume/{link_id}":{"delete":{"tags":["studio/shot-links"],"summary":"删除项目-章节-镜头-服装关联","operationId":"delete_project_costume_link_api_v1_studio_shot_links_costume__link_id__delete","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-frame-images":{"get":{"tags":["studio/shot-frame-images"],"summary":"镜头分镜帧图片列表(分页)","operationId":"list_shot_frame_images_api_v1_studio_shot_frame_images_get","parameters":[{"name":"shot_detail_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按镜头细节过滤","title":"Shot Detail Id"},"description":"按镜头细节过滤"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ShotFrameImageRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/shot-frame-images"],"summary":"创建镜头分镜帧图片","operationId":"create_shot_frame_image_api_v1_studio_shot_frame_images_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotFrameImageCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotFrameImageRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-frame-images/{image_id}":{"patch":{"tags":["studio/shot-frame-images"],"summary":"更新镜头分镜帧图片","operationId":"update_shot_frame_image_api_v1_studio_shot_frame_images__image_id__patch","parameters":[{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","title":"Image Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotFrameImageUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotFrameImageRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/shot-frame-images"],"summary":"删除镜头分镜帧图片","operationId":"delete_shot_frame_image_api_v1_studio_shot_frame_images__image_id__delete","parameters":[{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","title":"Image Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/entities/existence-check":{"post":{"tags":["studio/entities"],"summary":"批量检测资产名称是否存在(模糊匹配,不分页)","operationId":"check_entity_names_existence_api_v1_studio_entities_existence_check_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityNameExistenceCheckRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_EntityNameExistenceCheckResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/entities/{entity_type}":{"get":{"tags":["studio/entities"],"summary":"统一实体列表(分页)","operationId":"list_entities_api_v1_studio_entities__entity_type__get","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 name/description","title":"Q"},"description":"关键字,过滤 name/description"},{"name":"style","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"题材/风格(单值)","title":"Style"},"description":"题材/风格(单值)"},{"name":"visual_style","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"画面表现形式(单值:真人/动漫)","title":"Visual Style"},"description":"画面表现形式(单值:真人/动漫)"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_dict_str__Any___"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/entities"],"summary":"统一创建实体","operationId":"create_entity_api_v1_studio_entities__entity_type__post","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_str__Any__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/entities/{entity_type}/{entity_id}":{"get":{"tags":["studio/entities"],"summary":"统一获取实体","operationId":"get_entity_api_v1_studio_entities__entity_type___entity_id__get","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_str__Any__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/entities"],"summary":"统一更新实体","operationId":"update_entity_api_v1_studio_entities__entity_type___entity_id__patch","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_str__Any__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/entities"],"summary":"统一删除实体","operationId":"delete_entity_api_v1_studio_entities__entity_type___entity_id__delete","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/entities/{entity_type}/{entity_id}/images":{"get":{"tags":["studio/entities"],"summary":"统一实体图片列表(分页)","operationId":"list_entity_images_api_v1_studio_entities__entity_type___entity_id__images_get","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_dict_str__Any___"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/entities"],"summary":"统一创建实体图片","operationId":"create_entity_image_api_v1_studio_entities__entity_type___entity_id__images_post","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_str__Any__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/entities/{entity_type}/{entity_id}/images/{image_id}":{"patch":{"tags":["studio/entities"],"summary":"统一更新实体图片","operationId":"update_entity_image_api_v1_studio_entities__entity_type___entity_id__images__image_id__patch","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","title":"Image Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_str__Any__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/entities"],"summary":"统一删除实体图片","operationId":"delete_entity_image_api_v1_studio_entities__entity_type___entity_id__images__image_id__delete","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","title":"Image Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/prompts":{"get":{"tags":["studio/prompts"],"summary":"提示词模板列表(分页)","operationId":"list_prompt_templates_api_v1_studio_prompts_get","parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/PromptCategory"},{"type":"null"}],"description":"按类别过滤","title":"Category"},"description":"按类别过滤"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 name","title":"Q"},"description":"关键字,过滤 name"},{"name":"is_default","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"过滤是否为默认","title":"Is Default"},"description":"过滤是否为默认"},{"name":"is_system","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"过滤是否为系统预置","title":"Is System"},"description":"过滤是否为系统预置"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_PromptTemplateRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/prompts"],"summary":"创建提示词模板","operationId":"create_prompt_template_api_v1_studio_prompts_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTemplateCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PromptTemplateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/prompts/categories":{"get":{"tags":["studio/prompts"],"summary":"获取提示词类别枚举(含中文映射)","operationId":"list_prompt_categories_api_v1_studio_prompts_categories_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_list_PromptCategoryOptionRead__"}}}}}}},"/api/v1/studio/prompts/{template_id}":{"get":{"tags":["studio/prompts"],"summary":"获取提示词模板详情","operationId":"get_prompt_template_api_v1_studio_prompts__template_id__get","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PromptTemplateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/prompts"],"summary":"局部更新提示词模板","operationId":"update_prompt_template_api_v1_studio_prompts__template_id__patch","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTemplateUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PromptTemplateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/prompts"],"summary":"删除提示词模板","operationId":"delete_prompt_template_api_v1_studio_prompts__template_id__delete","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/files":{"get":{"tags":["studio/files"],"summary":"文件列表(分页)","operationId":"list_files_api_api_v1_studio_files_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 name","title":"Q"},"description":"关键字,过滤 name"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 file_usages 限定项目;提供后仅返回该项目下有关联记录的文件","title":"Project Id"},"description":"按 file_usages 限定项目;提供后仅返回该项目下有关联记录的文件"},{"name":"chapter_title","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"章节标题(精确匹配,与 project_id 联用)","title":"Chapter Title"},"description":"章节标题(精确匹配,与 project_id 联用)"},{"name":"shot_title","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"镜头标题(精确匹配,与 project_id 联用)","title":"Shot Title"},"description":"镜头标题(精确匹配,与 project_id 联用)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_FileRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/files/upload":{"post":{"tags":["studio/files"],"summary":"上传文件并创建 FileItem 记录","operationId":"upload_file_api_api_v1_studio_files_upload_post","parameters":[{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_file_api_api_v1_studio_files_upload_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_FileRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/files/{file_id}/download":{"get":{"tags":["studio/files"],"summary":"下载文件二进制内容","operationId":"download_file_api_api_v1_studio_files__file_id__download_get","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","title":"File Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/files/{file_id}/storage-info":{"get":{"tags":["studio/files"],"summary":"获取对象存储详情(head_object)","operationId":"get_file_storage_info_api_api_v1_studio_files__file_id__storage_info_get","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","title":"File Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/files/{file_id}":{"get":{"tags":["studio/files"],"summary":"获取文件详情(元信息 + file_usages)","operationId":"get_file_detail_api_v1_studio_files__file_id__get","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","title":"File Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_FileDetailRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/files"],"summary":"更新文件元信息","operationId":"update_file_meta_api_v1_studio_files__file_id__patch","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","title":"File Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_FileRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/files"],"summary":"删除文件(记录 + 存储对象)","operationId":"delete_file_api_api_v1_studio_files__file_id__delete","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","title":"File Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/actors/{actor_id}/image-tasks":{"post":{"tags":["studio/image-tasks"],"summary":"演员图片生成(任务版)","description":"为指定演员创建图片生成任务,并通过 `GenerationTaskLink` 关联。","operationId":"create_actor_image_generation_task_api_v1_studio_image_tasks_actors__actor_id__image_tasks_post","parameters":[{"name":"actor_id","in":"path","required":true,"schema":{"type":"string","title":"Actor Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioImageTaskRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/actors/{actor_id}/render-prompt":{"post":{"tags":["studio/image-tasks"],"summary":"演员图片提示词渲染","operationId":"render_actor_image_prompt_api_v1_studio_image_tasks_actors__actor_id__render_prompt_post","parameters":[{"name":"actor_id","in":"path","required":true,"schema":{"type":"string","title":"Actor Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioImageTaskRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_RenderedPromptResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/assets/{asset_type}/{asset_id}/image-tasks":{"post":{"tags":["studio/image-tasks"],"summary":"道具/场景/服装图片生成(任务版)","description":"为道具/场景/服装创建图片生成任务。\n\n- asset_type: prop / scene / costume\n- path 参数 asset_id 为对应资产 ID\n- body.image_id 必须为该资产下对应图片表记录的 ID(PropImage/SceneImage/CostumeImage)","operationId":"create_asset_image_generation_task_api_v1_studio_image_tasks_assets__asset_type___asset_id__image_tasks_post","parameters":[{"name":"asset_type","in":"path","required":true,"schema":{"type":"string","title":"Asset Type"}},{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioImageTaskRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/assets/{asset_type}/{asset_id}/render-prompt":{"post":{"tags":["studio/image-tasks"],"summary":"道具/场景/服装图片提示词渲染","operationId":"render_asset_image_prompt_api_v1_studio_image_tasks_assets__asset_type___asset_id__render_prompt_post","parameters":[{"name":"asset_type","in":"path","required":true,"schema":{"type":"string","title":"Asset Type"}},{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioImageTaskRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_RenderedPromptResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/characters/{character_id}/image-tasks":{"post":{"tags":["studio/image-tasks"],"summary":"角色图片生成(任务版)","description":"为角色创建图片生成任务(对应 CharacterImage 业务)。\n\n- path 参数 character_id 为 Character.id\n- body.image_id 必须为该角色下的 CharacterImage.id","operationId":"create_character_image_generation_task_api_v1_studio_image_tasks_characters__character_id__image_tasks_post","parameters":[{"name":"character_id","in":"path","required":true,"schema":{"type":"string","title":"Character Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioImageTaskRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/characters/{character_id}/render-prompt":{"post":{"tags":["studio/image-tasks"],"summary":"角色图片提示词渲染","operationId":"render_character_image_prompt_api_v1_studio_image_tasks_characters__character_id__render_prompt_post","parameters":[{"name":"character_id","in":"path","required":true,"schema":{"type":"string","title":"Character Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioImageTaskRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_RenderedPromptResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/shot/{shot_id}/frame-image-tasks":{"post":{"tags":["studio/image-tasks"],"summary":"镜头分镜帧图片生成(任务版)","description":"为镜头分镜帧图片生成任务(基于 `shot_id + frame_type` 自动定位数据)。","operationId":"create_shot_frame_image_generation_task_api_v1_studio_image_tasks_shot__shot_id__frame_image_tasks_post","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotFrameImageTaskRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/shot/{shot_id}/frame-render-prompt":{"post":{"tags":["studio/image-tasks"],"summary":"镜头分镜帧提示词渲染","operationId":"render_shot_frame_prompt_api_v1_studio_image_tasks_shot__shot_id__frame_render_prompt_post","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotFramePromptRenderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_RenderedShotFramePromptRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-character-links":{"get":{"tags":["studio/shot-character-links"],"summary":"查询镜头角色关联列表(ShotCharacterLink)","operationId":"list_shot_character_links_api_v1_studio_shot_character_links_get","parameters":[{"name":"shot_id","in":"query","required":true,"schema":{"type":"string","description":"镜头 ID","title":"Shot Id"},"description":"镜头 ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_list_ShotCharacterLinkRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/shot-character-links"],"summary":"创建/更新镜头角色关联(ShotCharacterLink)","operationId":"upsert_shot_character_link_api_v1_studio_shot_character_links_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotCharacterLinkCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotCharacterLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/divide-async":{"post":{"tags":["script-processing"],"summary":"异步将剧本分割为多个镜头","description":"创建章节分镜提取任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"divide_script_async_api_v1_script_processing_divide_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptDividerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/divide":{"post":{"tags":["script-processing"],"summary":"将剧本分割为多个镜头","description":"输入完整剧本文本,输出分镜列表(index/start_line/end_line/script_excerpt/shot_name/time_of_day)。注意:此阶段不强制稳定ID,角色以“称呼/名字”弱信息输出,稳定ID在合并阶段统一分配。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 divide-async。","operationId":"divide_script_api_v1_script_processing_divide_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptDividerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ScriptDivisionResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/merge-entities-async":{"post":{"tags":["script-processing"],"summary":"异步合并多镜头的实体信息","description":"创建实体合并任务并立即返回 task_id;当前保留为预备能力,尚无真实前端入口。","operationId":"merge_entities_async_api_v1_script_processing_merge_entities_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityMergerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/merge-entities":{"post":{"tags":["script-processing"],"summary":"合并多镜头的实体信息","description":"输入全部分镜提取结果(可选带上脚本分镜与历史实体库),输出合并后的实体库:角色库/地点库/场景库/道具库(静态画像 + 变体列表)。该步骤会统一分配稳定ID(如 char_001/loc_001/prop_001/scene_001)。当提供 previous_merge 与 conflict_resolutions 时,将进行冲突重试合并,优先消解 conflicts 并尽量保持 ID 稳定。当前接口保留为预备能力,尚无真实前端入口。","operationId":"merge_entities_api_v1_script_processing_merge_entities_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityMergerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_EntityMergeResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-variants-async":{"post":{"tags":["script-processing"],"summary":"异步分析服装/外形变体","description":"创建变体分析任务并立即返回 task_id;当前保留为预备能力,尚无真实前端入口。","operationId":"analyze_variants_async_api_v1_script_processing_analyze_variants_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VariantAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-variants":{"post":{"tags":["script-processing"],"summary":"分析服装/外形变体","description":"检测角色服装/外形变化,构建演变时间线,生成章节变体建议列表与变体建议。当前接口保留为预备能力,尚无真实前端入口。","operationId":"analyze_variants_api_v1_script_processing_analyze_variants_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VariantAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_VariantAnalysisResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/check-consistency-async":{"post":{"tags":["script-processing"],"summary":"异步检查角色混淆一致性(基于原文)","description":"创建一致性检查任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"check_consistency_async_api_v1_script_processing_check_consistency_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptConsistencyCheckRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/check-consistency":{"post":{"tags":["script-processing"],"summary":"检查角色混淆一致性(基于原文)","description":"检测同一角色在不同段落/镜头被赋予不同身份/行为主体导致混淆,并给出修改建议。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 check-consistency-async。","operationId":"check_consistency_api_v1_script_processing_check_consistency_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptConsistencyCheckRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ScriptConsistencyCheckResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-character-portrait-async":{"post":{"tags":["script-processing"],"summary":"异步分析人物画像缺失信息","description":"创建人物画像分析任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"analyze_character_portrait_async_api_v1_script_processing_analyze_character_portrait_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CharacterPortraitAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-character-portrait":{"post":{"tags":["script-processing"],"summary":"分析人物画像缺失信息","description":"根据原文人物上下文与人物描述,判断缺少哪些关键信息,并给出优化后的人物画像描述。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 analyze-character-portrait-async。","operationId":"analyze_character_portrait_api_v1_script_processing_analyze_character_portrait_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CharacterPortraitAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_CharacterPortraitAnalysisResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-prop-info-async":{"post":{"tags":["script-processing"],"summary":"异步分析道具信息缺失项","description":"创建道具信息分析任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"analyze_prop_info_async_api_v1_script_processing_analyze_prop_info_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropInfoAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-prop-info":{"post":{"tags":["script-processing"],"summary":"分析道具信息缺失项","description":"根据原文道具上下文与道具描述,判断缺少哪些关键信息,并给出优化后的可生成道具描述。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 analyze-prop-info-async。","operationId":"analyze_prop_info_api_v1_script_processing_analyze_prop_info_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropInfoAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PropInfoAnalysisResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-scene-info-async":{"post":{"tags":["script-processing"],"summary":"异步分析场景信息缺失项","description":"创建场景信息分析任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"analyze_scene_info_async_api_v1_script_processing_analyze_scene_info_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneInfoAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-scene-info":{"post":{"tags":["script-processing"],"summary":"分析场景信息缺失项","description":"根据原文场景上下文与场景描述,判断缺少哪些关键信息,并给出优化后的可生成场景描述。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 analyze-scene-info-async。","operationId":"analyze_scene_info_api_v1_script_processing_analyze_scene_info_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneInfoAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_SceneInfoAnalysisResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-costume-info-async":{"post":{"tags":["script-processing"],"summary":"异步分析服装信息缺失项","description":"创建服装信息分析任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"analyze_costume_info_async_api_v1_script_processing_analyze_costume_info_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CostumeInfoAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-costume-info":{"post":{"tags":["script-processing"],"summary":"分析服装信息缺失项","description":"根据原文服装上下文与服装描述,判断缺少哪些关键信息,并给出优化后的可生成服装描述。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 analyze-costume-info-async。","operationId":"analyze_costume_info_api_v1_script_processing_analyze_costume_info_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CostumeInfoAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_CostumeInfoAnalysisResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/optimize-script-async":{"post":{"tags":["script-processing"],"summary":"异步基于一致性检查优化剧本","description":"创建剧本优化任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"optimize_script_async_api_v1_script_processing_optimize_script_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptOptimizeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/optimize-script":{"post":{"tags":["script-processing"],"summary":"基于一致性检查优化剧本","description":"将一致性检查输出及原文作为输入,生成优化后的剧本(尽量少改,只改与角色混淆 issues 相关段落)。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 optimize-script-async。","operationId":"optimize_script_api_v1_script_processing_optimize_script_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptOptimizeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ScriptOptimizationResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/simplify-script":{"post":{"tags":["script-processing"],"summary":"智能精简剧本","description":"在保留剧情主体并保证剧情连续的前提下精简剧本文本。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 simplify-script-async。","operationId":"simplify_script_api_v1_script_processing_simplify_script_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptSimplifyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ScriptSimplificationResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/simplify-script-async":{"post":{"tags":["script-processing"],"summary":"异步智能精简剧本","description":"创建剧本精简任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"simplify_script_async_api_v1_script_processing_simplify_script_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptSimplifyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/extract-async":{"post":{"tags":["script-processing"],"summary":"异步项目级信息提取(最终输出)","description":"创建项目级信息提取任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"extract_script_async_api_v1_script_processing_extract_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptExtractRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/extract":{"post":{"tags":["script-processing"],"summary":"项目级信息提取(最终输出)","description":"输入分镜结果(可选带一致性检查结果),输出可导入 Studio 的草稿结构(name-based,ID 由导入接口生成)。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 extract-async。","operationId":"extract_script_api_v1_script_processing_extract_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptExtractRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_StudioScriptExtractionDraft_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/health":{"get":{"summary":"Health","description":"健康检查。","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"ApiResponse_AsyncTaskCreateRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/AsyncTaskCreateRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[AsyncTaskCreateRead]"},"ApiResponse_ChapterRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ChapterRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ChapterRead]"},"ApiResponse_CharacterPortraitAnalysisResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/CharacterPortraitAnalysisResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[CharacterPortraitAnalysisResult]"},"ApiResponse_CostumeInfoAnalysisResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/CostumeInfoAnalysisResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[CostumeInfoAnalysisResult]"},"ApiResponse_EntityMergeResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/EntityMergeResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[EntityMergeResult]"},"ApiResponse_EntityNameExistenceCheckResponse_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/EntityNameExistenceCheckResponse"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[EntityNameExistenceCheckResponse]"},"ApiResponse_FileDetailRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/FileDetailRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[FileDetailRead]"},"ApiResponse_FileRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/FileRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[FileRead]"},"ApiResponse_GenerationTaskLinkRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/GenerationTaskLinkRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[GenerationTaskLinkRead]"},"ApiResponse_ImageGenerationOptionsRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ImageGenerationOptionsRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ImageGenerationOptionsRead]"},"ApiResponse_ModelRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ModelRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ModelRead]"},"ApiResponse_ModelSettingsRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ModelSettingsRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ModelSettingsRead]"},"ApiResponse_NoneType_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"type":"null","title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[NoneType]"},"ApiResponse_PaginatedData_Any__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_Any_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[Any]]"},"ApiResponse_PaginatedData_ChapterRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ChapterRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ChapterRead]]"},"ApiResponse_PaginatedData_FileRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_FileRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[FileRead]]"},"ApiResponse_PaginatedData_GenerationTaskLinkRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_GenerationTaskLinkRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[GenerationTaskLinkRead]]"},"ApiResponse_PaginatedData_ModelRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ModelRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ModelRead]]"},"ApiResponse_PaginatedData_ProjectRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ProjectRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ProjectRead]]"},"ApiResponse_PaginatedData_PromptTemplateRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_PromptTemplateRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[PromptTemplateRead]]"},"ApiResponse_PaginatedData_ProviderRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ProviderRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ProviderRead]]"},"ApiResponse_PaginatedData_ShotDetailRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ShotDetailRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ShotDetailRead]]"},"ApiResponse_PaginatedData_ShotDialogLineRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ShotDialogLineRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ShotDialogLineRead]]"},"ApiResponse_PaginatedData_ShotFrameImageRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ShotFrameImageRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ShotFrameImageRead]]"},"ApiResponse_PaginatedData_ShotLinkedAssetItem__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ShotLinkedAssetItem_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ShotLinkedAssetItem]]"},"ApiResponse_PaginatedData_ShotRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ShotRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ShotRead]]"},"ApiResponse_PaginatedData_TaskListItemRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_TaskListItemRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[TaskListItemRead]]"},"ApiResponse_PaginatedData_dict_str__Any___":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_dict_str__Any__"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[dict[str, Any]]]"},"ApiResponse_ProjectActorLinkRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProjectActorLinkRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProjectActorLinkRead]"},"ApiResponse_ProjectCostumeLinkRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProjectCostumeLinkRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProjectCostumeLinkRead]"},"ApiResponse_ProjectPropLinkRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProjectPropLinkRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProjectPropLinkRead]"},"ApiResponse_ProjectRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProjectRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProjectRead]"},"ApiResponse_ProjectSceneLinkRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProjectSceneLinkRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProjectSceneLinkRead]"},"ApiResponse_ProjectStyleOptionsRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProjectStyleOptionsRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProjectStyleOptionsRead]"},"ApiResponse_PromptTemplateRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PromptTemplateRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PromptTemplateRead]"},"ApiResponse_PropInfoAnalysisResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PropInfoAnalysisResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PropInfoAnalysisResult]"},"ApiResponse_ProviderRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProviderRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProviderRead]"},"ApiResponse_RenderedPromptResponse_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/RenderedPromptResponse"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[RenderedPromptResponse]"},"ApiResponse_RenderedShotFramePromptRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/RenderedShotFramePromptRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[RenderedShotFramePromptRead]"},"ApiResponse_SceneInfoAnalysisResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/SceneInfoAnalysisResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[SceneInfoAnalysisResult]"},"ApiResponse_ScriptConsistencyCheckResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ScriptConsistencyCheckResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ScriptConsistencyCheckResult]"},"ApiResponse_ScriptDivisionResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ScriptDivisionResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ScriptDivisionResult]"},"ApiResponse_ScriptOptimizationResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ScriptOptimizationResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ScriptOptimizationResult]"},"ApiResponse_ScriptSimplificationResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ScriptSimplificationResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ScriptSimplificationResult]"},"ApiResponse_ShotAssetsOverviewRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotAssetsOverviewRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotAssetsOverviewRead]"},"ApiResponse_ShotCharacterLinkRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotCharacterLinkRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotCharacterLinkRead]"},"ApiResponse_ShotDetailRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotDetailRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotDetailRead]"},"ApiResponse_ShotDialogLineRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotDialogLineRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotDialogLineRead]"},"ApiResponse_ShotFrameImageRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotFrameImageRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotFrameImageRead]"},"ApiResponse_ShotPreparationMutationResultRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotPreparationMutationResultRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotPreparationMutationResultRead]"},"ApiResponse_ShotPreparationStateRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotPreparationStateRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotPreparationStateRead]"},"ApiResponse_ShotRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotRead]"},"ApiResponse_ShotVideoPromptPreviewRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotVideoPromptPreviewRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotVideoPromptPreviewRead]"},"ApiResponse_ShotVideoReadinessRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotVideoReadinessRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotVideoReadinessRead]"},"ApiResponse_StudioScriptExtractionDraft_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/StudioScriptExtractionDraft"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[StudioScriptExtractionDraft]"},"ApiResponse_TaskCancelRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/TaskCancelRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[TaskCancelRead]"},"ApiResponse_TaskCreated_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/TaskCreated"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[TaskCreated]"},"ApiResponse_TaskLinkAdoptRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/TaskLinkAdoptRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[TaskLinkAdoptRead]"},"ApiResponse_TaskResultRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/TaskResultRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[TaskResultRead]"},"ApiResponse_TaskStatusRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/TaskStatusRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[TaskStatusRead]"},"ApiResponse_VariantAnalysisResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/VariantAnalysisResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[VariantAnalysisResult]"},"ApiResponse_VideoGenerationOptionsRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/VideoGenerationOptionsRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[VideoGenerationOptionsRead]"},"ApiResponse_VideoPromptPreviewResponse_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/VideoPromptPreviewResponse"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[VideoPromptPreviewResponse]"},"ApiResponse_dict_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[dict]"},"ApiResponse_dict_str__Any__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[dict[str, Any]]"},"ApiResponse_list_PromptCategoryOptionRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/PromptCategoryOptionRead"},"type":"array"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[list[PromptCategoryOptionRead]]"},"ApiResponse_list_ProviderSupportedRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/ProviderSupportedRead"},"type":"array"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[list[ProviderSupportedRead]]"},"ApiResponse_list_ShotCharacterLinkRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/ShotCharacterLinkRead"},"type":"array"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[list[ShotCharacterLinkRead]]"},"ApiResponse_list_ShotExtractedCandidateRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/ShotExtractedCandidateRead"},"type":"array"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[list[ShotExtractedCandidateRead]]"},"ApiResponse_list_ShotExtractedDialogueCandidateRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/ShotExtractedDialogueCandidateRead"},"type":"array"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[list[ShotExtractedDialogueCandidateRead]]"},"ApiResponse_list_ShotRuntimeSummaryRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/ShotRuntimeSummaryRead"},"type":"array"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[list[ShotRuntimeSummaryRead]]"},"AsyncTaskCreateRead":{"properties":{"task_id":{"type":"string","title":"Task Id","description":"任务 ID"},"status":{"$ref":"#/components/schemas/TaskStatus","description":"任务状态"},"reused":{"type":"boolean","title":"Reused","description":"是否复用了当前业务实体已有的活跃任务","default":false},"relation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Type","description":"业务关联类型"},"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"业务关联实体 ID"}},"type":"object","required":["task_id","status"],"title":"AsyncTaskCreateRead"},"Body_upload_file_api_api_v1_studio_files_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"要上传的二进制文件"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"可选:写入 file_usages 的项目 ID"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id"},"usage_kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Usage Kind","description":"与 project_id 同时提供时写入 file_usages"},"source_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Ref"}},"type":"object","required":["file"],"title":"Body_upload_file_api_api_v1_studio_files_upload_post"},"CameraAngle":{"type":"string","enum":["EYE_LEVEL","HIGH_ANGLE","LOW_ANGLE","BIRD_EYE","DUTCH","OVER_SHOULDER"],"title":"CameraAngle","description":"机位角度(与 `app.schemas.skills.common.CameraAngle` 对齐,存英文 code)。"},"CameraMovement":{"type":"string","enum":["STATIC","PAN","TILT","DOLLY_IN","DOLLY_OUT","TRACK","CRANE","HANDHELD","STEADICAM","ZOOM_IN","ZOOM_OUT"],"title":"CameraMovement","description":"运镜方式(与 `app.schemas.skills.common.CameraMovement` 对齐,存英文 code)。"},"CameraShotType":{"type":"string","enum":["ECU","CU","MCU","MS","MLS","LS","ELS"],"title":"CameraShotType","description":"景别(与 `app.schemas.skills.common.ShotType` 对齐,存英文 code)。"},"ChapterCreate":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"所属项目 ID"},"index":{"type":"integer","title":"Index","description":"章节序号(项目内唯一)"},"title":{"type":"string","title":"Title","description":"章节标题"},"summary":{"type":"string","title":"Summary","description":"章节摘要","default":""},"raw_text":{"type":"string","title":"Raw Text","description":"章节原文","default":""},"condensed_text":{"type":"string","title":"Condensed Text","description":"精简原文","default":""},"storyboard_count":{"type":"integer","title":"Storyboard Count","description":"分镜数量","default":0},"status":{"$ref":"#/components/schemas/ChapterStatus","description":"章节状态","default":"draft"},"id":{"type":"string","title":"Id","description":"章节 ID"}},"type":"object","required":["project_id","index","title","id"],"title":"ChapterCreate"},"ChapterRead":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"所属项目 ID"},"index":{"type":"integer","title":"Index","description":"章节序号(项目内唯一)"},"title":{"type":"string","title":"Title","description":"章节标题"},"summary":{"type":"string","title":"Summary","description":"章节摘要","default":""},"raw_text":{"type":"string","title":"Raw Text","description":"章节原文","default":""},"condensed_text":{"type":"string","title":"Condensed Text","description":"精简原文","default":""},"storyboard_count":{"type":"integer","title":"Storyboard Count","description":"分镜数量","default":0},"status":{"$ref":"#/components/schemas/ChapterStatus","description":"章节状态","default":"draft"},"id":{"type":"string","title":"Id"},"shot_count":{"type":"integer","title":"Shot Count","description":"分镜数(shots 条数聚合)","default":0}},"type":"object","required":["project_id","index","title","id"],"title":"ChapterRead"},"ChapterStatus":{"type":"string","enum":["draft","shooting","done"],"title":"ChapterStatus","description":"章节生产状态。"},"ChapterUpdate":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"},"index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Index"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"raw_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Raw Text"},"condensed_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Condensed Text"},"storyboard_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Storyboard Count"},"status":{"anyOf":[{"$ref":"#/components/schemas/ChapterStatus"},{"type":"null"}]}},"type":"object","title":"ChapterUpdate"},"CharacterPortraitAnalysisRequest":{"properties":{"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"任务关联实体 ID(资产页恢复任务可选)"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"character_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Character Context","description":"原文人物上下文(可为空;用于提供额外背景,帮助判断缺失信息)"},"character_description":{"type":"string","minLength":1,"title":"Character Description","description":"原文人物描述"}},"type":"object","required":["character_description"],"title":"CharacterPortraitAnalysisRequest","description":"人物画像缺失信息分析请求。"},"CharacterPortraitAnalysisResult":{"properties":{"issues":{"items":{"type":"string"},"type":"array","title":"Issues"},"optimized_description":{"type":"string","title":"Optimized Description"}},"additionalProperties":false,"type":"object","required":["issues","optimized_description"],"title":"CharacterPortraitAnalysisResult","description":"根据原文人物描述,分析缺少的信息,并给出优化后的可生成画像描述。"},"CostumeInfoAnalysisRequest":{"properties":{"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"任务关联实体 ID(资产页恢复任务可选)"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"costume_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Costume Context","description":"原文服装上下文(可为空;用于提供额外背景,帮助判断缺失信息)"},"costume_description":{"type":"string","minLength":1,"title":"Costume Description","description":"原文服装描述"}},"type":"object","required":["costume_description"],"title":"CostumeInfoAnalysisRequest","description":"服装信息缺失分析请求。"},"CostumeInfoAnalysisResult":{"properties":{"issues":{"items":{"type":"string"},"type":"array","title":"Issues"},"optimized_description":{"type":"string","title":"Optimized Description"}},"additionalProperties":false,"type":"object","required":["issues","optimized_description"],"title":"CostumeInfoAnalysisResult","description":"根据原文服装/造型描述,分析缺少的信息,并给出优化后的可生成服装描述。"},"CostumeTimeline":{"properties":{"character_id":{"type":"string","title":"Character Id","description":"角色稳定ID"},"character_name":{"type":"string","title":"Character Name","description":"角色名称"},"timeline_entries":{"items":{"$ref":"#/components/schemas/CostumeTimelineEntry"},"type":"array","title":"Timeline Entries","description":"时间线条目"}},"additionalProperties":false,"type":"object","required":["character_id","character_name"],"title":"CostumeTimeline","description":"单角色的服装演变时间线。"},"CostumeTimelineEntry":{"properties":{"shot_index":{"type":"integer","minimum":1.0,"title":"Shot Index","description":"镜头序号"},"scene_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Id","description":"可选:所属场景稳定ID(若已可推断)"},"costume_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Costume Note","description":"服装/外形要点(简短)"},"changes":{"items":{"type":"string"},"type":"array","title":"Changes","description":"与上一条相比的变化点"},"evidence":{"items":{"$ref":"#/components/schemas/EvidenceSpan"},"type":"array","title":"Evidence","description":"原文依据(可选)"}},"additionalProperties":false,"type":"object","required":["shot_index"],"title":"CostumeTimelineEntry","description":"单角色的服装演变时间线条目。"},"DialogueLineMode":{"type":"string","enum":["DIALOGUE","VOICE_OVER","OFF_SCREEN","PHONE"],"title":"DialogueLineMode","description":"对白模式(与 `app.schemas.skills.common.DialogueLineMode` 对齐,存英文 code)。"},"EntityEntry":{"properties":{"id":{"type":"string","title":"Id","description":"实体稳定ID(合并阶段分配)"},"name":{"type":"string","title":"Name","description":"实体名称"},"type":{"type":"string","enum":["character","scene","prop","location"],"title":"Type","description":"实体类型"},"normalized_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Normalized Name","description":"归一化名称(来自文本,可选)"},"aliases":{"items":{"type":"string"},"type":"array","title":"Aliases","description":"别名/称呼(来自文本,可选)"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"基础画像/描述(忠实文本,简短)"},"confidence":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Confidence","description":"合并确定度 0-1(可选)"},"first_appearance":{"anyOf":[{"$ref":"#/components/schemas/EvidenceSpan"},{"type":"null"}],"description":"首次出场证据(可选)"},"costume_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Costume Note","description":"服装/造型描述(可选,便于变体与资产关联)"},"traits":{"items":{"type":"string"},"type":"array","title":"Traits","description":"性格/特征词(可选)"},"location_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location Type","description":"地点类型:房间/街道/森林/车厢等(可选)"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"道具类别(可选:weapon/document/vehicle/clothing/device/magic_item/other)"},"owner_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner Character Id","description":"拥有者角色ID(可选)"},"evidence":{"items":{"$ref":"#/components/schemas/EvidenceSpan"},"type":"array","title":"Evidence","description":"支撑该实体画像的证据片段(可选)"},"first_shot":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"First Shot","description":"首次出现的镜头序号"},"appearances":{"items":{"type":"integer"},"type":"array","title":"Appearances","description":"出现镜头列表"},"variants":{"items":{"$ref":"#/components/schemas/EntityVariant"},"type":"array","title":"Variants","description":"变体列表"}},"additionalProperties":false,"type":"object","required":["id","name","type"],"title":"EntityEntry","description":"合并后的实体条目(脚本处理中间态)。"},"EntityLibrary":{"properties":{"characters":{"items":{"$ref":"#/components/schemas/EntityEntry"},"type":"array","title":"Characters","description":"角色库"},"locations":{"items":{"$ref":"#/components/schemas/EntityEntry"},"type":"array","title":"Locations","description":"地点库"},"scenes":{"items":{"$ref":"#/components/schemas/EntityEntry"},"type":"array","title":"Scenes","description":"场景库"},"props":{"items":{"$ref":"#/components/schemas/EntityEntry"},"type":"array","title":"Props","description":"道具库"},"total_entries":{"type":"integer","minimum":0.0,"title":"Total Entries","description":"总实体数"}},"additionalProperties":false,"type":"object","required":["total_entries"],"title":"EntityLibrary","description":"合并后的实体库(脚本处理中间态)。"},"EntityMergeResult":{"properties":{"merged_library":{"$ref":"#/components/schemas/EntityLibrary","description":"合并后的实体库"},"merge_stats":{"additionalProperties":true,"type":"object","title":"Merge Stats","description":"合并统计信息"},"conflicts":{"items":{"type":"string"},"type":"array","title":"Conflicts","description":"发现的冲突/待处理项"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"合并说明"}},"additionalProperties":false,"type":"object","required":["merged_library"],"title":"EntityMergeResult","description":"实体合并结果(脚本处理中间态)。"},"EntityMergerRequest":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"all_shot_extractions":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"All Shot Extractions","description":"所有镜头提取结果(ShotElementExtractionResult 的序列化形式)"},"historical_library":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Historical Library","description":"历史实体库(可选,用于增量合并)"},"script_division":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Script Division","description":"脚本分镜结果(可选;ScriptDivisionResult 序列化),用于定位与统计"},"previous_merge":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Previous Merge","description":"上一次合并结果(可选;EntityMergeResult 序列化),用于冲突重试合并"},"conflict_resolutions":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Conflict Resolutions","description":"冲突解决建议列表(可选;用于冲突重试合并)"}},"type":"object","required":["all_shot_extractions"],"title":"EntityMergerRequest","description":"实体合并请求。"},"EntityNameExistenceCheckRequest":{"properties":{"project_id":{"type":"string","minLength":1,"title":"Project Id","description":"项目 ID(必填)"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"镜头 ID(可选;不传则 linked_to_shot 恒为 false)"},"character_names":{"items":{"type":"string"},"type":"array","title":"Character Names","description":"角色名称列表"},"prop_names":{"items":{"type":"string"},"type":"array","title":"Prop Names","description":"道具名称列表"},"scene_names":{"items":{"type":"string"},"type":"array","title":"Scene Names","description":"场景名称列表"},"costume_names":{"items":{"type":"string"},"type":"array","title":"Costume Names","description":"服装名称列表"}},"additionalProperties":false,"type":"object","required":["project_id"],"title":"EntityNameExistenceCheckRequest","description":"批量检测项目内/全局资产名称是否存在(模糊匹配)。"},"EntityNameExistenceCheckResponse":{"properties":{"characters":{"items":{"$ref":"#/components/schemas/EntityNameExistenceItem"},"type":"array","title":"Characters"},"props":{"items":{"$ref":"#/components/schemas/EntityNameExistenceItem"},"type":"array","title":"Props"},"scenes":{"items":{"$ref":"#/components/schemas/EntityNameExistenceItem"},"type":"array","title":"Scenes"},"costumes":{"items":{"$ref":"#/components/schemas/EntityNameExistenceItem"},"type":"array","title":"Costumes"}},"additionalProperties":false,"type":"object","title":"EntityNameExistenceCheckResponse","description":"批量存在性检测结果(按资产类型分组)。"},"EntityNameExistenceItem":{"properties":{"name":{"type":"string","title":"Name","description":"输入名称(原样回传)"},"exists":{"type":"boolean","title":"Exists","description":"数据库中是否存在(模糊命中)"},"linked_to_project":{"type":"boolean","title":"Linked To Project","description":"是否已关联到该项目(角色等同于 exists)"},"linked_to_shot":{"type":"boolean","title":"Linked To Shot","description":"是否已关联到请求中的 shot(未传 shot_id 时为 false)","default":false},"asset_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Asset Id","description":"命中的资产 ID(如 prop_id/scene_id/costume_id/character_id)"},"link_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Link Id","description":"若已关联到项目,对应 Project*Link 的 id;否则为空"}},"additionalProperties":false,"type":"object","required":["name","exists","linked_to_project"],"title":"EntityNameExistenceItem","description":"单个名称的存在性结果。"},"EntityVariant":{"properties":{"variant_key":{"type":"string","title":"Variant Key","description":"变体键(例如 outfit_v1、wounded_state 等)"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"变体描述(简短)"},"affected_shots":{"items":{"type":"integer"},"type":"array","title":"Affected Shots","description":"涉及镜头序号"},"evidence":{"items":{"$ref":"#/components/schemas/EvidenceSpan"},"type":"array","title":"Evidence","description":"原文依据(可选)"}},"additionalProperties":false,"type":"object","required":["variant_key"],"title":"EntityVariant","description":"实体变体条目(最小可用结构,便于服装/外形演变)。"},"EvidenceSpan":{"properties":{"chunk_id":{"type":"string","title":"Chunk Id","description":"输入文本块的唯一ID(例如 chapter1_p03)"},"start_char":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Start Char","description":"在该 chunk 中的起始字符位置(可选)"},"end_char":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"End Char","description":"在该 chunk 中的结束字符位置(可选)"},"quote":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Quote","description":"不超过200字的原文摘录(可选,便于人工审核)"}},"additionalProperties":false,"type":"object","required":["chunk_id"],"title":"EvidenceSpan","description":"可追溯证据:原文定位(chunk + 起止位置/摘录),用于审核与回查。"},"FileDetailRead":{"properties":{"id":{"type":"string","title":"Id","description":"文件 ID"},"type":{"$ref":"#/components/schemas/FileTypeEnum","description":"文件类型"},"name":{"type":"string","title":"Name","description":"文件名/标题"},"thumbnail":{"type":"string","title":"Thumbnail","description":"缩略图 URL/路径","default":""},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"标签"},"usages":{"items":{"$ref":"#/components/schemas/FileUsageRead"},"type":"array","title":"Usages"}},"type":"object","required":["id","type","name"],"title":"FileDetailRead","description":"含 file_usages 列表(详情接口)。"},"FileRead":{"properties":{"id":{"type":"string","title":"Id","description":"文件 ID"},"type":{"$ref":"#/components/schemas/FileTypeEnum","description":"文件类型"},"name":{"type":"string","title":"Name","description":"文件名/标题"},"thumbnail":{"type":"string","title":"Thumbnail","description":"缩略图 URL/路径","default":""},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"标签"}},"type":"object","required":["id","type","name"],"title":"FileRead"},"FileTypeEnum":{"type":"string","enum":["image","video"],"title":"FileTypeEnum"},"FileUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"},"usage":{"anyOf":[{"$ref":"#/components/schemas/FileUsageWrite"},{"type":"null"}],"description":"若提供则 upsert 一条 file_usages"}},"type":"object","title":"FileUpdate"},"FileUsageRead":{"properties":{"id":{"type":"integer","title":"Id"},"file_id":{"type":"string","title":"File Id"},"project_id":{"type":"string","title":"Project Id"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id"},"usage_kind":{"type":"string","title":"Usage Kind"},"source_ref":{"type":"string","title":"Source Ref"}},"type":"object","required":["id","file_id","project_id","chapter_id","shot_id","usage_kind","source_ref"],"title":"FileUsageRead"},"FileUsageWrite":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"项目 ID"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"镜头 ID"},"usage_kind":{"type":"string","title":"Usage Kind","description":"用途:shot_frame / generated_video / character_image / asset_image / upload / api 等"},"source_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Ref","description":"幂等键(可选)"}},"type":"object","required":["project_id","usage_kind"],"title":"FileUsageWrite","description":"写入 file_usages 的关联信息(与 FileItem 一并提交)。"},"GenerationTaskLinkCreate":{"properties":{"task_id":{"type":"string","title":"Task Id","description":"生成任务 ID"},"resource_type":{"type":"string","title":"Resource Type","description":"生成资源类型(如 image/video/text/task_link)"},"relation_type":{"type":"string","title":"Relation Type","description":"业务类型(如 prop/costume/scene 等)"},"relation_entity_id":{"type":"string","title":"Relation Entity Id","description":"关联业务实体 ID"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"关联产物文件 ID(files.id;适用于图片/音频/视频)"},"status":{"type":"string","title":"Status","description":"关联状态:accepted=已采用、todo=待操作、rejected=未采用;默认 todo","default":"todo"}},"type":"object","required":["task_id","resource_type","relation_type","relation_entity_id"],"title":"GenerationTaskLinkCreate","description":"创建生成任务关联请求体。"},"GenerationTaskLinkRead":{"properties":{"task_id":{"type":"string","title":"Task Id","description":"生成任务 ID"},"resource_type":{"type":"string","title":"Resource Type","description":"生成资源类型(如 image/video/text/task_link)"},"relation_type":{"type":"string","title":"Relation Type","description":"业务类型(如 prop/costume/scene 等)"},"relation_entity_id":{"type":"string","title":"Relation Entity Id","description":"关联业务实体 ID"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"关联产物文件 ID(files.id;适用于图片/音频/视频)"},"status":{"type":"string","title":"Status","description":"关联状态:accepted=已采用、todo=待操作、rejected=未采用"},"id":{"type":"integer","title":"Id","description":"关联行 ID"}},"type":"object","required":["task_id","resource_type","relation_type","relation_entity_id","status","id"],"title":"GenerationTaskLinkRead","description":"生成任务关联返回体。"},"GenerationTaskLinkUpdate":{"properties":{"resource_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource Type","description":"生成资源类型(如 image/video/text/task_link)"},"relation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Type","description":"业务类型(如 prop/costume/scene 等)"},"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"关联业务实体 ID"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"关联产物文件 ID(files.id;适用于图片/音频/视频)"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"关联状态:accepted=已采用、todo=待操作、rejected=未采用"}},"type":"object","title":"GenerationTaskLinkUpdate","description":"更新生成任务关联请求体(不包含 is_adopted,采用状态由专用接口正向变更)。"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ImageGenerationOptionsRead":{"properties":{"provider":{"type":"string","title":"Provider","description":"供应商稳定键"},"model_id":{"type":"string","title":"Model Id","description":"默认图片模型 ID"},"model_name":{"type":"string","title":"Model Name","description":"默认图片模型名称"},"supported_ratios":{"items":{"type":"string"},"type":"array","title":"Supported Ratios","description":"当前模型支持的目标比例"},"default_resolution_profile":{"type":"string","title":"Default Resolution Profile","description":"当前模型默认分辨率档位"},"ratio_size_profiles":{"additionalProperties":{"additionalProperties":{"type":"string"},"type":"object"},"type":"object","title":"Ratio Size Profiles","description":"按比例和分辨率档位映射得到的像素尺寸"}},"type":"object","required":["provider","model_id","model_name","default_resolution_profile"],"title":"ImageGenerationOptionsRead","description":"当前默认图片模型对应的关键帧规格选项。"},"LogLevel":{"type":"string","enum":["debug","info","warn","error"],"title":"LogLevel","description":"全局日志级别。"},"ModelCategoryKey":{"type":"string","enum":["text","image","video"],"title":"ModelCategoryKey","description":"模型类别:文本/图片/视频。"},"ModelCreate":{"properties":{"name":{"type":"string","title":"Name","description":"模型名称"},"category":{"$ref":"#/components/schemas/ModelCategoryKey","description":"模型类别:text/image/video"},"provider_id":{"type":"string","title":"Provider Id","description":"所属供应商 ID"},"params":{"additionalProperties":true,"type":"object","title":"Params","description":"模型参数(JSON)"},"description":{"type":"string","title":"Description","description":"说明","default":""},"created_by":{"type":"string","title":"Created By","description":"创建人","default":""},"id":{"type":"string","title":"Id","description":"模型 ID"}},"type":"object","required":["name","category","provider_id","id"],"title":"ModelCreate","description":"创建模型请求体。"},"ModelRead":{"properties":{"name":{"type":"string","title":"Name","description":"模型名称"},"category":{"$ref":"#/components/schemas/ModelCategoryKey","description":"模型类别:text/image/video"},"provider_id":{"type":"string","title":"Provider Id","description":"所属供应商 ID"},"params":{"additionalProperties":true,"type":"object","title":"Params","description":"模型参数(JSON)"},"description":{"type":"string","title":"Description","description":"说明","default":""},"created_by":{"type":"string","title":"Created By","description":"创建人","default":""},"id":{"type":"string","title":"Id","description":"模型 ID"}},"type":"object","required":["name","category","provider_id","id"],"title":"ModelRead","description":"对外返回的模型信息。"},"ModelSettingsRead":{"properties":{"default_text_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Text Model Id","description":"默认文本模型 ID"},"default_image_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Image Model Id","description":"默认图片模型 ID"},"default_video_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Video Model Id","description":"默认视频模型 ID"},"api_timeout":{"type":"integer","title":"Api Timeout","description":"API 超时(秒)","default":30},"log_level":{"$ref":"#/components/schemas/LogLevel","description":"日志级别","default":"info"},"id":{"type":"integer","title":"Id","description":"设置行 ID(通常为 1)"}},"type":"object","required":["id"],"title":"ModelSettingsRead","description":"对外返回的模型全局设置。"},"ModelSettingsUpdate":{"properties":{"default_text_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Text Model Id","description":"默认文本模型 ID"},"default_image_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Image Model Id","description":"默认图片模型 ID"},"default_video_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Video Model Id","description":"默认视频模型 ID"},"api_timeout":{"type":"integer","title":"Api Timeout","description":"API 超时(秒)","default":30},"log_level":{"$ref":"#/components/schemas/LogLevel","description":"日志级别","default":"info"}},"type":"object","title":"ModelSettingsUpdate","description":"更新或保存模型全局设置请求体。"},"ModelUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"模型名称"},"category":{"anyOf":[{"$ref":"#/components/schemas/ModelCategoryKey"},{"type":"null"}],"description":"模型类别"},"provider_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider Id","description":"所属供应商 ID"},"params":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Params","description":"模型参数(JSON)"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"说明"}},"type":"object","title":"ModelUpdate","description":"更新模型请求体(全部可选)。"},"PaginatedData_Any_":{"properties":{"items":{"items":{},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[Any]"},"PaginatedData_ChapterRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ChapterRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ChapterRead]"},"PaginatedData_FileRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/FileRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[FileRead]"},"PaginatedData_GenerationTaskLinkRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/GenerationTaskLinkRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[GenerationTaskLinkRead]"},"PaginatedData_ModelRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ModelRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ModelRead]"},"PaginatedData_ProjectRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ProjectRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ProjectRead]"},"PaginatedData_PromptTemplateRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/PromptTemplateRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[PromptTemplateRead]"},"PaginatedData_ProviderRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ProviderRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ProviderRead]"},"PaginatedData_ShotDetailRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ShotDetailRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ShotDetailRead]"},"PaginatedData_ShotDialogLineRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ShotDialogLineRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ShotDialogLineRead]"},"PaginatedData_ShotFrameImageRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ShotFrameImageRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ShotFrameImageRead]"},"PaginatedData_ShotLinkedAssetItem_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ShotLinkedAssetItem"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ShotLinkedAssetItem]"},"PaginatedData_ShotRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ShotRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ShotRead]"},"PaginatedData_TaskListItemRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/TaskListItemRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[TaskListItemRead]"},"PaginatedData_dict_str__Any__":{"properties":{"items":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[dict[str, Any]]"},"Pagination":{"properties":{"page":{"type":"integer","title":"Page","description":"当前页,从 1 开始"},"page_size":{"type":"integer","title":"Page Size","description":"每页条数"},"total":{"type":"integer","title":"Total","description":"总条数"},"max_page":{"type":"integer","title":"Max Page","description":"最大页码"}},"type":"object","required":["page","page_size","total","max_page"],"title":"Pagination","description":"分页信息。"},"ProjectActorLinkRead":{"properties":{"id":{"type":"integer","title":"Id","description":"关联行 ID"},"project_id":{"type":"string","title":"Project Id","description":"项目 ID"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(可空)"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"镜头 ID(可空)"},"actor_id":{"type":"string","title":"Actor Id"},"thumbnail":{"type":"string","title":"Thumbnail","description":"演员缩略图下载地址","default":""}},"type":"object","required":["id","project_id","actor_id"],"title":"ProjectActorLinkRead"},"ProjectAssetLinkCreate":{"properties":{"project_id":{"type":"string","title":"Project Id"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id"},"asset_id":{"type":"string","title":"Asset Id"}},"type":"object","required":["project_id","asset_id"],"title":"ProjectAssetLinkCreate"},"ProjectCostumeLinkRead":{"properties":{"id":{"type":"integer","title":"Id","description":"关联行 ID"},"project_id":{"type":"string","title":"Project Id","description":"项目 ID"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(可空)"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"镜头 ID(可空)"},"costume_id":{"type":"string","title":"Costume Id"},"thumbnail":{"type":"string","title":"Thumbnail","description":"服装缩略图下载地址","default":""}},"type":"object","required":["id","project_id","costume_id"],"title":"ProjectCostumeLinkRead"},"ProjectCreate":{"properties":{"name":{"type":"string","title":"Name","description":"项目名称"},"description":{"type":"string","title":"Description","description":"项目简介","default":""},"style":{"$ref":"#/components/schemas/ProjectStyle","description":"题材/风格","examples":["真人都市","真人科幻","真人古装","动漫科幻","动漫3D","国漫","水墨画"]},"visual_style":{"$ref":"#/components/schemas/ProjectVisualStyle","description":"画面表现形式","default":"现实"},"seed":{"type":"integer","title":"Seed","description":"随机种子","default":0},"unify_style":{"type":"boolean","title":"Unify Style","description":"是否统一风格","default":true},"progress":{"type":"integer","title":"Progress","description":"进度百分比(0-100)","default":0},"default_video_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Video Ratio","description":"项目级默认视频比例;分镜未覆盖时生效"},"stats":{"additionalProperties":true,"type":"object","title":"Stats","description":"聚合统计(JSON)"},"id":{"type":"string","title":"Id","description":"项目 ID"}},"type":"object","required":["name","style","id"],"title":"ProjectCreate"},"ProjectPropLinkRead":{"properties":{"id":{"type":"integer","title":"Id","description":"关联行 ID"},"project_id":{"type":"string","title":"Project Id","description":"项目 ID"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(可空)"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"镜头 ID(可空)"},"prop_id":{"type":"string","title":"Prop Id"},"thumbnail":{"type":"string","title":"Thumbnail","description":"道具缩略图下载地址","default":""}},"type":"object","required":["id","project_id","prop_id"],"title":"ProjectPropLinkRead"},"ProjectRead":{"properties":{"name":{"type":"string","title":"Name","description":"项目名称"},"description":{"type":"string","title":"Description","description":"项目简介","default":""},"style":{"$ref":"#/components/schemas/ProjectStyle","description":"题材/风格","examples":["真人都市","真人科幻","真人古装","动漫科幻","动漫3D","国漫","水墨画"]},"visual_style":{"$ref":"#/components/schemas/ProjectVisualStyle","description":"画面表现形式","default":"现实"},"seed":{"type":"integer","title":"Seed","description":"随机种子","default":0},"unify_style":{"type":"boolean","title":"Unify Style","description":"是否统一风格","default":true},"progress":{"type":"integer","title":"Progress","description":"进度百分比(0-100)","default":0},"default_video_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Video Ratio","description":"项目级默认视频比例;分镜未覆盖时生效"},"stats":{"additionalProperties":true,"type":"object","title":"Stats","description":"聚合统计(JSON)"},"id":{"type":"string","title":"Id"}},"type":"object","required":["name","style","id"],"title":"ProjectRead"},"ProjectSceneLinkRead":{"properties":{"id":{"type":"integer","title":"Id","description":"关联行 ID"},"project_id":{"type":"string","title":"Project Id","description":"项目 ID"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(可空)"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"镜头 ID(可空)"},"scene_id":{"type":"string","title":"Scene Id"},"thumbnail":{"type":"string","title":"Thumbnail","description":"场景缩略图下载地址","default":""}},"type":"object","required":["id","project_id","scene_id"],"title":"ProjectSceneLinkRead"},"ProjectStyle":{"type":"string","enum":["真人都市","真人科幻","真人古装","动漫科幻","动漫3D","国漫","水墨画"],"title":"ProjectStyle","description":"项目题材/风格维度(不用于区分真人/动漫)。"},"ProjectStyleOptionsRead":{"properties":{"visual_styles":{"items":{"$ref":"#/components/schemas/StyleOption"},"type":"array","title":"Visual Styles","description":"视觉风格可选项"},"styles_by_visual_style":{"additionalProperties":{"items":{"$ref":"#/components/schemas/StyleOption"},"type":"array"},"type":"object","title":"Styles By Visual Style","description":"按视觉风格分组的视频风格选项"},"default_style_by_visual_style":{"additionalProperties":{"type":"string"},"type":"object","title":"Default Style By Visual Style","description":"各视觉风格默认视频风格"}},"type":"object","title":"ProjectStyleOptionsRead","description":"项目风格候选项。"},"ProjectUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"style":{"anyOf":[{"$ref":"#/components/schemas/ProjectStyle"},{"type":"null"}],"description":"题材/风格","examples":["真人都市","真人科幻","真人古装","动漫科幻","动漫3D","国漫","水墨画"]},"visual_style":{"anyOf":[{"$ref":"#/components/schemas/ProjectVisualStyle"},{"type":"null"}]},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed"},"unify_style":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Unify Style"},"progress":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Progress"},"default_video_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Video Ratio"},"stats":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Stats"}},"type":"object","title":"ProjectUpdate"},"ProjectVisualStyle":{"type":"string","enum":["现实","动漫"],"title":"ProjectVisualStyle","description":"画面表现形式维度:用于区分现实/动漫等。"},"PromptCategory":{"type":"string","enum":["frame_head_image","frame_tail_image","frame_key_image","frame_head_prompt","frame_tail_prompt","frame_key_prompt","video_prompt","storyboard_prompt","bgm","sfx","character_image_front","character_image_other","actor_image_front","actor_image_other","prop_image_front","prop_image_other","scene_image_front","scene_image_other","costume_image_front","costume_image_other","combined"],"title":"PromptCategory","description":"提示词模板类别。"},"PromptCategoryOptionRead":{"properties":{"value":{"$ref":"#/components/schemas/PromptCategory","description":"类别枚举值"},"label":{"type":"string","title":"Label","description":"中文名称"},"description":{"type":"string","title":"Description","description":"类别简介","default":""}},"type":"object","required":["value","label"],"title":"PromptCategoryOptionRead","description":"提示词类别选项(枚举值 + 中文标签 + 简介)。"},"PromptTemplateCreate":{"properties":{"category":{"$ref":"#/components/schemas/PromptCategory","description":"模板类别"},"name":{"type":"string","title":"Name","description":"模板名称"},"content":{"type":"string","title":"Content","description":"模板内容"},"preview":{"type":"string","title":"Preview","description":"预览文案","default":""},"variables":{"items":{"type":"string"},"type":"array","title":"Variables","description":"变量名列表"},"is_default":{"type":"boolean","title":"Is Default","description":"是否为默认提示词","default":false}},"type":"object","required":["category","name","content"],"title":"PromptTemplateCreate","description":"创建提示词模板。id 由后端自动生成;is_system 不可由客户端设置。"},"PromptTemplateRead":{"properties":{"id":{"type":"string","title":"Id","description":"模板 ID"},"category":{"$ref":"#/components/schemas/PromptCategory","description":"模板类别"},"name":{"type":"string","title":"Name","description":"模板名称"},"preview":{"type":"string","title":"Preview","description":"预览文案"},"content":{"type":"string","title":"Content","description":"模板内容"},"variables":{"items":{"type":"string"},"type":"array","title":"Variables","description":"变量名列表"},"is_default":{"type":"boolean","title":"Is Default","description":"是否为默认提示词"},"is_system":{"type":"boolean","title":"Is System","description":"是否为系统预置"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"创建时间"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"最后更新时间"}},"type":"object","required":["id","category","name","preview","content","variables","is_default","is_system","created_at","updated_at"],"title":"PromptTemplateRead","description":"读取提示词模板(含全部字段)。"},"PromptTemplateUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"模板名称"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content","description":"模板内容"},"preview":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preview","description":"预览文案"},"variables":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Variables","description":"变量名列表(整体替换)"},"is_default":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Default","description":"是否为默认提示词"}},"type":"object","title":"PromptTemplateUpdate","description":"局部更新提示词模板。不含 id / is_system。"},"PropInfoAnalysisRequest":{"properties":{"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"任务关联实体 ID(资产页恢复任务可选)"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"prop_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prop Context","description":"原文道具上下文(可为空;用于提供额外背景,帮助判断缺失信息)"},"prop_description":{"type":"string","minLength":1,"title":"Prop Description","description":"原文道具描述"}},"type":"object","required":["prop_description"],"title":"PropInfoAnalysisRequest","description":"道具信息缺失分析请求。"},"PropInfoAnalysisResult":{"properties":{"issues":{"items":{"type":"string"},"type":"array","title":"Issues"},"optimized_description":{"type":"string","title":"Optimized Description"}},"additionalProperties":false,"type":"object","required":["issues","optimized_description"],"title":"PropInfoAnalysisResult","description":"根据原文道具描述,分析缺少的信息,并给出优化后的可生成道具描述。"},"ProviderCreate":{"properties":{"name":{"type":"string","title":"Name","description":"供应商名称"},"base_url":{"type":"string","title":"Base Url","description":"文本/通用 API Base URL"},"image_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Base Url","description":"图片能力 API Base URL(可选覆盖)"},"video_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Base Url","description":"视频能力 API Base URL(可选覆盖)"},"description":{"type":"string","title":"Description","description":"说明","default":""},"status":{"$ref":"#/components/schemas/ProviderStatus","description":"状态:active/testing/disabled","default":"testing"},"created_by":{"type":"string","title":"Created By","description":"创建人","default":""},"id":{"type":"string","title":"Id","description":"供应商 ID"},"api_key":{"type":"string","title":"Api Key","description":"API Key(敏感,不在响应中回显)","default":""},"api_secret":{"type":"string","title":"Api Secret","description":"API Secret(敏感,不在响应中回显)","default":""}},"type":"object","required":["name","base_url","id"],"title":"ProviderCreate","description":"创建供应商时的请求体,允许填写敏感字段。"},"ProviderRead":{"properties":{"name":{"type":"string","title":"Name","description":"供应商名称"},"base_url":{"type":"string","title":"Base Url","description":"文本/通用 API Base URL"},"image_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Base Url","description":"图片能力 API Base URL(可选覆盖)"},"video_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Base Url","description":"视频能力 API Base URL(可选覆盖)"},"description":{"type":"string","title":"Description","description":"说明","default":""},"status":{"$ref":"#/components/schemas/ProviderStatus","description":"状态:active/testing/disabled","default":"testing"},"created_by":{"type":"string","title":"Created By","description":"创建人","default":""},"id":{"type":"string","title":"Id","description":"供应商 ID"}},"type":"object","required":["name","base_url","id"],"title":"ProviderRead","description":"对外返回的供应商信息(不包含 api_key/api_secret)。"},"ProviderStatus":{"type":"string","enum":["active","testing","disabled"],"title":"ProviderStatus","description":"供应商启用状态。"},"ProviderSupportedRead":{"properties":{"key":{"type":"string","title":"Key","description":"供应商稳定键"},"display_name":{"type":"string","title":"Display Name","description":"供应商展示名"},"aliases":{"items":{"type":"string"},"type":"array","title":"Aliases","description":"可识别别名"},"supported_categories":{"items":{"$ref":"#/components/schemas/ModelCategoryKey"},"type":"array","title":"Supported Categories","description":"支持的模型类别"},"default_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Base Url","description":"默认 API Base URL"},"requires_api_key":{"type":"boolean","title":"Requires Api Key","description":"是否要求 api_key","default":true},"requires_api_secret":{"type":"boolean","title":"Requires Api Secret","description":"是否要求 api_secret","default":false},"is_experimental":{"type":"boolean","title":"Is Experimental","description":"是否实验性供应商","default":false}},"type":"object","required":["key","display_name"],"title":"ProviderSupportedRead","description":"系统支持的供应商能力清单。"},"ProviderUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"供应商名称"},"base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Url","description":"文本/通用 API Base URL"},"image_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Base Url","description":"图片能力 API Base URL(可选覆盖)"},"video_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Base Url","description":"视频能力 API Base URL(可选覆盖)"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"说明"},"status":{"anyOf":[{"$ref":"#/components/schemas/ProviderStatus"},{"type":"null"}],"description":"状态:active/testing/disabled"},"api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key","description":"API Key(敏感,不在响应中回显)"},"api_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Secret","description":"API Secret(敏感,不在响应中回显)"}},"type":"object","title":"ProviderUpdate","description":"更新供应商时的可选字段。"},"RenderedPromptResponse":{"properties":{"prompt":{"type":"string","title":"Prompt","description":"渲染后的提示词(已套用模板与变量替换)"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"参考图 file_id 列表(自动选择;顺序有效)"}},"type":"object","required":["prompt"],"title":"RenderedPromptResponse"},"RenderedShotFramePromptRead":{"properties":{"base_prompt":{"type":"string","title":"Base Prompt","description":"原始基础提示词(不含图片映射说明)"},"rendered_prompt":{"type":"string","title":"Rendered Prompt","description":"最终提交给模型的提示词(含图片映射说明)"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"最终参考图 file_id 列表,顺序与 mappings 一致"},"mappings":{"items":{"$ref":"#/components/schemas/ShotFramePromptMappingRead"},"type":"array","title":"Mappings","description":"图片与实体名称的映射关系,顺序与 images 完全一致"}},"type":"object","required":["base_prompt","rendered_prompt"],"title":"RenderedShotFramePromptRead","description":"关键帧最终生成提示词渲染结果。"},"SceneInfoAnalysisRequest":{"properties":{"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"任务关联实体 ID(资产页恢复任务可选)"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"scene_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Context","description":"原文场景上下文(可为空;用于提供额外背景,帮助判断缺失信息)"},"scene_description":{"type":"string","minLength":1,"title":"Scene Description","description":"原文场景描述"}},"type":"object","required":["scene_description"],"title":"SceneInfoAnalysisRequest","description":"场景信息缺失分析请求。"},"SceneInfoAnalysisResult":{"properties":{"issues":{"items":{"type":"string"},"type":"array","title":"Issues"},"optimized_description":{"type":"string","title":"Optimized Description"}},"additionalProperties":false,"type":"object","required":["issues","optimized_description"],"title":"SceneInfoAnalysisResult","description":"根据原文场景描述,分析缺少的信息,并给出优化后的可生成场景描述。"},"ScriptConsistencyCheckRequest":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"script_text":{"type":"string","minLength":1,"title":"Script Text","description":"完整剧本文本"}},"type":"object","required":["script_text"],"title":"ScriptConsistencyCheckRequest","description":"一致性检查请求(角色混淆)。"},"ScriptConsistencyCheckResult":{"properties":{"issues":{"items":{"$ref":"#/components/schemas/ScriptConsistencyIssue"},"type":"array","title":"Issues","description":"问题列表"},"has_issues":{"type":"boolean","title":"Has Issues","description":"是否发现问题"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"总结(可选)"}},"additionalProperties":false,"type":"object","required":["has_issues"],"title":"ScriptConsistencyCheckResult","description":"基于原文的一致性检查结果(聚焦角色混淆)。"},"ScriptConsistencyIssue":{"properties":{"issue_type":{"type":"string","const":"character_confusion","title":"Issue Type","description":"固定为角色混淆类问题","default":"character_confusion"},"character_candidates":{"items":{"type":"string"},"type":"array","title":"Character Candidates","description":"涉及的角色候选(名字/称呼/ID 皆可,优先用原文称呼)"},"description":{"type":"string","title":"Description","description":"问题描述(为什么会混淆)"},"suggestion":{"type":"string","title":"Suggestion","description":"修改建议(如何改写以消除混淆)"},"affected_lines":{"anyOf":[{"additionalProperties":{"type":"integer"},"type":"object"},{"type":"null"}],"title":"Affected Lines","description":"受影响的行号范围,形如 {start_line: x, end_line: y}"},"evidence":{"items":{"$ref":"#/components/schemas/EvidenceSpan"},"type":"array","title":"Evidence","description":"原文依据(可选)"}},"additionalProperties":false,"type":"object","required":["description","suggestion"],"title":"ScriptConsistencyIssue","description":"角色混淆类一致性问题:同一角色在不同镜头被赋予不同身份/行为主体导致混淆。"},"ScriptDividerRequest":{"properties":{"script_text":{"type":"string","minLength":1,"title":"Script Text","description":"完整剧本文本"},"write_to_db":{"type":"boolean","title":"Write To Db","description":"是否将分镜写入数据库(AI Studio shots 表)","default":false},"chapter_id":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(write_to_db=true 时必填)"}},"type":"object","required":["script_text"],"title":"ScriptDividerRequest","description":"剧本分镜请求。"},"ScriptDivisionResult":{"properties":{"shots":{"items":{"$ref":"#/components/schemas/ShotDivision"},"type":"array","title":"Shots","description":"分镜列表"},"total_shots":{"type":"integer","minimum":0.0,"title":"Total Shots","description":"总镜头数"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"拆分说明或建议(可选)"}},"additionalProperties":false,"type":"object","required":["total_shots"],"title":"ScriptDivisionResult","description":"剧本分镜结果:镜头列表(每镜起止行号+预览文本)。"},"ScriptExtractRequest":{"properties":{"project_id":{"type":"string","minLength":1,"title":"Project Id","description":"项目 ID"},"chapter_id":{"type":"string","minLength":1,"title":"Chapter Id","description":"章节 ID"},"script_division":{"additionalProperties":true,"type":"object","title":"Script Division","description":"分镜结果(ScriptDivisionResult 序列化)"},"consistency":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Consistency","description":"一致性检查结果(可选;ScriptConsistencyCheckResult 序列化)"},"refresh_cache":{"type":"boolean","title":"Refresh Cache","description":"是否跳过后端缓存并强制重新提取","default":false}},"type":"object","required":["project_id","chapter_id","script_division"],"title":"ScriptExtractRequest","description":"项目级信息提取请求(最终输出)。"},"ScriptOptimizationResult":{"properties":{"optimized_script_text":{"type":"string","title":"Optimized Script Text","description":"优化后的剧本文本"},"change_summary":{"type":"string","title":"Change Summary","description":"改动摘要(只围绕 issues)"}},"additionalProperties":false,"type":"object","required":["optimized_script_text","change_summary"],"title":"ScriptOptimizationResult","description":"剧本优化输出:仅在发现角色混淆问题时使用。"},"ScriptOptimizeRequest":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"script_text":{"type":"string","minLength":1,"title":"Script Text","description":"原文剧本文本"},"consistency":{"additionalProperties":true,"type":"object","title":"Consistency","description":"一致性检查输出(ScriptConsistencyCheckResult 序列化)"}},"type":"object","required":["script_text","consistency"],"title":"ScriptOptimizeRequest","description":"剧本优化请求(基于一致性检查结果)。"},"ScriptSimplificationResult":{"properties":{"simplified_script_text":{"type":"string","title":"Simplified Script Text","description":"精简后的剧本文本"},"simplification_summary":{"type":"string","title":"Simplification Summary","description":"精简策略摘要(说明删改原则)"}},"additionalProperties":false,"type":"object","required":["simplified_script_text","simplification_summary"],"title":"ScriptSimplificationResult","description":"剧本精简输出:在保留剧情主体与连续性的前提下压缩篇幅。"},"ScriptSimplifyRequest":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"script_text":{"type":"string","minLength":1,"title":"Script Text","description":"原文剧本文本"}},"type":"object","required":["script_text"],"title":"ScriptSimplifyRequest","description":"智能精简剧本请求。"},"ShotAssetOverviewItem":{"properties":{"key":{"type":"string","title":"Key","description":"合并键:type:name"},"type":{"type":"string","enum":["character","prop","scene","costume"],"title":"Type","description":"实体类型:character/prop/scene/costume"},"name":{"type":"string","title":"Name","description":"资产名称"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"候选描述(来自 extraction payload)"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail","description":"缩略图"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"缩略图或参考图文件 ID"},"source":{"type":"string","enum":["linked","candidate","both"],"title":"Source","description":"来源:linked/candidate/both"},"candidate_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Candidate Id","description":"候选项 ID"},"candidate_status":{"anyOf":[{"$ref":"#/components/schemas/ShotCandidateStatus"},{"type":"null"}],"description":"候选确认状态"},"linked_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linked Entity Id","description":"当前已关联实体 ID"},"linked_image_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Linked Image Id","description":"当前已关联实体的 image 行 ID"},"is_linked":{"type":"boolean","title":"Is Linked","description":"当前是否已关联到镜头"}},"type":"object","required":["key","type","name","source","is_linked"],"title":"ShotAssetOverviewItem","description":"分镜资产总览项:统一返回已关联资产与提取候选的合并视图。"},"ShotAssetsOverviewRead":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"skip_extraction":{"type":"boolean","title":"Skip Extraction","description":"是否明确跳过提取"},"status":{"$ref":"#/components/schemas/ShotStatus","description":"镜头流程状态"},"summary":{"$ref":"#/components/schemas/ShotAssetsOverviewSummary","description":"总览统计"},"items":{"items":{"$ref":"#/components/schemas/ShotAssetOverviewItem"},"type":"array","title":"Items","description":"资产总览项"}},"type":"object","required":["shot_id","skip_extraction","status","summary"],"title":"ShotAssetsOverviewRead"},"ShotAssetsOverviewSummary":{"properties":{"linked_count":{"type":"integer","title":"Linked Count","description":"已关联项数量"},"pending_count":{"type":"integer","title":"Pending Count","description":"待确认候选数量"},"ignored_count":{"type":"integer","title":"Ignored Count","description":"已忽略候选数量"},"total_count":{"type":"integer","title":"Total Count","description":"总项数(含 ignored)"}},"type":"object","required":["linked_count","pending_count","ignored_count","total_count"],"title":"ShotAssetsOverviewSummary"},"ShotCandidateStatus":{"type":"string","enum":["pending","linked","ignored"],"title":"ShotCandidateStatus","description":"镜头提取候选确认状态。"},"ShotCandidateType":{"type":"string","enum":["character","scene","prop","costume"],"title":"ShotCandidateType","description":"镜头提取候选类型。"},"ShotCharacterLinkCreate":{"properties":{"shot_id":{"type":"string","title":"Shot Id"},"character_id":{"type":"string","title":"Character Id"},"index":{"type":"integer","title":"Index","default":0},"note":{"type":"string","title":"Note","default":""}},"type":"object","required":["shot_id","character_id"],"title":"ShotCharacterLinkCreate"},"ShotCharacterLinkRead":{"properties":{"id":{"type":"integer","title":"Id","description":"关联行 ID"},"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"character_id":{"type":"string","title":"Character Id","description":"角色 ID"},"index":{"type":"integer","title":"Index","description":"镜头内角色排序","default":0},"note":{"type":"string","title":"Note","description":"备注","default":""}},"type":"object","required":["id","shot_id","character_id"],"title":"ShotCharacterLinkRead"},"ShotCreate":{"properties":{"id":{"type":"string","title":"Id","description":"镜头 ID"},"chapter_id":{"type":"string","title":"Chapter Id","description":"所属章节 ID"},"index":{"type":"integer","title":"Index","description":"镜头序号(章节内唯一)"},"title":{"type":"string","title":"Title","description":"镜头标题"},"thumbnail":{"type":"string","title":"Thumbnail","description":"缩略图 URL/路径","default":""},"status":{"$ref":"#/components/schemas/ShotStatus","description":"镜头状态","default":"pending"},"skip_extraction":{"type":"boolean","title":"Skip Extraction","description":"是否明确跳过信息提取","default":false},"script_excerpt":{"type":"string","title":"Script Excerpt","description":"剧本摘录","default":""},"generated_video_file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Generated Video File Id","description":"已生成视频关联的文件 ID(files.id,type=video)"}},"type":"object","required":["id","chapter_id","index","title"],"title":"ShotCreate"},"ShotDetailCreate":{"properties":{"id":{"type":"string","title":"Id","description":"镜头 ID(与 shots.id 共享主键)"},"camera_shot":{"$ref":"#/components/schemas/CameraShotType","description":"景别"},"angle":{"$ref":"#/components/schemas/CameraAngle","description":"机位角度"},"movement":{"$ref":"#/components/schemas/CameraMovement","description":"运镜方式"},"scene_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Id","description":"关联场景 ID(可空)"},"duration":{"type":"integer","title":"Duration","description":"时长(秒)","default":0},"override_video_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Video Ratio","description":"分镜级视频比例覆盖;为空表示继承项目默认"},"mood_tags":{"items":{"type":"string"},"type":"array","title":"Mood Tags","description":"情绪标签"},"atmosphere":{"type":"string","title":"Atmosphere","description":"氛围描述","default":""},"follow_atmosphere":{"type":"boolean","title":"Follow Atmosphere","description":"是否沿用氛围","default":true},"has_bgm":{"type":"boolean","title":"Has Bgm","description":"是否包含 BGM","default":false},"vfx_type":{"$ref":"#/components/schemas/VFXType","description":"视效类型","default":"NONE"},"vfx_note":{"type":"string","title":"Vfx Note","description":"视效说明","default":""},"first_frame_prompt":{"type":"string","title":"First Frame Prompt","description":"镜头分镜首帧提示词","default":""},"last_frame_prompt":{"type":"string","title":"Last Frame Prompt","description":"镜头分镜尾帧提示词","default":""},"key_frame_prompt":{"type":"string","title":"Key Frame Prompt","description":"镜头分镜关键帧提示词","default":""}},"type":"object","required":["id","camera_shot","angle","movement"],"title":"ShotDetailCreate"},"ShotDetailRead":{"properties":{"id":{"type":"string","title":"Id","description":"镜头 ID(与 shots.id 共享主键)"},"camera_shot":{"$ref":"#/components/schemas/CameraShotType","description":"景别"},"angle":{"$ref":"#/components/schemas/CameraAngle","description":"机位角度"},"movement":{"$ref":"#/components/schemas/CameraMovement","description":"运镜方式"},"scene_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Id","description":"关联场景 ID(可空)"},"duration":{"type":"integer","title":"Duration","description":"时长(秒)","default":0},"override_video_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Video Ratio","description":"分镜级视频比例覆盖;为空表示继承项目默认"},"mood_tags":{"items":{"type":"string"},"type":"array","title":"Mood Tags","description":"情绪标签"},"atmosphere":{"type":"string","title":"Atmosphere","description":"氛围描述","default":""},"follow_atmosphere":{"type":"boolean","title":"Follow Atmosphere","description":"是否沿用氛围","default":true},"has_bgm":{"type":"boolean","title":"Has Bgm","description":"是否包含 BGM","default":false},"vfx_type":{"$ref":"#/components/schemas/VFXType","description":"视效类型","default":"NONE"},"vfx_note":{"type":"string","title":"Vfx Note","description":"视效说明","default":""},"first_frame_prompt":{"type":"string","title":"First Frame Prompt","description":"镜头分镜首帧提示词","default":""},"last_frame_prompt":{"type":"string","title":"Last Frame Prompt","description":"镜头分镜尾帧提示词","default":""},"key_frame_prompt":{"type":"string","title":"Key Frame Prompt","description":"镜头分镜关键帧提示词","default":""}},"type":"object","required":["id","camera_shot","angle","movement"],"title":"ShotDetailRead"},"ShotDetailUpdate":{"properties":{"camera_shot":{"anyOf":[{"$ref":"#/components/schemas/CameraShotType"},{"type":"null"}]},"angle":{"anyOf":[{"$ref":"#/components/schemas/CameraAngle"},{"type":"null"}]},"movement":{"anyOf":[{"$ref":"#/components/schemas/CameraMovement"},{"type":"null"}]},"scene_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Id"},"duration":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration"},"override_video_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Video Ratio"},"mood_tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Mood Tags"},"atmosphere":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Atmosphere"},"follow_atmosphere":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Follow Atmosphere"},"has_bgm":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Has Bgm"},"vfx_type":{"anyOf":[{"$ref":"#/components/schemas/VFXType"},{"type":"null"}]},"vfx_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vfx Note"},"first_frame_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Frame Prompt"},"last_frame_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Frame Prompt"},"key_frame_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key Frame Prompt"}},"type":"object","title":"ShotDetailUpdate"},"ShotDialogLineCreate":{"properties":{"shot_detail_id":{"type":"string","title":"Shot Detail Id"},"index":{"type":"integer","title":"Index","default":0},"text":{"type":"string","title":"Text"},"line_mode":{"$ref":"#/components/schemas/DialogueLineMode","default":"DIALOGUE"},"speaker_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Character Id"},"target_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Character Id"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name"},"target_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Name"}},"type":"object","required":["shot_detail_id","text"],"title":"ShotDialogLineCreate"},"ShotDialogLineRead":{"properties":{"id":{"type":"integer","title":"Id","description":"对话行 ID"},"shot_detail_id":{"type":"string","title":"Shot Detail Id","description":"所属镜头细节 ID"},"index":{"type":"integer","title":"Index","description":"行号(镜头内排序)","default":0},"text":{"type":"string","title":"Text","description":"台词内容"},"line_mode":{"$ref":"#/components/schemas/DialogueLineMode","description":"对白模式","default":"DIALOGUE"},"speaker_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Character Id","description":"说话角色 ID"},"target_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Character Id","description":"听者角色 ID"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name","description":"说话角色名称(用于回填关联;可空)"},"target_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Name","description":"听者角色名称(用于回填关联;可空)"}},"type":"object","required":["id","shot_detail_id","text"],"title":"ShotDialogLineRead"},"ShotDialogLineUpdate":{"properties":{"index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Index"},"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text"},"line_mode":{"anyOf":[{"$ref":"#/components/schemas/DialogueLineMode"},{"type":"null"}]},"speaker_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Character Id"},"target_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Character Id"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name"},"target_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Name"}},"type":"object","title":"ShotDialogLineUpdate"},"ShotDialogueCandidateStatus":{"type":"string","enum":["pending","accepted","ignored"],"title":"ShotDialogueCandidateStatus","description":"镜头对白提取候选确认状态。"},"ShotDivision":{"properties":{"index":{"type":"integer","minimum":1.0,"title":"Index","description":"镜头序号(章节内唯一)"},"start_line":{"type":"integer","minimum":1.0,"title":"Start Line","description":"起始行号(1-based)"},"end_line":{"type":"integer","minimum":1.0,"title":"End Line","description":"结束行号(1-based)"},"script_excerpt":{"type":"string","title":"Script Excerpt","description":"镜头对应的剧本摘录/文本"},"shot_name":{"type":"string","title":"Shot Name","description":"镜头名称(分镜名/镜头标题)","default":""},"time_of_day":{"anyOf":[{"type":"string","enum":["DAY","NIGHT","DAWN","DUSK","UNKNOWN","日","夜","黎明","黄昏","不明","未知"]},{"type":"null"}],"title":"Time Of Day","description":"时间(日/夜/未知等,可选)"}},"additionalProperties":false,"type":"object","required":["index","start_line","end_line","script_excerpt"],"title":"ShotDivision","description":"剧本分镜中的单镜信息:行号 + 预览文本(可选弱语义)。"},"ShotExtractedCandidateLinkRequest":{"properties":{"linked_entity_id":{"type":"string","title":"Linked Entity Id","description":"确认关联到的实体 ID"}},"type":"object","required":["linked_entity_id"],"title":"ShotExtractedCandidateLinkRequest"},"ShotExtractedCandidateRead":{"properties":{"id":{"type":"integer","title":"Id","description":"候选项 ID"},"shot_id":{"type":"string","title":"Shot Id","description":"所属镜头 ID"},"candidate_type":{"$ref":"#/components/schemas/ShotCandidateType","description":"候选类型"},"candidate_name":{"type":"string","title":"Candidate Name","description":"提取出的候选名称"},"candidate_status":{"$ref":"#/components/schemas/ShotCandidateStatus","description":"候选确认状态"},"linked_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linked Entity Id","description":"已关联实体 ID"},"source":{"type":"string","title":"Source","description":"候选来源"},"payload":{"additionalProperties":true,"type":"object","title":"Payload","description":"候选附加信息"},"confirmed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Confirmed At","description":"确认时间"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"创建时间"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"更新时间"}},"type":"object","required":["id","shot_id","candidate_type","candidate_name","candidate_status","source","created_at","updated_at"],"title":"ShotExtractedCandidateRead"},"ShotExtractedDialogueCandidateAcceptRequest":{"properties":{"index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Index","description":"写入对白行时使用的排序;为空则使用候选排序"},"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text","description":"接受时可覆盖对白文本"},"line_mode":{"anyOf":[{"$ref":"#/components/schemas/DialogueLineMode"},{"type":"null"}],"description":"接受时可覆盖对白模式"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name","description":"接受时可覆盖说话角色名称"},"target_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Name","description":"接受时可覆盖听者角色名称"}},"type":"object","title":"ShotExtractedDialogueCandidateAcceptRequest"},"ShotExtractedDialogueCandidateRead":{"properties":{"id":{"type":"integer","title":"Id","description":"对白候选项 ID"},"shot_id":{"type":"string","title":"Shot Id","description":"所属镜头 ID"},"index":{"type":"integer","title":"Index","description":"镜头内对白候选排序"},"text":{"type":"string","title":"Text","description":"提取出的对白文本"},"line_mode":{"$ref":"#/components/schemas/DialogueLineMode","description":"对白模式"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name","description":"说话角色名称"},"target_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Name","description":"听者角色名称"},"candidate_status":{"$ref":"#/components/schemas/ShotDialogueCandidateStatus","description":"对白候选确认状态"},"linked_dialog_line_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Linked Dialog Line Id","description":"已接受后关联的对白行 ID"},"source":{"type":"string","title":"Source","description":"候选来源"},"payload":{"additionalProperties":true,"type":"object","title":"Payload","description":"候选附加信息"},"confirmed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Confirmed At","description":"确认时间"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"创建时间"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"更新时间"}},"type":"object","required":["id","shot_id","index","text","line_mode","candidate_status","source","created_at","updated_at"],"title":"ShotExtractedDialogueCandidateRead"},"ShotExtractionSummaryRead":{"properties":{"state":{"type":"string","enum":["not_extracted","extracted_empty","extracted_pending","extracted_resolved","skipped"],"title":"State","description":"镜头提取确认状态摘要"},"has_extracted":{"type":"boolean","title":"Has Extracted","description":"是否已执行过提取"},"last_extracted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Extracted At","description":"最近一次提取完成时间"},"asset_candidate_total":{"type":"integer","title":"Asset Candidate Total","description":"资产候选总数","default":0},"dialogue_candidate_total":{"type":"integer","title":"Dialogue Candidate Total","description":"对白候选总数","default":0},"pending_asset_count":{"type":"integer","title":"Pending Asset Count","description":"待确认资产候选数","default":0},"pending_dialogue_count":{"type":"integer","title":"Pending Dialogue Count","description":"待确认对白候选数","default":0}},"type":"object","required":["state","has_extracted"],"title":"ShotExtractionSummaryRead"},"ShotFrameImageCreate":{"properties":{"shot_detail_id":{"type":"string","title":"Shot Detail Id"},"frame_type":{"$ref":"#/components/schemas/ShotFrameType"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"},"format":{"type":"string","title":"Format","default":"png"}},"type":"object","required":["shot_detail_id","frame_type"],"title":"ShotFrameImageCreate"},"ShotFrameImageRead":{"properties":{"id":{"type":"integer","title":"Id","description":"图片行 ID"},"shot_detail_id":{"type":"string","title":"Shot Detail Id","description":"所属镜头细节 ID"},"frame_type":{"$ref":"#/components/schemas/ShotFrameType","description":"帧类型:first/last/key"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"关联的 FileItem ID(可为空,允许先创建占位)"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width","description":"宽(px)"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height","description":"高(px)"},"format":{"type":"string","title":"Format","description":"格式","default":"png"}},"type":"object","required":["id","shot_detail_id","frame_type"],"title":"ShotFrameImageRead"},"ShotFrameImageTaskRequest":{"properties":{"model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id","description":"可选模型 ID(models.id);不传则使用 ModelSettings.default_image_model_id;Provider 由模型关联反查"},"frame_type":{"$ref":"#/components/schemas/ShotFrameType","description":"first | last | key"},"prompt":{"type":"string","minLength":1,"title":"Prompt","description":"提示词(由前端传入,创建任务接口必填)。"},"images":{"items":{"$ref":"#/components/schemas/ShotLinkedAssetItem"},"type":"array","title":"Images","description":"参考资产条目列表(可多张,顺序有效)。后端会使用 item.file_id 作为参考图;无效条目会被跳过。"},"target_ratio":{"type":"string","enum":["16:9","4:3","1:1","3:4","9:16","21:9","3:2","2:3"],"title":"Target Ratio","description":"目标视频画幅比例;关键帧将按该画幅生成,以提升后续视频参考稳定性"},"resolution_profile":{"anyOf":[{"type":"string","enum":["standard","high"]},{"type":"null"}],"title":"Resolution Profile","description":"关键帧输出分辨率档位,默认 standard","default":"standard"}},"type":"object","required":["frame_type","prompt","target_ratio"],"title":"ShotFrameImageTaskRequest","description":"镜头分镜帧图片生成请求体:只根据 `shot_id + frame_type` 定位 ShotFrameImage。\n\n用于替代旧接口中通过 `image_id` 直接传入 ShotFrameImage.id 的方式。"},"ShotFrameImageUpdate":{"properties":{"frame_type":{"anyOf":[{"$ref":"#/components/schemas/ShotFrameType"},{"type":"null"}]},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"},"format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Format"}},"type":"object","title":"ShotFrameImageUpdate"},"ShotFramePromptMappingRead":{"properties":{"token":{"type":"string","title":"Token","description":"提示词中的图片占位 token,如 图1 / 图2"},"type":{"type":"string","enum":["character","prop","scene","costume"],"title":"Type","description":"实体类型:character/prop/scene/costume"},"id":{"type":"string","title":"Id","description":"实体 ID(如 character_id/prop_id/scene_id/costume_id)"},"name":{"type":"string","title":"Name","description":"实体名称"},"file_id":{"type":"string","title":"File Id","description":"本次渲染与生成使用的文件 ID"}},"type":"object","required":["token","type","id","name","file_id"],"title":"ShotFramePromptMappingRead","description":"关键帧提示词渲染后的图片映射关系。"},"ShotFramePromptRenderRequest":{"properties":{"frame_type":{"$ref":"#/components/schemas/ShotFrameType","description":"first | last | key"},"prompt":{"type":"string","minLength":1,"title":"Prompt","description":"原始基础提示词。渲染接口要求显式传入,用于生成最终提示词。"},"images":{"items":{"$ref":"#/components/schemas/ShotLinkedAssetItem"},"type":"array","title":"Images","description":"参考资产条目列表(可多张,顺序有效)。后端会使用 item.file_id 作为参考图;无效条目会被跳过。"}},"type":"object","required":["frame_type","prompt"],"title":"ShotFramePromptRenderRequest","description":"镜头分镜帧提示词渲染请求体。"},"ShotFramePromptRequest":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"frame_type":{"type":"string","title":"Frame Type","description":"first | last | key"}},"type":"object","required":["shot_id","frame_type"],"title":"ShotFramePromptRequest","description":"镜头分镜帧提示词生成任务请求。"},"ShotFrameType":{"type":"string","enum":["first","last","key"],"title":"ShotFrameType","description":"镜头分镜帧类型:首帧/尾帧/关键帧。"},"ShotLinkedAssetItem":{"properties":{"type":{"type":"string","enum":["character","prop","scene","costume"],"title":"Type","description":"实体类型:character/prop/scene/costume"},"id":{"type":"string","title":"Id","description":"实体 ID(如 character_id/prop_id/scene_id/costume_id)"},"image_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Image Id","description":"最佳缩略图对应的 image 行 ID(如 PropImage.id);无图则为 null"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"最佳缩略图对应的文件 ID(files.id);用于参考图输入;无图则为 null"},"name":{"type":"string","title":"Name","description":"实体名称"},"thumbnail":{"type":"string","title":"Thumbnail","description":"缩略图下载地址(/api/v1/studio/files/{file_id}/download)","default":""}},"type":"object","required":["type","id","name"],"title":"ShotLinkedAssetItem","description":"按分镜聚合返回的关联资产条目(角色/道具/场景/服装)。"},"ShotPreparationLinkEntityType":{"type":"string","enum":["character","scene","prop","costume"],"title":"ShotPreparationLinkEntityType"},"ShotPreparationLinkRequest":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"项目 ID"},"chapter_id":{"type":"string","title":"Chapter Id","description":"章节 ID"},"entity_type":{"$ref":"#/components/schemas/ShotPreparationLinkEntityType","description":"准备页关联的实体类型"},"linked_entity_id":{"type":"string","title":"Linked Entity Id","description":"要关联的实体 ID"}},"type":"object","required":["project_id","chapter_id","entity_type","linked_entity_id"],"title":"ShotPreparationLinkRequest"},"ShotPreparationMutationAction":{"type":"string","enum":["link_asset_candidate","ignore_asset_candidate","accept_dialogue_candidate","ignore_dialogue_candidate","skip_extraction","resume_extraction"],"title":"ShotPreparationMutationAction"},"ShotPreparationMutationResultRead":{"properties":{"action":{"$ref":"#/components/schemas/ShotPreparationMutationAction","description":"本次执行的准备页动作"},"state":{"$ref":"#/components/schemas/ShotPreparationStateRead","description":"动作完成后的最新准备页聚合状态"}},"type":"object","required":["action","state"],"title":"ShotPreparationMutationResultRead","description":"准备页命令执行后的统一响应。"},"ShotPreparationStateRead":{"properties":{"shot":{"$ref":"#/components/schemas/ShotRead","description":"当前镜头最新状态"},"assets_overview":{"$ref":"#/components/schemas/ShotAssetsOverviewRead","description":"资产确认区聚合状态"},"dialogue_candidates":{"items":{"$ref":"#/components/schemas/ShotExtractedDialogueCandidateRead"},"type":"array","title":"Dialogue Candidates","description":"当前待处理/已存在的对白候选"},"saved_dialogue_lines":{"items":{"$ref":"#/components/schemas/ShotDialogLineRead"},"type":"array","title":"Saved Dialogue Lines","description":"当前已保存的对白行"},"pending_confirm_count":{"type":"integer","title":"Pending Confirm Count","description":"当前仍待确认的总数量(资产 + 对白)"},"ready_for_generation":{"type":"boolean","title":"Ready For Generation","description":"当前镜头是否已完成准备,可进入后续生成"}},"type":"object","required":["shot","assets_overview","pending_confirm_count","ready_for_generation"],"title":"ShotPreparationStateRead","description":"分镜准备页聚合状态。"},"ShotPromptAssetRef":{"properties":{"type":{"type":"string","enum":["character","prop","scene","costume"],"title":"Type","description":"资产类型"},"name":{"type":"string","title":"Name","description":"资产名称"},"description":{"type":"string","title":"Description","description":"资产描述或提取候选描述","default":""},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"可作为参考图的文件 ID"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail","description":"缩略图"}},"type":"object","required":["type","name"],"title":"ShotPromptAssetRef","description":"用于提示词渲染的镜头资产引用。"},"ShotPromptCameraInfo":{"properties":{"camera_shot":{"type":"string","title":"Camera Shot","description":"景别","default":""},"angle":{"type":"string","title":"Angle","description":"机位角度","default":""},"movement":{"type":"string","title":"Movement","description":"运镜方式","default":""},"duration":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration","description":"镜头时长(秒)"}},"type":"object","title":"ShotPromptCameraInfo","description":"用于提示词渲染的镜头语言信息。"},"ShotRead":{"properties":{"id":{"type":"string","title":"Id","description":"镜头 ID"},"chapter_id":{"type":"string","title":"Chapter Id","description":"所属章节 ID"},"index":{"type":"integer","title":"Index","description":"镜头序号(章节内唯一)"},"title":{"type":"string","title":"Title","description":"镜头标题"},"thumbnail":{"type":"string","title":"Thumbnail","description":"缩略图 URL/路径","default":""},"status":{"$ref":"#/components/schemas/ShotStatus","description":"镜头状态","default":"pending"},"skip_extraction":{"type":"boolean","title":"Skip Extraction","description":"是否明确跳过信息提取","default":false},"script_excerpt":{"type":"string","title":"Script Excerpt","description":"剧本摘录","default":""},"generated_video_file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Generated Video File Id","description":"已生成视频关联的文件 ID(files.id,type=video)"},"last_extracted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Extracted At","description":"最近一次完成信息提取的时间"},"extraction":{"$ref":"#/components/schemas/ShotExtractionSummaryRead","description":"镜头提取状态摘要"}},"type":"object","required":["id","chapter_id","index","title","extraction"],"title":"ShotRead"},"ShotRuntimeSummaryRead":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"has_active_tasks":{"type":"boolean","title":"Has Active Tasks","description":"是否存在进行中的关联任务"},"has_active_video_tasks":{"type":"boolean","title":"Has Active Video Tasks","description":"是否存在进行中的视频任务"},"has_active_prompt_tasks":{"type":"boolean","title":"Has Active Prompt Tasks","description":"是否存在进行中的提示词任务"},"has_active_frame_tasks":{"type":"boolean","title":"Has Active Frame Tasks","description":"是否存在进行中的分镜帧图片任务"},"active_task_count":{"type":"integer","title":"Active Task Count","description":"进行中的唯一任务数"}},"type":"object","required":["shot_id","has_active_tasks","has_active_video_tasks","has_active_prompt_tasks","has_active_frame_tasks","active_task_count"],"title":"ShotRuntimeSummaryRead"},"ShotSkipExtractionUpdate":{"properties":{"skip":{"type":"boolean","title":"Skip","description":"是否明确跳过信息提取"}},"type":"object","required":["skip"],"title":"ShotSkipExtractionUpdate"},"ShotStatus":{"type":"string","enum":["pending","generating","ready"],"title":"ShotStatus","description":"镜头生成状态(更多是“生产流程”而非剧情状态)。"},"ShotUpdate":{"properties":{"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id"},"index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Index"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail"},"status":{"anyOf":[{"$ref":"#/components/schemas/ShotStatus"},{"type":"null"}]},"skip_extraction":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Skip Extraction"},"script_excerpt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Script Excerpt"},"generated_video_file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Generated Video File Id"}},"type":"object","title":"ShotUpdate"},"ShotVideoPromptPackRead":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"title":{"type":"string","title":"Title","description":"镜头标题","default":""},"script_excerpt":{"type":"string","title":"Script Excerpt","description":"剧本摘录","default":""},"action_beats":{"items":{"type":"string"},"type":"array","title":"Action Beats","description":"动作/场景要点"},"dialogue_summary":{"type":"string","title":"Dialogue Summary","description":"对白摘要","default":""},"characters":{"items":{"$ref":"#/components/schemas/ShotPromptAssetRef"},"type":"array","title":"Characters","description":"角色引用"},"scene":{"anyOf":[{"$ref":"#/components/schemas/ShotPromptAssetRef"},{"type":"null"}],"description":"场景引用"},"props":{"items":{"$ref":"#/components/schemas/ShotPromptAssetRef"},"type":"array","title":"Props","description":"道具引用"},"costumes":{"items":{"$ref":"#/components/schemas/ShotPromptAssetRef"},"type":"array","title":"Costumes","description":"服装引用"},"camera":{"$ref":"#/components/schemas/ShotPromptCameraInfo","description":"镜头语言"},"atmosphere":{"type":"string","title":"Atmosphere","description":"氛围描述","default":""},"visual_style":{"type":"string","title":"Visual Style","description":"项目视觉风格","default":""},"style":{"type":"string","title":"Style","description":"项目题材/风格","default":""},"negative_prompt":{"type":"string","title":"Negative Prompt","description":"默认负面提示词","default":""}},"type":"object","required":["shot_id"],"title":"ShotVideoPromptPackRead","description":"视频提示词渲染前的标准上下文包。"},"ShotVideoPromptPreviewRead":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"template_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Id","description":"使用的提示词模板 ID"},"template_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Name","description":"使用的提示词模板名称"},"rendered_prompt":{"type":"string","title":"Rendered Prompt","description":"渲染后的提示词"},"pack":{"$ref":"#/components/schemas/ShotVideoPromptPackRead","description":"渲染上下文包"},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"渲染时发现的非阻塞提示"}},"type":"object","required":["shot_id","rendered_prompt","pack"],"title":"ShotVideoPromptPreviewRead","description":"视频提示词预览结果。"},"ShotVideoReadinessCheck":{"properties":{"key":{"type":"string","title":"Key","description":"检查项 key"},"ok":{"type":"boolean","title":"Ok","description":"是否通过"},"message":{"type":"string","title":"Message","description":"面向前端展示的说明"}},"type":"object","required":["key","ok","message"],"title":"ShotVideoReadinessCheck","description":"单项视频生成准备度检查结果。"},"ShotVideoReadinessRead":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"reference_mode":{"type":"string","title":"Reference Mode","description":"参考模式"},"ready":{"type":"boolean","title":"Ready","description":"是否满足当前 reference_mode 下的视频生成条件"},"checks":{"items":{"$ref":"#/components/schemas/ShotVideoReadinessCheck"},"type":"array","title":"Checks","description":"准备度检查项"}},"type":"object","required":["shot_id","reference_mode","ready"],"title":"ShotVideoReadinessRead","description":"镜头视频生成准备度。"},"StudioAssetDraft":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"资产 ID(已落库时回填,如 scene_id / prop_id / costume_id)"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"关联的文件 ID(可空)"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail","description":"缩略图下载地址(可空)"},"name":{"type":"string","title":"Name","description":"名称(同项目内建议唯一)"},"description":{"type":"string","title":"Description","description":"描述","default":""},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"标签"},"prompt_template_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt Template Id","description":"提示词模板 ID(可空)"},"view_count":{"type":"integer","minimum":1.0,"title":"View Count","description":"计划生成视角图数量","default":1}},"additionalProperties":false,"type":"object","required":["name"],"title":"StudioAssetDraft","description":"Studio 资产草稿(Scene/Prop/Costume)。\n\n导入 API 未传 id 时由服务端生成;分镜详情回填时可带 scene_id/prop_id/costume_id。"},"StudioCharacterDraft":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"角色 ID(已落库时回填 character_id)"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"关联的文件 ID(可空)"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail","description":"缩略图下载地址(可空)"},"index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Index","description":"镜头内角色排序(shot_character_links.index)"},"name":{"type":"string","title":"Name","description":"角色名称(同项目内建议唯一)"},"description":{"type":"string","title":"Description","description":"角色描述","default":""},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"标签(可选)"},"costume_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Costume Name","description":"服装名称(可选,导入时映射到 costume_id)"},"prop_names":{"items":{"type":"string"},"type":"array","title":"Prop Names","description":"角色常用道具名称列表(可选)"}},"additionalProperties":false,"type":"object","required":["name"],"title":"StudioCharacterDraft","description":"Studio 角色草稿。\n\n导入 API 未传 id 时由服务端生成;分镜详情回填时可带 character_id。"},"StudioImageTaskRequest":{"properties":{"model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id","description":"可选模型 ID(models.id);不传则使用 ModelSettings.default_image_model_id;Provider 由模型关联反查"},"image_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Image Id","description":"图片模型 ID,如 ActorImage.id / SceneImage.id / PropImage.id 等;必须与路径主体 ID 匹配"},"prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt","description":"提示词(由前端传入)。创建任务接口必填;render-prompt 接口可不传"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"参考图 file_id 列表(可多张,顺序有效)。创建任务接口会基于 file_id 从数据中解析为参考图"}},"type":"object","title":"StudioImageTaskRequest","description":"Studio 专用图片任务请求体:可选模型 ID,不传则用默认图片模型;供应商由模型反查。\n\nimage_id 表示具体的图片模型 ID,例如:\n- 演员图片:ActorImage.id\n- 场景图片:SceneImage.id\n- 道具图片:PropImage.id\n- 服装图片:CostumeImage.id\n- 角色图片:CharacterImage.id\n- 分镜帧图片:ShotFrameImage.id"},"StudioScriptExtractionDraft":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"项目 ID(必填)"},"chapter_id":{"type":"string","title":"Chapter Id","description":"章节 ID(必填,用于创建 shots/links)"},"script_text":{"type":"string","title":"Script Text","description":"剧本文本(可为优化后版本)"},"characters":{"items":{"$ref":"#/components/schemas/StudioCharacterDraft"},"type":"array","title":"Characters"},"scenes":{"items":{"$ref":"#/components/schemas/StudioAssetDraft"},"type":"array","title":"Scenes"},"props":{"items":{"$ref":"#/components/schemas/StudioAssetDraft"},"type":"array","title":"Props"},"costumes":{"items":{"$ref":"#/components/schemas/StudioAssetDraft"},"type":"array","title":"Costumes"},"shots":{"items":{"$ref":"#/components/schemas/StudioShotDraft"},"type":"array","title":"Shots","description":"镜头草稿列表"}},"additionalProperties":false,"type":"object","required":["project_id","chapter_id","script_text"],"title":"StudioScriptExtractionDraft","description":"用于导入 Studio 的提取结果草稿(name-based)。"},"StudioShotDraft":{"properties":{"index":{"type":"integer","minimum":1.0,"title":"Index","description":"镜头序号(章节内唯一)"},"title":{"type":"string","title":"Title","description":"镜头标题"},"script_excerpt":{"type":"string","title":"Script Excerpt","description":"剧本摘录","default":""},"scene_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Name","description":"场景名称(可选)"},"character_names":{"items":{"type":"string"},"type":"array","title":"Character Names","description":"本镜出现角色名称列表"},"prop_names":{"items":{"type":"string"},"type":"array","title":"Prop Names","description":"本镜关键道具名称列表"},"costume_names":{"items":{"type":"string"},"type":"array","title":"Costume Names","description":"本镜服装名称列表"},"dialogue_lines":{"items":{"$ref":"#/components/schemas/StudioShotDraftDialogueLine"},"type":"array","title":"Dialogue Lines","description":"对白列表"},"actions":{"items":{"type":"string"},"type":"array","title":"Actions","description":"动作/场景描述"}},"additionalProperties":false,"type":"object","required":["index","title"],"title":"StudioShotDraft","description":"镜头草稿:不含 shot_id,由导入 API 生成;引用实体用 name。"},"StudioShotDraftDialogueLine":{"properties":{"index":{"type":"integer","minimum":0.0,"title":"Index","description":"镜头内排序","default":0},"text":{"type":"string","title":"Text","description":"台词内容"},"line_mode":{"type":"string","enum":["DIALOGUE","VOICE_OVER","OFF_SCREEN","PHONE"],"title":"Line Mode","description":"对白模式","default":"DIALOGUE"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name","description":"说话角色名称(可空)"},"target_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Name","description":"听者角色名称(可空)"}},"additionalProperties":false,"type":"object","required":["text"],"title":"StudioShotDraftDialogueLine","description":"镜头对白草稿:speaker/target 使用角色 name,导入时映射为 character_id。"},"StyleOption":{"properties":{"value":{"type":"string","title":"Value","description":"选项值"},"label":{"type":"string","title":"Label","description":"选项展示文案"}},"type":"object","required":["value","label"],"title":"StyleOption","description":"通用下拉选项。"},"TaskCancelRead":{"properties":{"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/TaskStatus"},"cancel_requested":{"type":"boolean","title":"Cancel Requested","description":"是否已登记取消请求"},"cancel_requested_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cancel Requested At Ts","description":"请求取消时间戳"},"effective_immediately":{"type":"boolean","title":"Effective Immediately","description":"是否已立即取消完成","default":false}},"type":"object","required":["task_id","status","cancel_requested"],"title":"TaskCancelRead"},"TaskCancelRequest":{"properties":{"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"取消原因(可选)"}},"type":"object","title":"TaskCancelRequest"},"TaskCreated":{"properties":{"task_id":{"type":"string","title":"Task Id","description":"任务 ID"}},"type":"object","required":["task_id"],"title":"TaskCreated"},"TaskLinkAdoptRead":{"properties":{"task_id":{"type":"string","title":"Task Id"},"link_type":{"type":"string","title":"Link Type","description":"project | chapter | shot"},"entity_id":{"type":"string","title":"Entity Id","description":"项目/章节/镜头 ID"},"is_adopted":{"type":"boolean","title":"Is Adopted","description":"是否采用(仅可正向变更为 true)"}},"type":"object","required":["task_id","link_type","entity_id","is_adopted"],"title":"TaskLinkAdoptRead","description":"采用状态更新结果。"},"TaskLinkAdoptRequest":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"绑定项目 ID(可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"绑定章节 ID(可选)"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"绑定镜头 ID(可选)"},"task_id":{"type":"string","title":"Task Id","description":"任务 ID"}},"type":"object","required":["task_id"],"title":"TaskLinkAdoptRequest","description":"更新采用状态请求:task_id + 三选一绑定对象(project_id/chapter_id/shot_id)。"},"TaskListItemRead":{"properties":{"task_id":{"type":"string","title":"Task Id"},"task_kind":{"type":"string","title":"Task Kind","description":"业务任务类型"},"status":{"$ref":"#/components/schemas/TaskStatus"},"progress":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Progress"},"cancel_requested":{"type":"boolean","title":"Cancel Requested","description":"是否已请求取消","default":false},"cancel_requested_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cancel Requested At Ts","description":"请求取消时间戳"},"started_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Started At Ts","description":"任务开始执行时间戳"},"finished_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Finished At Ts","description":"任务结束时间戳"},"elapsed_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Elapsed Ms","description":"任务累计执行耗时(毫秒)"},"created_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Created At Ts","description":"任务创建时间戳"},"updated_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Updated At Ts","description":"任务更新时间戳"},"executor_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Executor Type","description":"执行器类型,如 celery"},"executor_task_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Executor Task Id","description":"执行器侧任务 ID"},"relation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Type","description":"业务关联类型"},"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"业务关联实体 ID"},"resource_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource Type","description":"资源类型"},"navigate_relation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Navigate Relation Type","description":"前端默认跳转关联类型"},"navigate_relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Navigate Relation Entity Id","description":"前端默认跳转关联实体 ID"}},"type":"object","required":["task_id","task_kind","status","progress"],"title":"TaskListItemRead"},"TaskResultRead":{"properties":{"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/TaskStatus"},"progress":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Progress"},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result"},"error":{"type":"string","title":"Error","default":""},"cancel_requested":{"type":"boolean","title":"Cancel Requested","description":"是否已请求取消","default":false},"cancel_requested_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cancel Requested At Ts","description":"请求取消时间戳"},"started_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Started At Ts","description":"任务开始执行时间戳"},"finished_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Finished At Ts","description":"任务结束时间戳"},"elapsed_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Elapsed Ms","description":"任务累计执行耗时(毫秒)"}},"type":"object","required":["task_id","status","progress"],"title":"TaskResultRead"},"TaskStatus":{"type":"string","enum":["pending","running","streaming","succeeded","failed","cancelled"],"title":"TaskStatus","description":"任务状态枚举。"},"TaskStatusRead":{"properties":{"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/TaskStatus"},"progress":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Progress"},"cancel_requested":{"type":"boolean","title":"Cancel Requested","description":"是否已请求取消","default":false},"cancel_requested_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cancel Requested At Ts","description":"请求取消时间戳"},"started_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Started At Ts","description":"任务开始执行时间戳"},"finished_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Finished At Ts","description":"任务结束时间戳"},"elapsed_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Elapsed Ms","description":"任务累计执行耗时(毫秒)"}},"type":"object","required":["task_id","status","progress"],"title":"TaskStatusRead"},"VFXType":{"type":"string","enum":["NONE","PARTICLES","VOLUMETRIC_FOG","CG_DOUBLE","DIGITAL_ENVIRONMENT","MATTE_PAINTING","FIRE_SMOKE","WATER_SIM","DESTRUCTION","ENERGY_MAGIC","COMPOSITING_CLEANUP","SLOW_MOTION_TIME","OTHER"],"title":"VFXType","description":"视效类型(与 `app.schemas.skills.common.VFXType` 对齐,存英文 code)。"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VariantAnalysisRequest":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"merged_library":{"additionalProperties":true,"type":"object","title":"Merged Library","description":"合并后的实体库(EntityLibrary 的序列化形式;来自 EntityMerger 输出的 merged_library)"},"all_shot_extractions":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"All Shot Extractions","description":"所有镜头提取结果"},"script_division":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Script Division","description":"脚本分镜结果(可选;ScriptDivisionResult 序列化),用于章节/段落分组"}},"type":"object","required":["merged_library","all_shot_extractions"],"title":"VariantAnalysisRequest","description":"变体分析请求。"},"VariantAnalysisResult":{"properties":{"costume_timelines":{"items":{"$ref":"#/components/schemas/CostumeTimeline"},"type":"array","title":"Costume Timelines","description":"各角色服装演变时间线"},"variant_suggestions":{"items":{"$ref":"#/components/schemas/VariantSuggestion"},"type":"array","title":"Variant Suggestions","description":"变体建议列表"},"chapter_variants":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object","title":"Chapter Variants","description":"章节变体建议"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"分析说明"}},"additionalProperties":false,"type":"object","title":"VariantAnalysisResult","description":"变体分析结果。"},"VariantSuggestion":{"properties":{"entity_id":{"type":"string","title":"Entity Id","description":"实体ID"},"entity_name":{"type":"string","title":"Entity Name","description":"实体名称"},"entity_type":{"type":"string","title":"Entity Type","description":"实体类型(character/scene/prop/location)"},"suggestion":{"type":"string","title":"Suggestion","description":"变体建议说明"},"affected_shots":{"items":{"type":"integer"},"type":"array","title":"Affected Shots","description":"涉及的镜头"},"evidence":{"items":{"$ref":"#/components/schemas/EvidenceSpan"},"type":"array","title":"Evidence","description":"原文依据(可选)"}},"additionalProperties":false,"type":"object","required":["entity_id","entity_name","entity_type","suggestion"],"title":"VariantSuggestion","description":"变体建议。"},"VideoGenerationOptionsRead":{"properties":{"provider":{"type":"string","title":"Provider","description":"供应商稳定键"},"model_id":{"type":"string","title":"Model Id","description":"默认视频模型 ID"},"model_name":{"type":"string","title":"Model Name","description":"默认视频模型名称"},"allowed_ratios":{"items":{"type":"string"},"type":"array","title":"Allowed Ratios","description":"当前模型允许的比例选项"},"default_ratio":{"type":"string","title":"Default Ratio","description":"当前模型默认比例"}},"type":"object","required":["provider","model_id","model_name","default_ratio"],"title":"VideoGenerationOptionsRead","description":"当前默认视频模型对应的生成参数选项。"},"VideoGenerationTaskRequest":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"reference_mode":{"type":"string","enum":["first","last","key","first_last","first_last_key","text_only"],"title":"Reference Mode","description":"参考模式:first | last | key | first_last | first_last_key | text_only"},"prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt","description":"视频提示词(text_only 必填)"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"参考图 file_id 列表,数量需与 reference_mode 严格匹配"},"ratio":{"type":"string","enum":["16:9","4:3","1:1","3:4","9:16","21:9"],"title":"Ratio","description":"视频画幅比例,如 16:9 / 9:16"}},"type":"object","required":["shot_id","reference_mode","ratio"],"title":"VideoGenerationTaskRequest","description":"视频生成任务请求。"},"VideoPromptPreviewResponse":{"properties":{"prompt":{"type":"string","title":"Prompt","description":"最终用于视频生成的提示词"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"关联参考图 file_id 列表"}},"type":"object","required":["prompt"],"title":"VideoPromptPreviewResponse"}}}} \ No newline at end of file +{"openapi":"3.1.0","info":{"title":"Jellyfish API","version":"0.1.0"},"paths":{"/api/v1/health":{"get":{"tags":["health"],"summary":"V1 Health","operationId":"v1_health_api_v1_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_"}}}}}}},"/api/v1/film/tasks/video/preview-prompt":{"post":{"tags":["film"],"summary":"视频提示词预览","description":"预览视频生成的提示词与自动关联参考图。","operationId":"preview_video_generation_prompt_api_v1_film_tasks_video_preview_prompt_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoGenerationTaskRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_VideoPromptPreviewResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/tasks/video":{"post":{"tags":["film"],"summary":"视频生成(任务版)","description":"创建视频生成任务并后台执行,结果通过 /tasks/{task_id}/result 获取。","operationId":"create_video_generation_task_api_v1_film_tasks_video_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoGenerationTaskRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/tasks/shot-frame-prompts":{"post":{"tags":["film"],"summary":"镜头分镜帧提示词生成(任务版)","operationId":"create_shot_frame_prompt_task_api_v1_film_tasks_shot_frame_prompts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotFramePromptRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/tasks":{"get":{"tags":["film"],"summary":"全局任务列表(任务中心)","operationId":"list_tasks_api_v1_film_tasks_get","parameters":[{"name":"statuses","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/TaskStatus"}},{"type":"null"}],"description":"按任务状态过滤,可多选","title":"Statuses"},"description":"按任务状态过滤,可多选"},{"name":"task_kind","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 task_kind 过滤","title":"Task Kind"},"description":"按 task_kind 过滤"},{"name":"relation_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 relation_type 过滤","title":"Relation Type"},"description":"按 relation_type 过滤"},{"name":"relation_entity_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 relation_entity_id 过滤","title":"Relation Entity Id"},"description":"按 relation_entity_id 过滤"},{"name":"recent_seconds","in":"query","required":false,"schema":{"type":"integer","maximum":86400,"minimum":0,"description":"默认返回最近结束任务的时间窗口(秒)","default":300,"title":"Recent Seconds"},"description":"默认返回最近结束任务的时间窗口(秒)"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"页码","default":1,"title":"Page"},"description":"页码"},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"每页条数","default":20,"title":"Page Size"},"description":"每页条数"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_TaskListItemRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/tasks/{task_id}/status":{"get":{"tags":["film"],"summary":"查询任务状态/进度(轮询)","operationId":"get_task_status_api_v1_film_tasks__task_id__status_get","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskStatusRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/tasks/{task_id}/result":{"get":{"tags":["film"],"summary":"获取任务结果","operationId":"get_task_result_api_v1_film_tasks__task_id__result_get","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/tasks/{task_id}/cancel":{"post":{"tags":["film"],"summary":"请求取消任务","operationId":"cancel_task_api_v1_film_tasks__task_id__cancel_post","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskCancelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCancelRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/task-links/adopt":{"patch":{"tags":["film"],"summary":"更新任务关联的采用状态(仅可正向变更)","description":"将指定任务链接的状态设为 accepted;已采用不可改为未采用。","operationId":"adopt_task_link_api_v1_film_task_links_adopt_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskLinkAdoptRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskLinkAdoptRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/task-links":{"get":{"tags":["film"],"summary":"生成任务关联列表(分页,支持多条件过滤)","operationId":"list_task_links_api_v1_film_task_links_get","parameters":[{"name":"resource_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 resource_type 过滤","title":"Resource Type"},"description":"按 resource_type 过滤"},{"name":"relation_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 relation_type 过滤","title":"Relation Type"},"description":"按 relation_type 过滤"},{"name":"relation_entity_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 relation_entity_id 过滤","title":"Relation Entity Id"},"description":"按 relation_entity_id 过滤"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按关联状态过滤(accepted/todo/rejected)","title":"Status"},"description":"按关联状态过滤(accepted/todo/rejected)"},{"name":"task_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 task_id 过滤","title":"Task Id"},"description":"按 task_id 过滤"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"排序字段:updated_at/created_at/id/status","title":"Order"},"description":"排序字段:updated_at/created_at/id/status"},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","description":"是否倒序;默认 true","default":true,"title":"Is Desc"},"description":"是否倒序;默认 true"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"页码","default":1,"title":"Page"},"description":"页码"},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"每页条数","default":10,"title":"Page Size"},"description":"每页条数"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_GenerationTaskLinkRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["film"],"summary":"创建生成任务关联","operationId":"create_task_link_api_v1_film_task_links_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationTaskLinkCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_GenerationTaskLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/film/task-links/{link_id}":{"get":{"tags":["film"],"summary":"获取生成任务关联详情","operationId":"get_task_link_api_v1_film_task_links__link_id__get","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_GenerationTaskLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["film"],"summary":"更新生成任务关联(不支持直接修改 is_adopted)","operationId":"update_task_link_api_v1_film_task_links__link_id__patch","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationTaskLinkUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_GenerationTaskLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["film"],"summary":"删除生成任务关联","operationId":"delete_task_link_api_v1_film_task_links__link_id__delete","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/llm/providers":{"get":{"tags":["llm"],"summary":"列出模型供应商(分页)","operationId":"list_providers_api_v1_llm_providers_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 name/description","title":"Q"},"description":"关键字,过滤 name/description"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"排序字段:name, created_at, updated_at","title":"Order"},"description":"排序字段:name, created_at, updated_at"},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","description":"是否倒序","default":false,"title":"Is Desc"},"description":"是否倒序"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"页码","default":1,"title":"Page"},"description":"页码"},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"每页条数","default":10,"title":"Page Size"},"description":"每页条数"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ProviderRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["llm"],"summary":"创建模型供应商","operationId":"create_provider_api_v1_llm_providers_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProviderRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/llm/providers/supported":{"get":{"tags":["llm"],"summary":"列出系统支持的供应商能力","operationId":"list_supported_providers_api_v1_llm_providers_supported_get","parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ModelCategoryKey"},{"type":"null"}],"description":"按模型类别过滤:text/image/video","title":"Category"},"description":"按模型类别过滤:text/image/video"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_list_ProviderSupportedRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/llm/image-generation-options":{"get":{"tags":["llm"],"summary":"获取当前默认图片模型的关键帧规格选项","operationId":"get_image_generation_options_api_v1_llm_image_generation_options_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ImageGenerationOptionsRead_"}}}}}}},"/api/v1/llm/video-generation-options":{"get":{"tags":["llm"],"summary":"获取当前默认视频模型的动态比例选项","operationId":"get_video_generation_options_api_v1_llm_video_generation_options_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_VideoGenerationOptionsRead_"}}}}}}},"/api/v1/llm/providers/{provider_id}":{"get":{"tags":["llm"],"summary":"获取单个模型供应商","operationId":"get_provider_api_v1_llm_providers__provider_id__get","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"string","title":"Provider Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProviderRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["llm"],"summary":"更新模型供应商","operationId":"update_provider_api_v1_llm_providers__provider_id__patch","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"string","title":"Provider Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProviderRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["llm"],"summary":"删除模型供应商","operationId":"delete_provider_api_v1_llm_providers__provider_id__delete","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"string","title":"Provider Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/llm/models":{"get":{"tags":["llm"],"summary":"列出模型(分页)","operationId":"list_models_api_v1_llm_models_get","parameters":[{"name":"provider_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按供应商过滤","title":"Provider Id"},"description":"按供应商过滤"},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ModelCategoryKey"},{"type":"null"}],"description":"按模型类别过滤","title":"Category"},"description":"按模型类别过滤"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 name/description","title":"Q"},"description":"关键字,过滤 name/description"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"排序字段:name, category, created_at, updated_at","title":"Order"},"description":"排序字段:name, category, created_at, updated_at"},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","description":"是否倒序","default":false,"title":"Is Desc"},"description":"是否倒序"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"页码","default":1,"title":"Page"},"description":"页码"},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"每页条数","default":10,"title":"Page Size"},"description":"每页条数"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ModelRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["llm"],"summary":"创建模型","operationId":"create_model_api_v1_llm_models_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ModelRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/llm/models/{model_id}":{"get":{"tags":["llm"],"summary":"获取单个模型","operationId":"get_model_api_v1_llm_models__model_id__get","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ModelRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["llm"],"summary":"更新模型","operationId":"update_model_api_v1_llm_models__model_id__patch","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ModelRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["llm"],"summary":"删除模型","operationId":"delete_model_api_v1_llm_models__model_id__delete","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/llm/model-settings":{"get":{"tags":["llm"],"summary":"获取模型全局设置(单例)","operationId":"get_model_settings_api_v1_llm_model_settings_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ModelSettingsRead_"}}}}}},"put":{"tags":["llm"],"summary":"更新模型全局设置(单例)","operationId":"update_model_settings_api_v1_llm_model_settings_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelSettingsUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ModelSettingsRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/projects/style-options":{"get":{"tags":["studio/projects"],"summary":"获取项目风格候选项","operationId":"get_project_style_options_api_v1_studio_projects_style_options_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectStyleOptionsRead_"}}}}}}},"/api/v1/studio/projects":{"get":{"tags":["studio/projects"],"summary":"项目列表(分页)","operationId":"list_projects_api_v1_studio_projects_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 name/description","title":"Q"},"description":"关键字,过滤 name/description"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"排序字段","title":"Order"},"description":"排序字段"},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","description":"是否倒序","default":false,"title":"Is Desc"},"description":"是否倒序"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ProjectRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/projects"],"summary":"创建项目","operationId":"create_project_api_v1_studio_projects_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/projects/{project_id}":{"get":{"tags":["studio/projects"],"summary":"获取项目","operationId":"get_project_api_v1_studio_projects__project_id__get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/projects"],"summary":"更新项目","operationId":"update_project_api_v1_studio_projects__project_id__patch","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/projects"],"summary":"删除项目","operationId":"delete_project_api_v1_studio_projects__project_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","title":"Project Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/chapters":{"get":{"tags":["studio/chapters"],"summary":"章节列表(分页)","operationId":"list_chapters_api_v1_studio_chapters_get","parameters":[{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按项目过滤","title":"Project Id"},"description":"按项目过滤"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 title/summary","title":"Q"},"description":"关键字,过滤 title/summary"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"排序字段","title":"Order"},"description":"排序字段"},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","description":"是否倒序","default":false,"title":"Is Desc"},"description":"是否倒序"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ChapterRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/chapters"],"summary":"创建章节","operationId":"create_chapter_api_v1_studio_chapters_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChapterCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ChapterRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/chapters/{chapter_id}":{"get":{"tags":["studio/chapters"],"summary":"获取章节","operationId":"get_chapter_api_v1_studio_chapters__chapter_id__get","parameters":[{"name":"chapter_id","in":"path","required":true,"schema":{"type":"string","title":"Chapter Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ChapterRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/chapters"],"summary":"更新章节","operationId":"update_chapter_api_v1_studio_chapters__chapter_id__patch","parameters":[{"name":"chapter_id","in":"path","required":true,"schema":{"type":"string","title":"Chapter Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChapterUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ChapterRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/chapters"],"summary":"删除章节","operationId":"delete_chapter_api_v1_studio_chapters__chapter_id__delete","parameters":[{"name":"chapter_id","in":"path","required":true,"schema":{"type":"string","title":"Chapter Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots":{"get":{"tags":["studio/shots"],"summary":"镜头列表(分页)","operationId":"list_shots_api_v1_studio_shots_get","parameters":[{"name":"chapter_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按章节过滤","title":"Chapter Id"},"description":"按章节过滤"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 title/script_excerpt","title":"Q"},"description":"关键字,过滤 title/script_excerpt"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ShotRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/shots"],"summary":"创建镜头","operationId":"create_shot_api_v1_studio_shots_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/runtime-summary":{"get":{"tags":["studio/shots"],"summary":"按章节获取镜头运行时任务态摘要","operationId":"list_shot_runtime_summary_api_v1_studio_shots_runtime_summary_get","parameters":[{"name":"chapter_id","in":"query","required":true,"schema":{"type":"string","description":"章节 ID","title":"Chapter Id"},"description":"章节 ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_list_ShotRuntimeSummaryRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/extraction-draft":{"get":{"tags":["studio/shots"],"summary":"分镜详情:按镜头关联拼装 StudioScriptExtractionDraft","operationId":"get_shot_extraction_draft_api_v1_studio_shots__shot_id__extraction_draft_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_StudioScriptExtractionDraft_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/extracted-candidates":{"get":{"tags":["studio/shots"],"summary":"获取镜头提取候选项","operationId":"get_shot_extracted_candidates_api_v1_studio_shots__shot_id__extracted_candidates_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_list_ShotExtractedCandidateRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/extracted-dialogue-candidates":{"get":{"tags":["studio/shots"],"summary":"获取镜头提取对白候选项","operationId":"get_shot_extracted_dialogue_candidates_api_v1_studio_shots__shot_id__extracted_dialogue_candidates_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_list_ShotExtractedDialogueCandidateRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/assets-overview":{"get":{"tags":["studio/shots"],"summary":"获取镜头资产总览(已关联资产 + 提取候选)","operationId":"get_shot_assets_overview_api_api_v1_studio_shots__shot_id__assets_overview_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotAssetsOverviewRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/preparation-state":{"get":{"tags":["studio/shots"],"summary":"获取镜头准备页聚合状态","operationId":"get_shot_preparation_state_api_api_v1_studio_shots__shot_id__preparation_state_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationStateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/preparation-link":{"post":{"tags":["studio/shots"],"summary":"准备页关联现有实体并返回最新聚合状态","operationId":"link_existing_asset_for_preparation_api_api_v1_studio_shots__shot_id__preparation_link_post","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotPreparationLinkRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationMutationResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/video-prompt-preview":{"get":{"tags":["studio/shots"],"summary":"预览镜头视频提示词","operationId":"preview_shot_video_prompt_api_v1_studio_shots__shot_id__video_prompt_preview_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}},{"name":"template_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"指定视频提示词模板 ID;不传则使用默认模板","title":"Template Id"},"description":"指定视频提示词模板 ID;不传则使用默认模板"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotVideoPromptPreviewRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/video-readiness":{"get":{"tags":["studio/shots"],"summary":"获取镜头视频生成准备度","operationId":"get_shot_video_readiness_api_api_v1_studio_shots__shot_id__video_readiness_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}},{"name":"reference_mode","in":"query","required":false,"schema":{"type":"string","description":"参考模式:first/last/key/first_last/first_last_key/text_only","default":"text_only","title":"Reference Mode"},"description":"参考模式:first/last/key/first_last/first_last_key/text_only"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotVideoReadinessRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/skip-extraction":{"patch":{"tags":["studio/shots"],"summary":"设置是否跳过镜头信息提取","operationId":"update_shot_skip_extraction_api_v1_studio_shots__shot_id__skip_extraction_patch","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotSkipExtractionUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationMutationResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/extracted-candidates/{candidate_id}/link":{"patch":{"tags":["studio/shots"],"summary":"确认并关联镜头提取候选项","operationId":"link_extracted_candidate_api_v1_studio_shots_extracted_candidates__candidate_id__link_patch","parameters":[{"name":"candidate_id","in":"path","required":true,"schema":{"type":"integer","title":"Candidate Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotExtractedCandidateLinkRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationMutationResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/extracted-candidates/{candidate_id}/ignore":{"patch":{"tags":["studio/shots"],"summary":"忽略镜头提取候选项","operationId":"ignore_extracted_candidate_api_v1_studio_shots_extracted_candidates__candidate_id__ignore_patch","parameters":[{"name":"candidate_id","in":"path","required":true,"schema":{"type":"integer","title":"Candidate Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationMutationResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/extracted-dialogue-candidates/{candidate_id}/accept":{"patch":{"tags":["studio/shots"],"summary":"接受镜头提取对白候选项","operationId":"accept_extracted_dialogue_candidate_api_v1_studio_shots_extracted_dialogue_candidates__candidate_id__accept_patch","parameters":[{"name":"candidate_id","in":"path","required":true,"schema":{"type":"integer","title":"Candidate Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ShotExtractedDialogueCandidateAcceptRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationMutationResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/extracted-dialogue-candidates/{candidate_id}/ignore":{"patch":{"tags":["studio/shots"],"summary":"忽略镜头提取对白候选项","operationId":"ignore_extracted_dialogue_candidate_api_v1_studio_shots_extracted_dialogue_candidates__candidate_id__ignore_patch","parameters":[{"name":"candidate_id","in":"path","required":true,"schema":{"type":"integer","title":"Candidate Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotPreparationMutationResultRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}":{"get":{"tags":["studio/shots"],"summary":"获取镜头","operationId":"get_shot_api_v1_studio_shots__shot_id__get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/shots"],"summary":"更新镜头","operationId":"update_shot_api_v1_studio_shots__shot_id__patch","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/shots"],"summary":"删除镜头","operationId":"delete_shot_api_v1_studio_shots__shot_id__delete","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shots/{shot_id}/linked-assets":{"get":{"tags":["studio/shots"],"summary":"获取镜头关联的角色/道具/场景/服装(分页)","operationId":"list_shot_linked_assets_api_v1_studio_shots__shot_id__linked_assets_get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ShotLinkedAssetItem__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-details":{"get":{"tags":["studio/shot-details"],"summary":"镜头细节列表(分页)","operationId":"list_shot_details_api_v1_studio_shot_details_get","parameters":[{"name":"shot_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按镜头过滤(id 同 shot_id)","title":"Shot Id"},"description":"按镜头过滤(id 同 shot_id)"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ShotDetailRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/shot-details"],"summary":"创建镜头细节","operationId":"create_shot_detail_api_v1_studio_shot_details_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotDetailCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotDetailRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-details/{shot_id}":{"get":{"tags":["studio/shot-details"],"summary":"获取镜头细节","operationId":"get_shot_detail_api_v1_studio_shot_details__shot_id__get","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotDetailRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/shot-details"],"summary":"更新镜头细节","operationId":"update_shot_detail_api_v1_studio_shot_details__shot_id__patch","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotDetailUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotDetailRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/shot-details"],"summary":"删除镜头细节","operationId":"delete_shot_detail_api_v1_studio_shot_details__shot_id__delete","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-dialog-lines":{"get":{"tags":["studio/shot-dialog-lines"],"summary":"镜头对话行列表(分页)","operationId":"list_shot_dialog_lines_api_v1_studio_shot_dialog_lines_get","parameters":[{"name":"shot_detail_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按镜头细节过滤","title":"Shot Detail Id"},"description":"按镜头细节过滤"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 text","title":"Q"},"description":"关键字,过滤 text"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ShotDialogLineRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/shot-dialog-lines"],"summary":"创建镜头对话行","operationId":"create_shot_dialog_line_api_v1_studio_shot_dialog_lines_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotDialogLineCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotDialogLineRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-dialog-lines/{line_id}":{"patch":{"tags":["studio/shot-dialog-lines"],"summary":"更新镜头对话行","operationId":"update_shot_dialog_line_api_v1_studio_shot_dialog_lines__line_id__patch","parameters":[{"name":"line_id","in":"path","required":true,"schema":{"type":"integer","title":"Line Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotDialogLineUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotDialogLineRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/shot-dialog-lines"],"summary":"删除镜头对话行","operationId":"delete_shot_dialog_line_api_v1_studio_shot_dialog_lines__line_id__delete","parameters":[{"name":"line_id","in":"path","required":true,"schema":{"type":"integer","title":"Line Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/{entity_type}":{"get":{"tags":["studio/shot-links"],"summary":"项目-章节-镜头-实体关联列表(分页)","operationId":"list_project_entity_links_api_v1_studio_shot_links__entity_type__get","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"}},{"name":"chapter_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id"}},{"name":"shot_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id"}},{"name":"asset_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Asset Id"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_Any__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/actor":{"post":{"tags":["studio/shot-links"],"summary":"创建项目-章节-镜头-演员关联","operationId":"create_project_actor_link_api_v1_studio_shot_links_actor_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAssetLinkCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectActorLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/actor/{link_id}":{"delete":{"tags":["studio/shot-links"],"summary":"删除项目-章节-镜头-演员关联","operationId":"delete_project_actor_link_api_v1_studio_shot_links_actor__link_id__delete","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/scene":{"post":{"tags":["studio/shot-links"],"summary":"创建项目-章节-镜头-场景关联","operationId":"create_project_scene_link_api_v1_studio_shot_links_scene_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAssetLinkCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectSceneLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/scene/{link_id}":{"delete":{"tags":["studio/shot-links"],"summary":"删除项目-章节-镜头-场景关联","operationId":"delete_project_scene_link_api_v1_studio_shot_links_scene__link_id__delete","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/prop":{"post":{"tags":["studio/shot-links"],"summary":"创建项目-章节-镜头-道具关联","operationId":"create_project_prop_link_api_v1_studio_shot_links_prop_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAssetLinkCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectPropLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/prop/{link_id}":{"delete":{"tags":["studio/shot-links"],"summary":"删除项目-章节-镜头-道具关联","operationId":"delete_project_prop_link_api_v1_studio_shot_links_prop__link_id__delete","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/costume":{"post":{"tags":["studio/shot-links"],"summary":"创建项目-章节-镜头-服装关联","operationId":"create_project_costume_link_api_v1_studio_shot_links_costume_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAssetLinkCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ProjectCostumeLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-links/costume/{link_id}":{"delete":{"tags":["studio/shot-links"],"summary":"删除项目-章节-镜头-服装关联","operationId":"delete_project_costume_link_api_v1_studio_shot_links_costume__link_id__delete","parameters":[{"name":"link_id","in":"path","required":true,"schema":{"type":"integer","title":"Link Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-frame-images":{"get":{"tags":["studio/shot-frame-images"],"summary":"镜头分镜帧图片列表(分页)","operationId":"list_shot_frame_images_api_v1_studio_shot_frame_images_get","parameters":[{"name":"shot_detail_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按镜头细节过滤","title":"Shot Detail Id"},"description":"按镜头细节过滤"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_ShotFrameImageRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/shot-frame-images"],"summary":"创建镜头分镜帧图片","operationId":"create_shot_frame_image_api_v1_studio_shot_frame_images_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotFrameImageCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotFrameImageRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-frame-images/{image_id}":{"patch":{"tags":["studio/shot-frame-images"],"summary":"更新镜头分镜帧图片","operationId":"update_shot_frame_image_api_v1_studio_shot_frame_images__image_id__patch","parameters":[{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","title":"Image Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotFrameImageUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotFrameImageRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/shot-frame-images"],"summary":"删除镜头分镜帧图片","operationId":"delete_shot_frame_image_api_v1_studio_shot_frame_images__image_id__delete","parameters":[{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","title":"Image Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/entities/existence-check":{"post":{"tags":["studio/entities"],"summary":"批量检测资产名称是否存在(模糊匹配,不分页)","operationId":"check_entity_names_existence_api_v1_studio_entities_existence_check_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityNameExistenceCheckRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_EntityNameExistenceCheckResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/entities/{entity_type}":{"get":{"tags":["studio/entities"],"summary":"统一实体列表(分页)","operationId":"list_entities_api_v1_studio_entities__entity_type__get","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 name/description","title":"Q"},"description":"关键字,过滤 name/description"},{"name":"style","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"题材/风格(单值)","title":"Style"},"description":"题材/风格(单值)"},{"name":"visual_style","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"画面表现形式(单值:真人/动漫)","title":"Visual Style"},"description":"画面表现形式(单值:真人/动漫)"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_dict_str__Any___"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/entities"],"summary":"统一创建实体","operationId":"create_entity_api_v1_studio_entities__entity_type__post","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_str__Any__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/entities/{entity_type}/{entity_id}":{"get":{"tags":["studio/entities"],"summary":"统一获取实体","operationId":"get_entity_api_v1_studio_entities__entity_type___entity_id__get","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_str__Any__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/entities"],"summary":"统一更新实体","operationId":"update_entity_api_v1_studio_entities__entity_type___entity_id__patch","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_str__Any__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/entities"],"summary":"统一删除实体","operationId":"delete_entity_api_v1_studio_entities__entity_type___entity_id__delete","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/entities/{entity_type}/{entity_id}/images":{"get":{"tags":["studio/entities"],"summary":"统一实体图片列表(分页)","operationId":"list_entity_images_api_v1_studio_entities__entity_type___entity_id__images_get","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_dict_str__Any___"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/entities"],"summary":"统一创建实体图片","operationId":"create_entity_image_api_v1_studio_entities__entity_type___entity_id__images_post","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_str__Any__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/entities/{entity_type}/{entity_id}/images/{image_id}":{"patch":{"tags":["studio/entities"],"summary":"统一更新实体图片","operationId":"update_entity_image_api_v1_studio_entities__entity_type___entity_id__images__image_id__patch","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","title":"Image Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_str__Any__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/entities"],"summary":"统一删除实体图片","operationId":"delete_entity_image_api_v1_studio_entities__entity_type___entity_id__images__image_id__delete","parameters":[{"name":"entity_type","in":"path","required":true,"schema":{"type":"string","title":"Entity Type"}},{"name":"entity_id","in":"path","required":true,"schema":{"type":"string","title":"Entity Id"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","title":"Image Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/prompts":{"get":{"tags":["studio/prompts"],"summary":"提示词模板列表(分页)","operationId":"list_prompt_templates_api_v1_studio_prompts_get","parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/PromptCategory"},{"type":"null"}],"description":"按类别过滤","title":"Category"},"description":"按类别过滤"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 name","title":"Q"},"description":"关键字,过滤 name"},{"name":"is_default","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"过滤是否为默认","title":"Is Default"},"description":"过滤是否为默认"},{"name":"is_system","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"过滤是否为系统预置","title":"Is System"},"description":"过滤是否为系统预置"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_PromptTemplateRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/prompts"],"summary":"创建提示词模板","operationId":"create_prompt_template_api_v1_studio_prompts_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTemplateCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PromptTemplateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/prompts/categories":{"get":{"tags":["studio/prompts"],"summary":"获取提示词类别枚举(含中文映射)","operationId":"list_prompt_categories_api_v1_studio_prompts_categories_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_list_PromptCategoryOptionRead__"}}}}}}},"/api/v1/studio/prompts/{template_id}":{"get":{"tags":["studio/prompts"],"summary":"获取提示词模板详情","operationId":"get_prompt_template_api_v1_studio_prompts__template_id__get","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PromptTemplateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/prompts"],"summary":"局部更新提示词模板","operationId":"update_prompt_template_api_v1_studio_prompts__template_id__patch","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTemplateUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PromptTemplateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/prompts"],"summary":"删除提示词模板","operationId":"delete_prompt_template_api_v1_studio_prompts__template_id__delete","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/files":{"get":{"tags":["studio/files"],"summary":"文件列表(分页)","operationId":"list_files_api_api_v1_studio_files_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"关键字,过滤 name","title":"Q"},"description":"关键字,过滤 name"},{"name":"order","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Order"}},{"name":"is_desc","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Is Desc"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Page Size"}},{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"按 file_usages 限定项目;提供后仅返回该项目下有关联记录的文件","title":"Project Id"},"description":"按 file_usages 限定项目;提供后仅返回该项目下有关联记录的文件"},{"name":"chapter_title","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"章节标题(精确匹配,与 project_id 联用)","title":"Chapter Title"},"description":"章节标题(精确匹配,与 project_id 联用)"},{"name":"shot_title","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"镜头标题(精确匹配,与 project_id 联用)","title":"Shot Title"},"description":"镜头标题(精确匹配,与 project_id 联用)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PaginatedData_FileRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/files/upload":{"post":{"tags":["studio/files"],"summary":"上传文件并创建 FileItem 记录","operationId":"upload_file_api_api_v1_studio_files_upload_post","parameters":[{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_file_api_api_v1_studio_files_upload_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_FileRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/files/{file_id}/download":{"get":{"tags":["studio/files"],"summary":"下载文件二进制内容","operationId":"download_file_api_api_v1_studio_files__file_id__download_get","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","title":"File Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/files/{file_id}/storage-info":{"get":{"tags":["studio/files"],"summary":"获取对象存储详情(head_object)","operationId":"get_file_storage_info_api_api_v1_studio_files__file_id__storage_info_get","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","title":"File Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_dict_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/files/{file_id}":{"get":{"tags":["studio/files"],"summary":"获取文件详情(元信息 + file_usages)","operationId":"get_file_detail_api_v1_studio_files__file_id__get","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","title":"File Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_FileDetailRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["studio/files"],"summary":"更新文件元信息","operationId":"update_file_meta_api_v1_studio_files__file_id__patch","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","title":"File Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_FileRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["studio/files"],"summary":"删除文件(记录 + 存储对象)","operationId":"delete_file_api_api_v1_studio_files__file_id__delete","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","title":"File Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_NoneType_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/actors/{actor_id}/image-tasks":{"post":{"tags":["studio/image-tasks"],"summary":"演员图片生成(任务版)","description":"为指定演员创建图片生成任务,并通过 `GenerationTaskLink` 关联。","operationId":"create_actor_image_generation_task_api_v1_studio_image_tasks_actors__actor_id__image_tasks_post","parameters":[{"name":"actor_id","in":"path","required":true,"schema":{"type":"string","title":"Actor Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioImageTaskRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/actors/{actor_id}/render-prompt":{"post":{"tags":["studio/image-tasks"],"summary":"演员图片提示词渲染","operationId":"render_actor_image_prompt_api_v1_studio_image_tasks_actors__actor_id__render_prompt_post","parameters":[{"name":"actor_id","in":"path","required":true,"schema":{"type":"string","title":"Actor Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioImageTaskRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_RenderedPromptResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/assets/{asset_type}/{asset_id}/image-tasks":{"post":{"tags":["studio/image-tasks"],"summary":"道具/场景/服装图片生成(任务版)","description":"为道具/场景/服装创建图片生成任务。\n\n- asset_type: prop / scene / costume\n- path 参数 asset_id 为对应资产 ID\n- body.image_id 必须为该资产下对应图片表记录的 ID(PropImage/SceneImage/CostumeImage)","operationId":"create_asset_image_generation_task_api_v1_studio_image_tasks_assets__asset_type___asset_id__image_tasks_post","parameters":[{"name":"asset_type","in":"path","required":true,"schema":{"type":"string","title":"Asset Type"}},{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioImageTaskRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/assets/{asset_type}/{asset_id}/render-prompt":{"post":{"tags":["studio/image-tasks"],"summary":"道具/场景/服装图片提示词渲染","operationId":"render_asset_image_prompt_api_v1_studio_image_tasks_assets__asset_type___asset_id__render_prompt_post","parameters":[{"name":"asset_type","in":"path","required":true,"schema":{"type":"string","title":"Asset Type"}},{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioImageTaskRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_RenderedPromptResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/characters/{character_id}/image-tasks":{"post":{"tags":["studio/image-tasks"],"summary":"角色图片生成(任务版)","description":"为角色创建图片生成任务(对应 CharacterImage 业务)。\n\n- path 参数 character_id 为 Character.id\n- body.image_id 必须为该角色下的 CharacterImage.id","operationId":"create_character_image_generation_task_api_v1_studio_image_tasks_characters__character_id__image_tasks_post","parameters":[{"name":"character_id","in":"path","required":true,"schema":{"type":"string","title":"Character Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioImageTaskRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/characters/{character_id}/render-prompt":{"post":{"tags":["studio/image-tasks"],"summary":"角色图片提示词渲染","operationId":"render_character_image_prompt_api_v1_studio_image_tasks_characters__character_id__render_prompt_post","parameters":[{"name":"character_id","in":"path","required":true,"schema":{"type":"string","title":"Character Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudioImageTaskRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_RenderedPromptResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/shot/{shot_id}/frame-image-tasks":{"post":{"tags":["studio/image-tasks"],"summary":"镜头分镜帧图片生成(任务版)","description":"为镜头分镜帧图片生成任务(基于 `shot_id + frame_type` 自动定位数据)。","operationId":"create_shot_frame_image_generation_task_api_v1_studio_image_tasks_shot__shot_id__frame_image_tasks_post","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotFrameImageTaskRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_TaskCreated_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/image-tasks/shot/{shot_id}/frame-render-prompt":{"post":{"tags":["studio/image-tasks"],"summary":"镜头分镜帧提示词渲染","operationId":"render_shot_frame_prompt_api_v1_studio_image_tasks_shot__shot_id__frame_render_prompt_post","parameters":[{"name":"shot_id","in":"path","required":true,"schema":{"type":"string","title":"Shot Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotFramePromptRenderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_RenderedShotFramePromptRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/studio/shot-character-links":{"get":{"tags":["studio/shot-character-links"],"summary":"查询镜头角色关联列表(ShotCharacterLink)","operationId":"list_shot_character_links_api_v1_studio_shot_character_links_get","parameters":[{"name":"shot_id","in":"query","required":true,"schema":{"type":"string","description":"镜头 ID","title":"Shot Id"},"description":"镜头 ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_list_ShotCharacterLinkRead__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["studio/shot-character-links"],"summary":"创建/更新镜头角色关联(ShotCharacterLink)","operationId":"upsert_shot_character_link_api_v1_studio_shot_character_links_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotCharacterLinkCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ShotCharacterLinkRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/divide-async":{"post":{"tags":["script-processing"],"summary":"异步将剧本分割为多个镜头","description":"创建章节分镜提取任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"divide_script_async_api_v1_script_processing_divide_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptDividerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/divide":{"post":{"tags":["script-processing"],"summary":"将剧本分割为多个镜头","description":"输入完整剧本文本,输出分镜列表(index/start_line/end_line/script_excerpt/shot_name/time_of_day)。注意:此阶段不强制稳定ID,角色以“称呼/名字”弱信息输出,稳定ID在合并阶段统一分配。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 divide-async。","operationId":"divide_script_api_v1_script_processing_divide_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptDividerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ScriptDivisionResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/merge-entities-async":{"post":{"tags":["script-processing"],"summary":"异步合并多镜头的实体信息","description":"创建实体合并任务并立即返回 task_id;当前保留为预备能力,尚无真实前端入口。","operationId":"merge_entities_async_api_v1_script_processing_merge_entities_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityMergerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/merge-entities":{"post":{"tags":["script-processing"],"summary":"合并多镜头的实体信息","description":"输入全部分镜提取结果(可选带上脚本分镜与历史实体库),输出合并后的实体库:角色库/地点库/场景库/道具库(静态画像 + 变体列表)。该步骤会统一分配稳定ID(如 char_001/loc_001/prop_001/scene_001)。当提供 previous_merge 与 conflict_resolutions 时,将进行冲突重试合并,优先消解 conflicts 并尽量保持 ID 稳定。当前接口保留为预备能力,尚无真实前端入口。","operationId":"merge_entities_api_v1_script_processing_merge_entities_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityMergerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_EntityMergeResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-variants-async":{"post":{"tags":["script-processing"],"summary":"异步分析服装/外形变体","description":"创建变体分析任务并立即返回 task_id;当前保留为预备能力,尚无真实前端入口。","operationId":"analyze_variants_async_api_v1_script_processing_analyze_variants_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VariantAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-variants":{"post":{"tags":["script-processing"],"summary":"分析服装/外形变体","description":"检测角色服装/外形变化,构建演变时间线,生成章节变体建议列表与变体建议。当前接口保留为预备能力,尚无真实前端入口。","operationId":"analyze_variants_api_v1_script_processing_analyze_variants_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VariantAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_VariantAnalysisResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/check-consistency-async":{"post":{"tags":["script-processing"],"summary":"异步检查角色混淆一致性(基于原文)","description":"创建一致性检查任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"check_consistency_async_api_v1_script_processing_check_consistency_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptConsistencyCheckRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/check-consistency":{"post":{"tags":["script-processing"],"summary":"检查角色混淆一致性(基于原文)","description":"检测同一角色在不同段落/镜头被赋予不同身份/行为主体导致混淆,并给出修改建议。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 check-consistency-async。","operationId":"check_consistency_api_v1_script_processing_check_consistency_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptConsistencyCheckRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ScriptConsistencyCheckResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-character-portrait-async":{"post":{"tags":["script-processing"],"summary":"异步分析人物画像缺失信息","description":"创建人物画像分析任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"analyze_character_portrait_async_api_v1_script_processing_analyze_character_portrait_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CharacterPortraitAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-character-portrait":{"post":{"tags":["script-processing"],"summary":"分析人物画像缺失信息","description":"根据原文人物上下文与人物描述,判断缺少哪些关键信息,并给出优化后的人物画像描述。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 analyze-character-portrait-async。","operationId":"analyze_character_portrait_api_v1_script_processing_analyze_character_portrait_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CharacterPortraitAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_CharacterPortraitAnalysisResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-prop-info-async":{"post":{"tags":["script-processing"],"summary":"异步分析道具信息缺失项","description":"创建道具信息分析任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"analyze_prop_info_async_api_v1_script_processing_analyze_prop_info_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropInfoAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-prop-info":{"post":{"tags":["script-processing"],"summary":"分析道具信息缺失项","description":"根据原文道具上下文与道具描述,判断缺少哪些关键信息,并给出优化后的可生成道具描述。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 analyze-prop-info-async。","operationId":"analyze_prop_info_api_v1_script_processing_analyze_prop_info_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropInfoAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_PropInfoAnalysisResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-scene-info-async":{"post":{"tags":["script-processing"],"summary":"异步分析场景信息缺失项","description":"创建场景信息分析任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"analyze_scene_info_async_api_v1_script_processing_analyze_scene_info_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneInfoAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-scene-info":{"post":{"tags":["script-processing"],"summary":"分析场景信息缺失项","description":"根据原文场景上下文与场景描述,判断缺少哪些关键信息,并给出优化后的可生成场景描述。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 analyze-scene-info-async。","operationId":"analyze_scene_info_api_v1_script_processing_analyze_scene_info_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneInfoAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_SceneInfoAnalysisResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-costume-info-async":{"post":{"tags":["script-processing"],"summary":"异步分析服装信息缺失项","description":"创建服装信息分析任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"analyze_costume_info_async_api_v1_script_processing_analyze_costume_info_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CostumeInfoAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/analyze-costume-info":{"post":{"tags":["script-processing"],"summary":"分析服装信息缺失项","description":"根据原文服装上下文与服装描述,判断缺少哪些关键信息,并给出优化后的可生成服装描述。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 analyze-costume-info-async。","operationId":"analyze_costume_info_api_v1_script_processing_analyze_costume_info_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CostumeInfoAnalysisRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_CostumeInfoAnalysisResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/optimize-script-async":{"post":{"tags":["script-processing"],"summary":"异步基于一致性检查优化剧本","description":"创建剧本优化任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"optimize_script_async_api_v1_script_processing_optimize_script_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptOptimizeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/optimize-script":{"post":{"tags":["script-processing"],"summary":"基于一致性检查优化剧本","description":"将一致性检查输出及原文作为输入,生成优化后的剧本(尽量少改,只改与角色混淆 issues 相关段落)。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 optimize-script-async。","operationId":"optimize_script_api_v1_script_processing_optimize_script_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptOptimizeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ScriptOptimizationResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/simplify-script":{"post":{"tags":["script-processing"],"summary":"智能精简剧本","description":"在保留剧情主体并保证剧情连续的前提下精简剧本文本。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 simplify-script-async。","operationId":"simplify_script_api_v1_script_processing_simplify_script_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptSimplifyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_ScriptSimplificationResult_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/simplify-script-async":{"post":{"tags":["script-processing"],"summary":"异步智能精简剧本","description":"创建剧本精简任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"simplify_script_async_api_v1_script_processing_simplify_script_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptSimplifyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/extract-async":{"post":{"tags":["script-processing"],"summary":"异步项目级信息提取(最终输出)","description":"创建项目级信息提取任务并立即返回 task_id;前端可通过任务状态接口轮询。","operationId":"extract_script_async_api_v1_script_processing_extract_async_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptExtractRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_AsyncTaskCreateRead_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/script-processing/extract":{"post":{"tags":["script-processing"],"summary":"项目级信息提取(最终输出)","description":"输入分镜结果(可选带一致性检查结果),输出可导入 Studio 的草稿结构(name-based,ID 由导入接口生成)。当前同步接口主要用于兼容旧调用与调试场景;页面主流程优先使用 extract-async。","operationId":"extract_script_api_v1_script_processing_extract_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScriptExtractRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse_StudioScriptExtractionDraft_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/health":{"get":{"summary":"Health","description":"健康检查。","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"ActionBeatPhaseRead":{"properties":{"text":{"type":"string","title":"Text","description":"动作拍点原文"},"phase":{"type":"string","enum":["trigger","peak","aftermath"],"title":"Phase","description":"推断阶段:触发 / 峰值 / 收束"}},"type":"object","required":["text","phase"],"title":"ActionBeatPhaseRead","description":"动作拍点的轻量阶段推断结果。"},"ApiResponse_AsyncTaskCreateRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/AsyncTaskCreateRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[AsyncTaskCreateRead]"},"ApiResponse_ChapterRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ChapterRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ChapterRead]"},"ApiResponse_CharacterPortraitAnalysisResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/CharacterPortraitAnalysisResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[CharacterPortraitAnalysisResult]"},"ApiResponse_CostumeInfoAnalysisResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/CostumeInfoAnalysisResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[CostumeInfoAnalysisResult]"},"ApiResponse_EntityMergeResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/EntityMergeResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[EntityMergeResult]"},"ApiResponse_EntityNameExistenceCheckResponse_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/EntityNameExistenceCheckResponse"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[EntityNameExistenceCheckResponse]"},"ApiResponse_FileDetailRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/FileDetailRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[FileDetailRead]"},"ApiResponse_FileRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/FileRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[FileRead]"},"ApiResponse_GenerationTaskLinkRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/GenerationTaskLinkRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[GenerationTaskLinkRead]"},"ApiResponse_ImageGenerationOptionsRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ImageGenerationOptionsRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ImageGenerationOptionsRead]"},"ApiResponse_ModelRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ModelRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ModelRead]"},"ApiResponse_ModelSettingsRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ModelSettingsRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ModelSettingsRead]"},"ApiResponse_NoneType_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"type":"null","title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[NoneType]"},"ApiResponse_PaginatedData_Any__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_Any_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[Any]]"},"ApiResponse_PaginatedData_ChapterRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ChapterRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ChapterRead]]"},"ApiResponse_PaginatedData_FileRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_FileRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[FileRead]]"},"ApiResponse_PaginatedData_GenerationTaskLinkRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_GenerationTaskLinkRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[GenerationTaskLinkRead]]"},"ApiResponse_PaginatedData_ModelRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ModelRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ModelRead]]"},"ApiResponse_PaginatedData_ProjectRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ProjectRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ProjectRead]]"},"ApiResponse_PaginatedData_PromptTemplateRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_PromptTemplateRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[PromptTemplateRead]]"},"ApiResponse_PaginatedData_ProviderRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ProviderRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ProviderRead]]"},"ApiResponse_PaginatedData_ShotDetailRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ShotDetailRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ShotDetailRead]]"},"ApiResponse_PaginatedData_ShotDialogLineRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ShotDialogLineRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ShotDialogLineRead]]"},"ApiResponse_PaginatedData_ShotFrameImageRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ShotFrameImageRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ShotFrameImageRead]]"},"ApiResponse_PaginatedData_ShotLinkedAssetItem__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ShotLinkedAssetItem_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ShotLinkedAssetItem]]"},"ApiResponse_PaginatedData_ShotRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_ShotRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[ShotRead]]"},"ApiResponse_PaginatedData_TaskListItemRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_TaskListItemRead_"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[TaskListItemRead]]"},"ApiResponse_PaginatedData_dict_str__Any___":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PaginatedData_dict_str__Any__"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PaginatedData[dict[str, Any]]]"},"ApiResponse_ProjectActorLinkRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProjectActorLinkRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProjectActorLinkRead]"},"ApiResponse_ProjectCostumeLinkRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProjectCostumeLinkRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProjectCostumeLinkRead]"},"ApiResponse_ProjectPropLinkRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProjectPropLinkRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProjectPropLinkRead]"},"ApiResponse_ProjectRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProjectRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProjectRead]"},"ApiResponse_ProjectSceneLinkRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProjectSceneLinkRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProjectSceneLinkRead]"},"ApiResponse_ProjectStyleOptionsRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProjectStyleOptionsRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProjectStyleOptionsRead]"},"ApiResponse_PromptTemplateRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PromptTemplateRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PromptTemplateRead]"},"ApiResponse_PropInfoAnalysisResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/PropInfoAnalysisResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[PropInfoAnalysisResult]"},"ApiResponse_ProviderRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ProviderRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ProviderRead]"},"ApiResponse_RenderedPromptResponse_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/RenderedPromptResponse"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[RenderedPromptResponse]"},"ApiResponse_RenderedShotFramePromptRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/RenderedShotFramePromptRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[RenderedShotFramePromptRead]"},"ApiResponse_SceneInfoAnalysisResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/SceneInfoAnalysisResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[SceneInfoAnalysisResult]"},"ApiResponse_ScriptConsistencyCheckResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ScriptConsistencyCheckResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ScriptConsistencyCheckResult]"},"ApiResponse_ScriptDivisionResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ScriptDivisionResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ScriptDivisionResult]"},"ApiResponse_ScriptOptimizationResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ScriptOptimizationResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ScriptOptimizationResult]"},"ApiResponse_ScriptSimplificationResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ScriptSimplificationResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ScriptSimplificationResult]"},"ApiResponse_ShotAssetsOverviewRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotAssetsOverviewRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotAssetsOverviewRead]"},"ApiResponse_ShotCharacterLinkRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotCharacterLinkRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotCharacterLinkRead]"},"ApiResponse_ShotDetailRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotDetailRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotDetailRead]"},"ApiResponse_ShotDialogLineRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotDialogLineRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotDialogLineRead]"},"ApiResponse_ShotFrameImageRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotFrameImageRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotFrameImageRead]"},"ApiResponse_ShotPreparationMutationResultRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotPreparationMutationResultRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotPreparationMutationResultRead]"},"ApiResponse_ShotPreparationStateRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotPreparationStateRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotPreparationStateRead]"},"ApiResponse_ShotRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotRead]"},"ApiResponse_ShotVideoPromptPreviewRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotVideoPromptPreviewRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotVideoPromptPreviewRead]"},"ApiResponse_ShotVideoReadinessRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/ShotVideoReadinessRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[ShotVideoReadinessRead]"},"ApiResponse_StudioScriptExtractionDraft_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/StudioScriptExtractionDraft"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[StudioScriptExtractionDraft]"},"ApiResponse_TaskCancelRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/TaskCancelRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[TaskCancelRead]"},"ApiResponse_TaskCreated_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/TaskCreated"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[TaskCreated]"},"ApiResponse_TaskLinkAdoptRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/TaskLinkAdoptRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[TaskLinkAdoptRead]"},"ApiResponse_TaskResultRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/TaskResultRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[TaskResultRead]"},"ApiResponse_TaskStatusRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/TaskStatusRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[TaskStatusRead]"},"ApiResponse_VariantAnalysisResult_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/VariantAnalysisResult"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[VariantAnalysisResult]"},"ApiResponse_VideoGenerationOptionsRead_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/VideoGenerationOptionsRead"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[VideoGenerationOptionsRead]"},"ApiResponse_VideoPromptPreviewResponse_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"$ref":"#/components/schemas/VideoPromptPreviewResponse"},{"type":"null"}],"description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[VideoPromptPreviewResponse]"},"ApiResponse_dict_":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[dict]"},"ApiResponse_dict_str__Any__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[dict[str, Any]]"},"ApiResponse_list_PromptCategoryOptionRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/PromptCategoryOptionRead"},"type":"array"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[list[PromptCategoryOptionRead]]"},"ApiResponse_list_ProviderSupportedRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/ProviderSupportedRead"},"type":"array"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[list[ProviderSupportedRead]]"},"ApiResponse_list_ShotCharacterLinkRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/ShotCharacterLinkRead"},"type":"array"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[list[ShotCharacterLinkRead]]"},"ApiResponse_list_ShotExtractedCandidateRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/ShotExtractedCandidateRead"},"type":"array"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[list[ShotExtractedCandidateRead]]"},"ApiResponse_list_ShotExtractedDialogueCandidateRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/ShotExtractedDialogueCandidateRead"},"type":"array"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[list[ShotExtractedDialogueCandidateRead]]"},"ApiResponse_list_ShotRuntimeSummaryRead__":{"properties":{"code":{"type":"integer","title":"Code","description":"与 HTTP 状态码一致","default":200},"message":{"type":"string","title":"Message","description":"提示信息","default":"success"},"data":{"anyOf":[{"items":{"$ref":"#/components/schemas/ShotRuntimeSummaryRead"},"type":"array"},{"type":"null"}],"title":"Data","description":"实际数据"},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta","description":"附加元信息"}},"type":"object","title":"ApiResponse[list[ShotRuntimeSummaryRead]]"},"AsyncTaskCreateRead":{"properties":{"task_id":{"type":"string","title":"Task Id","description":"任务 ID"},"status":{"$ref":"#/components/schemas/TaskStatus","description":"任务状态"},"reused":{"type":"boolean","title":"Reused","description":"是否复用了当前业务实体已有的活跃任务","default":false},"relation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Type","description":"业务关联类型"},"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"业务关联实体 ID"}},"type":"object","required":["task_id","status"],"title":"AsyncTaskCreateRead"},"Body_upload_file_api_api_v1_studio_files_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"要上传的二进制文件"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"可选:写入 file_usages 的项目 ID"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id"},"usage_kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Usage Kind","description":"与 project_id 同时提供时写入 file_usages"},"source_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Ref"}},"type":"object","required":["file"],"title":"Body_upload_file_api_api_v1_studio_files_upload_post"},"CameraAngle":{"type":"string","enum":["EYE_LEVEL","HIGH_ANGLE","LOW_ANGLE","BIRD_EYE","DUTCH","OVER_SHOULDER"],"title":"CameraAngle","description":"机位角度(与 `app.schemas.skills.common.CameraAngle` 对齐,存英文 code)。"},"CameraMovement":{"type":"string","enum":["STATIC","PAN","TILT","DOLLY_IN","DOLLY_OUT","TRACK","CRANE","HANDHELD","STEADICAM","ZOOM_IN","ZOOM_OUT"],"title":"CameraMovement","description":"运镜方式(与 `app.schemas.skills.common.CameraMovement` 对齐,存英文 code)。"},"CameraShotType":{"type":"string","enum":["ECU","CU","MCU","MS","MLS","LS","ELS"],"title":"CameraShotType","description":"景别(与 `app.schemas.skills.common.ShotType` 对齐,存英文 code)。"},"ChapterCreate":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"所属项目 ID"},"index":{"type":"integer","title":"Index","description":"章节序号(项目内唯一)"},"title":{"type":"string","title":"Title","description":"章节标题"},"summary":{"type":"string","title":"Summary","description":"章节摘要","default":""},"raw_text":{"type":"string","title":"Raw Text","description":"章节原文","default":""},"condensed_text":{"type":"string","title":"Condensed Text","description":"精简原文","default":""},"storyboard_count":{"type":"integer","title":"Storyboard Count","description":"分镜数量","default":0},"status":{"$ref":"#/components/schemas/ChapterStatus","description":"章节状态","default":"draft"},"id":{"type":"string","title":"Id","description":"章节 ID"}},"type":"object","required":["project_id","index","title","id"],"title":"ChapterCreate"},"ChapterRead":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"所属项目 ID"},"index":{"type":"integer","title":"Index","description":"章节序号(项目内唯一)"},"title":{"type":"string","title":"Title","description":"章节标题"},"summary":{"type":"string","title":"Summary","description":"章节摘要","default":""},"raw_text":{"type":"string","title":"Raw Text","description":"章节原文","default":""},"condensed_text":{"type":"string","title":"Condensed Text","description":"精简原文","default":""},"storyboard_count":{"type":"integer","title":"Storyboard Count","description":"分镜数量","default":0},"status":{"$ref":"#/components/schemas/ChapterStatus","description":"章节状态","default":"draft"},"id":{"type":"string","title":"Id"},"shot_count":{"type":"integer","title":"Shot Count","description":"分镜数(shots 条数聚合)","default":0}},"type":"object","required":["project_id","index","title","id"],"title":"ChapterRead"},"ChapterStatus":{"type":"string","enum":["draft","shooting","done"],"title":"ChapterStatus","description":"章节生产状态。"},"ChapterUpdate":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"},"index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Index"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"raw_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Raw Text"},"condensed_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Condensed Text"},"storyboard_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Storyboard Count"},"status":{"anyOf":[{"$ref":"#/components/schemas/ChapterStatus"},{"type":"null"}]}},"type":"object","title":"ChapterUpdate"},"CharacterPortraitAnalysisRequest":{"properties":{"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"任务关联实体 ID(资产页恢复任务可选)"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"character_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Character Context","description":"原文人物上下文(可为空;用于提供额外背景,帮助判断缺失信息)"},"character_description":{"type":"string","minLength":1,"title":"Character Description","description":"原文人物描述"}},"type":"object","required":["character_description"],"title":"CharacterPortraitAnalysisRequest","description":"人物画像缺失信息分析请求。"},"CharacterPortraitAnalysisResult":{"properties":{"issues":{"items":{"type":"string"},"type":"array","title":"Issues"},"optimized_description":{"type":"string","title":"Optimized Description"}},"additionalProperties":false,"type":"object","required":["issues","optimized_description"],"title":"CharacterPortraitAnalysisResult","description":"根据原文人物描述,分析缺少的信息,并给出优化后的可生成画像描述。"},"CostumeInfoAnalysisRequest":{"properties":{"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"任务关联实体 ID(资产页恢复任务可选)"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"costume_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Costume Context","description":"原文服装上下文(可为空;用于提供额外背景,帮助判断缺失信息)"},"costume_description":{"type":"string","minLength":1,"title":"Costume Description","description":"原文服装描述"}},"type":"object","required":["costume_description"],"title":"CostumeInfoAnalysisRequest","description":"服装信息缺失分析请求。"},"CostumeInfoAnalysisResult":{"properties":{"issues":{"items":{"type":"string"},"type":"array","title":"Issues"},"optimized_description":{"type":"string","title":"Optimized Description"}},"additionalProperties":false,"type":"object","required":["issues","optimized_description"],"title":"CostumeInfoAnalysisResult","description":"根据原文服装/造型描述,分析缺少的信息,并给出优化后的可生成服装描述。"},"CostumeTimeline":{"properties":{"character_id":{"type":"string","title":"Character Id","description":"角色稳定ID"},"character_name":{"type":"string","title":"Character Name","description":"角色名称"},"timeline_entries":{"items":{"$ref":"#/components/schemas/CostumeTimelineEntry"},"type":"array","title":"Timeline Entries","description":"时间线条目"}},"additionalProperties":false,"type":"object","required":["character_id","character_name"],"title":"CostumeTimeline","description":"单角色的服装演变时间线。"},"CostumeTimelineEntry":{"properties":{"shot_index":{"type":"integer","minimum":1.0,"title":"Shot Index","description":"镜头序号"},"scene_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Id","description":"可选:所属场景稳定ID(若已可推断)"},"costume_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Costume Note","description":"服装/外形要点(简短)"},"changes":{"items":{"type":"string"},"type":"array","title":"Changes","description":"与上一条相比的变化点"},"evidence":{"items":{"$ref":"#/components/schemas/EvidenceSpan"},"type":"array","title":"Evidence","description":"原文依据(可选)"}},"additionalProperties":false,"type":"object","required":["shot_index"],"title":"CostumeTimelineEntry","description":"单角色的服装演变时间线条目。"},"DialogueLineMode":{"type":"string","enum":["DIALOGUE","VOICE_OVER","OFF_SCREEN","PHONE"],"title":"DialogueLineMode","description":"对白模式(与 `app.schemas.skills.common.DialogueLineMode` 对齐,存英文 code)。"},"EntityEntry":{"properties":{"id":{"type":"string","title":"Id","description":"实体稳定ID(合并阶段分配)"},"name":{"type":"string","title":"Name","description":"实体名称"},"type":{"type":"string","enum":["character","scene","prop","location"],"title":"Type","description":"实体类型"},"normalized_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Normalized Name","description":"归一化名称(来自文本,可选)"},"aliases":{"items":{"type":"string"},"type":"array","title":"Aliases","description":"别名/称呼(来自文本,可选)"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"基础画像/描述(忠实文本,简短)"},"confidence":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Confidence","description":"合并确定度 0-1(可选)"},"first_appearance":{"anyOf":[{"$ref":"#/components/schemas/EvidenceSpan"},{"type":"null"}],"description":"首次出场证据(可选)"},"costume_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Costume Note","description":"服装/造型描述(可选,便于变体与资产关联)"},"traits":{"items":{"type":"string"},"type":"array","title":"Traits","description":"性格/特征词(可选)"},"location_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location Type","description":"地点类型:房间/街道/森林/车厢等(可选)"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category","description":"道具类别(可选:weapon/document/vehicle/clothing/device/magic_item/other)"},"owner_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner Character Id","description":"拥有者角色ID(可选)"},"evidence":{"items":{"$ref":"#/components/schemas/EvidenceSpan"},"type":"array","title":"Evidence","description":"支撑该实体画像的证据片段(可选)"},"first_shot":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"First Shot","description":"首次出现的镜头序号"},"appearances":{"items":{"type":"integer"},"type":"array","title":"Appearances","description":"出现镜头列表"},"variants":{"items":{"$ref":"#/components/schemas/EntityVariant"},"type":"array","title":"Variants","description":"变体列表"}},"additionalProperties":false,"type":"object","required":["id","name","type"],"title":"EntityEntry","description":"合并后的实体条目(脚本处理中间态)。"},"EntityLibrary":{"properties":{"characters":{"items":{"$ref":"#/components/schemas/EntityEntry"},"type":"array","title":"Characters","description":"角色库"},"locations":{"items":{"$ref":"#/components/schemas/EntityEntry"},"type":"array","title":"Locations","description":"地点库"},"scenes":{"items":{"$ref":"#/components/schemas/EntityEntry"},"type":"array","title":"Scenes","description":"场景库"},"props":{"items":{"$ref":"#/components/schemas/EntityEntry"},"type":"array","title":"Props","description":"道具库"},"total_entries":{"type":"integer","minimum":0.0,"title":"Total Entries","description":"总实体数"}},"additionalProperties":false,"type":"object","required":["total_entries"],"title":"EntityLibrary","description":"合并后的实体库(脚本处理中间态)。"},"EntityMergeResult":{"properties":{"merged_library":{"$ref":"#/components/schemas/EntityLibrary","description":"合并后的实体库"},"merge_stats":{"additionalProperties":true,"type":"object","title":"Merge Stats","description":"合并统计信息"},"conflicts":{"items":{"type":"string"},"type":"array","title":"Conflicts","description":"发现的冲突/待处理项"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"合并说明"}},"additionalProperties":false,"type":"object","required":["merged_library"],"title":"EntityMergeResult","description":"实体合并结果(脚本处理中间态)。"},"EntityMergerRequest":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"all_shot_extractions":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"All Shot Extractions","description":"所有镜头提取结果(ShotElementExtractionResult 的序列化形式)"},"historical_library":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Historical Library","description":"历史实体库(可选,用于增量合并)"},"script_division":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Script Division","description":"脚本分镜结果(可选;ScriptDivisionResult 序列化),用于定位与统计"},"previous_merge":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Previous Merge","description":"上一次合并结果(可选;EntityMergeResult 序列化),用于冲突重试合并"},"conflict_resolutions":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Conflict Resolutions","description":"冲突解决建议列表(可选;用于冲突重试合并)"}},"type":"object","required":["all_shot_extractions"],"title":"EntityMergerRequest","description":"实体合并请求。"},"EntityNameExistenceCheckRequest":{"properties":{"project_id":{"type":"string","minLength":1,"title":"Project Id","description":"项目 ID(必填)"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"镜头 ID(可选;不传则 linked_to_shot 恒为 false)"},"character_names":{"items":{"type":"string"},"type":"array","title":"Character Names","description":"角色名称列表"},"prop_names":{"items":{"type":"string"},"type":"array","title":"Prop Names","description":"道具名称列表"},"scene_names":{"items":{"type":"string"},"type":"array","title":"Scene Names","description":"场景名称列表"},"costume_names":{"items":{"type":"string"},"type":"array","title":"Costume Names","description":"服装名称列表"}},"additionalProperties":false,"type":"object","required":["project_id"],"title":"EntityNameExistenceCheckRequest","description":"批量检测项目内/全局资产名称是否存在(模糊匹配)。"},"EntityNameExistenceCheckResponse":{"properties":{"characters":{"items":{"$ref":"#/components/schemas/EntityNameExistenceItem"},"type":"array","title":"Characters"},"props":{"items":{"$ref":"#/components/schemas/EntityNameExistenceItem"},"type":"array","title":"Props"},"scenes":{"items":{"$ref":"#/components/schemas/EntityNameExistenceItem"},"type":"array","title":"Scenes"},"costumes":{"items":{"$ref":"#/components/schemas/EntityNameExistenceItem"},"type":"array","title":"Costumes"}},"additionalProperties":false,"type":"object","title":"EntityNameExistenceCheckResponse","description":"批量存在性检测结果(按资产类型分组)。"},"EntityNameExistenceItem":{"properties":{"name":{"type":"string","title":"Name","description":"输入名称(原样回传)"},"exists":{"type":"boolean","title":"Exists","description":"数据库中是否存在(模糊命中)"},"linked_to_project":{"type":"boolean","title":"Linked To Project","description":"是否已关联到该项目(角色等同于 exists)"},"linked_to_shot":{"type":"boolean","title":"Linked To Shot","description":"是否已关联到请求中的 shot(未传 shot_id 时为 false)","default":false},"asset_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Asset Id","description":"命中的资产 ID(如 prop_id/scene_id/costume_id/character_id)"},"link_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Link Id","description":"若已关联到项目,对应 Project*Link 的 id;否则为空"}},"additionalProperties":false,"type":"object","required":["name","exists","linked_to_project"],"title":"EntityNameExistenceItem","description":"单个名称的存在性结果。"},"EntityVariant":{"properties":{"variant_key":{"type":"string","title":"Variant Key","description":"变体键(例如 outfit_v1、wounded_state 等)"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"变体描述(简短)"},"affected_shots":{"items":{"type":"integer"},"type":"array","title":"Affected Shots","description":"涉及镜头序号"},"evidence":{"items":{"$ref":"#/components/schemas/EvidenceSpan"},"type":"array","title":"Evidence","description":"原文依据(可选)"}},"additionalProperties":false,"type":"object","required":["variant_key"],"title":"EntityVariant","description":"实体变体条目(最小可用结构,便于服装/外形演变)。"},"EvidenceSpan":{"properties":{"chunk_id":{"type":"string","title":"Chunk Id","description":"输入文本块的唯一ID(例如 chapter1_p03)"},"start_char":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Start Char","description":"在该 chunk 中的起始字符位置(可选)"},"end_char":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"End Char","description":"在该 chunk 中的结束字符位置(可选)"},"quote":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Quote","description":"不超过200字的原文摘录(可选,便于人工审核)"}},"additionalProperties":false,"type":"object","required":["chunk_id"],"title":"EvidenceSpan","description":"可追溯证据:原文定位(chunk + 起止位置/摘录),用于审核与回查。"},"FileDetailRead":{"properties":{"id":{"type":"string","title":"Id","description":"文件 ID"},"type":{"$ref":"#/components/schemas/FileTypeEnum","description":"文件类型"},"name":{"type":"string","title":"Name","description":"文件名/标题"},"thumbnail":{"type":"string","title":"Thumbnail","description":"缩略图 URL/路径","default":""},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"标签"},"usages":{"items":{"$ref":"#/components/schemas/FileUsageRead"},"type":"array","title":"Usages"}},"type":"object","required":["id","type","name"],"title":"FileDetailRead","description":"含 file_usages 列表(详情接口)。"},"FileRead":{"properties":{"id":{"type":"string","title":"Id","description":"文件 ID"},"type":{"$ref":"#/components/schemas/FileTypeEnum","description":"文件类型"},"name":{"type":"string","title":"Name","description":"文件名/标题"},"thumbnail":{"type":"string","title":"Thumbnail","description":"缩略图 URL/路径","default":""},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"标签"}},"type":"object","required":["id","type","name"],"title":"FileRead"},"FileTypeEnum":{"type":"string","enum":["image","video"],"title":"FileTypeEnum"},"FileUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"},"usage":{"anyOf":[{"$ref":"#/components/schemas/FileUsageWrite"},{"type":"null"}],"description":"若提供则 upsert 一条 file_usages"}},"type":"object","title":"FileUpdate"},"FileUsageRead":{"properties":{"id":{"type":"integer","title":"Id"},"file_id":{"type":"string","title":"File Id"},"project_id":{"type":"string","title":"Project Id"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id"},"usage_kind":{"type":"string","title":"Usage Kind"},"source_ref":{"type":"string","title":"Source Ref"}},"type":"object","required":["id","file_id","project_id","chapter_id","shot_id","usage_kind","source_ref"],"title":"FileUsageRead"},"FileUsageWrite":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"项目 ID"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"镜头 ID"},"usage_kind":{"type":"string","title":"Usage Kind","description":"用途:shot_frame / generated_video / character_image / asset_image / upload / api 等"},"source_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Ref","description":"幂等键(可选)"}},"type":"object","required":["project_id","usage_kind"],"title":"FileUsageWrite","description":"写入 file_usages 的关联信息(与 FileItem 一并提交)。"},"FrameGuidanceDecisionRead":{"properties":{"text":{"type":"string","title":"Text","description":"guidance 原文"},"category":{"type":"string","title":"Category","description":"guidance 分类,如 summary / continuity / composition / screen"},"reason_tag":{"type":"string","title":"Reason Tag","description":"简短原因标签,如 首帧保空间 / 关键帧保轴线","default":""},"reason":{"type":"string","title":"Reason","description":"该 guidance 被保留或压缩的原因说明"}},"type":"object","required":["text","category","reason"],"title":"FrameGuidanceDecisionRead","description":"分镜帧 guidance 的保留/压缩决策结果。"},"GenerationTaskLinkCreate":{"properties":{"task_id":{"type":"string","title":"Task Id","description":"生成任务 ID"},"resource_type":{"type":"string","title":"Resource Type","description":"生成资源类型(如 image/video/text/task_link)"},"relation_type":{"type":"string","title":"Relation Type","description":"业务类型(如 prop/costume/scene 等)"},"relation_entity_id":{"type":"string","title":"Relation Entity Id","description":"关联业务实体 ID"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"关联产物文件 ID(files.id;适用于图片/音频/视频)"},"status":{"type":"string","title":"Status","description":"关联状态:accepted=已采用、todo=待操作、rejected=未采用;默认 todo","default":"todo"}},"type":"object","required":["task_id","resource_type","relation_type","relation_entity_id"],"title":"GenerationTaskLinkCreate","description":"创建生成任务关联请求体。"},"GenerationTaskLinkRead":{"properties":{"task_id":{"type":"string","title":"Task Id","description":"生成任务 ID"},"resource_type":{"type":"string","title":"Resource Type","description":"生成资源类型(如 image/video/text/task_link)"},"relation_type":{"type":"string","title":"Relation Type","description":"业务类型(如 prop/costume/scene 等)"},"relation_entity_id":{"type":"string","title":"Relation Entity Id","description":"关联业务实体 ID"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"关联产物文件 ID(files.id;适用于图片/音频/视频)"},"status":{"type":"string","title":"Status","description":"关联状态:accepted=已采用、todo=待操作、rejected=未采用"},"id":{"type":"integer","title":"Id","description":"关联行 ID"}},"type":"object","required":["task_id","resource_type","relation_type","relation_entity_id","status","id"],"title":"GenerationTaskLinkRead","description":"生成任务关联返回体。"},"GenerationTaskLinkUpdate":{"properties":{"resource_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource Type","description":"生成资源类型(如 image/video/text/task_link)"},"relation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Type","description":"业务类型(如 prop/costume/scene 等)"},"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"关联业务实体 ID"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"关联产物文件 ID(files.id;适用于图片/音频/视频)"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"关联状态:accepted=已采用、todo=待操作、rejected=未采用"}},"type":"object","title":"GenerationTaskLinkUpdate","description":"更新生成任务关联请求体(不包含 is_adopted,采用状态由专用接口正向变更)。"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ImageGenerationOptionsRead":{"properties":{"provider":{"type":"string","title":"Provider","description":"供应商稳定键"},"model_id":{"type":"string","title":"Model Id","description":"默认图片模型 ID"},"model_name":{"type":"string","title":"Model Name","description":"默认图片模型名称"},"supported_ratios":{"items":{"type":"string"},"type":"array","title":"Supported Ratios","description":"当前模型支持的目标比例"},"default_resolution_profile":{"type":"string","title":"Default Resolution Profile","description":"当前模型默认分辨率档位"},"ratio_size_profiles":{"additionalProperties":{"additionalProperties":{"type":"string"},"type":"object"},"type":"object","title":"Ratio Size Profiles","description":"按比例和分辨率档位映射得到的像素尺寸"}},"type":"object","required":["provider","model_id","model_name","default_resolution_profile"],"title":"ImageGenerationOptionsRead","description":"当前默认图片模型对应的关键帧规格选项。"},"LogLevel":{"type":"string","enum":["debug","info","warn","error"],"title":"LogLevel","description":"全局日志级别。"},"ModelCategoryKey":{"type":"string","enum":["text","image","video"],"title":"ModelCategoryKey","description":"模型类别:文本/图片/视频。"},"ModelCreate":{"properties":{"name":{"type":"string","title":"Name","description":"模型名称"},"category":{"$ref":"#/components/schemas/ModelCategoryKey","description":"模型类别:text/image/video"},"provider_id":{"type":"string","title":"Provider Id","description":"所属供应商 ID"},"params":{"additionalProperties":true,"type":"object","title":"Params","description":"模型参数(JSON)"},"description":{"type":"string","title":"Description","description":"说明","default":""},"created_by":{"type":"string","title":"Created By","description":"创建人","default":""},"id":{"type":"string","title":"Id","description":"模型 ID"}},"type":"object","required":["name","category","provider_id","id"],"title":"ModelCreate","description":"创建模型请求体。"},"ModelRead":{"properties":{"name":{"type":"string","title":"Name","description":"模型名称"},"category":{"$ref":"#/components/schemas/ModelCategoryKey","description":"模型类别:text/image/video"},"provider_id":{"type":"string","title":"Provider Id","description":"所属供应商 ID"},"params":{"additionalProperties":true,"type":"object","title":"Params","description":"模型参数(JSON)"},"description":{"type":"string","title":"Description","description":"说明","default":""},"created_by":{"type":"string","title":"Created By","description":"创建人","default":""},"id":{"type":"string","title":"Id","description":"模型 ID"}},"type":"object","required":["name","category","provider_id","id"],"title":"ModelRead","description":"对外返回的模型信息。"},"ModelSettingsRead":{"properties":{"default_text_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Text Model Id","description":"默认文本模型 ID"},"default_image_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Image Model Id","description":"默认图片模型 ID"},"default_video_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Video Model Id","description":"默认视频模型 ID"},"api_timeout":{"type":"integer","title":"Api Timeout","description":"API 超时(秒)","default":30},"log_level":{"$ref":"#/components/schemas/LogLevel","description":"日志级别","default":"info"},"id":{"type":"integer","title":"Id","description":"设置行 ID(通常为 1)"}},"type":"object","required":["id"],"title":"ModelSettingsRead","description":"对外返回的模型全局设置。"},"ModelSettingsUpdate":{"properties":{"default_text_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Text Model Id","description":"默认文本模型 ID"},"default_image_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Image Model Id","description":"默认图片模型 ID"},"default_video_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Video Model Id","description":"默认视频模型 ID"},"api_timeout":{"type":"integer","title":"Api Timeout","description":"API 超时(秒)","default":30},"log_level":{"$ref":"#/components/schemas/LogLevel","description":"日志级别","default":"info"}},"type":"object","title":"ModelSettingsUpdate","description":"更新或保存模型全局设置请求体。"},"ModelUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"模型名称"},"category":{"anyOf":[{"$ref":"#/components/schemas/ModelCategoryKey"},{"type":"null"}],"description":"模型类别"},"provider_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider Id","description":"所属供应商 ID"},"params":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Params","description":"模型参数(JSON)"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"说明"}},"type":"object","title":"ModelUpdate","description":"更新模型请求体(全部可选)。"},"PaginatedData_Any_":{"properties":{"items":{"items":{},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[Any]"},"PaginatedData_ChapterRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ChapterRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ChapterRead]"},"PaginatedData_FileRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/FileRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[FileRead]"},"PaginatedData_GenerationTaskLinkRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/GenerationTaskLinkRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[GenerationTaskLinkRead]"},"PaginatedData_ModelRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ModelRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ModelRead]"},"PaginatedData_ProjectRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ProjectRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ProjectRead]"},"PaginatedData_PromptTemplateRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/PromptTemplateRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[PromptTemplateRead]"},"PaginatedData_ProviderRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ProviderRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ProviderRead]"},"PaginatedData_ShotDetailRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ShotDetailRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ShotDetailRead]"},"PaginatedData_ShotDialogLineRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ShotDialogLineRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ShotDialogLineRead]"},"PaginatedData_ShotFrameImageRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ShotFrameImageRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ShotFrameImageRead]"},"PaginatedData_ShotLinkedAssetItem_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ShotLinkedAssetItem"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ShotLinkedAssetItem]"},"PaginatedData_ShotRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ShotRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[ShotRead]"},"PaginatedData_TaskListItemRead_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/TaskListItemRead"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[TaskListItemRead]"},"PaginatedData_dict_str__Any__":{"properties":{"items":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Items","description":"当前页数据"},"pagination":{"$ref":"#/components/schemas/Pagination","description":"分页信息"}},"type":"object","required":["items","pagination"],"title":"PaginatedData[dict[str, Any]]"},"Pagination":{"properties":{"page":{"type":"integer","title":"Page","description":"当前页,从 1 开始"},"page_size":{"type":"integer","title":"Page Size","description":"每页条数"},"total":{"type":"integer","title":"Total","description":"总条数"},"max_page":{"type":"integer","title":"Max Page","description":"最大页码"}},"type":"object","required":["page","page_size","total","max_page"],"title":"Pagination","description":"分页信息。"},"ProjectActorLinkRead":{"properties":{"id":{"type":"integer","title":"Id","description":"关联行 ID"},"project_id":{"type":"string","title":"Project Id","description":"项目 ID"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(可空)"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"镜头 ID(可空)"},"actor_id":{"type":"string","title":"Actor Id"},"thumbnail":{"type":"string","title":"Thumbnail","description":"演员缩略图下载地址","default":""}},"type":"object","required":["id","project_id","actor_id"],"title":"ProjectActorLinkRead"},"ProjectAssetLinkCreate":{"properties":{"project_id":{"type":"string","title":"Project Id"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id"},"asset_id":{"type":"string","title":"Asset Id"}},"type":"object","required":["project_id","asset_id"],"title":"ProjectAssetLinkCreate"},"ProjectCostumeLinkRead":{"properties":{"id":{"type":"integer","title":"Id","description":"关联行 ID"},"project_id":{"type":"string","title":"Project Id","description":"项目 ID"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(可空)"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"镜头 ID(可空)"},"costume_id":{"type":"string","title":"Costume Id"},"thumbnail":{"type":"string","title":"Thumbnail","description":"服装缩略图下载地址","default":""}},"type":"object","required":["id","project_id","costume_id"],"title":"ProjectCostumeLinkRead"},"ProjectCreate":{"properties":{"name":{"type":"string","title":"Name","description":"项目名称"},"description":{"type":"string","title":"Description","description":"项目简介","default":""},"style":{"$ref":"#/components/schemas/ProjectStyle","description":"题材/风格","examples":["真人都市","真人科幻","真人古装","动漫科幻","动漫3D","国漫","水墨画"]},"visual_style":{"$ref":"#/components/schemas/ProjectVisualStyle","description":"画面表现形式","default":"现实"},"seed":{"type":"integer","title":"Seed","description":"随机种子","default":0},"unify_style":{"type":"boolean","title":"Unify Style","description":"是否统一风格","default":true},"progress":{"type":"integer","title":"Progress","description":"进度百分比(0-100)","default":0},"default_video_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Video Ratio","description":"项目级默认视频比例;分镜未覆盖时生效"},"stats":{"additionalProperties":true,"type":"object","title":"Stats","description":"聚合统计(JSON)"},"id":{"type":"string","title":"Id","description":"项目 ID"}},"type":"object","required":["name","style","id"],"title":"ProjectCreate"},"ProjectPropLinkRead":{"properties":{"id":{"type":"integer","title":"Id","description":"关联行 ID"},"project_id":{"type":"string","title":"Project Id","description":"项目 ID"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(可空)"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"镜头 ID(可空)"},"prop_id":{"type":"string","title":"Prop Id"},"thumbnail":{"type":"string","title":"Thumbnail","description":"道具缩略图下载地址","default":""}},"type":"object","required":["id","project_id","prop_id"],"title":"ProjectPropLinkRead"},"ProjectRead":{"properties":{"name":{"type":"string","title":"Name","description":"项目名称"},"description":{"type":"string","title":"Description","description":"项目简介","default":""},"style":{"$ref":"#/components/schemas/ProjectStyle","description":"题材/风格","examples":["真人都市","真人科幻","真人古装","动漫科幻","动漫3D","国漫","水墨画"]},"visual_style":{"$ref":"#/components/schemas/ProjectVisualStyle","description":"画面表现形式","default":"现实"},"seed":{"type":"integer","title":"Seed","description":"随机种子","default":0},"unify_style":{"type":"boolean","title":"Unify Style","description":"是否统一风格","default":true},"progress":{"type":"integer","title":"Progress","description":"进度百分比(0-100)","default":0},"default_video_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Video Ratio","description":"项目级默认视频比例;分镜未覆盖时生效"},"stats":{"additionalProperties":true,"type":"object","title":"Stats","description":"聚合统计(JSON)"},"id":{"type":"string","title":"Id"}},"type":"object","required":["name","style","id"],"title":"ProjectRead"},"ProjectSceneLinkRead":{"properties":{"id":{"type":"integer","title":"Id","description":"关联行 ID"},"project_id":{"type":"string","title":"Project Id","description":"项目 ID"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(可空)"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"镜头 ID(可空)"},"scene_id":{"type":"string","title":"Scene Id"},"thumbnail":{"type":"string","title":"Thumbnail","description":"场景缩略图下载地址","default":""}},"type":"object","required":["id","project_id","scene_id"],"title":"ProjectSceneLinkRead"},"ProjectStyle":{"type":"string","enum":["真人都市","真人科幻","真人古装","动漫科幻","动漫3D","国漫","水墨画"],"title":"ProjectStyle","description":"项目题材/风格维度(不用于区分真人/动漫)。"},"ProjectStyleOptionsRead":{"properties":{"visual_styles":{"items":{"$ref":"#/components/schemas/StyleOption"},"type":"array","title":"Visual Styles","description":"视觉风格可选项"},"styles_by_visual_style":{"additionalProperties":{"items":{"$ref":"#/components/schemas/StyleOption"},"type":"array"},"type":"object","title":"Styles By Visual Style","description":"按视觉风格分组的视频风格选项"},"default_style_by_visual_style":{"additionalProperties":{"type":"string"},"type":"object","title":"Default Style By Visual Style","description":"各视觉风格默认视频风格"}},"type":"object","title":"ProjectStyleOptionsRead","description":"项目风格候选项。"},"ProjectUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"style":{"anyOf":[{"$ref":"#/components/schemas/ProjectStyle"},{"type":"null"}],"description":"题材/风格","examples":["真人都市","真人科幻","真人古装","动漫科幻","动漫3D","国漫","水墨画"]},"visual_style":{"anyOf":[{"$ref":"#/components/schemas/ProjectVisualStyle"},{"type":"null"}]},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed"},"unify_style":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Unify Style"},"progress":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Progress"},"default_video_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Video Ratio"},"stats":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Stats"}},"type":"object","title":"ProjectUpdate"},"ProjectVisualStyle":{"type":"string","enum":["现实","动漫"],"title":"ProjectVisualStyle","description":"画面表现形式维度:用于区分现实/动漫等。"},"PromptCategory":{"type":"string","enum":["frame_head_image","frame_tail_image","frame_key_image","frame_head_prompt","frame_tail_prompt","frame_key_prompt","video_prompt","storyboard_prompt","bgm","sfx","character_image_front","character_image_other","actor_image_front","actor_image_other","prop_image_front","prop_image_other","scene_image_front","scene_image_other","costume_image_front","costume_image_other","combined"],"title":"PromptCategory","description":"提示词模板类别。"},"PromptCategoryOptionRead":{"properties":{"value":{"$ref":"#/components/schemas/PromptCategory","description":"类别枚举值"},"label":{"type":"string","title":"Label","description":"中文名称"},"description":{"type":"string","title":"Description","description":"类别简介","default":""}},"type":"object","required":["value","label"],"title":"PromptCategoryOptionRead","description":"提示词类别选项(枚举值 + 中文标签 + 简介)。"},"PromptTemplateCreate":{"properties":{"category":{"$ref":"#/components/schemas/PromptCategory","description":"模板类别"},"name":{"type":"string","title":"Name","description":"模板名称"},"content":{"type":"string","title":"Content","description":"模板内容"},"preview":{"type":"string","title":"Preview","description":"预览文案","default":""},"variables":{"items":{"type":"string"},"type":"array","title":"Variables","description":"变量名列表"},"is_default":{"type":"boolean","title":"Is Default","description":"是否为默认提示词","default":false}},"type":"object","required":["category","name","content"],"title":"PromptTemplateCreate","description":"创建提示词模板。id 由后端自动生成;is_system 不可由客户端设置。"},"PromptTemplateRead":{"properties":{"id":{"type":"string","title":"Id","description":"模板 ID"},"category":{"$ref":"#/components/schemas/PromptCategory","description":"模板类别"},"name":{"type":"string","title":"Name","description":"模板名称"},"preview":{"type":"string","title":"Preview","description":"预览文案"},"content":{"type":"string","title":"Content","description":"模板内容"},"variables":{"items":{"type":"string"},"type":"array","title":"Variables","description":"变量名列表"},"is_default":{"type":"boolean","title":"Is Default","description":"是否为默认提示词"},"is_system":{"type":"boolean","title":"Is System","description":"是否为系统预置"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"创建时间"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"最后更新时间"}},"type":"object","required":["id","category","name","preview","content","variables","is_default","is_system","created_at","updated_at"],"title":"PromptTemplateRead","description":"读取提示词模板(含全部字段)。"},"PromptTemplateUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"模板名称"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content","description":"模板内容"},"preview":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preview","description":"预览文案"},"variables":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Variables","description":"变量名列表(整体替换)"},"is_default":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Default","description":"是否为默认提示词"}},"type":"object","title":"PromptTemplateUpdate","description":"局部更新提示词模板。不含 id / is_system。"},"PropInfoAnalysisRequest":{"properties":{"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"任务关联实体 ID(资产页恢复任务可选)"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"prop_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prop Context","description":"原文道具上下文(可为空;用于提供额外背景,帮助判断缺失信息)"},"prop_description":{"type":"string","minLength":1,"title":"Prop Description","description":"原文道具描述"}},"type":"object","required":["prop_description"],"title":"PropInfoAnalysisRequest","description":"道具信息缺失分析请求。"},"PropInfoAnalysisResult":{"properties":{"issues":{"items":{"type":"string"},"type":"array","title":"Issues"},"optimized_description":{"type":"string","title":"Optimized Description"}},"additionalProperties":false,"type":"object","required":["issues","optimized_description"],"title":"PropInfoAnalysisResult","description":"根据原文道具描述,分析缺少的信息,并给出优化后的可生成道具描述。"},"ProviderCreate":{"properties":{"name":{"type":"string","title":"Name","description":"供应商名称"},"base_url":{"type":"string","title":"Base Url","description":"文本/通用 API Base URL"},"image_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Base Url","description":"图片能力 API Base URL(可选覆盖)"},"video_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Base Url","description":"视频能力 API Base URL(可选覆盖)"},"description":{"type":"string","title":"Description","description":"说明","default":""},"status":{"$ref":"#/components/schemas/ProviderStatus","description":"状态:active/testing/disabled","default":"testing"},"created_by":{"type":"string","title":"Created By","description":"创建人","default":""},"id":{"type":"string","title":"Id","description":"供应商 ID"},"api_key":{"type":"string","title":"Api Key","description":"API Key(敏感,不在响应中回显)","default":""},"api_secret":{"type":"string","title":"Api Secret","description":"API Secret(敏感,不在响应中回显)","default":""}},"type":"object","required":["name","base_url","id"],"title":"ProviderCreate","description":"创建供应商时的请求体,允许填写敏感字段。"},"ProviderRead":{"properties":{"name":{"type":"string","title":"Name","description":"供应商名称"},"base_url":{"type":"string","title":"Base Url","description":"文本/通用 API Base URL"},"image_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Base Url","description":"图片能力 API Base URL(可选覆盖)"},"video_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Base Url","description":"视频能力 API Base URL(可选覆盖)"},"description":{"type":"string","title":"Description","description":"说明","default":""},"status":{"$ref":"#/components/schemas/ProviderStatus","description":"状态:active/testing/disabled","default":"testing"},"created_by":{"type":"string","title":"Created By","description":"创建人","default":""},"id":{"type":"string","title":"Id","description":"供应商 ID"}},"type":"object","required":["name","base_url","id"],"title":"ProviderRead","description":"对外返回的供应商信息(不包含 api_key/api_secret)。"},"ProviderStatus":{"type":"string","enum":["active","testing","disabled"],"title":"ProviderStatus","description":"供应商启用状态。"},"ProviderSupportedRead":{"properties":{"key":{"type":"string","title":"Key","description":"供应商稳定键"},"display_name":{"type":"string","title":"Display Name","description":"供应商展示名"},"aliases":{"items":{"type":"string"},"type":"array","title":"Aliases","description":"可识别别名"},"supported_categories":{"items":{"$ref":"#/components/schemas/ModelCategoryKey"},"type":"array","title":"Supported Categories","description":"支持的模型类别"},"default_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Base Url","description":"默认 API Base URL"},"requires_api_key":{"type":"boolean","title":"Requires Api Key","description":"是否要求 api_key","default":true},"requires_api_secret":{"type":"boolean","title":"Requires Api Secret","description":"是否要求 api_secret","default":false},"is_experimental":{"type":"boolean","title":"Is Experimental","description":"是否实验性供应商","default":false}},"type":"object","required":["key","display_name"],"title":"ProviderSupportedRead","description":"系统支持的供应商能力清单。"},"ProviderUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"供应商名称"},"base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Url","description":"文本/通用 API Base URL"},"image_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Base Url","description":"图片能力 API Base URL(可选覆盖)"},"video_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Base Url","description":"视频能力 API Base URL(可选覆盖)"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"说明"},"status":{"anyOf":[{"$ref":"#/components/schemas/ProviderStatus"},{"type":"null"}],"description":"状态:active/testing/disabled"},"api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key","description":"API Key(敏感,不在响应中回显)"},"api_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Secret","description":"API Secret(敏感,不在响应中回显)"}},"type":"object","title":"ProviderUpdate","description":"更新供应商时的可选字段。"},"RenderedPromptResponse":{"properties":{"prompt":{"type":"string","title":"Prompt","description":"渲染后的提示词(已套用模板与变量替换)"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"参考图 file_id 列表(自动选择;顺序有效)"}},"type":"object","required":["prompt"],"title":"RenderedPromptResponse"},"RenderedShotFramePromptRead":{"properties":{"base_prompt":{"type":"string","title":"Base Prompt","description":"原始基础提示词(不含图片映射说明)"},"rendered_prompt":{"type":"string","title":"Rendered Prompt","description":"最终提交给模型的提示词(含图片映射说明)"},"selected_guidance":{"items":{"type":"string"},"type":"array","title":"Selected Guidance","description":"最终 prompt 实际保留的 guidance 列表"},"dropped_guidance":{"items":{"type":"string"},"type":"array","title":"Dropped Guidance","description":"本次渲染中被压缩掉的 guidance 列表"},"selected_guidance_details":{"items":{"$ref":"#/components/schemas/FrameGuidanceDecisionRead"},"type":"array","title":"Selected Guidance Details","description":"最终保留 guidance 的决策详情"},"dropped_guidance_details":{"items":{"$ref":"#/components/schemas/FrameGuidanceDecisionRead"},"type":"array","title":"Dropped Guidance Details","description":"被压缩 guidance 的决策详情"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"最终参考图 file_id 列表,顺序与 mappings 一致"},"mappings":{"items":{"$ref":"#/components/schemas/ShotFramePromptMappingRead"},"type":"array","title":"Mappings","description":"图片与实体名称的映射关系,顺序与 images 完全一致"}},"type":"object","required":["base_prompt","rendered_prompt"],"title":"RenderedShotFramePromptRead","description":"关键帧最终生成提示词渲染结果。"},"SceneInfoAnalysisRequest":{"properties":{"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"任务关联实体 ID(资产页恢复任务可选)"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"scene_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Context","description":"原文场景上下文(可为空;用于提供额外背景,帮助判断缺失信息)"},"scene_description":{"type":"string","minLength":1,"title":"Scene Description","description":"原文场景描述"}},"type":"object","required":["scene_description"],"title":"SceneInfoAnalysisRequest","description":"场景信息缺失分析请求。"},"SceneInfoAnalysisResult":{"properties":{"issues":{"items":{"type":"string"},"type":"array","title":"Issues"},"optimized_description":{"type":"string","title":"Optimized Description"}},"additionalProperties":false,"type":"object","required":["issues","optimized_description"],"title":"SceneInfoAnalysisResult","description":"根据原文场景描述,分析缺少的信息,并给出优化后的可生成场景描述。"},"ScriptConsistencyCheckRequest":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"script_text":{"type":"string","minLength":1,"title":"Script Text","description":"完整剧本文本"}},"type":"object","required":["script_text"],"title":"ScriptConsistencyCheckRequest","description":"一致性检查请求(角色混淆)。"},"ScriptConsistencyCheckResult":{"properties":{"issues":{"items":{"$ref":"#/components/schemas/ScriptConsistencyIssue"},"type":"array","title":"Issues","description":"问题列表"},"has_issues":{"type":"boolean","title":"Has Issues","description":"是否发现问题"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"总结(可选)"}},"additionalProperties":false,"type":"object","required":["has_issues"],"title":"ScriptConsistencyCheckResult","description":"基于原文的一致性检查结果(聚焦角色混淆)。"},"ScriptConsistencyIssue":{"properties":{"issue_type":{"type":"string","const":"character_confusion","title":"Issue Type","description":"固定为角色混淆类问题","default":"character_confusion"},"character_candidates":{"items":{"type":"string"},"type":"array","title":"Character Candidates","description":"涉及的角色候选(名字/称呼/ID 皆可,优先用原文称呼)"},"description":{"type":"string","title":"Description","description":"问题描述(为什么会混淆)"},"suggestion":{"type":"string","title":"Suggestion","description":"修改建议(如何改写以消除混淆)"},"affected_lines":{"anyOf":[{"additionalProperties":{"type":"integer"},"type":"object"},{"type":"null"}],"title":"Affected Lines","description":"受影响的行号范围,形如 {start_line: x, end_line: y}"},"evidence":{"items":{"$ref":"#/components/schemas/EvidenceSpan"},"type":"array","title":"Evidence","description":"原文依据(可选)"}},"additionalProperties":false,"type":"object","required":["description","suggestion"],"title":"ScriptConsistencyIssue","description":"角色混淆类一致性问题:同一角色在不同镜头被赋予不同身份/行为主体导致混淆。"},"ScriptDividerRequest":{"properties":{"script_text":{"type":"string","minLength":1,"title":"Script Text","description":"完整剧本文本"},"write_to_db":{"type":"boolean","title":"Write To Db","description":"是否将分镜写入数据库(AI Studio shots 表)","default":false},"chapter_id":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(write_to_db=true 时必填)"}},"type":"object","required":["script_text"],"title":"ScriptDividerRequest","description":"剧本分镜请求。"},"ScriptDivisionResult":{"properties":{"shots":{"items":{"$ref":"#/components/schemas/ShotDivision"},"type":"array","title":"Shots","description":"分镜列表"},"total_shots":{"type":"integer","minimum":0.0,"title":"Total Shots","description":"总镜头数"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"拆分说明或建议(可选)"}},"additionalProperties":false,"type":"object","required":["total_shots"],"title":"ScriptDivisionResult","description":"剧本分镜结果:镜头列表(每镜起止行号+预览文本)。"},"ScriptExtractRequest":{"properties":{"project_id":{"type":"string","minLength":1,"title":"Project Id","description":"项目 ID"},"chapter_id":{"type":"string","minLength":1,"title":"Chapter Id","description":"章节 ID"},"script_division":{"additionalProperties":true,"type":"object","title":"Script Division","description":"分镜结果(ScriptDivisionResult 序列化)"},"consistency":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Consistency","description":"一致性检查结果(可选;ScriptConsistencyCheckResult 序列化)"},"refresh_cache":{"type":"boolean","title":"Refresh Cache","description":"是否跳过后端缓存并强制重新提取","default":false}},"type":"object","required":["project_id","chapter_id","script_division"],"title":"ScriptExtractRequest","description":"项目级信息提取请求(最终输出)。"},"ScriptOptimizationResult":{"properties":{"optimized_script_text":{"type":"string","title":"Optimized Script Text","description":"优化后的剧本文本"},"change_summary":{"type":"string","title":"Change Summary","description":"改动摘要(只围绕 issues)"}},"additionalProperties":false,"type":"object","required":["optimized_script_text","change_summary"],"title":"ScriptOptimizationResult","description":"剧本优化输出:仅在发现角色混淆问题时使用。"},"ScriptOptimizeRequest":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"script_text":{"type":"string","minLength":1,"title":"Script Text","description":"原文剧本文本"},"consistency":{"additionalProperties":true,"type":"object","title":"Consistency","description":"一致性检查输出(ScriptConsistencyCheckResult 序列化)"}},"type":"object","required":["script_text","consistency"],"title":"ScriptOptimizeRequest","description":"剧本优化请求(基于一致性检查结果)。"},"ScriptSimplificationResult":{"properties":{"simplified_script_text":{"type":"string","title":"Simplified Script Text","description":"精简后的剧本文本"},"simplification_summary":{"type":"string","title":"Simplification Summary","description":"精简策略摘要(说明删改原则)"}},"additionalProperties":false,"type":"object","required":["simplified_script_text","simplification_summary"],"title":"ScriptSimplificationResult","description":"剧本精简输出:在保留剧情主体与连续性的前提下压缩篇幅。"},"ScriptSimplifyRequest":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"script_text":{"type":"string","minLength":1,"title":"Script Text","description":"原文剧本文本"}},"type":"object","required":["script_text"],"title":"ScriptSimplifyRequest","description":"智能精简剧本请求。"},"ShotAssetOverviewItem":{"properties":{"key":{"type":"string","title":"Key","description":"合并键:type:name"},"type":{"type":"string","enum":["character","prop","scene","costume"],"title":"Type","description":"实体类型:character/prop/scene/costume"},"name":{"type":"string","title":"Name","description":"资产名称"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"候选描述(来自 extraction payload)"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail","description":"缩略图"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"缩略图或参考图文件 ID"},"source":{"type":"string","enum":["linked","candidate","both"],"title":"Source","description":"来源:linked/candidate/both"},"candidate_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Candidate Id","description":"候选项 ID"},"candidate_status":{"anyOf":[{"$ref":"#/components/schemas/ShotCandidateStatus"},{"type":"null"}],"description":"候选确认状态"},"linked_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linked Entity Id","description":"当前已关联实体 ID"},"linked_image_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Linked Image Id","description":"当前已关联实体的 image 行 ID"},"is_linked":{"type":"boolean","title":"Is Linked","description":"当前是否已关联到镜头"}},"type":"object","required":["key","type","name","source","is_linked"],"title":"ShotAssetOverviewItem","description":"分镜资产总览项:统一返回已关联资产与提取候选的合并视图。"},"ShotAssetsOverviewRead":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"skip_extraction":{"type":"boolean","title":"Skip Extraction","description":"是否明确跳过提取"},"status":{"$ref":"#/components/schemas/ShotStatus","description":"镜头流程状态"},"summary":{"$ref":"#/components/schemas/ShotAssetsOverviewSummary","description":"总览统计"},"items":{"items":{"$ref":"#/components/schemas/ShotAssetOverviewItem"},"type":"array","title":"Items","description":"资产总览项"}},"type":"object","required":["shot_id","skip_extraction","status","summary"],"title":"ShotAssetsOverviewRead"},"ShotAssetsOverviewSummary":{"properties":{"linked_count":{"type":"integer","title":"Linked Count","description":"已关联项数量"},"pending_count":{"type":"integer","title":"Pending Count","description":"待确认候选数量"},"ignored_count":{"type":"integer","title":"Ignored Count","description":"已忽略候选数量"},"total_count":{"type":"integer","title":"Total Count","description":"总项数(含 ignored)"}},"type":"object","required":["linked_count","pending_count","ignored_count","total_count"],"title":"ShotAssetsOverviewSummary"},"ShotCandidateStatus":{"type":"string","enum":["pending","linked","ignored"],"title":"ShotCandidateStatus","description":"镜头提取候选确认状态。"},"ShotCandidateType":{"type":"string","enum":["character","scene","prop","costume"],"title":"ShotCandidateType","description":"镜头提取候选类型。"},"ShotCharacterLinkCreate":{"properties":{"shot_id":{"type":"string","title":"Shot Id"},"character_id":{"type":"string","title":"Character Id"},"index":{"type":"integer","title":"Index","default":0},"note":{"type":"string","title":"Note","default":""}},"type":"object","required":["shot_id","character_id"],"title":"ShotCharacterLinkCreate"},"ShotCharacterLinkRead":{"properties":{"id":{"type":"integer","title":"Id","description":"关联行 ID"},"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"character_id":{"type":"string","title":"Character Id","description":"角色 ID"},"index":{"type":"integer","title":"Index","description":"镜头内角色排序","default":0},"note":{"type":"string","title":"Note","description":"备注","default":""}},"type":"object","required":["id","shot_id","character_id"],"title":"ShotCharacterLinkRead"},"ShotCreate":{"properties":{"id":{"type":"string","title":"Id","description":"镜头 ID"},"chapter_id":{"type":"string","title":"Chapter Id","description":"所属章节 ID"},"index":{"type":"integer","title":"Index","description":"镜头序号(章节内唯一)"},"title":{"type":"string","title":"Title","description":"镜头标题"},"thumbnail":{"type":"string","title":"Thumbnail","description":"缩略图 URL/路径","default":""},"status":{"$ref":"#/components/schemas/ShotStatus","description":"镜头状态","default":"pending"},"skip_extraction":{"type":"boolean","title":"Skip Extraction","description":"是否明确跳过信息提取","default":false},"script_excerpt":{"type":"string","title":"Script Excerpt","description":"剧本摘录","default":""},"generated_video_file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Generated Video File Id","description":"已生成视频关联的文件 ID(files.id,type=video)"}},"type":"object","required":["id","chapter_id","index","title"],"title":"ShotCreate"},"ShotDetailCreate":{"properties":{"id":{"type":"string","title":"Id","description":"镜头 ID(与 shots.id 共享主键)"},"camera_shot":{"$ref":"#/components/schemas/CameraShotType","description":"景别"},"angle":{"$ref":"#/components/schemas/CameraAngle","description":"机位角度"},"movement":{"$ref":"#/components/schemas/CameraMovement","description":"运镜方式"},"scene_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Id","description":"关联场景 ID(可空)"},"duration":{"type":"integer","title":"Duration","description":"时长(秒)","default":0},"override_video_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Video Ratio","description":"分镜级视频比例覆盖;为空表示继承项目默认"},"mood_tags":{"items":{"type":"string"},"type":"array","title":"Mood Tags","description":"情绪标签"},"atmosphere":{"type":"string","title":"Atmosphere","description":"氛围描述","default":""},"follow_atmosphere":{"type":"boolean","title":"Follow Atmosphere","description":"是否沿用氛围","default":true},"has_bgm":{"type":"boolean","title":"Has Bgm","description":"是否包含 BGM","default":false},"vfx_type":{"$ref":"#/components/schemas/VFXType","description":"视效类型","default":"NONE"},"vfx_note":{"type":"string","title":"Vfx Note","description":"视效说明","default":""},"action_beats":{"items":{"type":"string"},"type":"array","title":"Action Beats","description":"动作拍点(按时间顺序排列)"},"first_frame_prompt":{"type":"string","title":"First Frame Prompt","description":"镜头分镜首帧提示词","default":""},"last_frame_prompt":{"type":"string","title":"Last Frame Prompt","description":"镜头分镜尾帧提示词","default":""},"key_frame_prompt":{"type":"string","title":"Key Frame Prompt","description":"镜头分镜关键帧提示词","default":""}},"type":"object","required":["id","camera_shot","angle","movement"],"title":"ShotDetailCreate"},"ShotDetailRead":{"properties":{"id":{"type":"string","title":"Id","description":"镜头 ID(与 shots.id 共享主键)"},"camera_shot":{"$ref":"#/components/schemas/CameraShotType","description":"景别"},"angle":{"$ref":"#/components/schemas/CameraAngle","description":"机位角度"},"movement":{"$ref":"#/components/schemas/CameraMovement","description":"运镜方式"},"scene_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Id","description":"关联场景 ID(可空)"},"duration":{"type":"integer","title":"Duration","description":"时长(秒)","default":0},"override_video_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Video Ratio","description":"分镜级视频比例覆盖;为空表示继承项目默认"},"mood_tags":{"items":{"type":"string"},"type":"array","title":"Mood Tags","description":"情绪标签"},"atmosphere":{"type":"string","title":"Atmosphere","description":"氛围描述","default":""},"follow_atmosphere":{"type":"boolean","title":"Follow Atmosphere","description":"是否沿用氛围","default":true},"has_bgm":{"type":"boolean","title":"Has Bgm","description":"是否包含 BGM","default":false},"vfx_type":{"$ref":"#/components/schemas/VFXType","description":"视效类型","default":"NONE"},"vfx_note":{"type":"string","title":"Vfx Note","description":"视效说明","default":""},"action_beats":{"items":{"type":"string"},"type":"array","title":"Action Beats","description":"动作拍点(按时间顺序排列)"},"first_frame_prompt":{"type":"string","title":"First Frame Prompt","description":"镜头分镜首帧提示词","default":""},"last_frame_prompt":{"type":"string","title":"Last Frame Prompt","description":"镜头分镜尾帧提示词","default":""},"key_frame_prompt":{"type":"string","title":"Key Frame Prompt","description":"镜头分镜关键帧提示词","default":""}},"type":"object","required":["id","camera_shot","angle","movement"],"title":"ShotDetailRead"},"ShotDetailUpdate":{"properties":{"camera_shot":{"anyOf":[{"$ref":"#/components/schemas/CameraShotType"},{"type":"null"}]},"angle":{"anyOf":[{"$ref":"#/components/schemas/CameraAngle"},{"type":"null"}]},"movement":{"anyOf":[{"$ref":"#/components/schemas/CameraMovement"},{"type":"null"}]},"scene_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Id"},"duration":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration"},"override_video_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Override Video Ratio"},"mood_tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Mood Tags"},"atmosphere":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Atmosphere"},"follow_atmosphere":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Follow Atmosphere"},"has_bgm":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Has Bgm"},"vfx_type":{"anyOf":[{"$ref":"#/components/schemas/VFXType"},{"type":"null"}]},"vfx_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vfx Note"},"action_beats":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Action Beats"},"first_frame_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Frame Prompt"},"last_frame_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Frame Prompt"},"key_frame_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key Frame Prompt"}},"type":"object","title":"ShotDetailUpdate"},"ShotDialogLineCreate":{"properties":{"shot_detail_id":{"type":"string","title":"Shot Detail Id"},"index":{"type":"integer","title":"Index","default":0},"text":{"type":"string","title":"Text"},"line_mode":{"$ref":"#/components/schemas/DialogueLineMode","default":"DIALOGUE"},"speaker_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Character Id"},"target_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Character Id"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name"},"target_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Name"}},"type":"object","required":["shot_detail_id","text"],"title":"ShotDialogLineCreate"},"ShotDialogLineRead":{"properties":{"id":{"type":"integer","title":"Id","description":"对话行 ID"},"shot_detail_id":{"type":"string","title":"Shot Detail Id","description":"所属镜头细节 ID"},"index":{"type":"integer","title":"Index","description":"行号(镜头内排序)","default":0},"text":{"type":"string","title":"Text","description":"台词内容"},"line_mode":{"$ref":"#/components/schemas/DialogueLineMode","description":"对白模式","default":"DIALOGUE"},"speaker_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Character Id","description":"说话角色 ID"},"target_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Character Id","description":"听者角色 ID"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name","description":"说话角色名称(用于回填关联;可空)"},"target_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Name","description":"听者角色名称(用于回填关联;可空)"}},"type":"object","required":["id","shot_detail_id","text"],"title":"ShotDialogLineRead"},"ShotDialogLineUpdate":{"properties":{"index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Index"},"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text"},"line_mode":{"anyOf":[{"$ref":"#/components/schemas/DialogueLineMode"},{"type":"null"}]},"speaker_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Character Id"},"target_character_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Character Id"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name"},"target_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Name"}},"type":"object","title":"ShotDialogLineUpdate"},"ShotDialogueCandidateStatus":{"type":"string","enum":["pending","accepted","ignored"],"title":"ShotDialogueCandidateStatus","description":"镜头对白提取候选确认状态。"},"ShotDivision":{"properties":{"index":{"type":"integer","minimum":1.0,"title":"Index","description":"镜头序号(章节内唯一)"},"start_line":{"type":"integer","minimum":1.0,"title":"Start Line","description":"起始行号(1-based)"},"end_line":{"type":"integer","minimum":1.0,"title":"End Line","description":"结束行号(1-based)"},"script_excerpt":{"type":"string","title":"Script Excerpt","description":"镜头对应的剧本摘录/文本"},"shot_name":{"type":"string","title":"Shot Name","description":"镜头名称(分镜名/镜头标题)","default":""},"time_of_day":{"anyOf":[{"type":"string","enum":["DAY","NIGHT","DAWN","DUSK","UNKNOWN","日","夜","黎明","黄昏","不明","未知"]},{"type":"null"}],"title":"Time Of Day","description":"时间(日/夜/未知等,可选)"}},"additionalProperties":false,"type":"object","required":["index","start_line","end_line","script_excerpt"],"title":"ShotDivision","description":"剧本分镜中的单镜信息:行号 + 预览文本(可选弱语义)。"},"ShotExtractedCandidateLinkRequest":{"properties":{"linked_entity_id":{"type":"string","title":"Linked Entity Id","description":"确认关联到的实体 ID"}},"type":"object","required":["linked_entity_id"],"title":"ShotExtractedCandidateLinkRequest"},"ShotExtractedCandidateRead":{"properties":{"id":{"type":"integer","title":"Id","description":"候选项 ID"},"shot_id":{"type":"string","title":"Shot Id","description":"所属镜头 ID"},"candidate_type":{"$ref":"#/components/schemas/ShotCandidateType","description":"候选类型"},"candidate_name":{"type":"string","title":"Candidate Name","description":"提取出的候选名称"},"candidate_status":{"$ref":"#/components/schemas/ShotCandidateStatus","description":"候选确认状态"},"linked_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linked Entity Id","description":"已关联实体 ID"},"source":{"type":"string","title":"Source","description":"候选来源"},"payload":{"additionalProperties":true,"type":"object","title":"Payload","description":"候选附加信息"},"confirmed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Confirmed At","description":"确认时间"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"创建时间"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"更新时间"}},"type":"object","required":["id","shot_id","candidate_type","candidate_name","candidate_status","source","created_at","updated_at"],"title":"ShotExtractedCandidateRead"},"ShotExtractedDialogueCandidateAcceptRequest":{"properties":{"index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Index","description":"写入对白行时使用的排序;为空则使用候选排序"},"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text","description":"接受时可覆盖对白文本"},"line_mode":{"anyOf":[{"$ref":"#/components/schemas/DialogueLineMode"},{"type":"null"}],"description":"接受时可覆盖对白模式"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name","description":"接受时可覆盖说话角色名称"},"target_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Name","description":"接受时可覆盖听者角色名称"}},"type":"object","title":"ShotExtractedDialogueCandidateAcceptRequest"},"ShotExtractedDialogueCandidateRead":{"properties":{"id":{"type":"integer","title":"Id","description":"对白候选项 ID"},"shot_id":{"type":"string","title":"Shot Id","description":"所属镜头 ID"},"index":{"type":"integer","title":"Index","description":"镜头内对白候选排序"},"text":{"type":"string","title":"Text","description":"提取出的对白文本"},"line_mode":{"$ref":"#/components/schemas/DialogueLineMode","description":"对白模式"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name","description":"说话角色名称"},"target_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Name","description":"听者角色名称"},"candidate_status":{"$ref":"#/components/schemas/ShotDialogueCandidateStatus","description":"对白候选确认状态"},"linked_dialog_line_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Linked Dialog Line Id","description":"已接受后关联的对白行 ID"},"source":{"type":"string","title":"Source","description":"候选来源"},"payload":{"additionalProperties":true,"type":"object","title":"Payload","description":"候选附加信息"},"confirmed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Confirmed At","description":"确认时间"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"创建时间"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","description":"更新时间"}},"type":"object","required":["id","shot_id","index","text","line_mode","candidate_status","source","created_at","updated_at"],"title":"ShotExtractedDialogueCandidateRead"},"ShotExtractionSummaryRead":{"properties":{"state":{"type":"string","enum":["not_extracted","extracted_empty","extracted_pending","extracted_resolved","skipped"],"title":"State","description":"镜头提取确认状态摘要"},"has_extracted":{"type":"boolean","title":"Has Extracted","description":"是否已执行过提取"},"last_extracted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Extracted At","description":"最近一次提取完成时间"},"asset_candidate_total":{"type":"integer","title":"Asset Candidate Total","description":"资产候选总数","default":0},"dialogue_candidate_total":{"type":"integer","title":"Dialogue Candidate Total","description":"对白候选总数","default":0},"pending_asset_count":{"type":"integer","title":"Pending Asset Count","description":"待确认资产候选数","default":0},"pending_dialogue_count":{"type":"integer","title":"Pending Dialogue Count","description":"待确认对白候选数","default":0}},"type":"object","required":["state","has_extracted"],"title":"ShotExtractionSummaryRead"},"ShotFrameImageCreate":{"properties":{"shot_detail_id":{"type":"string","title":"Shot Detail Id"},"frame_type":{"$ref":"#/components/schemas/ShotFrameType"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"},"format":{"type":"string","title":"Format","default":"png"}},"type":"object","required":["shot_detail_id","frame_type"],"title":"ShotFrameImageCreate"},"ShotFrameImageRead":{"properties":{"id":{"type":"integer","title":"Id","description":"图片行 ID"},"shot_detail_id":{"type":"string","title":"Shot Detail Id","description":"所属镜头细节 ID"},"frame_type":{"$ref":"#/components/schemas/ShotFrameType","description":"帧类型:first/last/key"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"关联的 FileItem ID(可为空,允许先创建占位)"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width","description":"宽(px)"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height","description":"高(px)"},"format":{"type":"string","title":"Format","description":"格式","default":"png"}},"type":"object","required":["id","shot_detail_id","frame_type"],"title":"ShotFrameImageRead"},"ShotFrameImageTaskRequest":{"properties":{"model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id","description":"可选模型 ID(models.id);不传则使用 ModelSettings.default_image_model_id;Provider 由模型关联反查"},"frame_type":{"$ref":"#/components/schemas/ShotFrameType","description":"first | last | key"},"prompt":{"type":"string","minLength":1,"title":"Prompt","description":"提示词(由前端传入,创建任务接口必填)。"},"images":{"items":{"$ref":"#/components/schemas/ShotLinkedAssetItem"},"type":"array","title":"Images","description":"参考资产条目列表(可多张,顺序有效)。后端会使用 item.file_id 作为参考图;无效条目会被跳过。"},"target_ratio":{"type":"string","enum":["16:9","4:3","1:1","3:4","9:16","21:9","3:2","2:3"],"title":"Target Ratio","description":"目标视频画幅比例;关键帧将按该画幅生成,以提升后续视频参考稳定性"},"resolution_profile":{"anyOf":[{"type":"string","enum":["standard","high"]},{"type":"null"}],"title":"Resolution Profile","description":"关键帧输出分辨率档位,默认 standard","default":"standard"}},"type":"object","required":["frame_type","prompt","target_ratio"],"title":"ShotFrameImageTaskRequest","description":"镜头分镜帧图片生成请求体:只根据 `shot_id + frame_type` 定位 ShotFrameImage。\n\n用于替代旧接口中通过 `image_id` 直接传入 ShotFrameImage.id 的方式。"},"ShotFrameImageUpdate":{"properties":{"frame_type":{"anyOf":[{"$ref":"#/components/schemas/ShotFrameType"},{"type":"null"}]},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"},"format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Format"}},"type":"object","title":"ShotFrameImageUpdate"},"ShotFramePromptMappingRead":{"properties":{"token":{"type":"string","title":"Token","description":"提示词中的图片占位 token,如 图1 / 图2"},"type":{"type":"string","enum":["character","prop","scene","costume"],"title":"Type","description":"实体类型:character/prop/scene/costume"},"id":{"type":"string","title":"Id","description":"实体 ID(如 character_id/prop_id/scene_id/costume_id)"},"name":{"type":"string","title":"Name","description":"实体名称"},"file_id":{"type":"string","title":"File Id","description":"本次渲染与生成使用的文件 ID"}},"type":"object","required":["token","type","id","name","file_id"],"title":"ShotFramePromptMappingRead","description":"关键帧提示词渲染后的图片映射关系。"},"ShotFramePromptRenderRequest":{"properties":{"frame_type":{"$ref":"#/components/schemas/ShotFrameType","description":"first | last | key"},"prompt":{"type":"string","minLength":1,"title":"Prompt","description":"原始基础提示词。渲染接口要求显式传入,用于生成最终提示词。"},"images":{"items":{"$ref":"#/components/schemas/ShotLinkedAssetItem"},"type":"array","title":"Images","description":"参考资产条目列表(可多张,顺序有效)。后端会使用 item.file_id 作为参考图;无效条目会被跳过。"}},"type":"object","required":["frame_type","prompt"],"title":"ShotFramePromptRenderRequest","description":"镜头分镜帧提示词渲染请求体。"},"ShotFramePromptRequest":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"frame_type":{"type":"string","title":"Frame Type","description":"first | last | key"}},"type":"object","required":["shot_id","frame_type"],"title":"ShotFramePromptRequest","description":"镜头分镜帧提示词生成任务请求。"},"ShotFrameType":{"type":"string","enum":["first","last","key"],"title":"ShotFrameType","description":"镜头分镜帧类型:首帧/尾帧/关键帧。"},"ShotLinkedAssetItem":{"properties":{"type":{"type":"string","enum":["character","prop","scene","costume"],"title":"Type","description":"实体类型:character/prop/scene/costume"},"id":{"type":"string","title":"Id","description":"实体 ID(如 character_id/prop_id/scene_id/costume_id)"},"image_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Image Id","description":"最佳缩略图对应的 image 行 ID(如 PropImage.id);无图则为 null"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"最佳缩略图对应的文件 ID(files.id);用于参考图输入;无图则为 null"},"name":{"type":"string","title":"Name","description":"实体名称"},"thumbnail":{"type":"string","title":"Thumbnail","description":"缩略图下载地址(/api/v1/studio/files/{file_id}/download)","default":""}},"type":"object","required":["type","id","name"],"title":"ShotLinkedAssetItem","description":"按分镜聚合返回的关联资产条目(角色/道具/场景/服装)。"},"ShotPreparationLinkEntityType":{"type":"string","enum":["character","scene","prop","costume"],"title":"ShotPreparationLinkEntityType"},"ShotPreparationLinkRequest":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"项目 ID"},"chapter_id":{"type":"string","title":"Chapter Id","description":"章节 ID"},"entity_type":{"$ref":"#/components/schemas/ShotPreparationLinkEntityType","description":"准备页关联的实体类型"},"linked_entity_id":{"type":"string","title":"Linked Entity Id","description":"要关联的实体 ID"}},"type":"object","required":["project_id","chapter_id","entity_type","linked_entity_id"],"title":"ShotPreparationLinkRequest"},"ShotPreparationMutationAction":{"type":"string","enum":["link_asset_candidate","ignore_asset_candidate","accept_dialogue_candidate","ignore_dialogue_candidate","skip_extraction","resume_extraction"],"title":"ShotPreparationMutationAction"},"ShotPreparationMutationResultRead":{"properties":{"action":{"$ref":"#/components/schemas/ShotPreparationMutationAction","description":"本次执行的准备页动作"},"state":{"$ref":"#/components/schemas/ShotPreparationStateRead","description":"动作完成后的最新准备页聚合状态"}},"type":"object","required":["action","state"],"title":"ShotPreparationMutationResultRead","description":"准备页命令执行后的统一响应。"},"ShotPreparationStateRead":{"properties":{"shot":{"$ref":"#/components/schemas/ShotRead","description":"当前镜头最新状态"},"assets_overview":{"$ref":"#/components/schemas/ShotAssetsOverviewRead","description":"资产确认区聚合状态"},"dialogue_candidates":{"items":{"$ref":"#/components/schemas/ShotExtractedDialogueCandidateRead"},"type":"array","title":"Dialogue Candidates","description":"当前待处理/已存在的对白候选"},"saved_dialogue_lines":{"items":{"$ref":"#/components/schemas/ShotDialogLineRead"},"type":"array","title":"Saved Dialogue Lines","description":"当前已保存的对白行"},"pending_confirm_count":{"type":"integer","title":"Pending Confirm Count","description":"当前仍待确认的总数量(资产 + 对白)"},"basic_info_ready":{"type":"boolean","title":"Basic Info Ready","description":"标题与剧本摘录是否已补齐"},"semantic_defaults_ready":{"type":"boolean","title":"Semantic Defaults Ready","description":"镜头语言默认值是否已确认"},"action_beats_ready":{"type":"boolean","title":"Action Beats Ready","description":"动作拍点是否已确认"},"action_beats_count":{"type":"integer","title":"Action Beats Count","description":"当前已确认动作拍点数量","default":0},"action_beat_phases":{"items":{"$ref":"#/components/schemas/ActionBeatPhaseRead"},"type":"array","title":"Action Beat Phases","description":"当前动作拍点的阶段推断结果"},"ready_for_generation":{"type":"boolean","title":"Ready For Generation","description":"当前镜头是否已完成准备,可进入后续生成"}},"type":"object","required":["shot","assets_overview","pending_confirm_count","basic_info_ready","semantic_defaults_ready","action_beats_ready","ready_for_generation"],"title":"ShotPreparationStateRead","description":"分镜准备页聚合状态。"},"ShotPromptAssetRef":{"properties":{"type":{"type":"string","enum":["character","prop","scene","costume"],"title":"Type","description":"资产类型"},"name":{"type":"string","title":"Name","description":"资产名称"},"description":{"type":"string","title":"Description","description":"资产描述或提取候选描述","default":""},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"可作为参考图的文件 ID"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail","description":"缩略图"}},"type":"object","required":["type","name"],"title":"ShotPromptAssetRef","description":"用于提示词渲染的镜头资产引用。"},"ShotPromptCameraInfo":{"properties":{"camera_shot":{"type":"string","title":"Camera Shot","description":"景别","default":""},"angle":{"type":"string","title":"Angle","description":"机位角度","default":""},"movement":{"type":"string","title":"Movement","description":"运镜方式","default":""},"duration":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration","description":"镜头时长(秒)"}},"type":"object","title":"ShotPromptCameraInfo","description":"用于提示词渲染的镜头语言信息。"},"ShotRead":{"properties":{"id":{"type":"string","title":"Id","description":"镜头 ID"},"chapter_id":{"type":"string","title":"Chapter Id","description":"所属章节 ID"},"index":{"type":"integer","title":"Index","description":"镜头序号(章节内唯一)"},"title":{"type":"string","title":"Title","description":"镜头标题"},"thumbnail":{"type":"string","title":"Thumbnail","description":"缩略图 URL/路径","default":""},"status":{"$ref":"#/components/schemas/ShotStatus","description":"镜头状态","default":"pending"},"skip_extraction":{"type":"boolean","title":"Skip Extraction","description":"是否明确跳过信息提取","default":false},"script_excerpt":{"type":"string","title":"Script Excerpt","description":"剧本摘录","default":""},"generated_video_file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Generated Video File Id","description":"已生成视频关联的文件 ID(files.id,type=video)"},"last_extracted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Extracted At","description":"最近一次完成信息提取的时间"},"extraction":{"$ref":"#/components/schemas/ShotExtractionSummaryRead","description":"镜头提取状态摘要"}},"type":"object","required":["id","chapter_id","index","title","extraction"],"title":"ShotRead"},"ShotRuntimeSummaryRead":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"has_active_tasks":{"type":"boolean","title":"Has Active Tasks","description":"是否存在进行中的关联任务"},"has_active_video_tasks":{"type":"boolean","title":"Has Active Video Tasks","description":"是否存在进行中的视频任务"},"has_active_prompt_tasks":{"type":"boolean","title":"Has Active Prompt Tasks","description":"是否存在进行中的提示词任务"},"has_active_frame_tasks":{"type":"boolean","title":"Has Active Frame Tasks","description":"是否存在进行中的分镜帧图片任务"},"active_task_count":{"type":"integer","title":"Active Task Count","description":"进行中的唯一任务数"}},"type":"object","required":["shot_id","has_active_tasks","has_active_video_tasks","has_active_prompt_tasks","has_active_frame_tasks","active_task_count"],"title":"ShotRuntimeSummaryRead"},"ShotSemanticSuggestion":{"properties":{"camera_shot":{"anyOf":[{"$ref":"#/components/schemas/CameraShotType"},{"type":"null"}],"description":"建议景别"},"angle":{"anyOf":[{"$ref":"#/components/schemas/CameraAngle"},{"type":"null"}],"description":"建议机位"},"movement":{"anyOf":[{"$ref":"#/components/schemas/CameraMovement"},{"type":"null"}],"description":"建议运镜"},"duration":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Duration","description":"建议时长(秒)"},"action_beats":{"items":{"type":"string"},"type":"array","title":"Action Beats","description":"按时间顺序排列的动作拍点"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"不确定项说明"}},"additionalProperties":false,"type":"object","title":"ShotSemanticSuggestion","description":"镜头语义默认建议:用于准备阶段初始化镜头语言与动作拍点。"},"ShotSkipExtractionUpdate":{"properties":{"skip":{"type":"boolean","title":"Skip","description":"是否明确跳过信息提取"}},"type":"object","required":["skip"],"title":"ShotSkipExtractionUpdate"},"ShotStatus":{"type":"string","enum":["pending","generating","ready"],"title":"ShotStatus","description":"镜头生成状态(更多是“生产流程”而非剧情状态)。"},"ShotUpdate":{"properties":{"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id"},"index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Index"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail"},"status":{"anyOf":[{"$ref":"#/components/schemas/ShotStatus"},{"type":"null"}]},"skip_extraction":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Skip Extraction"},"script_excerpt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Script Excerpt"},"generated_video_file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Generated Video File Id"}},"type":"object","title":"ShotUpdate"},"ShotVideoPromptPackRead":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"title":{"type":"string","title":"Title","description":"镜头标题","default":""},"script_excerpt":{"type":"string","title":"Script Excerpt","description":"剧本摘录","default":""},"action_beats":{"items":{"type":"string"},"type":"array","title":"Action Beats","description":"动作/场景要点"},"action_beat_phases":{"items":{"$ref":"#/components/schemas/ActionBeatPhaseRead"},"type":"array","title":"Action Beat Phases","description":"动作拍点的阶段推断结果"},"previous_shot_summary":{"type":"string","title":"Previous Shot Summary","description":"上一镜头摘要,用于提示词连续性约束","default":""},"next_shot_goal":{"type":"string","title":"Next Shot Goal","description":"下一镜头目标,用于提示词连续性约束","default":""},"continuity_guidance":{"type":"string","title":"Continuity Guidance","description":"当前镜头与相邻镜头的承接建议","default":""},"composition_anchor":{"type":"string","title":"Composition Anchor","description":"当前镜头的构图与空间锚点建议","default":""},"screen_direction_guidance":{"type":"string","title":"Screen Direction Guidance","description":"当前镜头的人物朝向、视线与左右轴线建议","default":""},"dialogue_summary":{"type":"string","title":"Dialogue Summary","description":"对白摘要","default":""},"characters":{"items":{"$ref":"#/components/schemas/ShotPromptAssetRef"},"type":"array","title":"Characters","description":"角色引用"},"scene":{"anyOf":[{"$ref":"#/components/schemas/ShotPromptAssetRef"},{"type":"null"}],"description":"场景引用"},"props":{"items":{"$ref":"#/components/schemas/ShotPromptAssetRef"},"type":"array","title":"Props","description":"道具引用"},"costumes":{"items":{"$ref":"#/components/schemas/ShotPromptAssetRef"},"type":"array","title":"Costumes","description":"服装引用"},"camera":{"$ref":"#/components/schemas/ShotPromptCameraInfo","description":"镜头语言"},"atmosphere":{"type":"string","title":"Atmosphere","description":"氛围描述","default":""},"visual_style":{"type":"string","title":"Visual Style","description":"项目视觉风格","default":""},"style":{"type":"string","title":"Style","description":"项目题材/风格","default":""},"negative_prompt":{"type":"string","title":"Negative Prompt","description":"默认负面提示词","default":""}},"type":"object","required":["shot_id"],"title":"ShotVideoPromptPackRead","description":"视频提示词渲染前的标准上下文包。"},"ShotVideoPromptPreviewRead":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"template_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Id","description":"使用的提示词模板 ID"},"template_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Name","description":"使用的提示词模板名称"},"rendered_prompt":{"type":"string","title":"Rendered Prompt","description":"渲染后的提示词"},"pack":{"$ref":"#/components/schemas/ShotVideoPromptPackRead","description":"渲染上下文包"},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","description":"渲染时发现的非阻塞提示"}},"type":"object","required":["shot_id","rendered_prompt","pack"],"title":"ShotVideoPromptPreviewRead","description":"视频提示词预览结果。"},"ShotVideoReadinessCheck":{"properties":{"key":{"type":"string","title":"Key","description":"检查项 key"},"ok":{"type":"boolean","title":"Ok","description":"是否通过"},"message":{"type":"string","title":"Message","description":"面向前端展示的说明"}},"type":"object","required":["key","ok","message"],"title":"ShotVideoReadinessCheck","description":"单项视频生成准备度检查结果。"},"ShotVideoReadinessRead":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"reference_mode":{"type":"string","title":"Reference Mode","description":"参考模式"},"ready":{"type":"boolean","title":"Ready","description":"是否满足当前 reference_mode 下的视频生成条件"},"checks":{"items":{"$ref":"#/components/schemas/ShotVideoReadinessCheck"},"type":"array","title":"Checks","description":"准备度检查项"}},"type":"object","required":["shot_id","reference_mode","ready"],"title":"ShotVideoReadinessRead","description":"镜头视频生成准备度。"},"StudioAssetDraft":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"资产 ID(已落库时回填,如 scene_id / prop_id / costume_id)"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"关联的文件 ID(可空)"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail","description":"缩略图下载地址(可空)"},"name":{"type":"string","title":"Name","description":"名称(同项目内建议唯一)"},"description":{"type":"string","title":"Description","description":"描述","default":""},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"标签"},"prompt_template_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt Template Id","description":"提示词模板 ID(可空)"},"view_count":{"type":"integer","minimum":1.0,"title":"View Count","description":"计划生成视角图数量","default":1}},"additionalProperties":false,"type":"object","required":["name"],"title":"StudioAssetDraft","description":"Studio 资产草稿(Scene/Prop/Costume)。\n\n导入 API 未传 id 时由服务端生成;分镜详情回填时可带 scene_id/prop_id/costume_id。"},"StudioCharacterDraft":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id","description":"角色 ID(已落库时回填 character_id)"},"file_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Id","description":"关联的文件 ID(可空)"},"thumbnail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail","description":"缩略图下载地址(可空)"},"index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Index","description":"镜头内角色排序(shot_character_links.index)"},"name":{"type":"string","title":"Name","description":"角色名称(同项目内建议唯一)"},"description":{"type":"string","title":"Description","description":"角色描述","default":""},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"标签(可选)"},"costume_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Costume Name","description":"服装名称(可选,导入时映射到 costume_id)"},"prop_names":{"items":{"type":"string"},"type":"array","title":"Prop Names","description":"角色常用道具名称列表(可选)"}},"additionalProperties":false,"type":"object","required":["name"],"title":"StudioCharacterDraft","description":"Studio 角色草稿。\n\n导入 API 未传 id 时由服务端生成;分镜详情回填时可带 character_id。"},"StudioImageTaskRequest":{"properties":{"model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id","description":"可选模型 ID(models.id);不传则使用 ModelSettings.default_image_model_id;Provider 由模型关联反查"},"image_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Image Id","description":"图片模型 ID,如 ActorImage.id / SceneImage.id / PropImage.id 等;必须与路径主体 ID 匹配"},"prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt","description":"提示词(由前端传入)。创建任务接口必填;render-prompt 接口可不传"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"参考图 file_id 列表(可多张,顺序有效)。创建任务接口会基于 file_id 从数据中解析为参考图"}},"type":"object","title":"StudioImageTaskRequest","description":"Studio 专用图片任务请求体:可选模型 ID,不传则用默认图片模型;供应商由模型反查。\n\nimage_id 表示具体的图片模型 ID,例如:\n- 演员图片:ActorImage.id\n- 场景图片:SceneImage.id\n- 道具图片:PropImage.id\n- 服装图片:CostumeImage.id\n- 角色图片:CharacterImage.id\n- 分镜帧图片:ShotFrameImage.id"},"StudioScriptExtractionDraft":{"properties":{"project_id":{"type":"string","title":"Project Id","description":"项目 ID(必填)"},"chapter_id":{"type":"string","title":"Chapter Id","description":"章节 ID(必填,用于创建 shots/links)"},"script_text":{"type":"string","title":"Script Text","description":"剧本文本(可为优化后版本)"},"characters":{"items":{"$ref":"#/components/schemas/StudioCharacterDraft"},"type":"array","title":"Characters"},"scenes":{"items":{"$ref":"#/components/schemas/StudioAssetDraft"},"type":"array","title":"Scenes"},"props":{"items":{"$ref":"#/components/schemas/StudioAssetDraft"},"type":"array","title":"Props"},"costumes":{"items":{"$ref":"#/components/schemas/StudioAssetDraft"},"type":"array","title":"Costumes"},"shots":{"items":{"$ref":"#/components/schemas/StudioShotDraft"},"type":"array","title":"Shots","description":"镜头草稿列表"}},"additionalProperties":false,"type":"object","required":["project_id","chapter_id","script_text"],"title":"StudioScriptExtractionDraft","description":"用于导入 Studio 的提取结果草稿(name-based)。"},"StudioShotDraft":{"properties":{"index":{"type":"integer","minimum":1.0,"title":"Index","description":"镜头序号(章节内唯一)"},"title":{"type":"string","title":"Title","description":"镜头标题"},"script_excerpt":{"type":"string","title":"Script Excerpt","description":"剧本摘录","default":""},"scene_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scene Name","description":"场景名称(可选)"},"character_names":{"items":{"type":"string"},"type":"array","title":"Character Names","description":"本镜出现角色名称列表"},"prop_names":{"items":{"type":"string"},"type":"array","title":"Prop Names","description":"本镜关键道具名称列表"},"costume_names":{"items":{"type":"string"},"type":"array","title":"Costume Names","description":"本镜服装名称列表"},"dialogue_lines":{"items":{"$ref":"#/components/schemas/StudioShotDraftDialogueLine"},"type":"array","title":"Dialogue Lines","description":"对白列表"},"actions":{"items":{"type":"string"},"type":"array","title":"Actions","description":"动作/场景描述"},"semantic_suggestion":{"anyOf":[{"$ref":"#/components/schemas/ShotSemanticSuggestion"},{"type":"null"}],"description":"镜头语言默认建议与动作拍点候选"}},"additionalProperties":false,"type":"object","required":["index","title"],"title":"StudioShotDraft","description":"镜头草稿:不含 shot_id,由导入 API 生成;引用实体用 name。"},"StudioShotDraftDialogueLine":{"properties":{"index":{"type":"integer","minimum":0.0,"title":"Index","description":"镜头内排序","default":0},"text":{"type":"string","title":"Text","description":"台词内容"},"line_mode":{"type":"string","enum":["DIALOGUE","VOICE_OVER","OFF_SCREEN","PHONE"],"title":"Line Mode","description":"对白模式","default":"DIALOGUE"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name","description":"说话角色名称(可空)"},"target_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Name","description":"听者角色名称(可空)"}},"additionalProperties":false,"type":"object","required":["text"],"title":"StudioShotDraftDialogueLine","description":"镜头对白草稿:speaker/target 使用角色 name,导入时映射为 character_id。"},"StyleOption":{"properties":{"value":{"type":"string","title":"Value","description":"选项值"},"label":{"type":"string","title":"Label","description":"选项展示文案"}},"type":"object","required":["value","label"],"title":"StyleOption","description":"通用下拉选项。"},"TaskCancelRead":{"properties":{"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/TaskStatus"},"cancel_requested":{"type":"boolean","title":"Cancel Requested","description":"是否已登记取消请求"},"cancel_requested_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cancel Requested At Ts","description":"请求取消时间戳"},"effective_immediately":{"type":"boolean","title":"Effective Immediately","description":"是否已立即取消完成","default":false}},"type":"object","required":["task_id","status","cancel_requested"],"title":"TaskCancelRead"},"TaskCancelRequest":{"properties":{"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"取消原因(可选)"}},"type":"object","title":"TaskCancelRequest"},"TaskCreated":{"properties":{"task_id":{"type":"string","title":"Task Id","description":"任务 ID"}},"type":"object","required":["task_id"],"title":"TaskCreated"},"TaskLinkAdoptRead":{"properties":{"task_id":{"type":"string","title":"Task Id"},"link_type":{"type":"string","title":"Link Type","description":"project | chapter | shot"},"entity_id":{"type":"string","title":"Entity Id","description":"项目/章节/镜头 ID"},"is_adopted":{"type":"boolean","title":"Is Adopted","description":"是否采用(仅可正向变更为 true)"}},"type":"object","required":["task_id","link_type","entity_id","is_adopted"],"title":"TaskLinkAdoptRead","description":"采用状态更新结果。"},"TaskLinkAdoptRequest":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"绑定项目 ID(可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"绑定章节 ID(可选)"},"shot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shot Id","description":"绑定镜头 ID(可选)"},"task_id":{"type":"string","title":"Task Id","description":"任务 ID"}},"type":"object","required":["task_id"],"title":"TaskLinkAdoptRequest","description":"更新采用状态请求:task_id + 三选一绑定对象(project_id/chapter_id/shot_id)。"},"TaskListItemRead":{"properties":{"task_id":{"type":"string","title":"Task Id"},"task_kind":{"type":"string","title":"Task Kind","description":"业务任务类型"},"status":{"$ref":"#/components/schemas/TaskStatus"},"progress":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Progress"},"cancel_requested":{"type":"boolean","title":"Cancel Requested","description":"是否已请求取消","default":false},"cancel_requested_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cancel Requested At Ts","description":"请求取消时间戳"},"started_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Started At Ts","description":"任务开始执行时间戳"},"finished_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Finished At Ts","description":"任务结束时间戳"},"elapsed_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Elapsed Ms","description":"任务累计执行耗时(毫秒)"},"created_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Created At Ts","description":"任务创建时间戳"},"updated_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Updated At Ts","description":"任务更新时间戳"},"executor_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Executor Type","description":"执行器类型,如 celery"},"executor_task_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Executor Task Id","description":"执行器侧任务 ID"},"relation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Type","description":"业务关联类型"},"relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Relation Entity Id","description":"业务关联实体 ID"},"resource_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource Type","description":"资源类型"},"navigate_relation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Navigate Relation Type","description":"前端默认跳转关联类型"},"navigate_relation_entity_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Navigate Relation Entity Id","description":"前端默认跳转关联实体 ID"}},"type":"object","required":["task_id","task_kind","status","progress"],"title":"TaskListItemRead"},"TaskResultRead":{"properties":{"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/TaskStatus"},"progress":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Progress"},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result"},"error":{"type":"string","title":"Error","default":""},"cancel_requested":{"type":"boolean","title":"Cancel Requested","description":"是否已请求取消","default":false},"cancel_requested_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cancel Requested At Ts","description":"请求取消时间戳"},"started_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Started At Ts","description":"任务开始执行时间戳"},"finished_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Finished At Ts","description":"任务结束时间戳"},"elapsed_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Elapsed Ms","description":"任务累计执行耗时(毫秒)"}},"type":"object","required":["task_id","status","progress"],"title":"TaskResultRead"},"TaskStatus":{"type":"string","enum":["pending","running","streaming","succeeded","failed","cancelled"],"title":"TaskStatus","description":"任务状态枚举。"},"TaskStatusRead":{"properties":{"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/TaskStatus"},"progress":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Progress"},"cancel_requested":{"type":"boolean","title":"Cancel Requested","description":"是否已请求取消","default":false},"cancel_requested_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cancel Requested At Ts","description":"请求取消时间戳"},"started_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Started At Ts","description":"任务开始执行时间戳"},"finished_at_ts":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Finished At Ts","description":"任务结束时间戳"},"elapsed_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Elapsed Ms","description":"任务累计执行耗时(毫秒)"}},"type":"object","required":["task_id","status","progress"],"title":"TaskStatusRead"},"VFXType":{"type":"string","enum":["NONE","PARTICLES","VOLUMETRIC_FOG","CG_DOUBLE","DIGITAL_ENVIRONMENT","MATTE_PAINTING","FIRE_SMOKE","WATER_SIM","DESTRUCTION","ENERGY_MAGIC","COMPOSITING_CLEANUP","SLOW_MOTION_TIME","OTHER"],"title":"VFXType","description":"视效类型(与 `app.schemas.skills.common.VFXType` 对齐,存英文 code)。"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VariantAnalysisRequest":{"properties":{"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id","description":"项目 ID(异步任务关联可选)"},"chapter_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Chapter Id","description":"章节 ID(异步任务关联可选)"},"merged_library":{"additionalProperties":true,"type":"object","title":"Merged Library","description":"合并后的实体库(EntityLibrary 的序列化形式;来自 EntityMerger 输出的 merged_library)"},"all_shot_extractions":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"All Shot Extractions","description":"所有镜头提取结果"},"script_division":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Script Division","description":"脚本分镜结果(可选;ScriptDivisionResult 序列化),用于章节/段落分组"}},"type":"object","required":["merged_library","all_shot_extractions"],"title":"VariantAnalysisRequest","description":"变体分析请求。"},"VariantAnalysisResult":{"properties":{"costume_timelines":{"items":{"$ref":"#/components/schemas/CostumeTimeline"},"type":"array","title":"Costume Timelines","description":"各角色服装演变时间线"},"variant_suggestions":{"items":{"$ref":"#/components/schemas/VariantSuggestion"},"type":"array","title":"Variant Suggestions","description":"变体建议列表"},"chapter_variants":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object","title":"Chapter Variants","description":"章节变体建议"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"分析说明"}},"additionalProperties":false,"type":"object","title":"VariantAnalysisResult","description":"变体分析结果。"},"VariantSuggestion":{"properties":{"entity_id":{"type":"string","title":"Entity Id","description":"实体ID"},"entity_name":{"type":"string","title":"Entity Name","description":"实体名称"},"entity_type":{"type":"string","title":"Entity Type","description":"实体类型(character/scene/prop/location)"},"suggestion":{"type":"string","title":"Suggestion","description":"变体建议说明"},"affected_shots":{"items":{"type":"integer"},"type":"array","title":"Affected Shots","description":"涉及的镜头"},"evidence":{"items":{"$ref":"#/components/schemas/EvidenceSpan"},"type":"array","title":"Evidence","description":"原文依据(可选)"}},"additionalProperties":false,"type":"object","required":["entity_id","entity_name","entity_type","suggestion"],"title":"VariantSuggestion","description":"变体建议。"},"VideoGenerationOptionsRead":{"properties":{"provider":{"type":"string","title":"Provider","description":"供应商稳定键"},"model_id":{"type":"string","title":"Model Id","description":"默认视频模型 ID"},"model_name":{"type":"string","title":"Model Name","description":"默认视频模型名称"},"allowed_ratios":{"items":{"type":"string"},"type":"array","title":"Allowed Ratios","description":"当前模型允许的比例选项"},"default_ratio":{"type":"string","title":"Default Ratio","description":"当前模型默认比例"}},"type":"object","required":["provider","model_id","model_name","default_ratio"],"title":"VideoGenerationOptionsRead","description":"当前默认视频模型对应的生成参数选项。"},"VideoGenerationTaskRequest":{"properties":{"shot_id":{"type":"string","title":"Shot Id","description":"镜头 ID"},"reference_mode":{"type":"string","enum":["first","last","key","first_last","first_last_key","text_only"],"title":"Reference Mode","description":"参考模式:first | last | key | first_last | first_last_key | text_only"},"prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt","description":"视频提示词(text_only 必填)"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"参考图 file_id 列表,数量需与 reference_mode 严格匹配"},"ratio":{"type":"string","enum":["16:9","4:3","1:1","3:4","9:16","21:9"],"title":"Ratio","description":"视频画幅比例,如 16:9 / 9:16"}},"type":"object","required":["shot_id","reference_mode","ratio"],"title":"VideoGenerationTaskRequest","description":"视频生成任务请求。"},"VideoPromptPreviewResponse":{"properties":{"prompt":{"type":"string","title":"Prompt","description":"最终用于视频生成的提示词"},"images":{"items":{"type":"string"},"type":"array","title":"Images","description":"关联参考图 file_id 列表"},"pack":{"anyOf":[{"$ref":"#/components/schemas/ShotVideoPromptPackRead"},{"type":"null"}],"description":"视频提示词预览上下文包"}},"type":"object","required":["prompt"],"title":"VideoPromptPreviewResponse"}}}} \ No newline at end of file diff --git a/front/src/pages/aiStudio/chapter/ChapterStudio.tsx b/front/src/pages/aiStudio/chapter/ChapterStudio.tsx index 60c3728..ef33ac6 100644 --- a/front/src/pages/aiStudio/chapter/ChapterStudio.tsx +++ b/front/src/pages/aiStudio/chapter/ChapterStudio.tsx @@ -97,6 +97,7 @@ import type { ShotRuntimeSummaryRead, ProjectSceneLinkRead, ShotStatus, + ShotVideoPromptPackRead, } from '../../../services/generated' import { listTaskLinksNormalized } from '../../../services/filmTaskLinks' import { buildFileDownloadUrl, resolveAssetUrl } from '../assets/utils' @@ -129,6 +130,10 @@ type ShotFramePromptQualityChecks = { type FramePromptDerived = { basePrompt: string renderedPrompt: string + selectedGuidance: string[] + droppedGuidance: string[] + selectedGuidanceDetails: Array<{ text: string; category: string; reasonTag: string; reason: string }> + droppedGuidanceDetails: Array<{ text: string; category: string; reasonTag: string; reason: string }> images: string[] mappings: ShotFramePromptMappingRead[] } @@ -136,6 +141,7 @@ type VideoReferenceMode = 'first' | 'last' | 'key' | 'first_last' | 'first_last_ type VideoPromptDerived = { prompt: string images: string[] + pack: ShotVideoPromptPackRead | null } function normalizeFrameExclusiveTags(tags: string[]): string[] { @@ -159,6 +165,77 @@ function readDebugContextText( return typeof value === 'string' ? value.trim() : '' } +function buildKeyframeGuidanceSummary(items: string[]): string[] { + const result: string[] = [] + const seen = new Set() + items + .flatMap((item) => item.split(';')) + .map((item) => item.trim()) + .filter(Boolean) + .forEach((item) => { + if (seen.has(item)) return + seen.add(item) + result.push(item) + }) + return result +} + +function stripDirectiveLevelPrefix(item: string): string { + const text = String(item || '').trim() + if (text.startsWith('必须:')) return text.slice(3).trim() + if (text.startsWith('优先:')) return text.slice(3).trim() + return text +} + +function parseDirectorCommandSummary(summary: string): Array<{ + level: 'must' | 'prefer' + text: string +}> { + return String(summary || '') + .split(';') + .map((item) => item.trim()) + .filter(Boolean) + .map((item) => { + if (item.startsWith('必须:')) { + return { level: 'must' as const, text: item.slice(3).trim() } + } + if (item.startsWith('优先:')) { + return { level: 'prefer' as const, text: item.slice(3).trim() } + } + return { level: 'prefer' as const, text: item } + }) +} + +function buildGuidanceLevelSummary( + parsedDirectorCommands: Array<{ level: 'must' | 'prefer'; text: string }>, + guidanceSummary: string[], +): { must: number; prefer: number; normal: number } { + const must = parsedDirectorCommands.filter((item) => item.level === 'must').length + const prefer = parsedDirectorCommands.filter((item) => item.level === 'prefer').length + const parsedTexts = new Set(parsedDirectorCommands.map((item) => item.text.trim()).filter(Boolean)) + const normal = guidanceSummary + .map((item) => stripDirectiveLevelPrefix(item)) + .filter((item) => item && !parsedTexts.has(item)).length + return { must, prefer, normal } +} + +function buildActionBeatPhaseTags(summary: string): Array<{ text: string; phaseLabel: string }> { + return String(summary || '') + .split(';') + .map((item) => item.trim()) + .filter(Boolean) + .map((item) => { + const matched = item.match(/^\d+\.\s*(触发|峰值|收束)\s*·\s*(.+)$/) + if (!matched) { + return { phaseLabel: '阶段', text: item } + } + return { + phaseLabel: matched[1], + text: matched[2].trim(), + } + }) +} + type InspectorMode = 'push' | 'overlay' type ShotFilter = 'all' | 'pendingConfirm' | 'generating' | 'ready' | 'hidden' | 'problem' @@ -2951,10 +3028,13 @@ function Inspector(props: { const [keyframePromptPreviewFrameType, setKeyframePromptPreviewFrameType] = useState('key') const [keyframePromptDebugContext, setKeyframePromptDebugContext] = useState(null) const [keyframePromptDebugCollapsed, setKeyframePromptDebugCollapsed] = useState(true) + const [keyframeDirectiveCollapsed, setKeyframeDirectiveCollapsed] = useState(true) + const [keyframePromptDecisionCollapsed, setKeyframePromptDecisionCollapsed] = useState(true) const [keyframePromptQualityChecks, setKeyframePromptQualityChecks] = useState(null) const [videoPromptPreviewOpen, setVideoPromptPreviewOpen] = useState(false) const [videoPromptPreviewLoading, setVideoPromptPreviewLoading] = useState(false) const [videoPromptPreviewSubmitting, setVideoPromptPreviewSubmitting] = useState(false) + const [videoPromptContextCollapsed, setVideoPromptContextCollapsed] = useState(true) const resolveVideoRatioForRequest = useCallback(() => { const shotRatio = String(shotDetail?.override_video_ratio ?? '').trim() const projectRatio = String(projectDefaultVideoRatio ?? '').trim() @@ -2992,10 +3072,11 @@ function Inspector(props: { ratio, } as any, }) - const data = res.data as any + const data = (res as any)?.data ?? null return { prompt: typeof data?.prompt === 'string' ? data.prompt : '', images: Array.isArray(data?.images) ? (data.images as string[]).filter(Boolean) : [], + pack: data?.pack ?? null, } }, submit: async ({ derived, context }) => { @@ -3023,6 +3104,21 @@ function Inspector(props: { const videoPromptPreviewDraft = videoPromptDraft.base.prompt const videoPromptPreviewImages = videoPromptDraft.context.images const videoReferenceMode = videoPromptDraft.context.referenceMode + const videoPromptPreviewPack = videoPromptDraft.derived?.pack ?? null + const videoActionBeatPhases = videoPromptPreviewPack?.action_beat_phases ?? [] + const videoActionBeats = videoActionBeatPhases.length > 0 + ? videoActionBeatPhases.map((item) => ({ + text: item.text, + phase: item.phase, + })) + : (videoPromptPreviewPack?.action_beats ?? []).map((text) => ({ + text, + phase: null, + })) + const videoVisibleActionBeats = videoPromptContextCollapsed + ? videoActionBeats.slice(0, 2) + : videoActionBeats + const hiddenVideoActionBeatCount = Math.max(0, videoActionBeats.length - videoVisibleActionBeats.length) const [videoTaskPolling, setVideoTaskPolling] = useState(false) const [videoTaskStatus, setVideoTaskStatus] = useState(null) const [videoTaskId, setVideoTaskId] = useState(null) @@ -3639,6 +3735,10 @@ function Inspector(props: { return { basePrompt: '', renderedPrompt: '', + selectedGuidance: [], + droppedGuidance: [], + selectedGuidanceDetails: [], + droppedGuidanceDetails: [], images: [], mappings: [], } @@ -3672,6 +3772,32 @@ function Inspector(props: { return { basePrompt: typeof d?.base_prompt === 'string' ? d.base_prompt : basePrompt, renderedPrompt: typeof d?.rendered_prompt === 'string' ? d.rendered_prompt : '', + selectedGuidance: Array.isArray(d?.selected_guidance) + ? d.selected_guidance.map((item: unknown) => String(item ?? '').trim()).filter(Boolean) + : [], + droppedGuidance: Array.isArray(d?.dropped_guidance) + ? d.dropped_guidance.map((item: unknown) => String(item ?? '').trim()).filter(Boolean) + : [], + selectedGuidanceDetails: Array.isArray(d?.selected_guidance_details) + ? d.selected_guidance_details + .map((item: any) => ({ + text: String(item?.text ?? '').trim(), + category: String(item?.category ?? '').trim(), + reasonTag: String(item?.reason_tag ?? '').trim(), + reason: String(item?.reason ?? '').trim(), + })) + .filter((item: { text: string }) => item.text) + : [], + droppedGuidanceDetails: Array.isArray(d?.dropped_guidance_details) + ? d.dropped_guidance_details + .map((item: any) => ({ + text: String(item?.text ?? '').trim(), + category: String(item?.category ?? '').trim(), + reasonTag: String(item?.reason_tag ?? '').trim(), + reason: String(item?.reason ?? '').trim(), + })) + .filter((item: { text: string }) => item.text) + : [], images: Array.isArray(d?.images) ? (d.images as string[]).filter(Boolean) : [], mappings: Array.isArray(d?.mappings) ? (d.mappings as ShotFramePromptMappingRead[]) : [], } @@ -3734,6 +3860,16 @@ function Inspector(props: { }) const keyframePromptPreviewDraft = keyframePromptDraft.base.prompt const keyframePromptRenderedDraft = keyframePromptDraft.derived?.renderedPrompt ?? '' + const keyframePromptSelectedGuidance = keyframePromptDraft.derived?.selectedGuidance ?? [] + const keyframePromptDroppedGuidance = keyframePromptDraft.derived?.droppedGuidance ?? [] + const keyframePromptSelectedGuidanceDetails = keyframePromptDraft.derived?.selectedGuidanceDetails ?? [] + const keyframePromptDroppedGuidanceDetails = keyframePromptDraft.derived?.droppedGuidanceDetails ?? [] + const keyframePromptVisibleSelectedGuidanceDetails = keyframePromptDecisionCollapsed + ? keyframePromptSelectedGuidanceDetails.slice(0, 2) + : keyframePromptSelectedGuidanceDetails + const keyframePromptVisibleDroppedGuidanceDetails = keyframePromptDecisionCollapsed + ? keyframePromptDroppedGuidanceDetails.slice(0, 1) + : keyframePromptDroppedGuidanceDetails const keyframePromptRenderMappings = keyframePromptDraft.derived?.mappings ?? [] const keyframePromptPreviewRefFileIds = keyframePromptDraft.context.refFileIds const keyframePromptRenderState = keyframePromptDraft.state @@ -4120,6 +4256,7 @@ function Inspector(props: { base: { prompt: '' }, context: nextContext, }) + setVideoPromptContextCollapsed(true) setVideoPromptPreviewOpen(true) setVideoPromptPreviewLoading(true) try { @@ -4291,6 +4428,8 @@ function Inspector(props: { setKeyframePromptPreviewOpen(true) setKeyframePromptPreviewFrameType(frameType) setKeyframePromptDebugCollapsed(true) + setKeyframeDirectiveCollapsed(true) + setKeyframePromptDecisionCollapsed(true) const basePrompt = getPromptFromDetailByType(frameType) keyframePromptDraft.hydrate({ base: { frameType, prompt: basePrompt }, @@ -5496,6 +5635,30 @@ function Inspector(props: { const debugCostumeContext = readDebugContextText(keyframePromptDebugContext, 'costume_context') const debugShotDescription = readDebugContextText(keyframePromptDebugContext, 'shot_description') const debugDialogSummary = readDebugContextText(keyframePromptDebugContext, 'dialog_summary') + const debugPreviousShotTitle = readDebugContextText(keyframePromptDebugContext, 'previous_shot_title') + const debugPreviousShotScriptExcerpt = readDebugContextText(keyframePromptDebugContext, 'previous_shot_script_excerpt') + const debugPreviousShotEndState = readDebugContextText(keyframePromptDebugContext, 'previous_shot_end_state') + const debugNextShotTitle = readDebugContextText(keyframePromptDebugContext, 'next_shot_title') + const debugNextShotScriptExcerpt = readDebugContextText(keyframePromptDebugContext, 'next_shot_script_excerpt') + const debugNextShotStartGoal = readDebugContextText(keyframePromptDebugContext, 'next_shot_start_goal') + const debugContinuityGuidance = readDebugContextText(keyframePromptDebugContext, 'continuity_guidance') + const debugCompositionAnchor = readDebugContextText(keyframePromptDebugContext, 'composition_anchor') + const debugScreenDirectionGuidance = readDebugContextText(keyframePromptDebugContext, 'screen_direction_guidance') + const debugFrameSpecificGuidance = readDebugContextText(keyframePromptDebugContext, 'frame_specific_guidance') + const debugDirectorCommandSummary = readDebugContextText(keyframePromptDebugContext, 'director_command_summary') + const debugActionBeatPhases = readDebugContextText(keyframePromptDebugContext, 'action_beat_phases') + const debugSelectedActionBeatPhase = readDebugContextText(keyframePromptDebugContext, 'selected_action_beat_phase') + const debugSelectedActionBeatText = readDebugContextText(keyframePromptDebugContext, 'selected_action_beat_text') + const actionBeatPhaseTags = buildActionBeatPhaseTags(debugActionBeatPhases) + const parsedDirectorCommandSummary = parseDirectorCommandSummary(debugDirectorCommandSummary) + const keyframeGuidanceSummary = buildKeyframeGuidanceSummary([ + debugDirectorCommandSummary, + debugFrameSpecificGuidance, + debugContinuityGuidance, + debugCompositionAnchor, + debugScreenDirectionGuidance, + ]) + const guidanceLevelSummary = buildGuidanceLevelSummary(parsedDirectorCommandSummary, keyframeGuidanceSummary) const debugUnifyStyle = typeof keyframePromptDebugContext?.unify_style === 'boolean' ? (keyframePromptDebugContext.unify_style ? '是' : '否') @@ -5509,6 +5672,19 @@ function Inspector(props: { debugCostumeContext || debugShotDescription || debugDialogSummary || + debugPreviousShotTitle || + debugPreviousShotScriptExcerpt || + debugPreviousShotEndState || + debugNextShotTitle || + debugNextShotScriptExcerpt || + debugNextShotStartGoal || + debugContinuityGuidance || + debugCompositionAnchor || + debugScreenDirectionGuidance || + debugFrameSpecificGuidance || + debugDirectorCommandSummary || + debugActionBeatPhases || + debugSelectedActionBeatText || debugUnifyStyle, ) const hasPromptQualityChecks = keyframePromptQualityChecks !== null @@ -5636,6 +5812,116 @@ function Inspector(props: { placeholder="请输入基础提示词,例如人物动作、场景氛围、镜头视角等…" disabled={keyframePromptActionLoading || shotRenderPromptLoading} /> + {keyframeGuidanceSummary.length > 0 || debugDirectorCommandSummary ? ( +
+
+
+
基础提示词生成依据
+
+ 这些导演约束主要用于生成上游基础提示词,默认先看摘要;只有少量高优先级规则会再进入最终图片提示词。 +
+
+ +
+
+ {`必须 ${guidanceLevelSummary.must}`} + {`优先 ${guidanceLevelSummary.prefer}`} + {`普通 ${guidanceLevelSummary.normal}`} + {actionBeatPhaseTags.length > 0 ? ( + {`动作阶段 ${actionBeatPhaseTags.length}`} + ) : null} +
+
+ {(keyframeDirectiveCollapsed + ? ( + parsedDirectorCommandSummary.length > 0 + ? parsedDirectorCommandSummary + .slice(0, 2) + .map((item) => `${item.level === 'must' ? '必须' : '优先'} · ${item.text}`) + : keyframeGuidanceSummary.slice(0, 2) + ) + : keyframeGuidanceSummary + ).map((item) => ( + + + {item} + + + ))} +
+ {actionBeatPhaseTags.length > 0 ? ( +
+
+
当前帧消费的动作阶段
+ {debugSelectedActionBeatPhase && debugSelectedActionBeatText ? ( + + {`${debugSelectedActionBeatPhase} · ${debugSelectedActionBeatText}`} + + ) : null} +
+
+ {actionBeatPhaseTags.map((item, index) => ( + + + + {item.phaseLabel} · {item.text} + + + + ))} +
+
+ ) : null} + {!keyframeDirectiveCollapsed ? ( +
+ {debugDirectorCommandSummary ? ( +
+
高优先级导演指令
+
+ {parsedDirectorCommandSummary.map((item, index) => ( + + + + {item.level === 'must' ? '必须' : '优先'} · {item.text} + + + + ))} +
+
+ ) : null} + {keyframeGuidanceSummary.length > 0 ? ( +
+
补充 Guidance
+
+ {keyframeGuidanceSummary.map((item) => ( + + + {item} + + + ))} +
+
+ ) : null} +
+ ) : null} +
+ ) : null} {hasPromptDebugContext ? (
@@ -5647,13 +5933,13 @@ function Inspector(props: { type="text" onClick={() => setKeyframePromptDebugCollapsed((prev) => !prev)} > - {keyframePromptDebugCollapsed ? '展开' : '收起'} + {keyframePromptDebugCollapsed ? '展开细节' : '收起细节'}
{keyframePromptDebugCollapsed ? (
- 调试信息默认收起,展开后可查看最近一次 AI 生成使用的项目风格、镜头描述与实体上下文。 + 调试信息默认收起,展开后可查看最近一次 AI 生成使用的项目风格、镜头描述、连续性约束与实体上下文。
) : (
@@ -5679,6 +5965,84 @@ function Inspector(props: {
{debugDialogSummary}
) : null} + {debugActionBeatPhases ? ( +
+
动作拍点阶段
+
+ {actionBeatPhaseTags.map((item, index) => ( + + {`${item.phaseLabel} · ${item.text}`} + + ))} +
+ {debugSelectedActionBeatPhase || debugSelectedActionBeatText ? ( +
+ {`当前帧优先消费:${[debugSelectedActionBeatPhase, debugSelectedActionBeatText].filter(Boolean).join(' · ')}`} +
+ ) : null} +
+ ) : null} + {debugPreviousShotTitle || debugPreviousShotScriptExcerpt || debugPreviousShotEndState ? ( +
+
上一镜头承接
+
+ {debugPreviousShotTitle ?
标题:{debugPreviousShotTitle}
: null} + {debugPreviousShotScriptExcerpt ? ( +
摘录:{debugPreviousShotScriptExcerpt}
+ ) : null} + {debugPreviousShotEndState ? ( +
结尾状态:{debugPreviousShotEndState}
+ ) : null} +
+
+ ) : null} + {debugNextShotTitle || debugNextShotScriptExcerpt || debugNextShotStartGoal ? ( +
+
下一镜头衔接
+
+ {debugNextShotTitle ?
标题:{debugNextShotTitle}
: null} + {debugNextShotScriptExcerpt ? ( +
摘录:{debugNextShotScriptExcerpt}
+ ) : null} + {debugNextShotStartGoal ? ( +
起始目标:{debugNextShotStartGoal}
+ ) : null} +
+
+ ) : null} + {debugContinuityGuidance ? ( +
+
连续性建议
+
{debugContinuityGuidance}
+
+ ) : null} + {debugCompositionAnchor ? ( +
+
构图与空间锚点
+
{debugCompositionAnchor}
+
+ ) : null} + {debugScreenDirectionGuidance ? ( +
+
朝向与视线建议
+
{debugScreenDirectionGuidance}
+
+ ) : null} + {debugFrameSpecificGuidance ? ( +
+
当前帧专项建议
+
{debugFrameSpecificGuidance}
+
+ ) : null} {debugCharacterContext ? (
角色上下文
@@ -5778,6 +6142,100 @@ function Inspector(props: { ))}
) : null} + {keyframePromptSelectedGuidance.length > 0 || keyframePromptDroppedGuidance.length > 0 ? ( +
+
+
+
最终图片提示词收敛结果
+
+ 系统会从上游导演约束里挑出最关键的少量规则,补进最终图片提示词。 +
+
+ + {`保留 ${keyframePromptSelectedGuidance.length}`} + {`压缩 ${keyframePromptDroppedGuidance.length}`} + {(keyframePromptSelectedGuidance.length > 2 || keyframePromptDroppedGuidance.length > 0) ? ( + + ) : null} + +
+
+
+
实际保留的 Guidance
+ {keyframePromptSelectedGuidance.length > 0 ? ( +
+ {keyframePromptVisibleSelectedGuidanceDetails.map((item) => ( + + {item.reasonTag ? ( + + {item.reasonTag} + + ) : null} +
{item.text}
+ {item.reason ?
{item.reason}
: null} +
+ )} + > + + {item.text} + + + ))} + {keyframePromptDecisionCollapsed && keyframePromptSelectedGuidanceDetails.length > 2 ? ( + {`+${keyframePromptSelectedGuidanceDetails.length - 2} 条`} + ) : null} +
+ ) : ( +
当前没有额外 guidance 被保留。
+ )} +
+
+
已压缩的 Guidance
+ {keyframePromptDroppedGuidance.length > 0 ? ( + keyframePromptDecisionCollapsed ? ( +
+ 当前有 {keyframePromptDroppedGuidance.length} 条 guidance 被压缩,展开后可查看具体取舍原因。 +
+ ) : ( +
+ {keyframePromptVisibleDroppedGuidanceDetails.map((item) => ( + + {item.reasonTag ? ( + + {item.reasonTag} + + ) : null} +
{item.text}
+ {item.reason ?
{item.reason}
: null} +
+ )} + > + + {item.text} + + + ))} +
+ ) + ) : ( +
当前没有 guidance 被压缩。
+ )} +
+
+ + ) : null} {hasBasePrompt ? (
{keyframePromptRenderedDraft || '系统正在根据当前内容准备最终提示词…'} @@ -5821,6 +6279,102 @@ function Inspector(props: {
) : (
+
+
+
+
镜头连续性上下文
+
+ 这些上下文会参与视频模板渲染和最终提示词补强,默认先展示摘要,需要时再展开细节。 +
+
+ +
+
+ {`动作节拍 ${videoActionBeats.length}`} + {videoPromptPreviewPack?.previous_shot_summary ? ( + 上一镜头 + ) : null} + {videoPromptPreviewPack?.next_shot_goal ? ( + 下一镜头 + ) : null} + {videoPromptPreviewPack?.continuity_guidance ? ( + 连续性 + ) : null} +
+
+
+
动作节拍
+ {videoVisibleActionBeats.length > 0 ? ( +
+ {videoVisibleActionBeats.map((item, index) => ( + + {item.phase + ? `${item.phase === 'trigger' ? '触发' : item.phase === 'peak' ? '峰值' : '收束'} · ${item.text}` + : item.text} + + ))} + {videoPromptContextCollapsed && hiddenVideoActionBeatCount > 0 ? ( + {`+${hiddenVideoActionBeatCount}`} + ) : null} +
+ ) : ( +
暂无动作节拍
+ )} +
+ {!videoPromptContextCollapsed ? ( + <> +
+
上一镜头摘要
+
+ {videoPromptPreviewPack?.previous_shot_summary || '无'} +
+
+
+
下一镜头目标
+
+ {videoPromptPreviewPack?.next_shot_goal || '无'} +
+
+
+
连续性建议
+
+ {videoPromptPreviewPack?.continuity_guidance || '无'} +
+
+
+
构图与空间锚点
+
+ {videoPromptPreviewPack?.composition_anchor || '无'} +
+
+
+
朝向与视线建议
+
+ {videoPromptPreviewPack?.screen_direction_guidance || '无'} +
+
+ + ) : null} +
+
关联图片(参考图)
{videoPromptPreviewImages.length === 0 ? ( diff --git a/front/src/pages/aiStudio/shots/ChapterShotEditPage.tsx b/front/src/pages/aiStudio/shots/ChapterShotEditPage.tsx index 090f812..85a5752 100644 --- a/front/src/pages/aiStudio/shots/ChapterShotEditPage.tsx +++ b/front/src/pages/aiStudio/shots/ChapterShotEditPage.tsx @@ -5,6 +5,7 @@ import type { EntityNameExistenceItem, ShotAssetOverviewItem, ShotAssetsOverviewRead, + ShotDetailRead, ShotDialogLineRead, ShotDialogLineUpdate, ShotExtractionSummaryRead, @@ -17,6 +18,7 @@ import { StudioChaptersService, StudioEntitiesService, StudioProjectsService, + StudioShotDetailsService, StudioShotDialogLinesService, StudioShotsService, } from '../../../services/generated' @@ -195,7 +197,9 @@ export function ChapterShotEditPage() { const [scriptExcerpt, setScriptExcerpt] = useState('') const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) + const [semanticSaving, setSemanticSaving] = useState(false) const [preparationState, setPreparationState] = useState(null) + const [shotDetail, setShotDetail] = useState(null) const [shotAssetsOverview, setShotAssetsOverview] = useState(null) const preparationStateRequestSeqRef = useRef(0) const [extractingAssets, setExtractingAssets] = useState(false) @@ -328,7 +332,7 @@ export function ChapterShotEditPage() { setLoading(true) setDialogLoading(true) try { - const [projectRes, chRes, listRes, preparationRes] = await Promise.all([ + const [projectRes, chRes, listRes, preparationRes, detailRes] = await Promise.all([ StudioProjectsService.getProjectApiV1StudioProjectsProjectIdGet({ projectId }), StudioChaptersService.getChapterApiV1StudioChaptersChapterIdGet({ chapterId }), StudioShotsService.listShotsApiV1StudioShotsGet({ @@ -339,6 +343,7 @@ export function ChapterShotEditPage() { isDesc: false, }), StudioShotsService.getShotPreparationStateApiApiV1StudioShotsShotIdPreparationStateGet({ shotId }), + StudioShotDetailsService.getShotDetailApiV1StudioShotDetailsShotIdGet({ shotId }), ]) const nextVisualStyle = projectRes.data?.visual_style const nextStyle = projectRes.data?.style @@ -355,6 +360,7 @@ export function ChapterShotEditPage() { const items = listRes.data?.items ?? [] const preparationState = preparationRes.data ?? null + const detail = detailRes.data ?? null const s = preparationState?.shot ?? null if (!s) { @@ -369,6 +375,7 @@ export function ChapterShotEditPage() { } setPreparationState(preparationState) + setShotDetail(detail) setShot(s) setTitle(s.title ?? '') setScriptExcerpt(s.script_excerpt ?? '') @@ -719,26 +726,63 @@ export function ChapterShotEditPage() { return } setSaving(true) + setSemanticSaving(true) try { - const res = await StudioShotsService.updateShotApiV1StudioShotsShotIdPatch({ - shotId: shot.id, - requestBody: { - title: title.trim(), - script_excerpt: scriptExcerpt.trim() ? scriptExcerpt.trim() : null, - }, - }) - const next = res.data + const [shotRes, detailRes] = await Promise.all([ + StudioShotsService.updateShotApiV1StudioShotsShotIdPatch({ + shotId: shot.id, + requestBody: { + title: title.trim(), + script_excerpt: scriptExcerpt.trim() ? scriptExcerpt.trim() : null, + }, + }), + shotDetail + ? StudioShotDetailsService.updateShotDetailApiV1StudioShotDetailsShotIdPatch({ + shotId: shot.id, + requestBody: { + camera_shot: shotDetail.camera_shot, + angle: shotDetail.angle, + movement: shotDetail.movement, + duration: shotDetail.duration ?? 4, + action_beats: shotDetail.action_beats ?? [], + }, + }) + : Promise.resolve({ data: null } as any), + ]) + + const next = shotRes.data + const nextDetail = detailRes.data ?? null + if (nextDetail) { + setShotDetail(nextDetail) + } if (next) { setShot(next) setShots((prev) => prev.map((x) => (x.id === next.id ? next : x))) - message.success('已保存') + message.success('已保存基础信息与镜头语言') } } catch { message.error('保存失败') } finally { setSaving(false) + setSemanticSaving(false) } - }, [scriptExcerpt, shot, title]) + }, [scriptExcerpt, shot, shotDetail, title]) + + const updateShotSemantic = useCallback((patch: { + camera_shot?: ShotDetailRead['camera_shot'] + angle?: ShotDetailRead['angle'] + movement?: ShotDetailRead['movement'] + duration?: number + action_beats?: Array + }) => { + setShotDetail((prev) => { + if (!prev) return prev + return { + ...prev, + ...patch, + } + }) + }, []) const updateSkipExtraction = useCallback( async (skip: boolean) => { @@ -1146,16 +1190,21 @@ export function ChapterShotEditPage() { return } - const hasTitleAndExcerpt = !!title.trim() && !!scriptExcerpt.trim() + const hasTitleAndExcerpt = preparationState?.basic_info_ready ?? (!!title.trim() && !!scriptExcerpt.trim()) + const hasSemanticDefaults = preparationState?.semantic_defaults_ready + ?? (!!shotDetail?.camera_shot && !!shotDetail?.angle && !!shotDetail?.movement && (shotDetail?.duration ?? 0) > 0) + const actionBeatsCount = preparationState?.action_beats_count + ?? (shotDetail?.action_beats ?? []).filter((item) => item.trim().length > 0).length + const actionBeatsReady = preparationState?.action_beats_ready ?? (actionBeatsCount > 0) const linkedAssetCount = shotAssetsOverview?.summary.linked_count ?? 0 const pendingAssetCount = shotAssetsOverview?.summary.pending_count ?? 0 const pendingConfirmCount = preparationState?.pending_confirm_count ?? (pendingAssetCount + extractedDialogLines.length) const assetsReady = !!shotAssetsOverview && pendingAssetCount === 0 const dialogsReady = extractedDialogLines.length === 0 const statusReady = preparationState?.ready_for_generation ?? (shot?.status === 'ready') - const basicInfoReady = hasTitleAndExcerpt + const basicInfoReady = hasTitleAndExcerpt && hasSemanticDefaults const confirmReady = pendingConfirmCount === 0 - const currentShotActionable = shot ? isActionablePreparationShot(shot) || !basicInfoReady : false + const currentShotActionable = shot ? isActionablePreparationShot(shot) || !basicInfoReady || !actionBeatsReady : false const extractionSummary = getShotExtractionSummary(shot) const extractionStateMeta = getExtractionStateMeta(shot, pendingConfirmCount) const goToStudio = () => navigate(getChapterStudioPath(projectId, chapterId), { @@ -1164,14 +1213,24 @@ export function ChapterShotEditPage() { const nextStepTitle = statusReady ? '下一步:进入分镜工作室继续生成' : '下一步:先完成镜头准备,再进入工作室' const nextStepDescription = statusReady ? '当前镜头的信息提取确认已经完成,接下来更适合去分镜工作室继续关键帧、参考图、视频提示词和视频生成。' - : '当前镜头仍有提取候选或对白待确认。先在这里完成准备,准备完成后再进入分镜工作室继续生成。' + : actionBeatsReady + ? '当前镜头仍有提取候选、对白或镜头基础信息待确认。先在这里完成准备,准备完成后再进入分镜工作室继续生成。' + : '当前镜头的动作拍点还没有确认。建议先补齐动作序列,再进入工作室继续关键帧和视频生成。' const checklistItems = [ { key: 'script', - label: '标题与摘录', - tone: hasTitleAndExcerpt ? 'success' : 'warning', - text: hasTitleAndExcerpt ? '已保存基础信息' : '请先补标题和剧本摘录', + label: '标题、摘录与镜头语言', + tone: basicInfoReady ? 'success' : 'warning', + text: basicInfoReady ? '已确认基础信息与镜头语言' : '请先补齐标题、剧本摘录和镜头语言', + }, + { + key: 'action_beats', + label: '动作拍点', + tone: actionBeatsReady ? 'success' : 'warning', + text: actionBeatsReady + ? `已确认 ${actionBeatsCount} 条动作拍点` + : '请先确认当前镜头的动作变化序列', }, { key: 'assets', @@ -1266,8 +1325,18 @@ export function ChapterShotEditPage() { title={title} scriptExcerpt={scriptExcerpt} saving={saving} + semanticSaving={semanticSaving} + semantic={{ + camera_shot: shotDetail?.camera_shot ?? undefined, + angle: shotDetail?.angle ?? undefined, + movement: shotDetail?.movement ?? undefined, + duration: shotDetail?.duration ?? 4, + action_beats: shotDetail?.action_beats ?? [], + }} + actionBeatPhases={preparationState?.action_beat_phases ?? []} onTitleChange={setTitle} onScriptExcerptChange={setScriptExcerpt} + onSemanticChange={updateShotSemantic} onSave={() => void saveShot()} /> ), diff --git a/front/src/pages/aiStudio/shots/components/ChapterShotBasicInfoSection.tsx b/front/src/pages/aiStudio/shots/components/ChapterShotBasicInfoSection.tsx index f90261a..3969a53 100644 --- a/front/src/pages/aiStudio/shots/components/ChapterShotBasicInfoSection.tsx +++ b/front/src/pages/aiStudio/shots/components/ChapterShotBasicInfoSection.tsx @@ -1,12 +1,58 @@ -import { Button, Input } from 'antd' +import { Button, Input, InputNumber, Select, Tag } from 'antd' import { SaveOutlined } from '@ant-design/icons' +import type { ActionBeatPhaseRead, CameraAngle, CameraMovement, CameraShotType } from '../../../../services/generated' + +const CAMERA_SHOT_OPTIONS: Array<{ value: CameraShotType; label: string }> = [ + { value: 'ECU', label: '大特写' }, + { value: 'CU', label: '特写' }, + { value: 'MCU', label: '中近景' }, + { value: 'MS', label: '中景' }, + { value: 'MLS', label: '中远景' }, + { value: 'LS', label: '远景' }, + { value: 'ELS', label: '大远景' }, +] + +const CAMERA_ANGLE_OPTIONS: Array<{ value: CameraAngle; label: string }> = [ + { value: 'EYE_LEVEL', label: '平视' }, + { value: 'HIGH_ANGLE', label: '高角度' }, + { value: 'LOW_ANGLE', label: '低角度' }, + { value: 'BIRD_EYE', label: '鸟瞰' }, + { value: 'DUTCH', label: '荷兰式' }, + { value: 'OVER_SHOULDER', label: '过肩' }, +] + +const CAMERA_MOVEMENT_OPTIONS: Array<{ value: CameraMovement; label: string }> = [ + { value: 'STATIC', label: '固定镜头' }, + { value: 'PAN', label: '平移' }, + { value: 'TILT', label: '俯仰' }, + { value: 'DOLLY_IN', label: '推近' }, + { value: 'DOLLY_OUT', label: '拉远' }, + { value: 'TRACK', label: '跟拍' }, + { value: 'CRANE', label: '摇臂' }, + { value: 'HANDHELD', label: '手持' }, + { value: 'STEADICAM', label: '稳定器' }, + { value: 'ZOOM_IN', label: '变焦推近' }, + { value: 'ZOOM_OUT', label: '变焦拉远' }, +] + +type ShotSemanticDraft = { + camera_shot?: CameraShotType + angle?: CameraAngle + movement?: CameraMovement + duration?: number + action_beats?: Array +} type ChapterShotBasicInfoSectionProps = { title: string scriptExcerpt: string saving: boolean + semanticSaving: boolean + semantic: ShotSemanticDraft + actionBeatPhases?: Array onTitleChange: (value: string) => void onScriptExcerptChange: (value: string) => void + onSemanticChange: (patch: ShotSemanticDraft) => void onSave: () => void } @@ -14,15 +60,27 @@ export function ChapterShotBasicInfoSection({ title, scriptExcerpt, saving, + semanticSaving, + semantic, + actionBeatPhases, onTitleChange, onScriptExcerptChange, + onSemanticChange, onSave, }: ChapterShotBasicInfoSectionProps) { + const phaseByText = new Map((actionBeatPhases ?? []).map((item) => [item.text.trim(), item.phase])) + const phaseMeta = (phase?: ActionBeatPhaseRead['phase']) => { + if (phase === 'trigger') return { label: '触发', color: 'gold' as const } + if (phase === 'peak') return { label: '峰值', color: 'blue' as const } + if (phase === 'aftermath') return { label: '收束', color: 'green' as const } + return null + } + return (
镜头基础信息
-
先确认标题和内容,再继续处理系统提取结果。
+
先确认标题、摘录和镜头语言默认值,再继续处理系统提取结果。
@@ -55,6 +113,117 @@ export function ChapterShotBasicInfoSection({ placeholder="剧本摘录" />
+ +
+
+
+
镜头语言默认值
+
这里确认的是镜头语义真值,后续工作室可以微调,但仍然写回同一份分镜详情。
+
+ +
+ +
+
+
景别
+ onSemanticChange({ angle: value })} + options={CAMERA_ANGLE_OPTIONS} + placeholder="选择机位" + className="w-full" + /> +
+
+
运镜
+