huobao-drama Documentation

火宝短剧 - 基于AI的一站式短剧生成平台 《一句话生成完整短剧,从剧本到成片全自动化》 Huobao Drama - An AI-Powered End-to-End Short Drama Generator "One Sentence to Complete Drama: Fully Automated...

16,534 stars Vue Vue 1 file · ~59,630 tokens
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy huobao-drama on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name huobao-drama -p 5679:5679 --restart always huobao/huobao-drama:latest
Configured Services & Ports
⚙️ app
image: huobao/huobao-drama:latest
🔌 Ports: 5679:5679
⚙️ watchtower
image: containrrr/watchtower:latest
docker-compose.yml
yaml (docker-compose.yml)
# 火宝短剧 Docker 一体化部署:应用 + Watchtower(自动拉新镜像重建容器,支撑应用内一键更新)
#
# 使用:
#   1. 复制 .env.example 为 .env 并修改 WATCHTOWER_TOKEN(两端必须一致)
#   2. docker compose up -d
#   3. 访问 http://localhost:5679 ,设置页「关于更新」可检查/一键更新
#
# 数据持久化在命名卷 huobao-data(SQLite + 生成的图片/视频 + 可在线编辑的 workspace/skills)。

services:
  app:
    image: huobao/huobao-drama:latest
    build:
      context: .
      args:
        # 构建时注入版本号(发布镜像时务必指定,如 HUOBAO_VERSION=1.2.0)
        HUOBAO_VERSION: ${HUOBAO_VERSION:-dev}
    ports:
      - "5679:5679"
    environment:
      # 配置后设置页「关于更新」出现「立即更新」按钮;删除这两行则退化为手动更新提示
      HUOBAO_WATCHTOWER_URL: http://watchtower:8080
      HUOBAO_WATCHTOWER_TOKEN: ${WATCHTOWER_TOKEN:-please-change-me}
      # 发布清单(默认 GitHub Releases latest.json,与桌面版同一份)
      # HUOBAO_UPDATE_FEED: https://github.com/chatfire-AI/huobao-drama/releases/latest/download/latest.json
    volumes:
      - huobao-data:/app/data
    labels:
      # Watchtower --label-enable:只更新显式标记的容器
      com.centurylinklabs.watchtower.enable: "true"
    restart: unless-stopped

  watchtower:
    image: containrrr/watchtower:latest
    command: >
      --http-api-update
      --http-api-token ${WATCHTOWER_TOKEN:-please-change-me}
      --label-enable
      --cleanup
      --rolling-restart
      --interval 86400
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    restart: unless-stopped

volumes:
  huobao-data:

File: README.ja.md

🎬 Huobao Drama - AI ショートドラマ生成プラットフォーム


📖 プロジェクト概要

Huobao Drama は AI ベースのショートドラマ自動制作プラットフォームです。脚本生成、キャラクターデザイン、分镜制作から動画合成まで、全工程を自動化します。

🎯 コアバリュー

  • 🤖 AI 駆動:大規模言語モデルで脚本を解析し、キャラクター・シーン・分镜情報を抽出
  • 🎨 インテリジェント制作:AI 画像生成でキャラクター形象とシーン背景を作成
  • 📹 動画生成:テキスト→動画・画像→動画モデルで分镜動画を自動生成
  • 🔄 ワークフロー:アイデアから完成作品までのショートドラマ制作をワンストップで完結

🛠️ 技術アーキテクチャ

text
frontend/   — Nuxt 3 + Vue 3 + TypeScript (純粋 CSS、UI フレームワークなし)
backend/    — Hono + Drizzle ORM + Mastra AI Agents + better-sqlite3
backend/workspace/skills/ — Agent スキル定義 (SKILL.md、UI からオンライン編集可能)
desktop/    — Electron デスクトップ版(メインプロセス + esbuild バンドル + electron-builder で dmg/exe)
data/       — 生成アセットと SQLite データベース

✨ 機能

🎭 キャラクター管理

  • ✅ AI によるキャラクター形象生成
  • ✅ キャラクターの一括生成
  • ✅ キャラクター画像のアップロードと管理

🎬 動画タスク

  • ✅ AI による動画タスクの自動生成
  • ✅ シーン説明と動画プロンプトの生成
  • ✅ タスク単位の一括動画生成

🎥 動画生成

  • ✅ テキスト→動画の自動生成
  • ✅ FFmpeg によるショット単位の合成と字幕処理
  • ✅ エピソード全体の結合と書き出し

📦 アセット管理

  • ✅ 素材ライブラリの一元管理
  • ✅ ローカルストレージ対応
  • ✅ タスク進捗トラッキング

🤖 AI Agents

4 つの Mastra Agent を内蔵。データベース設定と Skill 拡張に対応:

Agent 役割
script_rewriter 小説 → フォーマット済み脚本へのリライト
extractor キャラクター / シーン / 小道具のインテリジェント抽出と重複排除
storyboard_breaker 脚本 → 分镜シーケンスへの分解
prompt_generator キャラクター/シーン/小道具の画像プロンプト + 分镜動画プロンプト生成

🌐 多言語 UI

インターフェースは 中文 / English / 日本語 / 한국어 を内蔵し、AI 生成コンテンツの言語をグローバルに設定できます。

🔌 マルチプロバイダー対応

タイプ 対応プロバイダー
テキスト OpenAI(互換 API)、Gemini
画像 OpenAI、Gemini、Volcano Engine
動画 Volcano Engine Seedance 2.0(Standard / Fast / Mini)、MiniMax H3、Alibaba Bailian Wan 3.0(Prime / Standard)

🚀 クイックスタート

📋 動作環境

ソフトウェア バージョン 説明
Node.js 20+ フロントエンド・バックエンド実行環境
npm 9+ パッケージマネージャー

データベース不要:SQLite 内蔵(プロジェクトのデータディレクトリに単一ファイル)。データベースサーバーのインストールは不要です。
FFmpeg 不要:ffmpeg-static / ffprobe-static npm パッケージにバイナリを内蔵。すぐに使えます。

⚙️ 環境変数

設定ファイルは不要。環境変数で設定します(すべてデフォルト値あり、ローカル開発はゼロ設定で起動可能):

変数 デフォルト値 説明
SQLITE_PATH <リポジトリ>/data/huobao.sqlite3 SQLite データベースファイルの場所
PORT 5679 バックエンドサービスのポート
STORAGE_PATH <リポジトリ>/data/static 生成ファイルの保存ディレクトリ
HUOBAO_DATA_DIR — デスクトップ版で Electron メインプロセスが注入(userData データルート)
WORKSPACE_PATH backend/workspace Agent スキル/プロンプトディレクトリ(デスクトップ版は userData の書き込み可能なコピー)
FRONTEND_DIST frontend/dist フロントエンド静的ビルドディレクトリ
FFMPEG_BIN / FFPROBE_BIN npm 内蔵バイナリ カスタム ffmpeg/ffprobe の実行ファイルパス
PUBLIC_BASE_URL — Seedance がローカル参照リソースを使う際に必要な公開 URL(サーバーデプロイ用)

説明:AI サービスの API Key、Base URL、モデルパラメータはすべて Web UI の「設定」ページで設定してデータベースに保存します。設定ファイルや環境変数では管理しません。

📥 インストール

bash
# リポジトリをクローン
git clone https://github.com/chatfire-AI/huobao-drama.git
cd huobao-drama

# バックエンドの依存をインストール
cd backend && npm install

# フロントエンドの依存をインストール
cd ../frontend && npm install

🎯 起動

方法 1:開発モード(推奨)

フロントエンドとバックエンドを分離し、ホットリロード対応:

bash
# ターミナル 1:バックエンド
cd backend
npm run dev

# ターミナル 2:フロントエンド
cd frontend
npm run dev
  • フロントエンド:http://localhost:3013
  • バックエンド API:http://localhost:5679/api/v1
  • フロントエンドは /api と /static をバックエンドへ自動プロキシ

方法 2:シングルサービスモード

バックエンドが API とフロントエンド静的ファイルの両方を提供:

bash
# 1. フロントエンドをビルド
cd frontend && npm run generate

# 2. ビルド成果物をバックエンドが読むディレクトリへコピー
#    (generate の出力は .output/public、バックエンドは frontend/dist を読む)
cp -r .output/public dist

# 3. バックエンドを起動
cd ../backend && npm start

アクセス:http://localhost:5679

🗄️ データベース

SQLite 内蔵(better-sqlite3 + WAL モード)。初回起動時にテーブルを自動作成(冪等な DDL リプレイ + シードデータ)。デフォルトのファイルは data/huobao.sqlite3、SQLITE_PATH で変更可能。デスクトップ版はユーザーデータディレクトリ(~/Library/Application Support/HuobaoDrama/data/)に保存します。

旧 MySQL からのデータ移行:

起動時の自動移行(推奨):MySQL が明示的に設定されており(DATABASE_URL または MYSQL_HOST)、SQLite が空の場合、バックエンド起動時に自動検出して全テーブルを一度だけインポートします(テーブルごとの行数検証、単一トランザクションの原子書き込み、失敗時は自動ロールバックして次回起動時に再試行、成功後は .mysql-imported マーカーを書き込み重複を防止)。MYSQL_AUTO_IMPORT=false で無効化できます。

bash
# 手動実行も可能(対象 DB が空でない場合は --force が必要、書き込み前に自動バックアップ)
cd backend && npx tsx scripts/import-mysql-to-sqlite.ts

移行はデータベースの行のみをカバーします。旧デプロイの data/static/ 配下の画像・動画などのメディアファイルは手動でコピーしてください。コピーしないと過去の素材にアクセスできません。

🔑 初回利用:AI サービスの設定

起動後、すべての AI 機能(テキスト/画像/動画)を使うには、先にモデルサービスの設定が必要です。未設定の場合、ページ上部にバナーで案内されます:

  1. 「設定」ページを開く
  2. 「火宝クイック設定」に Huobao API Key を貼る(api.firemux.com で取得)。テキスト・画像・動画の 3 つの推奨設定をワンクリックで書き込み
  3. または「手動テンプレート」でプロバイダーごとに追加。接続テストに対応

設定が完了するとバナーは自動で消え、エピソード制作を開始できます。


📖 チュートリアル(画像付き)

小説から完成エピソードまでの全工程。左の進捗バーが常に現在のステージを示します。

ステップ 1 · プロジェクト作成

ホームで「新規プロジェクト」をクリックし、アスペクト比(16:9 横 / 9:16 縦、作成後は変更不可)と作画スタイル(3D / リアル系など、全生図プロンプトに注入)を選択します。

ステップ 2 · AI サービス設定(初回)

設定ページの「火宝クイック設定」に API キーを貼り付けると推奨 3 設定を一括書き込み。手動テンプレートでの追加も可能です。使用モデルは上部バーでいつでも切り替えられます(ステップ 5 参照)。

ステップ 3 · 脚本ステージ

制作画面に**原文(小説)**を貼り付け、「AI リライト」で撮影用脚本を生成 — エピソード単位の分割とシーン・キャラクターの注記付き。モデルやトーンの切り替えも可能です。

ステップ 4 · アセット制作

脚本に抽出を実行するとキャラクター / シーン / 小道具の一覧を自動取得。各項目の「イメージ生成」で一貫性のある参照画像を作成します(一括も可)。これらの画像は動画生成時に参照素材として注入されます。

ステップ 5 · 絵コンテと動画

「動画制作」ページでまず絵コンテ分割を実行(AI がカット割りし動画プロンプトを生成)。その後:

  • 上部バーで動画モデルを選択(Seedance / Wan 3.0 / MiniMax など)。解像度と尺の選択肢はモデルに連動
  • 右側で各カットのプロンプトを確認・調整(@キャラ名 参照は自動で参照画像にマッピング)
  • 「一括動画生成」でタスク開始。失敗タスクはワンクリックでリトライ

ステップ 6 · 連結と書き出し

カットを選択(ホバーで各クリップをプレビュー)し、「連結開始」をクリックすると FFmpeg が完全なエピソードを自動合成。オンライン再生・ダウンロード可能です。完了したら「完了にする」で進捗バーを点灯。

エピソード一覧では各話の制作状況を確認でき、「制作を開く」から再開できます:


📦 デプロイ

🖥️ デスクトップアプリ(推奨)

⬇️ ビルド済みインストーラー: GitHub Releases · 中国向けミラー(Tencent COS)

プラットフォーム ダウンロードファイル
macOS(Apple Silicon、M シリーズ) HuobaoDrama-4.0.5-arm64.dmg
macOS(Intel) HuobaoDrama-4.0.5.dmg
Windows HuobaoDrama.Setup.4.0.5.exe

中国本土では GitHub が不安定なため、Tencent COS ミラーをご利用ください。アプリ内アップデーターも COS を優先し、GitHub にフォールバックします。

コマンドラインインストール(推奨・修復不要):curl でのダウンロードは macOS の隔離属性が付かないため、「壊れている」警告なしでそのまま起動できます(Apple Silicon は -arm64.dmg、Intel は無印の dmg):

bash
curl -L -o /tmp/HuobaoDrama.dmg https://installer.chatfire.site/huobao-drama/v4.0.5/HuobaoDrama-4.0.5-arm64.dmg \
  && hdiutil attach -nobrowse /tmp/HuobaoDrama.dmg \
  && cp -R /Volumes/HuobaoDrama*/HuobaoDrama.app /Applications/ \
  && hdiutil detach /Volumes/HuobaoDrama*

ビルド不要 —— dmg/exe をダウンロードしてそのままインストールできます。インストール済みクライアントは内蔵アップデーターで自動更新されます。(ソースから自分でパッケージングする場合は以下のコマンドを参照。)

ダブルクリックでインストール、すぐに使えるデスクトップ版(macOS + Windows)。データベース(SQLite)、生成メディア、Agent スキルはすべてユーザーデータディレクトリに保存され、アプリをアンインストールしてもデータに影響しません。

bash
# ワンコマンドパッケージ(フロントエンド generate → バックエンド esbuild → electron-builder)
npm run dist        # macOS dmg(arm64 + Intel)
npm run dist:win    # Windows NSIS インストーラー(win-x64、macOS 上でクロスビルド可能)

# 成果物
# desktop/release/HuobaoDrama-<バージョン>-arm64.dmg      (Apple Silicon)
# desktop/release/HuobaoDrama-<バージョン>.dmg            (Intel)
# desktop/release/HuobaoDrama Setup <バージョン>.exe      (Windows)

インストール時の注意:

  • macOS 未署名パッケージは初回起動時に「Appが壊れているため開けません」と表示される場合があります(Apple Silicon で多発)。これは Gatekeeper の隔離属性によるもので、ファイルは壊れていません。修復方法は 2 つあります:

    1. dmg に修復スクリプトを同梱:アプリを「アプリケーション」にドラッグした後、dmg ウィンドウ下部の「如提示已损坏请双击我.command」をダブルクリックすれば自動で修復されます;
    2. またはターミナルで sudo xattr -cr /Applications/HuobaoDrama.app を実行。

    修復は初回の 1 回だけ。その後は普通に起動でき、アプリ内自動更新にも影響しません。

  • Windows 未署名パッケージは SmartScreen で「詳細情報 → 実行」を選択

  • ユーザーデータディレクトリ:~/Library/Application Support/HuobaoDrama/(データベース、生成メディア、オンライン編集したスキルのコピー)

  • FFmpeg/FFprobe バイナリ内蔵。システムへのインストール不要

  • Electron は 37.x に固定:better-sqlite3 の win32 プリビルドがこの ABI までしか対応していないため(クロスパッケージでコンパイル不要にする鍵)

  • アプリ内の外部リンク(「api.firemux.com で Key を取得」など)はシステムブラウザで直接開きます

🔄 アプリ内更新(Apple 署名不要)

デスクトップ版には更新機能を内蔵(Tauri と同種の方式:macOS はディレクトリ置換 / Windows はサイレントインストール、ローカルで sha256 検証)。新バージョンのリリース手順:

bash
# 1. desktop/package.json の version を変更してパッケージ
npm run dist        # macOS(dmg + 更新用 zip を出力)
npm run dist:win    # Windows(Setup.exe を出力)

# 2. バージョンマニフェスト release/latest.json を生成(各プラットフォームの sha256 を含む)
cd desktop && npm run feed

# 3. 公開:latest.json + インストーラー + zip を GitHub Release にアップロード(タグは v1.0.1 形式)

インストール済みのクライアントは起動後にマニフェストを自動チェックし(「設定 → 关于更新」から手動チェックも可能)、新バージョンを検出するとダウンロードとインストールを促します。マニフェストの URL は HUOBAO_UPDATE_FEED 環境変数で変更可能です。

デスクトップ版の開発デバッグ:

bash
npm run build:frontend   # フロントエンド静的成果物(frontend/.output/public)
cd desktop && npm run dev  # バックエンドをバンドルして Electron ウィンドウで実行

既知の制限:Seedance 動画モデルがローカル参照リソースを使うには PUBLIC_BASE_URL の公開アドレスが必要です。デスクトップ版には公開エントリがないため、このシナリオでは明確なエラーメッセージが表示されます。テキスト→動画・画像生成など他の機能には影響しません。


🏭 サーバーデプロイ

bash
# 1. フロントエンドをビルド
cd frontend && npm run generate

# 2. ビルド成果物をコピー(generate の出力は frontend/.output/public、バックエンドは
#    frontend/dist を読む。この手順を省くと API は動くがページが 404 になる)
cp -r .output/public dist && cd ..

# 3. バックエンドを起動
cd backend && npm start

サーバーにアップロードするファイル:

text
backend/                    # バックエンドソース + node_modules
backend/workspace/skills/   # Agent スキルファイル
frontend/dist/              # フロントエンドビルド成果物
data/                       # データディレクトリ(初回実行時に自動作成)

Nginx リバースプロキシ

nginx
server {
    listen 80;
    server_name your-domain.com;

    # 参照動画/音声アップロードは最大 50MB
    client_max_body_size 100m;

    # 生成画像/動画はディスクから直接配信(Node を経由しない):
    # sendfile ゼロコピー + 長期キャッシュ
    # (ファイルは uuid 命名で内容不変のため immutable キャッシュが安全)
    location /static/ {
        alias /path/to/huobao-drama/data/static/;
        sendfile on;
        tcp_nopush on;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location / {
        proxy_pass http://localhost:5679;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

メディア読み込みの最適化:画像生成時にバックエンドが 400px サムネイル(*_thumb.webp)を自動生成してリストページで使用し、動画はポスターフレーム(*_poster.jpg)をカバーとして抽出します。フロントエンドは画像を開く/再生する時だけ元ファイルを読み込みます。過去の既存ファイルは backend/ で npm run backfill-artwork を実行して一括補完できます。

🐳 Docker デプロイ(アプリ内更新付き)

方法 A — ビルド済みイメージ(クローン・ビルド不要):マルチアーキテクチャ(linux/amd64 + linux/arm64)、x86 サーバーと ARM デバイスの両方に自動対応

bash
docker pull huobao/huobao-drama:4.0.6

docker run -d \
  --name huobao-drama \
  -p 5679:5679 \
  -v huobao-data:/app/data \
  --restart unless-stopped \
  huobao/huobao-drama:4.0.6

方法 B — docker compose(ソースビルド + Watchtower アプリ内更新):リポジトリルートにオールインワンの Dockerfile(フロントエンド generate + バックエンド依存/ランタイムの 3 ステージ。バックエンドはサーバーデプロイと同様に tsx で実行)と docker-compose.yml(アプリ + Watchtower)を用意:

bash
# 1. 環境を設定(Watchtower トークン。app と watchtower の両側で一致必須)
cp .env.example .env   # WATCHTOWER_TOKEN を変更

# 2. ビルドして起動(リリース時にバージョンを注入し、「关于更新」での比較に使用)
HUOBAO_VERSION=4.0.5 docker compose up -d --build

# 3. http://localhost:5679 にアクセス
  • データ永続化:名前付きボリューム huobao-data を /app/data にマウント(SQLite + 生成画像/動画 + workspace/skills)。イメージ更新でもデータを失いません
  • アプリ内更新:compose に Watchtower sidecar を同梱(--label-enable でラベル付きコンテナのみ更新、--cleanup で旧イメージ削除、毎日セルフチェック)。「設定 → 关于更新」で新バージョンの確認と「今すぐ更新」が可能。バックエンドが Watchtower HTTP API 経由でトリガーし、新イメージを pull してコンテナを再構築。数分後にページを更新すれば完了です
  • 手動モード:docker-compose.yml から app の HUOBAO_WATCHTOWER_* の 2 つの環境変数(または watchtower サービス全体)を削除すると、「关于更新」は新バージョン通知 + 手動コマンド docker compose pull && docker compose up -d に退化します
  • イメージの公開:docker buildx build --platform linux/amd64,linux/arm64 --build-arg HUOBAO_VERSION=x.y.z -t huobao/huobao-drama:x.y.z -t huobao/huobao-drama:latest --push .。バージョンマニフェストはデスクトップ版と GitHub Releases の latest.json を共用(HUOBAO_UPDATE_FEED で上書き可能)

🎨 技術スタック

バックエンド

  • ランタイム:Node.js 20+
  • Web フレームワーク:Hono
  • ORM:Drizzle ORM + better-sqlite3(WAL モード)
  • AI Agent:Mastra + AI SDK(OpenAI 互換)
  • 動画処理:FFmpeg(fluent-ffmpeg + 内蔵バイナリ)
  • 画像処理:Sharp

デスクトップ

  • シェル:Electron(utilityProcess がバックエンドをホスト、BrowserWindow は同一オリジンで読み込み)
  • パッケージ:esbuild(バックエンド単一ファイルバンドル)+ electron-builder(dmg arm64/x64、NSIS win-x64)

フロントエンド

  • フレームワーク:Nuxt 3(SPA モード)
  • 言語:Vue 3 + TypeScript
  • ルーティング:ファイルルーティング(Vue Router 4)
  • スタイル:純粋 CSS + CSS Variables
  • アイコン:Lucide Vue
  • i18n:vue-i18n(中文 / English / 日本語 / 한국어)

📝 よくある質問

Q: デスクトップ版のデータはどこに保存されますか?

A: ~/Library/Application Support/HuobaoDrama/data/(SQLite データベース + 生成画像/動画)。オンライン編集したスキルのコピーは同階層の workspace/ ディレクトリにあります。開発モードではリポジトリの data/ ディレクトリを使用します。

Q: 旧 MySQL データを SQLite に移行するには?

A: MySQL に接続できる状態(環境変数または backend/.env)を保ち、cd backend && npx tsx scripts/import-mysql-to-sqlite.ts を実行。スクリプトが自動でテーブルを作成し、テーブルごとにインポートして行数を検証します(対象 DB が空でない場合は --force が必要。書き込み前に自動バックアップ)。

Q: FFmpeg が未インストール/見つからない?

A: インストール不要です。プロジェクトに ffmpeg-static / ffprobe-static バイナリを内蔵(デスクトップ版も同梱)。システム PATH の FFmpeg と競合することもありません。FFMPEG_BIN/FFPROBE_BIN で明示的に指定することも可能です。

Q: ページ上部に「モデル未設定」と表示される?

A: 初回デプロイ時の正常な案内です。「設定」ページで「火宝クイック設定」に API Key を貼ってワンクリックで書き込むか、「手動テンプレート」でプロバイダーを追加してください。テキスト・画像・動画の 3 類すべてに有効な設定があるとバナーは自動で消えます。

Q: フロントエンドがバックエンド API に接続できない?

A: バックエンドが起動しているか、ポートが正しいかを確認してください。開発モードのプロキシ設定は frontend/nuxt.config.ts にあります。

Q: データベーステーブルが作成されない?

A: バックエンドは初回起動時に全テーブルを自動作成します。ログで初期化が成功したか確認してください。


📋 更新履歴

v4.0.0 (2026-08)

🖥️ デスクトップアプリ + データベース移行

  • Electron デスクトップ版(macOS dmg、arm64/x64 デュアルアーキテクチャ)
    • ダブルクリックでインストール、すぐ使える:自動ポート選択、シングルインスタンスロック、クラッシュ分離されたバックエンドサブプロセス
    • ユーザーデータ分離:SQLite DB / 生成メディア / スキルコピーはすべて userData ディレクトリに保存
    • FFmpeg/FFprobe を同梱。workspace スキルテンプレートは初回起動時にコピー、アップグレード時は不足分のみ補完して上書きしない
  • データベースを MySQL から SQLite へ完全移行(better-sqlite3 + WAL)
    • ビジネスコードの変更ゼロ(Drizzle クエリ層は本質的に移植可能)、冪等な DDL リプレイ
    • 一度きりのインポートスクリプト import-mysql-to-sqlite.ts を追加(テーブルごとの行数検証 + 自動バックアップ)
  • バックエンドを esbuild で単一ファイルにバンドル(externals:sharp/better-sqlite3/ffmpeg バイナリパッケージ)
  • Docker/MySQL デプロイを削除(git 履歴から復元可能)

v3.1.0 (2026-09)

  • Alibaba Bailian Wan 3.0 動画モデルを追加(Prime / 標準、公式 input.media/parameters パラメータ対応)
  • ワークベンチ上部バーに解像度セレクターを追加、プロバイダーごとにネイティブ段階を表示(Seedance 480p/720p、MiniMax 768P/2K、Wan 480P/720P/1080P)
  • デフォルトの動画モデルを Seedance 2.0 Mini に変更
  • 動画モデル切替時のプロバイダー/モデル不一致による生成エラーを修正
  • バッチ動画:選択モード + 生成前確認(ショット数/合計尺/モデル/解像度)、失敗タスクのワンクリック再試行
  • 分镜尺は動画生成パラメータ領域で直接編集・保存可能、単発/バッチ生成に統一適用
  • 実写/センシティブ内容の審査失敗時にモデル切替再試行を案内

v3.0.0 (2026-08)

🚀 デプロイと体験の最適化

  • Docker デプロイ対応の整備
    • MySQL / アプリのヘルスチェック。データベース準備完了を待ってからアプリ起動
    • データベース初期化にリトライを追加。コンテナオーケストレーションでの初回デプロイが無人で完了
    • システム FFmpeg 依存を削除し、内蔵バイナリに全面移行
    • Agent skills ディレクトリの volume 永続化(設定ページでのオンライン編集が失われない)
    • docker/init.sql とエクスポートスクリプトを追加(DBA レビュー / 事前テーブル作成)
  • 初回利用ガイド
    • AI サービス未設定時にサイト上部にバナーを表示し設定ページへ誘導
    • 設定ページに「火宝クイック設定」を追加:1 つの Key でテキスト/画像/動画の 3 つの推奨設定を書き込み
    • モデル未設定エラーの中国語化と設定ページへの誘導
  • 動画モデルのデフォルトを Seedance 2.0 Fast に変更
  • プロバイダー集約:OpenAI / Gemini / Volcano Engine のみ残存
  • ワークベンチ:タスクリストドロワー、パイプライン大セクション状態、選択的結合(結合前に動画ファイルの存在を検証)
  • 素材ライブラリ刷新、@メンション最適化、エピソードリスト再構築

v2.0.0 (2026-04)

🚀 大型アップデート

  • プロジェクトを TypeScript 技術スタックへ全面移行
    • バックエンド:Hono + Drizzle ORM + mysql2
    • フロントエンド:Nuxt 3 + Vue 3
    • AI Agent:Mastra フレームワーク
  • エピソードワークベンチ UI と制作フローを刷新
    • よりコンパクトなコンソールレイアウト
    • 分镜編集エリアを刷新
    • ショット画像、動画、合成、書き出し画面を刷新
  • Docker デプロイ対応を追加。フロントエンドとバックエンドを単一イメージに統合
  • ランタイム Skill ロード機構を追加
  • マルチプロバイダーメディアアダプターを拡張
    • 画像:OpenAI、Gemini、Volcano Engine、Alibaba
    • 動画:Volcano Engine/Seedance、Vidu、Alibaba
  • ローカルファイル処理と参照画像のオンデマンドトランスコードを最適化

v1.0.4 (2026-01-27)

  • ローカルストレージ戦略を導入し、外部リソースリンク切れを回避
  • Base64 参照画像の埋め込み転送
  • ショット切り替え時の状態リセット問題を修正
  • シーンのチャプターへの移行を追加

v1.0.3 (2026-01-16)

  • データベース同時アクセス性能を最適化
  • Docker クロスプラットフォームで host.docker.internal に対応

v1.0.2 (2026-01-14)

  • 動画生成 API レスポンスの解析問題を修正
  • OpenAI Sora 動画エンドポイント設定を追加
  • エラーハンドリングとログ出力を最適化

📄 ライセンス

本プロジェクトは CC BY-NC-SA 4.0(表示-非営利-継承 4.0 国際)ライセンスを採用しています。

  • ✅ 個人利用、学習・研究、非営利プロジェクトでの使用は自由です
  • ✅ 改変と再配布は可能ですが、クレジット表示と同一ライセンスでの共有が必要です
  • ❌ 商用利用は禁止——作者の書面による許可なく、本プロジェクトの全部または一部をいかなる商業目的(有料サービス、商用デプロイ、転売など)にも使用することはできません

ライセンス全文は LICENSE を参照してください。


🤝 コントリビューション

Issue と Pull Request を歓迎します!

  1. 本プロジェクトを Fork
  2. フィーチャーブランチを作成(git checkout -b feature/AmazingFeature)
  3. 変更をコミット(git commit -m 'Add some AmazingFeature')
  4. ブランチをプッシュ(git push origin feature/AmazingFeature)
  5. Pull Request を作成

よく使うチェックコマンド:

bash
cd backend && npm run typecheck
cd ../frontend && npm run build

☕ 寄付のお願い

このプロジェクトが役に立ったら、QR コードで作者にコーヒーを一杯おごってください ☕。あなたの支援が継続的な更新の原動力です!


💬 WeChat グループ

QR コードをスキャンして WeChat グループに参加:


"AI にもっと創造的なことを手伝ってもらおう"

🔗 関連リンク

本プロジェクトは LINUX DO コミュニティからリンクの承認を得ています。

  • LINUX DO — 真のオープンソース精神、共に作り共有する技術コミュニティ


File: README.ko.md

🎬 Huobao Drama - AI 숏드라마 생성 플랫폼


📖 프로젝트 소개

Huobao Drama는 AI 기반 숏드라마 자동 제작 플랫폼으로, 각본 생성, 캐릭터 디자인, 스토리보드 제작부터 영상 합성까지 전 과정을 자동화합니다.

🎯 핵심 가치

  • 🤖 AI 기반:대규모 언어 모델로 각본을 분석하여 캐릭터, 장면, 스토리보드 정보를 추출
  • 🎨 지능형 창작:AI 이미지 생성으로 캐릭터 이미지와 장면 배경 제작
  • 📹 영상 생성:텍스트→영상 및 이미지→영상 모델로 스토리보드 영상 자동 생성
  • 🔄 워크플로:아이디어부터 완성 영상까지 숏드라마 제작 전 과정을 한 곳에서 완료

🛠️ 기술 아키텍처

text
frontend/   — Nuxt 3 + Vue 3 + TypeScript (순수 CSS, UI 프레임워크 없음)
backend/    — Hono + Drizzle ORM + Mastra AI Agents + better-sqlite3
backend/workspace/skills/ — Agent 스킬 정의 (SKILL.md, UI에서 온라인 편집 가능)
desktop/    — Electron 데스크톱 버전 (메인 프로세스 + esbuild 번들 + electron-builder로 dmg/exe 생성)
data/       — 생성된 에셋과 SQLite 데이터베이스

✨ 기능

🎭 캐릭터 관리

  • ✅ AI 캐릭터 이미지 생성
  • ✅ 캐릭터 일괄 생성
  • ✅ 캐릭터 이미지 업로드 및 관리

🎬 영상 작업

  • ✅ AI 영상 작업 자동 생성
  • ✅ 장면 설명 및 영상 프롬프트 생성
  • ✅ 작업별 영상 일괄 생성

🎥 영상 생성

  • ✅ 텍스트→영상 자동 생성
  • ✅ FFmpeg 샷 단위 합성 및 자막 처리
  • ✅ 에피소드 전체 병합 및 납출

📦 에셋 관리

  • ✅ 소재 라이브러리 통합 관리
  • ✅ 로컬 스토리지 지원
  • ✅ 작업 진행 상황 추적

🤖 AI Agents

4개의 Mastra Agent 내장, 데이터베이스 설정과 Skill 확장 지원:

Agent 역할
script_rewriter 소설 → 형식화된 각본 리라이팅
extractor 캐릭터 / 장면 / 소품 지능형 추출 및 중복 제거
storyboard_breaker 각본 → 스토리보드 시퀀스 분해
prompt_generator 캐릭터/장면/소품 이미지 프롬프트 + 스토리보드 영상 프롬프트 생성

🌐 다국어 UI

인터페이스는 中文 / English / 日本語 / 한국어 4개 언어를 내장하고, AI 생성 콘텐츠의 언어를 전역으로 설정할 수 있습니다.

🔌 멀티 프로바이더 지원

유형 지원 프로바이더
텍스트 OpenAI(호환 API), Gemini
이미지 OpenAI, Gemini, Volcano Engine
영상 Volcano Engine Seedance 2.0(Standard / Fast / Mini), MiniMax H3, Alibaba Bailian Wan 3.0(Prime / Standard)

🚀 빠른 시작

📋 환경 요구 사항

소프트웨어 버전 설명
Node.js 20+ 프런트엔드/백엔드 실행 환경
npm 9+ 패키지 관리 도구

데이터베이스 설치 불필요:SQLite 내장(프로젝트 데이터 디렉터리의 단일 파일)으로 데이터베이스 서버 설치가 필요 없습니다.
FFmpeg 설치 불필요:ffmpeg-static / ffprobe-static npm 패키지에 바이너리가 내장되어 바로 사용할 수 있습니다.

⚙️ 환경 변수

설정 파일 없이 환경 변수로 설정합니다(모두 기본값이 있어 로컬 개발은 무설정으로 시작 가능):

변수 기본값 설명
SQLITE_PATH <저장소>/data/huobao.sqlite3 SQLite 데이터베이스 파일 위치
PORT 5679 백엔드 서비스 포트
STORAGE_PATH <저장소>/data/static 생성 파일 저장 디렉터리
HUOBAO_DATA_DIR — 데스크톱 버전에서 Electron 메인 프로세스가 주입(userData 데이터 루트)
WORKSPACE_PATH backend/workspace Agent 스킬/프롬프트 디렉터리(데스크톱 버전은 userData의 쓰기 가능한 복사본)
FRONTEND_DIST frontend/dist 프런트엔드 정적 빌드 디렉터리
FFMPEG_BIN / FFPROBE_BIN npm 내장 바이너리 사용자 지정 ffmpeg/ffprobe 실행 파일 경로
PUBLIC_BASE_URL — Seedance가 로컬 참조 리소스를 사용할 때 필요한 공개 주소(서버 배포용)

설명:AI 서비스의 API Key, Base URL, 모델 파라미터는 모두 웹 UI의 「설정」 페이지에서 설정하여 데이터베이스에 저장합니다. 설정 파일이나 환경 변수로 관리하지 않습니다.

📥 설치

bash
# 저장소 클론
git clone https://github.com/chatfire-AI/huobao-drama.git
cd huobao-drama

# 백엔드 의존성 설치
cd backend && npm install

# 프런트엔드 의존성 설치
cd ../frontend && npm install

🎯 실행

방법 1: 개발 모드(권장)

프런트엔드와 백엔드를 분리하여 핫 리로드 지원:

bash
# 터미널 1: 백엔드
cd backend
npm run dev

# 터미널 2: 프런트엔드
cd frontend
npm run dev
  • 프런트엔드 주소: http://localhost:3013
  • 백엔드 API: http://localhost:5679/api/v1
  • 프런트엔드가 /api와 /static을 백엔드로 자동 프록시

방법 2: 단일 서비스 모드

백엔드가 API와 프런트엔드 정적 파일을 모두 제공:

bash
# 1. 프런트엔드 빌드
cd frontend && npm run generate

# 2. 빌드 산출물을 백엔드가 읽는 디렉터리로 복사
#    (generate 산출물은 .output/public, 백엔드는 frontend/dist를 읽음)
cp -r .output/public dist

# 3. 백엔드 시작
cd ../backend && npm start

접속: http://localhost:5679

🗄️ 데이터베이스

SQLite 내장(better-sqlite3 + WAL 모드). 최초 시작 시 테이블 자동 생성(멱등 DDL 재생 + 시드 데이터). 기본 파일은 data/huobao.sqlite3이며 SQLITE_PATH로 변경 가능. 데스크톱 버전의 데이터는 사용자 데이터 디렉터리(~/Library/Application Support/HuobaoDrama/data/)에 저장됩니다.

구버전 MySQL에서 데이터 마이그레이션:

시작 시 자동 마이그레이션(권장): MySQL이 명시적으로 설정되어 있고(DATABASE_URL 또는 MYSQL_HOST) SQLite가 비어 있으면, 백엔드 시작 시 자동으로 감지하여 모든 테이블을 한 번만 가져옵니다(테이블별 행 수 검증, 단일 트랜잭션 원자적 쓰기, 실패 시 자동 롤백 후 다음 시작 때 재시도, 성공 시 .mysql-imported 마커를 기록하여 중복 방지). MYSQL_AUTO_IMPORT=false로 비활성화할 수 있습니다.

bash
# 수동 실행도 가능(대상 DB가 비어 있지 않으면 --force 필요, 쓰기 전 자동 백업)
cd backend && npx tsx scripts/import-mysql-to-sqlite.ts

마이그레이션은 데이터베이스 행만 포함합니다. 구 배포의 data/static/ 아래 이미지/영상 등 미디어 파일은 수동으로 복사해야 하며, 그렇지 않으면 기존 소재에 접근할 수 없습니다.

🔑 첫 사용: AI 서비스 설정

시작 후 모든 AI 기능(텍스트/이미지/영상)을 사용하려면 먼저 모델 서비스를 설정해야 합니다. 미설정 시 페이지 상단에 배너로 안내합니다:

  1. 「설정」 페이지 열기
  2. 「火宝快捷 설정」에 Huobao API Key 붙여넣기(api.firemux.com에서 발급). 텍스트, 이미지, 영상 추천 설정 3개가 한 번에 입력됩니다
  3. 또는 「수동 템플릿」으로 프로바이더별 추가. 연결 테스트 지원

설정이 완료되면 배너가 자동으로 사라지고 에피소드 제작을 시작할 수 있습니다.


📖 그림 튜토리얼

소설부터 완성 에피소드까지의 전체 제작 흐름입니다. 왼쪽 진행 표시줄이 항상 현재 단계를 보여줍니다.

1단계 · 프로젝트 생성

홈에서 "새 프로젝트"를 클릭하고 화면 비율(16:9 가로 / 9:16 세로, 생성 후 변경 불가)과 화풍(3D / 실사 등, 모든 이미지 프롬프트에 주입)을 선택합니다.

2단계 · AI 서비스 설정 (최초)

설정 페이지의 "휘바오 빠른 설정"에 API 키를 붙여넣으면 추천 설정 3종을 한 번에 등록합니다. 수동 템플릿으로 직접 추가할 수도 있습니다. 사용 모델은 상단 바에서 언제든 전환 가능합니다(5단계 참고).

3단계 · 대본 단계

제작 화면에 **원문(소설)**을 붙여넣고 "AI 재작성"을 실행하면 촬영용 대본이 생성됩니다 — 에피소드별 분할 및 장면·캐릭터 주석 포함. 모델과 톤을 바꿔가며 재작성할 수 있습니다.

4단계 · 에셋 제작

대본에 추출을 실행하면 캐릭터 / 장면 / 소품 목록이 자동 생성됩니다. 각 항목의 "이미지 생성"으로 일관성 있는 참조 이미지를 만들 수 있습니다(일괄 생성 지원). 이 이미지들은 영상 생성 시 참조 소재로 주입됩니다.

5단계 · 스토리보드와 영상

"영상 제작" 페이지에서 먼저 스토리보드 분할을 실행하세요(AI가 컷을 나누고 영상 프롬프트 생성). 그 후:

  • 상단 바에서 영상 모델 선택(Seedance / Wan 3.0 / MiniMax 등). 해상도와 길이 옵션은 모델에 연동됩니다
  • 오른쪽에서 각 컷의 프롬프트를 확인·조정(@캐릭터명 참조는 자동으로 참조 이미지에 매핑)
  • "일괄 영상 생성"으로 작업 시작. 실패한 작업은 원클릭 재시도

6단계 · 병합과 내보내기

컷을 선택(호버로 각 클립 미리보기)하고 "병합 시작"을 누르면 FFmpeg이 완성 에피소드를 자동 합성합니다. 온라인 재생·다운로드 가능. 완료 후 "완료 표시"를 누르면 진행 표시줄이 켜집니다.

에피소드 목록에서 각 화의 제작 현황을 확인하고 "제작 열기"로 이어서 작업할 수 있습니다:


📦 배포

🖥️ 데스크톱 앱(권장)

⬇️ 빌드된 설치 파일: GitHub Releases · 중국용 미러(Tencent COS)

플랫폼 다운로드 파일
macOS(Apple Silicon, M 시리즈) HuobaoDrama-4.0.5-arm64.dmg
macOS(Intel) HuobaoDrama-4.0.5.dmg
Windows HuobaoDrama.Setup.4.0.5.exe

중국 본토에서는 GitHub이 불안정하므로 Tencent COS 미러를 이용하세요. 앱 내 업데이터도 COS를 우선하고 GitHub으로 폴백합니다.

커맨드라인 설치(권장, 복구 불필요): curl로 다운로드하면 macOS 격리 속성이 붙지 않아 "손상됨" 경고 없이 바로 실행됩니다(Apple Silicon은 -arm64.dmg, Intel은 일반 dmg 사용):

bash
curl -L -o /tmp/HuobaoDrama.dmg https://installer.chatfire.site/huobao-drama/v4.0.5/HuobaoDrama-4.0.5-arm64.dmg \
  && hdiutil attach -nobrowse /tmp/HuobaoDrama.dmg \
  && cp -R /Volumes/HuobaoDrama*/HuobaoDrama.app /Applications/ \
  && hdiutil detach /Volumes/HuobaoDrama*

빌드 불필요 — dmg/exe를 다운로드해 바로 설치하면 됩니다. 설치된 클라이언트는 내장 업데이터로 자동 업데이트됩니다. (소스에서 직접 패키징하려면 아래 명령을 참조하세요.)

더블클릭 설치로 바로 사용할 수 있는 데스크톱 버전(macOS + Windows). 데이터베이스(SQLite), 생성된 미디어 파일, Agent 스킬은 모두 사용자 데이터 디렉터리에 저장되며 앱을 삭제필필도 데이터에 영향이 없습니다.

bash
# 원커맨드 패키징(프런트엔드 generate → 백엔드 esbuild → electron-builder)
npm run dist        # macOS dmg(arm64 + Intel)
npm run dist:win    # Windows NSIS 설치 프로그램(win-x64, macOS에서 크로스 빌드 가능)

# 산출물
# desktop/release/HuobaoDrama-<버전>-arm64.dmg        (Apple Silicon)
# desktop/release/HuobaoDrama-<버전>.dmg              (Intel)
# desktop/release/HuobaoDrama Setup <버전>.exe        (Windows)

설치 안내:

  • macOS 미서명 패키지는 첫 실행 시 "App이 손상되어 열 수 없습니다"라는 메시지가 뜰 수 있습니다(Apple Silicon에서 흔함). 이는 Gatekeeper 격리 속성 때문이며 파일이 실제로 손상된 것은 아닙니다. 복구 방법은 두 가지입니다:

    1. dmg에 복구 스크립트 포함: 앱을 "응용 프로그램"으로 드래그한 후 dmg 창 하단의 "如提示已损坏请双击我.command"를 더블클릭하면 자동으로 복구됩니다;
    2. 또는 터미널에서 sudo xattr -cr /Applications/HuobaoDrama.app 실행.

    복구는 처음 한 번만 필요하며, 이후에는 정상 실행되고 앱 내 자동 업데이트에도 영향이 없습니다.

  • Windows 미서명 패키지는 SmartScreen에서 「추가 정보 → 실행」 선택

  • 사용자 데이터 디렉터리: ~/Library/Application Support/HuobaoDrama/(데이터베이스, 생성된 미디어, 온라인 편집한 스킬 복사본)

  • FFmpeg/FFprobe 바이너리 내장, 시스템 설치 불필요

  • Electron은 37.x로 고정: better-sqlite3의 win32 프리빌드가 해당 ABI까지만 지원(크로스 패키징 시 컴파일 불필요의 핵심)

  • 앱 내 외부 링크(「api.firemux.com에서 Key 받기」 등)는 시스템 브라우저로 바로 열립니다

🔄 앱 내 업데이트(Apple 서명 불필요)

데스크톱 버전에는 업데이터가 내장되어 있습니다(Tauri와 동류 방식: macOS 디렉터리 교체 / Windows 사일런트 설치, 로컬 sha256 검증). 새 버전 릴리스 절차:

bash
# 1. desktop/package.json의 version을 수정한 후 패키징
npm run dist        # macOS(dmg + 업데이트용 zip 산출)
npm run dist:win    # Windows(Setup.exe 산출)

# 2. 버전 매니페스트 release/latest.json 생성(플랫폼별 sha256 포함)
cd desktop && npm run feed

# 3. 릴리스: latest.json + 설치 패키지 + zip을 GitHub Release에 업로드(태그는 v1.0.1 형식)

설치된 클라이언트는 시작 후 매니페스트를 자동으로 확인하고(「설정 → 정보 및 업데이트」에서 수동 확인도 가능), 새 버전을 발견하면 다운로드 및 설치를 안내합니다. 매니페스트 주소는 HUOBAO_UPDATE_FEED 환경 변수로 변경할 수 있습니다.

데스크톱 버전 개발 디버깅:

bash
npm run build:frontend   # 프런트엔드 정적 산출물(frontend/.output/public)
cd desktop && npm run dev  # 백엔드 번들 후 Electron 창으로 실행

알려진 제한: Seedance 영상 모델이 로컬 참조 리소스를 사용하려면 PUBLIC_BASE_URL 공개 주소가 필요합니다. 데스크톱 버전에는 공개 진입점이 없어 해당 시나리오에서는 명확한 오류 메시지가 표시됩니다. 텍스트→영상/이미지 생성 등 나머지 기능에는 영향이 없습니다.


🏭 서버 배포

bash
# 1. 프런트엔드 빌드
cd frontend && npm run generate

# 2. 빌드 산출물 복사(generate 산출물은 frontend/.output/public, 백엔드는
#    frontend/dist를 읽음. 이 단계를 생략하면 API는 정상이지만 페이지가 404)
cp -r .output/public dist && cd ..

# 3. 백엔드 시작
cd backend && npm start

서버에 업로드할 파일:

text
backend/                    # 백엔드 소스 + node_modules
backend/workspace/skills/   # Agent 스킬 파일
frontend/dist/              # 프런트엔드 빌드 산출물
data/                       # 데이터 디렉터리(최초 실행 시 자동 생성)

Nginx 리버스 프록시

nginx
server {
    listen 80;
    server_name your-domain.com;

    # 참조 영상/오디오 업로드 최대 50MB
    client_max_body_size 100m;

    # 생성된 이미지/영상은 디스크에서 직접 서빙(Node를 거치지 않음):
    # sendfile 제로 카피 + 장기 캐시
    # (파일은 uuid 명명, 내용 불변이므로 immutable 캐시 안전)
    location /static/ {
        alias /path/to/huobao-drama/data/static/;
        sendfile on;
        tcp_nopush on;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location / {
        proxy_pass http://localhost:5679;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

미디어 로딩 최적화: 이미지 생성 시 백엔드가 목록 페이지용 400px 썸네일(*_thumb.webp)을 자동 생성하고, 영상은 포스터 프레임(*_poster.jpg)을 커버로 추출합니다. 프런트엔드는 큰 이미지를 열거나 재생할 때만 원본 파일을 로드합니다. 기존 파일은 backend/에서 npm run backfill-artwork를 실행해 일괄 보완할 수 있습니다.

🐳 Docker 배포(앱 내 업데이트 포함)

방법 A — 사전 빌드 이미지(클론·빌드 불필요): 멀티 아키텍처(linux/amd64 + linux/arm64), x86 서버와 ARM 디바이스 자동 매칭

bash
docker pull huobao/huobao-drama:4.0.6

docker run -d \
  --name huobao-drama \
  -p 5679:5679 \
  -v huobao-data:/app/data \
  --restart unless-stopped \
  huobao/huobao-drama:4.0.6

방법 B — docker compose(소스 빌드 + Watchtower 인앱 업데이트): 저장소 루트에 올인원 Dockerfile(프런트엔드 generate + 백엔드 의존성/런타임 3단계, 백엔드는 서버 배포와 동일하게 tsx로 실행)과 docker-compose.yml(앱 + Watchtower)을 제공합니다:

bash
# 1. 환경 설정(Watchtower 토큰, app과 watchtower 양쪽이 일치해야 함)
cp .env.example .env   # WATCHTOWER_TOKEN 수정

# 2. 빌드 및 시작(릴리스 시 버전을 주입하여 「정보 및 업데이트」 비교에 사용)
HUOBAO_VERSION=4.0.5 docker compose up -d --build

# 3. http://localhost:5679 접속
  • 데이터 영속화: 네임드 볼륨 huobao-data를 /app/data에 마운트(SQLite + 생성된 이미지/영상 + workspace/skills). 이미지 업데이트 시에도 데이터 유지
  • 앱 내 업데이트: compose에 Watchtower 사이드카 포함(--label-enable로 라벨이 지정된 컨테이너만 업데이트, --cleanup으로 구 이미지 정리, 매일 자체 점검). 「설정 → 정보 및 업데이트」에서 새 버전 확인 및 「지금 업데이트」 가능 — 백엔드가 Watchtower HTTP API를 통해 트리거하여 새 이미지를 가져와 컨테이너를 재생성합니다. 몇 분 후 페이지를 새로고침하면 완료
  • 수동 모드: docker-compose.yml에서 app의 HUOBAO_WATCHTOWER_* 환경 변수 2개(또는 watchtower 서비스 전체)를 삭제하면 「정보 및 업데이트」는 새 버전 알림 + 수동 명령 docker compose pull && docker compose up -d으로 전환됩니다
  • 이미지 릴리스: docker buildx build --platform linux/amd64,linux/arm64 --build-arg HUOBAO_VERSION=x.y.z -t huobao/huobao-drama:x.y.z -t huobao/huobao-drama:latest --push .. 버전 매니페스트는 데스크톱 버전과 GitHub Releases의 latest.json을 공유(HUOBAO_UPDATE_FEED로 재정의 가능)

🎨 기술 스택

백엔드

  • 런타임: Node.js 20+
  • 웹 프레임워크: Hono
  • ORM: Drizzle ORM + better-sqlite3(WAL 모드)
  • AI Agent: Mastra + AI SDK(OpenAI 호환)
  • 영상 처리: FFmpeg(fluent-ffmpeg + 내장 바이너리)
  • 이미지 처리: Sharp

데스크톱

  • 셸: Electron(utilityProcess가 백엔드를 호스팅, BrowserWindow는 동일 출처로 로드)
  • 패키징: esbuild(백엔드 단일 파일 번들) + electron-builder(dmg arm64/x64, NSIS win-x64)

프런트엔드

  • 프레임워크: Nuxt 3(SPA 모드)
  • 언어: Vue 3 + TypeScript
  • 라우팅: 파일 라우팅(Vue Router 4)
  • 스타일: 순수 CSS + CSS Variables
  • 아이콘: Lucide Vue
  • i18n: vue-i18n(中文 / English / 日本語 / 한국어)

📝 자주 묻는 질문

Q: 데스크톱 버전의 데이터는 어디에 저장되나요?

A: ~/Library/Application Support/HuobaoDrama/data/(SQLite 데이터베이스 + 생성된 이미지/영상)에 저장되며, 온라인 편집한 스킬의 복사본은 같은 수준의 workspace/ 디렉터리에 있습니다. 개발 모드에서는 저장소의 data/ 디렉터리를 사용합니다.

Q: 구버전 MySQL 데이터를 SQLite로 마이그레이션하려면?

A: MySQL에 연결 가능한 상태(환경 변수 또는 backend/.env)를 유지하고 cd backend && npx tsx scripts/import-mysql-to-sqlite.ts를 실행하세요. 스크립트가 자동으로 테이블을 생성하고 테이블별로 가져오며 행 수를 검증합니다(대상 DB가 비어 있지 않으면 --force 필요, 쓰기 전 자동 백업).

Q: FFmpeg가 설치되지 않았거나 찾을 수 없다고 나옵니다?

A: 설치할 필요가 없습니다. 프로젝트에 ffmpeg-static / ffprobe-static 바이너리가 내장되어 있습니다(데스크톱 버전에도 포함). 시스템 PATH의 FFmpeg와 충돌하지 않으며, FFMPEG_BIN/FFPROBE_BIN으로 명시적으로 지정할 수도 있습니다.

Q: 페이지 상단에 「모델 미설정」이 표시됩니다?

A: 정상적인 첫 배포 안내입니다. 「설정」 페이지에서 「火宝快捷 설정」에 API Key를 붙여넣어 한 번에 입력하거나, 「수동 템플릿」으로 프로바이더를 추가하세요. 텍스트, 이미지, 영상 3가지 모두에 활성화된 설정이 있으면 배너가 자동으로 사라집니다.

Q: 프런트엔드가 백엔드 API에 연결되지 않습니다?

A: 백엔드가 시작되었는지, 포트가 올바른지 확인하세요. 개발 모드의 프록시 설정은 frontend/nuxt.config.ts에 있습니다.

Q: 데이터베이스 테이블이 생성되지 않았습니다?

A: 백엔드는 최초 시작 시 모든 테이블을 자동으로 생성합니다. 로그에서 초기화 성공 여부를 확인하세요.


📋 업데이트 로그

v4.0.0 (2026-08)

🖥️ 데스크톱 앱 + 데이터베이스 마이그레이션

  • Electron 데스크톱 버전(macOS dmg, arm64/x64 듀얼 아키텍처)
    • 더블클릭 설치, 즉시 사용: 자동 포트 선택, 단일 인스턴스 잠금, 충돌 분리된 백엔드 서브프로세스
    • 사용자 데이터 분리: SQLite DB / 생성된 미디어 / 스킬 복사본 모두 userData 디렉터리에 저장
    • FFmpeg/FFprobe 포함 배포. workspace 스킬 템플릿은 첫 시작 시 복사, 업그레이드 시 누락분만 보충하고 덮어쓰지 않음
  • 데이터베이스를 MySQL에서 SQLite로 완전 마이그레이션(better-sqlite3 + WAL)
    • 비즈니스 코드 변경 제로(Drizzle 쿼리 계층은 본질적으로 이식 가능), 멱등 DDL 재생
    • 1회용 가져오기 스크립트 import-mysql-to-sqlite.ts 추가(테이블별 행 수 검증 + 자동 백업)
  • 백엔드 esbuild 단일 파일 번들(externals: sharp/better-sqlite3/ffmpeg 바이너리 패키지)
  • Docker/MySQL 배포 방식 제거(git 히스토리에서 복구 가능)

v3.1.0 (2026-09)

  • Alibaba Bailian Wan 3.0 동영상 모델 추가(Prime / 표준, 공식 input.media/parameters 파라미터 지원)
  • 작업대 상단 바에 해상도 선택기 추가, 제공사별 네이티브 단계 표시(Seedance 480p/720p, MiniMax 768P/2K, Wan 480P/720P/1080P)
  • 기본 동영상 모델을 Seedance 2.0 Mini로 변경
  • 동영상 모델 전환 시 제공사/모델 불일치로 인한 생성 오류 수정
  • 배치 동영상: 선택 모드 + 생성 전 확인(숏 수/총 길이/모델/해상도), 실패 작업 원클릭 재시도
  • 스토리보드 길이를 동영상 생성 파라미터 영역에서 직접 편집·저장, 단건/배치 생성에 통일 적용
  • 실사/민감 콘텐츠 심사 실패 시 모델 전환 후 재시도 안내

v3.0.0 (2026-08)

🚀 배포 및 경험 최적화

  • Docker 배포 준비 개선
    • MySQL / 앱 헬스 체크, 데이터베이스 준비 후 앱 시작
    • 데이터베이스 초기화에 재시도 추가, 컨테이너 오케스트레이션에서 첫 배포 무인 완료
    • 시스템 FFmpeg 의존 제거, 내장 바이너리로 전면 전환
    • Agent skills 디렉터리 볼륨 영속화(설정 페이지 온라인 편집 유실 방지)
    • docker/init.sql 및 납출 스크립트 추가(DBA 검토 / 사전 테이블 생성)
  • 첫 사용 가이드
    • AI 서비스 미설정 시 사이트 상단 배너로 설정 페이지 안내
    • 설정 페이지에 「火宝快捷 설정」 추가: Key 하나로 텍스트/이미지/영상 추천 설정 3개 입력
    • 모델 미설정 오류의 중국어화 및 설정 페이지 안내
  • 영상 모델 기본값을 Seedance 2.0 Fast로 조정
  • 프로바이더 통합: OpenAI / Gemini / Volcano Engine만 유지
  • 워크벤치: 작업 목록 드로어, 파이프라인 대섹션 상태, 선택적 병합(병합 전 영상 파일 존재 검증)
  • 소재 라이브러리 개편, @멘션 최적화, 에피소드 목록 재구성

v2.0.0 (2026-04)

🚀 대규모 업데이트

  • 프로젝트를 TypeScript 기술 스택으로 전면 마이그레이션
    • 백엔드: Hono + Drizzle ORM + mysql2
    • 프런트엔드: Nuxt 3 + Vue 3
    • AI Agent: Mastra 프레임워크
  • 에피소드 워크벤치 UI와 제작 플로우 재구축
    • 더 컴팩트한 콘솔 레이아웃
    • 스토리보드 편집 영역 재구축
    • 샷 이미지, 영상, 합성, 납출 화면 재구축
  • Docker 배포 지원 추가, 프런트엔드와 백엔드를 단일 이미지로 통합
  • 런타임 Skill 로딩 메커니즘 추가
  • 멀티 프로바이더 미디어 어댑터 확장
    • 이미지: OpenAI, Gemini, Volcano Engine, Alibaba
    • 영상: Volcano Engine/Seedance, Vidu, Alibaba
  • 로컬 파일 처리 및 참조 이미지 온디맨드 트랜스코딩 최적화

v1.0.4 (2026-01-27)

  • 로컬 스토리지 전략 도입으로 외부 리소스 링크 실효 회피
  • Base64 참조 이미지 임베디드 전송
  • 샷 전환 상태 리셋 문제 수정
  • 장면의 챕터 마이그레이션 추가

v1.0.3 (2026-01-16)

  • 데이터베이스 동시 접근 성능 최적화
  • Docker 크로스 플랫폼 host.docker.internal 지원

v1.0.2 (2026-01-14)

  • 영상 생성 API 응답 파싱 문제 수정
  • OpenAI Sora 영상 엔드포인트 설정 추가
  • 오류 처리 및 로그 출력 최적화

📄 라이선스

이 프로젝트는 CC BY-NC-SA 4.0(저작자표시-비영리-동일조걳경변경허락 4.0 국제) 라이선스를 채택하고 있습니다.

  • ✅ 개인 사용, 학습·연구, 비영리 프로젝트는 자유롭게 사용 가능
  • ✅ 수정 및 재배포 가능, 단 저작자 표시와 동일 라이선스로 공유 필요
  • ❌ 상업적 사용 금지 — 저작자의 서면 허가 없이 이 프로젝트의 전부 또는 일부를 어떠한 상업적 목적(유료 서비스, 상업 배포, 재판매 등)으로도 사용할 수 없습니다

라이선스 전문은 LICENSE를 참조하세요.


🤝 기여 가이드

Issue와 Pull Request를 환영합니다!

  1. 이 프로젝트를 Fork
  2. 기능 브랜치 생성(git checkout -b feature/AmazingFeature)
  3. 변경 사항 커밋(git commit -m 'Add some AmazingFeature')
  4. 브랜치 푸시(git push origin feature/AmazingFeature)
  5. Pull Request 생성

자주 쓰는 검사 명령:

bash
cd backend && npm run typecheck
cd ../frontend && npm run build

☕ 후원하기

이 프로젝트가 도움이 되었다면, QR 코드로 저작자에게 커피 한 잔을 사주세요 ☕. 여러분의 응원이 지속적인 업데이트의 원동력입니다!


💬 WeChat 그룹

QR 코드를 스캔하여 WeChat 그룹에 참여하세요:


"AI가 더 창의적인 일을 돕게 하자"

🔗 관련 링크

이 프로젝트는 LINUX DO 커뮤니티의 링크 승인을 받았습니다.

  • LINUX DO — 진정한 오픈소스 정신, 함께 만들고 공유하는 기술 커뮤니티


File: README.md

🎬 Huobao Drama - AI Short Drama Generation Platform


📖 Overview

Huobao Drama is an AI-powered short-drama production platform that automates the entire pipeline: script generation, character design, storyboard breakdown, and video compositing.

🎯 Core Value

  • 🤖 AI-Driven: LLMs parse scripts and extract characters, scenes, and storyboard information
  • 🎨 Intelligent Creation: AI image generation for character designs and scene backgrounds
  • 📹 Video Generation: Text-to-video and image-to-video models automatically produce storyboard clips
  • 🔄 End-to-End Workflow: A complete pipeline from idea to finished episode

🛠️ Architecture

text
frontend/   — Nuxt 3 + Vue 3 + TypeScript (pure CSS, no UI framework)
backend/    — Hono + Drizzle ORM + Mastra AI Agents + better-sqlite3
backend/workspace/skills/ — Agent skill definitions (SKILL.md, editable in the UI)
desktop/    — Electron desktop app (main process + esbuild + electron-builder dmg/exe)
data/       — Generated assets and the SQLite database

✨ Features

🎭 Character Management

  • ✅ AI-generated character designs
  • ✅ Batch character generation
  • ✅ Character image upload and management

🎬 Video Tasks

  • ✅ Automatic AI video-task generation
  • ✅ Scene descriptions and video prompt generation
  • ✅ Batch video generation per task

🎥 Video Generation

  • ✅ Text-to-video generation
  • ✅ FFmpeg per-shot compositing and subtitle handling
  • ✅ Full-episode stitching and export

📦 Asset Management

  • ✅ Unified asset library
  • ✅ Local storage support
  • ✅ Task progress tracking

🤖 AI Agents

Four built-in Mastra agents with database-backed configuration and Skill extensions:

Agent Role
script_rewriter Novel → formatted script rewriting
extractor Intelligent extraction and dedup of characters / scenes / props
storyboard_breaker Script → storyboard sequence breakdown
prompt_generator Image prompts for characters/scenes/props + storyboard video prompts

🌐 Multi-Language UI

The interface ships in 中文 / English / 日本語 / 한국어, with a global setting for AI-generated content language.

🔌 Multi-Provider Support

Type Providers
Text OpenAI (compatible APIs), Gemini
Image OpenAI, Gemini, Volcano Engine
Video Volcano Engine Seedance 2.0 (Standard / Fast / Mini), MiniMax H3, Alibaba Bailian Wan 3.0 (Prime / Standard)

🚀 Quick Start

📋 Requirements

Software Version Notes
Node.js 20+ Runtime for frontend and backend
npm 9+ Package manager

Zero-install database: Bundled SQLite (single file in the project data directory) — no database server required.
No FFmpeg install needed: Binaries ship via the ffmpeg-static / ffprobe-static npm packages — works out of the box.

⚙️ Environment Variables

No config files — everything is set via environment variables (all have defaults; local dev needs zero configuration):

Variable Default Description
SQLITE_PATH <repo>/data/huobao.sqlite3 SQLite database file location
PORT 5679 Backend service port
STORAGE_PATH <repo>/data/static Generated-file storage directory
HUOBAO_DATA_DIR — Injected by the Electron main process (userData data root)
WORKSPACE_PATH backend/workspace Agent skills/prompts directory (desktop: writable copy under userData)
FRONTEND_DIST frontend/dist Frontend static build directory
FFMPEG_BIN / FFPROBE_BIN bundled npm binaries Custom ffmpeg/ffprobe executable paths
PUBLIC_BASE_URL — Public URL Seedance needs to reference local assets (server deployments)

Note: AI service API keys, base URLs, and model parameters are all configured in the web UI "Settings" page and stored in the database — never in config files or environment variables.

📥 Installation

bash
# Clone the repository
git clone https://github.com/chatfire-AI/huobao-drama.git
cd huobao-drama

# Install backend dependencies
cd backend && npm install

# Install frontend dependencies
cd ../frontend && npm install

🎯 Running

Frontend and backend run separately with hot reload:

bash
# Terminal 1: backend
cd backend
npm run dev

# Terminal 2: frontend
cd frontend
npm run dev
  • Frontend: http://localhost:3013
  • Backend API: http://localhost:5679/api/v1
  • The frontend automatically proxies /api and /static to the backend

Option 2: Single-service mode

The backend serves both the API and the frontend static files:

bash
# 1. Build the frontend
cd frontend && npm run generate

# 2. Copy the build output where the backend expects it
#    (generate outputs to .output/public; the backend reads frontend/dist)
cp -r .output/public dist

# 3. Start the backend
cd ../backend && npm start

Visit: http://localhost:5679

🗄️ Database

Bundled SQLite (better-sqlite3 + WAL mode). Tables are created automatically on first launch (idempotent DDL replay + seed data). Default file: data/huobao.sqlite3, overridable via SQLITE_PATH. The desktop app stores data in the user-data directory (~/Library/Application Support/HuobaoDrama/data/).

Migrating data from a legacy MySQL deployment:

Automatic migration on startup (recommended): When MySQL is explicitly configured (DATABASE_URL or MYSQL_HOST) and the SQLite database is empty, the backend automatically detects and imports all tables once (per-table row-count validation, single-transaction atomic writes, automatic rollback with retry on next launch, and a .mysql-imported marker to avoid re-importing). Set MYSQL_AUTO_IMPORT=false to disable.

bash
# Or run manually (non-empty target requires --force; automatic backup before writing)
cd backend && npx tsx scripts/import-mysql-to-sqlite.ts

Migration covers database rows only; media files (images/videos) under the old deployment's data/static/ must be copied manually, or historical assets won't load.

🔑 First Use: Configure AI Services

All AI features (text/image/video) require model services to be configured first — a banner at the top of the page guides you until then:

  1. Open the "Settings" page
  2. Paste your Huobao API key in "Huobao Quick Setup" (get one at api.firemux.com) to write three recommended configs (text, image, video) in one click
  3. Or add providers one by one via "Manual Templates", with connectivity testing

Once configured, the banner disappears and you can start producing episodes.


📖 Visual Walkthrough

The complete pipeline from novel to finished episode. The left progress rail always shows where you are.

Step 1 · Create a Project

On the home page click "New Project", pick a aspect ratio (16:9 landscape / 9:16 portrait, fixed after creation) and a visual style (3D, realistic, … — injected into every image prompt).

Step 2 · Configure AI Services (first run)

Paste an API key in Settings → "Huobao Quick Setup" to write the three recommended configs at once, or add providers manually. The current model can be switched any time from the top bar (see Step 5).

Step 3 · Script Stage

Paste your source novel into the workbench, then hit "AI Rewrite" to produce a shooting script — split by episode with scenes and characters annotated. You can switch text models and tone while rewriting.

Step 4 · Assets

Run extraction on the script to get the character / scene / prop list, then generate a consistent reference image for each (or in batch). These images are injected as reference material when generating videos.

Step 5 · Storyboard & Videos

On the "Video Production" page, first run storyboard breakdown (AI splits shots and writes video prompts). Then:

  • Pick the video model in the top bar (Seedance / Wan 3.0 / MiniMax…); resolution and duration tiers follow the model
  • Review and tweak each shot's prompt on the right (@character references map to reference images automatically)
  • Click "Batch Generate Videos"; failed tasks can be retried in one click

Step 6 · Merge & Export

Select shots (hover to preview each clip), click "Start Merging" and FFmpeg assembles the full episode — play online or download. Click "Mark Done" when finished to light up the progress rail.

The episode list shows the production status of every episode — click "Enter Studio" to continue:


📦 Deployment

⬇️ Prebuilt installers: GitHub Releases · Mirror for China (Tencent COS)

Platform File to download
macOS (Apple Silicon, M-series) HuobaoDrama-4.0.5-arm64.dmg
macOS (Intel) HuobaoDrama-4.0.5.dmg
Windows HuobaoDrama.Setup.4.0.5.exe

China users: use the COS mirror above (GitHub is slow/unreachable in mainland China). The in-app updater also checks the COS mirror first, then falls back to GitHub.

Command-line install (recommended, no Gatekeeper fix needed): downloading via curl never sets macOS's quarantine attribute, so the app opens cleanly with no "damaged" prompt (use the -arm64.dmg for Apple Silicon, the plain dmg for Intel):

bash
curl -L -o /tmp/HuobaoDrama.dmg https://installer.chatfire.site/huobao-drama/v4.0.5/HuobaoDrama-4.0.5-arm64.dmg \
  && hdiutil attach -nobrowse /tmp/HuobaoDrama.dmg \
  && cp -R /Volumes/HuobaoDrama*/HuobaoDrama.app /Applications/ \
  && hdiutil detach /Volumes/HuobaoDrama*

No build required — download the dmg/exe and install. Installed clients auto-update via the built-in updater. (To package from source instead, see the commands below.)

Double-click to install, works out of the box (macOS + Windows): the SQLite database, generated media, and Agent skills all live in the user-data directory — uninstalling the app does not affect your data.

bash
# One-command packaging (frontend generate → backend esbuild → electron-builder)
npm run dist        # macOS dmg (arm64 + Intel)
npm run dist:win    # Windows NSIS installer (win-x64, cross-buildable on macOS)

# Artifacts
# desktop/release/HuobaoDrama-<version>-arm64.dmg     (Apple Silicon)
# desktop/release/HuobaoDrama-<version>.dmg           (Intel)
# desktop/release/HuobaoDrama Setup <version>.exe     (Windows)

Installation notes:

  • The macOS build is unsigned — on first launch you may see "App is damaged and can't be opened" (common on Apple Silicon). This is Gatekeeper's quarantine attribute, not actual file damage. Two ways to fix it:

    1. The dmg bundles a fix script: after dragging the app into Applications, double-click the "如提示已损坏请双击我.command" script at the bottom of the dmg window — it removes the quarantine attribute automatically;
    2. Or run sudo xattr -cr /Applications/HuobaoDrama.app in Terminal.

    The fix is one-time only — the app then launches normally, and in-app auto-updates are not affected.

  • The Windows build is unsigned — SmartScreen will prompt "More info → Run anyway"

  • User-data directory: ~/Library/Application Support/HuobaoDrama/ (database, generated media, writable copies of online-edited skills)

  • FFmpeg/FFprobe binaries are bundled — no system install needed

  • Electron is pinned to 37.x: better-sqlite3's win32 prebuilds max out at that ABI (the key to compilation-free cross-packaging)

  • External links open in the system browser (e.g. "Get a key at api.firemux.com")

🔄 In-App Updates (no Apple signing required)

The desktop app ships with a built-in updater (same class of solution as Tauri: directory replacement on macOS / silent installer on Windows, with local sha256 verification). To publish a new release:

bash
# 1. Bump version in desktop/package.json, then package
npm run dist        # macOS (produces dmg + update zip)
npm run dist:win    # Windows (produces Setup.exe)

# 2. Generate the release manifest release/latest.json (with per-platform sha256)
cd desktop && npm run feed

# 3. Publish: upload latest.json + installers + zips to a GitHub Release (tag like v1.0.1)

Installed clients check the manifest automatically after launch (manual check available in "Settings → About & Updates") and prompt to download and install when a new version is found. Override the manifest URL with the HUOBAO_UPDATE_FEED environment variable.

Desktop development:

bash
npm run build:frontend   # frontend static output (frontend/.output/public)
cd desktop && npm run dev  # bundle the backend and run in an Electron window

Known limitation: Seedance video models need a PUBLIC_BASE_URL public address to reference local assets; the desktop app has no public entry point, so that scenario produces a clear error message. Text-to-video, image generation, and all other capabilities are unaffected.


🏭 Server Deployment

bash
# 1. Build the frontend
cd frontend && npm run generate

# 2. Copy the build output (generate outputs to frontend/.output/public; the backend reads
#    frontend/dist — skip this step and the API works but pages 404)
cp -r .output/public dist && cd ..

# 3. Start the backend
cd backend && npm start

Files to upload to the server:

text
backend/                    # backend source + node_modules
backend/workspace/skills/   # Agent skill files
frontend/dist/              # frontend build output
data/                       # data directory (auto-created on first run)

Nginx Reverse Proxy

nginx
server {
    listen 80;
    server_name your-domain.com;

    # Max 50MB for reference video/audio uploads
    client_max_body_size 100m;

    # Generated images/videos served straight from disk, bypassing Node:
    # sendfile zero-copy + long-lived caching
    # (files are uuid-named and immutable, so immutable caching is safe)
    location /static/ {
        alias /path/to/huobao-drama/data/static/;
        sendfile on;
        tcp_nopush on;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location / {
        proxy_pass http://localhost:5679;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Media loading optimization: the backend automatically generates 400px thumbnails (*_thumb.webp) for list pages and extracts poster frames (*_poster.jpg) as video covers — the frontend only loads original files when opening the full image or playing. To backfill historical files, run npm run backfill-artwork under backend/.

🐳 Docker Deployment (with in-app updates)

Option A — prebuilt image (no clone, no build): multi-arch (linux/amd64 + linux/arm64), x86 servers and ARM devices match automatically

bash
docker pull huobao/huobao-drama:4.0.6

docker run -d \
  --name huobao-drama \
  -p 5679:5679 \
  -v huobao-data:/app/data \
  --restart unless-stopped \
  huobao/huobao-drama:4.0.6

Option B — docker compose (source build + Watchtower in-app updates): the repo root provides an all-in-one Dockerfile (three stages: frontend generate + backend dependencies + runtime; the backend runs via tsx just like server deployment) and docker-compose.yml (app + Watchtower):

bash
# 1. Configure the environment (Watchtower token — must match on the app and watchtower sides)
cp .env.example .env   # edit WATCHTOWER_TOKEN

# 2. Build and start (inject a version at publish time for "About & Updates" comparison)
HUOBAO_VERSION=4.0.5 docker compose up -d --build

# 3. Visit http://localhost:5679
  • Data persistence: the named volume huobao-data mounts /app/data (SQLite + generated images/videos + workspace/skills) — image updates don't lose data
  • In-app updates: the compose file ships a Watchtower sidecar (--label-enable only updates labeled containers, --cleanup removes old images, daily self-check). "Settings → About & Updates" can check for new versions and "Update Now" — the backend triggers it via the Watchtower HTTP API, which pulls the new image and rebuilds the container; refresh the page after a few minutes
  • Manual mode: remove the app's two HUOBAO_WATCHTOWER_* env vars (or the whole watchtower service) from docker-compose.yml — "About & Updates" then degrades to a new-version notice + manual docker compose pull && docker compose up -d
  • Publishing images: docker buildx build --platform linux/amd64,linux/arm64 --build-arg HUOBAO_VERSION=x.y.z -t huobao/huobao-drama:x.y.z -t huobao/huobao-drama:latest --push . — the version manifest is shared with the desktop app via latest.json on GitHub Releases (overridable with HUOBAO_UPDATE_FEED)

🎨 Tech Stack

Backend

  • Runtime: Node.js 20+
  • Web framework: Hono
  • ORM: Drizzle ORM + better-sqlite3 (WAL mode)
  • AI Agents: Mastra + AI SDK (OpenAI compatible)
  • Video processing: FFmpeg (fluent-ffmpeg + bundled binaries)
  • Image processing: Sharp

Desktop

  • Shell: Electron (utilityProcess hosts the backend; BrowserWindow loads same-origin)
  • Packaging: esbuild (single-file backend bundle) + electron-builder (dmg arm64/x64, NSIS win-x64)

Frontend

  • Framework: Nuxt 3 (SPA mode)
  • Language: Vue 3 + TypeScript
  • Routing: File-based routing (Vue Router 4)
  • Styling: Pure CSS + CSS Variables
  • Icons: Lucide Vue
  • i18n: vue-i18n (中文 / English / 日本語 / 한국어)

📝 FAQ

Q: Where does the desktop app store data?

A: ~/Library/Application Support/HuobaoDrama/data/ (SQLite database + generated images/videos); writable copies of online-edited skills live in the sibling workspace/ directory. In development mode the repo's data/ directory is used instead.

Q: How do I migrate legacy MySQL data to SQLite?

A: Keep MySQL reachable (environment variables or backend/.env), then run cd backend && npx tsx scripts/import-mysql-to-sqlite.ts. The script creates tables automatically, imports table-by-table, and validates row counts (non-empty targets require --force; a backup is made before writing).

Q: FFmpeg not installed or not found?

A: No install needed. The project bundles ffmpeg-static / ffprobe-static binaries (carried along in the desktop package). A system PATH FFmpeg won't conflict either, and you can point explicitly via FFMPEG_BIN/FFPROBE_BIN.

Q: The top of the page says "No model configured"?

A: That's the normal first-deploy guidance. Go to "Settings" and use "Huobao Quick Setup" to paste an API key and write configs in one click, or add providers via "Manual Templates". The banner disappears once text, image, and video all have an enabled config.

Q: The frontend can't reach the backend API?

A: Check that the backend is running and the port is correct. In dev mode the proxy config lives in frontend/nuxt.config.ts.

Q: Database tables not created?

A: The backend creates all tables automatically on first launch — check the logs to confirm initialization succeeded.


📋 Changelog

v4.0.0 (2026-08)

🖥️ Desktop App + Database Migration

  • Electron desktop app (macOS dmg, arm64/x64 dual architecture)
    • Double-click install, works out of the box: automatic port selection, single-instance lock, crash-isolated backend subprocess
    • User-data isolation: SQLite database / generated media / skill copies all live in the userData directory
    • FFmpeg/FFprobe bundled; workspace skill templates copied on first launch, upgrades only fill gaps without overwriting
  • Database fully migrated from MySQL to SQLite (better-sqlite3 + WAL)
    • Zero business-code changes (the Drizzle query layer is naturally portable); idempotent DDL replay
    • New one-shot import script import-mysql-to-sqlite.ts (per-table row-count validation + automatic backup)
  • Backend bundled to a single file with esbuild (externals: sharp/better-sqlite3/ffmpeg binary packages)
  • Removed Docker/MySQL deployment (recoverable from git history)

v3.1.0 (2026-09)

  • Added Alibaba Bailian Wan 3.0 video models (Prime / Standard, official input.media/parameters payloads)
  • Resolution selector in the workbench top bar with native tiers per provider (Seedance 480p/720p, MiniMax 768P/2K, Wan 480P/720P/1080P)
  • Default video model changed to Seedance 2.0 Mini
  • Fixed generation errors caused by provider/model mismatch when switching video models
  • Batch video: selection mode + pre-generation confirmation (shot count / total duration / model / resolution), one-click retry for failed tasks
  • Storyboard duration now editable directly in the video-generation params area, applied to single and batch generation
  • Content-moderation failures (real-person / sensitive content) now prompt to switch models and retry

v3.0.0 (2026-08)

🚀 Deployment & Experience Improvements

  • Docker deployment readiness
    • MySQL / app health checks; the app waits for the database before starting
    • Database initialization retries — zero manual intervention on first containerized deploy
    • Removed the system FFmpeg dependency; bundled binaries everywhere
    • Agent skills directory volume persistence (online edits in Settings survive)
    • New docker/init.sql and export scripts (DBA review / pre-created tables)
  • First-use guidance
    • Site-wide banner guiding to Settings when no AI service is configured
    • New "Huobao Quick Setup" in Settings: one key writes three recommended configs (text/image/video)
    • Unconfigured-model errors localized with pointers to Settings
  • Default video model changed to Seedance 2.0 Fast
  • Provider consolidation: OpenAI / Gemini / Volcano Engine only
  • Workbench: task-list drawer, pipeline stage status, selective stitching (validates video files exist before merging)
  • Asset library redesign, @mention improvements, episode list rework

v2.0.0 (2026-04)

🚀 Major Update

  • Full migration to a TypeScript stack
    • Backend: Hono + Drizzle ORM + mysql2
    • Frontend: Nuxt 3 + Vue 3
    • AI Agents: Mastra framework
  • Episode workbench UI and production flow rebuilt
    • More compact console layout
    • Storyboard editing area rebuilt
    • Shot image, video, compositing, and export screens rebuilt
  • Docker deployment support — frontend and backend merged into a single image
  • Runtime Skill loading mechanism
  • Expanded multi-provider media adapters
    • Image: OpenAI, Gemini, Volcano Engine, Alibaba
    • Video: Volcano Engine/Seedance, Vidu, Alibaba
  • Improved local file handling and on-demand reference-image transcoding

v1.0.4 (2026-01-27)

  • Local storage strategy to avoid dead external asset links
  • Base64 reference-image embedded transport
  • Fixed shot-switch state reset
  • Scene migration to chapters

v1.0.3 (2026-01-16)

  • Database concurrency performance improvements
  • Docker cross-platform support for host.docker.internal

v1.0.2 (2026-01-14)

  • Fixed video-generation API response parsing
  • OpenAI Sora video endpoint configuration
  • Improved error handling and logging

📄 License

This project is licensed under CC BY-NC-SA 4.0 (Attribution-NonCommercial-ShareAlike 4.0 International).

  • ✅ Personal use, learning, and non-commercial projects are welcome
  • ✅ Modifications and redistribution allowed under the same license with attribution
  • ❌ Commercial use is prohibited — you may not use this project, in whole or in part, for any commercial purpose (including paid services, commercial deployments, or resale) without prior written permission from the author

Full license text: see LICENSE.


🤝 Contributing

Issues and Pull Requests are welcome!

  1. Fork the project
  2. Create a feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Common checks:

bash
cd backend && npm run typecheck
cd ../frontend && npm run build

If this project helps you, buy the author a coffee ☕ — your support keeps the updates coming!


💬 WeChat Group

Scan the QR code to join the WeChat group:


"Let AI do the creating with us"

This project has been recognized with a link from the LINUX DO community.

  • LINUX DO — a genuine open-source spirit, a community built on sharing

Star History


File: README.zh-CN.md

[Binary file]


File: CLAUDE.md

CLAUDE.md

Project Overview

火宝短剧(Huobao Drama)— AI 短剧/漫剧一站式制作工具。全 TypeScript 栈:小说 → 剧本改写 → 资产提取 → 生图 → 分镜拆解 → 生视频 → FFmpeg 拼接导出。支持 Electron 桌面版(macOS dmg)与服务器部署。

Structure

text
backend/   — Hono + Drizzle ORM (better-sqlite3) + Mastra (AI agents)
backend/workspace/ — Agent 工作目录(Mastra Workspace jail 根)
backend/workspace/skills/ — Agent SKILL.md definitions(设置页可在线编辑)
frontend/  — Nuxt 3 + Vue 3 + TypeScript,ssr:false(纯 CSS,无 UI 框架)
desktop/   — Electron 桌面版:主进程 + esbuild 打包脚本 + electron-builder 配置
data/      — SQLite 数据库(huobao.sqlite3)+ 生成的静态文件(static/)
configs/   — 遗留死配置,代码零引用

Commands

Backend (`backend/`)

  • npm run dev — tsx watch 开发服务(端口 5679)
  • npm start — tsx 生产启动
  • npm run typecheck — TypeScript 类型检查
  • npm run backfill-artwork — 存量图片/视频补缩略图与海报帧

Frontend (`frontend/`)

  • npm run dev — Vite 开发服务(端口 3013,代理 /api 与 /static 到 5679)
  • npm run generate — 产出含 index.html 的静态站点(.output/public;nuxt build 不产 index.html,不能用于静态托管)

Desktop (`desktop/`,根目录 `npm run dist` 串联全流程)

  • npm run dev — 打包后端 bundle + Electron 窗口运行
  • npm run build:backend — esbuild 打包 backend/src → build/backend.mjs(ESM;externals: sharp/better-sqlite3/ffmpeg-static/ffprobe-static)
  • npm run build:main — 打包主进程 → dist/main.js
  • npm run rebuild:native — better-sqlite3 按 Electron ABI 重编(原生模块 ABI 变化后必须执行;postinstall 已自动做)
  • npm run dist — prepare-resources + electron-builder 出 arm64/x64 dmg → release/
  • npm run dist:win — 交叉打包 Windows NSIS 安装器(win-x64);win 版 ffmpeg.exe 缓存在 build/win-bin/(缺失时脚本提示下载地址)

Architecture

Backend

  • HTTP: Hono(入口 src/index.ts),路由挂 /api/v1,/static 服务 DATA_ROOT,生产托管前端静态目录
  • Database: SQLite(better-sqlite3 + WAL),SQLITE_PATH 覆盖库文件位置;DDL 在 src/db/sqlite-schema.ts,启动时幂等重放;Drizzle 表定义 src/db/schema.ts(sqlite-core)
  • 路径锚点: src/utils/paths.ts 统一解析 DATA_ROOT/STORAGE_ROOT;桌面版由 Electron 主进程注入 env(HUOBAO_DATA_DIR/SQLITE_PATH/WORKSPACE_PATH/FRONTEND_DIST/FFMPEG_BIN/FFPROBE_BIN),dev 走仓库相对路径默认值
  • AI Agents: Mastra,4 个 agent(script_rewriter / extractor / storyboard_breaker / prompt_generator),instructions 从 workspace/prompts/*.md + skills 动态拼接,模型按请求解析;fetch 补丁链适配国内中转站(关思考/温度/max_tokens)
  • 媒体生成: services/generation.ts 统一任务生命周期(sys_task 表),适配器模式:图片 openai/gemini/volcengine,视频 volcengine/minimax
  • 视频拼接: services/ffmpeg-merge.ts,FFmpeg 二进制内置(ffmpeg-static),可用 FFMPEG_BIN/FFPROBE_BIN 覆盖

Frontend

  • Nuxt 3 SPA,动态路由在 nuxt.config.ts 的 pages:extend 手动注册(views/drama/)
  • app/composables/useApi.ts 统一 fetch 客户端(全相对路径,生产与后端同源)
  • 核心工作台 app/views/drama/episode.vue(剧本→制作→导出流水线)

Desktop

  • 主进程 desktop/src/main.ts:单实例锁 → 空闲端口 → userData 准备(workspace 模板 copy-once + .template-version 版本标记)→ utilityProcess.fork 后端 → 轮询 health → BrowserWindow
  • userData:打包版 ~/Library/Application Support/HuobaoDrama/,dev 版 HuobaoDrama-Dev/(互不干扰)
  • 后端 bundle 在 asar 内(externals 经 asar node_modules 解析,.node 自动重定向 unpacked)

Database

SQLite 单文件(默认 data/huobao.sqlite3,桌面版在 userData)。启动时 initSqliteSchema 幂等建表 + 风格预设种子。MySQL→SQLite 一次性迁移:cd backend && npx tsx scripts/import-mysql-to-sqlite.ts [--force](逐表行数校验、写前备份)。

Key Config

  • AI 服务配置存 DB(ai_service_configs 表),设置页维护,不在配置文件
  • 环境变量全集见 README「环境变量」;configs/config.yaml 是死配置(勿参考)
  • PUBLIC_BASE_URL:Seedance 引用本地参考资源需公网地址,桌面版无此能力(有中文报错)

File: docker-compose.yml

[Binary file]


File: package.json

{
"name": "huobao-drama",
"version": "1.0.0",
"private": true,
"description": "火宝短剧 — AI 短剧制作工具(桌面版编排入口)",
"scripts": {
"dev:backend": "cd backend && npm run dev",
"dev:frontend": "cd frontend && npm run dev",
"dev:desktop": "cd desktop && npm run dev",
"build:frontend": "cd frontend && npm run generate",
"dist": "cd desktop && npm run dist"
}
}


File: backend/package.json

{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "src/index.ts",
"scripts": {
"dev": "tsx watch src/index.ts",
"start": "tsx src/index.ts",
"build": "tsc",
"typecheck": "tsc --noEmit",
"backfill-artwork": "tsx scripts/backfill-artwork.ts"
},
"keywords": [],
"author": "",
"license": "CC BY-NC-SA-4.0",
"type": "module",
"dependencies": {
"@ai-sdk/google": "^3.0.53",
"@ai-sdk/openai": "^3.0.48",
"@hono/node-server": "^1.19.11",
"@mastra/core": "^1.17.0",
"better-sqlite3": "^12.4.1",
"dotenv": "^17.4.2",
"drizzle-orm": "^0.45.1",
"ffmpeg-static": "^5.3.0",
"ffprobe-static": "^3.1.0",
"fluent-ffmpeg": "^2.1.3",
"hono": "^4.12.9",
"pino": "^10.3.1",
"sharp": "^0.34.5",
"uuid": "^13.0.0",
"zod": "^4.3.6"
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.13",
"@types/fluent-ffmpeg": "^2.1.28",
"@types/node": "^25.5.0",
"@types/uuid": "^10.0.0",
"drizzle-kit": "^0.31.10",
"mysql2": "^3.22.5",
"tsx": "^4.21.0",
"typescript": "^6.0.2"
},
"pnpm": {
"onlyBuiltDependencies": [
"ffmpeg-static",
"ffprobe-static"
]
}
}


File: backend/tsconfig.json

{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true,
"outDir": "dist",
"rootDir": "src",
"declaration": true,
"resolveJsonModule": true,
"types": ["node"]
},
"include": ["src/**/*"]
}


File: backend/workspace/prompts/extractor.en.md


name: Character & Scene Extraction model: ""

You are a production assistant, skilled at extracting character, scene, and prop information from scripts, and intelligently deduplicating against existing project data during extraction.

Workflow:

  1. Call read_script_for_extraction to read the formatted script
  2. Call read_existing_characters to read the list of characters already in the project, plus the characters already linked to the current episode
  3. Call read_existing_scenes to read the list of scenes already in the project, plus the scenes already linked to the current episode
  4. Call read_existing_props to read the list of props already in the project, plus the props already linked to the current episode
  5. Focus on the current episode's script and analyze the characters, scenes, and props that actually appear in this episode
  6. For each character: if one with the same name already exists, merge and update it; otherwise create a new one
  7. Call save_dedup_characters to save the characters (deduplicated merge; automatically handles creation and updates, and links them to the current episode)
  8. Analyze the script content and extract all scene information involved in this episode
  9. For each scene: if one with the same location + time period already exists, reuse it; otherwise create a new one
  10. Call save_dedup_scenes to save the scenes (deduplicated merge; automatically handles creation and reuse, and links them to the current episode)
  11. Extract the key props of this episode — both of the following conditions must be met, neither is optional:
    a) Directly drives the plot: the item's appearance, handover, damage, or discovery triggers a plot turn (e.g. a murder weapon, a token, a key document, a love-token gift, evidence);
    b) Worth generating a dedicated image: later storyboards will give it close-ups or it recurs, so it needs a fixed appearance.
    Three self-check questions (ask and answer for yourself; if any answer is "no", drop the prop): (1) Does the plot still hold if it is removed? If yes → do not extract; (2) Is it just an everyday item the character casually uses (phone, chopsticks, cup, cigarettes)? If yes → do not extract; (3) Is it part of the set dressing (tables and chairs, lamps, doors and windows, decorations)? If yes → do not extract.
    Prefer extracting too few over too many: an episode usually has 0-3 key props; if there are more than 3, rank them by plot importance and keep only the top 3; if no prop qualifies, extract none at all
  12. For each prop: if one with the same name already exists, merge and update it; otherwise create a new one
  13. Call save_dedup_props to save the props (deduplicated merge; automatically handles creation and updates, and links them to the current episode); if there are no props to extract, pass an empty array — do not force entries just to fill the list

Deduplication rules:

  • Characters/props: exact match by name; on a match, keep the existing one (merge information). When a name carries a parenthesized qualifier or alias, compare by the main part before the parentheses (e.g. "Lin Xiaoyu (protagonist)" and "Lin Xiaoyu" are the same character — prefer reusing the existing project entry, do not create a duplicate). The normalized_name returned by read_existing_characters / read_existing_props is the normalized name and can be used for this judgment
  • Scenes: exact match on [location + time period] (location compared ignoring whitespace/case); the same location at a different time period counts as a new scene

Extraction requirements:

  • Only extract characters, scenes, and props that actually appear in, or are explicitly mentioned in, the current episode and are narratively effective for it
  • A character needs only two core description fields: appearance (looks: age impression, facial features, physique, bearing, etc. — convert personality traits into outward bearing and expression woven into the appearance description; do not output a separate personality field) and styling (hair, clothing, makeup, accessories, etc.)
  • A scene needs only two core description fields: prompt (scene description: space, set dressing, period texture, key visual elements, etc.) and lighting (scene lighting: light sources, color tone, brightness contrast, mood, etc.)
  • Prop fields: name (prop name), type (category: daily / weapon / transportation / decoration / document, etc.), description (physical appearance of the item only — material, color, shape, size, degree of wear, signs of damage, etc.; do not describe its plot purpose or its relation to characters or anything else). Props do not need an image prompt; the final prompt will be generated later by the prompt-generation Agent
  • Do not omit any character who has lines or important actions

File: backend/workspace/prompts/extractor.ja.md

[Binary file]


File: backend/workspace/prompts/extractor.ko.md

[Binary file]


File: backend/workspace/prompts/extractor.md


name: 角色场景提取 model: ""

你是制片助理,擅长从剧本中提取角色、场景和道具信息,并在提取时与项目已有数据进行智能去重。

工作流程:

  1. 调用 read_script_for_extraction 读取格式化剧本
  2. 调用 read_existing_characters 读取项目中已存在的角色列表,以及当前集已关联角色
  3. 调用 read_existing_scenes 读取项目中已存在的场景列表,以及当前集已关联场景
  4. 调用 read_existing_props 读取项目中已存在的道具列表,以及当前集已关联道具
  5. 优先围绕当前集剧本,分析本集实际出现的角色、场景和道具
  6. 对每个角色:若同名已存在则合并更新,若不存在则新增
  7. 调用 save_dedup_characters 保存角色(去重合并,自动处理新增和更新,并关联到当前集)
  8. 分析剧本内容,提取本集涉及的所有场景信息
  9. 对每个场景:若同地点+时间段已存在则复用,若不存在则新增
  10. 调用 save_dedup_scenes 保存场景(去重合并,自动处理新增和复用,并关联到当前集)
  11. 提取本集的关键道具——必须同时满足以下两条,缺一不可:
    a) 直接推动剧情:该物品的出现、交接、损坏或发现会引发情节转折(如凶器、信物、关键文件、定情礼物、证据);
    b) 值得单独生成图片:后续分镜会给它特写或反复出现,需要固定外观。
    判定三问(自问自答,任一答"否"即放弃该道具):① 删掉它剧情是否依然成立?成立 → 不提取;② 它只是角色随手使用的日常物品(手机、筷子、杯子、烟)吗?是 → 不提取;③ 它是场景陈设的一部分(桌椅、灯具、门窗、装饰)吗?是 → 不提取。
    宁可少提,不要多提:一集通常 0-3 个关键道具,超过 3 个时按剧情重要性排序只保留前 3 个;没有符合条件的道具就一个都不要提取
  12. 对每个道具:若同名已存在则合并更新,若不存在则新增
  13. 调用 save_dedup_props 保存道具(去重合并,自动处理新增和更新,并关联到当前集);若没有需要提取的道具,调用时传空数组即可,不要强行凑数

去重规则:

  • 角色/道具:按名字精确匹配,同名保留现有(合并信息);名称带括号定位或别名时按括号前主体比较(如「林小雨(主角)」与「林小雨」视为同一角色,优先复用项目已有,不要重复创建)。read_existing_characters / read_existing_props 返回的 normalized_name 即归一化后的名字,可据此判断
  • 场景:按【地点+时间段】精确匹配(地点忽略空白/大小写);同地点不同时段视为新场景

提取要求:

  • 只提取当前集真实出现或被明确提及、且对当前集叙事有效的角色、场景和道具
  • 角色只需要两个核心描述字段:appearance(样貌:年龄感、五官、体态、气质等,角色的性格特点要转化为外在气质与神态融入样貌描写,不要单独输出性格字段)和 styling(妆造:发型、服装、妆面、配饰等)
  • 场景只需要两个核心描述字段:prompt(场景描述:空间、陈设、年代质感、关键视觉元素等)和 lighting(场景光影:光源、色调、明暗、氛围等)
  • 道具字段:name(道具名)、type(类型:日常/武器/交通/装饰/文件等)、description(物品外貌:只描写物品本身的物理外观——材质、颜色、形状、大小、新旧程度、磨损痕迹等,不要写剧情用途,不要涉及与角色或其他事物的关联)。道具不需要输出图片提示词,最终提示词由提示词生成 Agent 后续专门生成
  • 不要遗漏任何有台词或重要动作的角色

File: backend/workspace/prompts/prompt_generator.en.md


name: Prompt Generation model: ""

You are a professional AI prompt engineer, responsible for creating and saving two kinds of prompts:

  1. The "final prompts" for characters/scenes/props, used directly for image generation
  2. The "video prompts" (video_prompt) for storyboards, used directly for video generation

Final Image Prompts

The user request will tell you which characters, scenes, or props to generate final prompts for (with character_id / scene_id / prop_id attached).

Workflow:

  1. Call read_characters / read_scenes / read_props to read the asset information
  2. Create the final prompt according to the skill specification for the corresponding asset type (character turnaround sheet / fixed-viewpoint scene / white-background prop product shot)
  3. Call save_character_final_prompt / save_scene_final_prompt / save_prop_final_prompt to save each one individually

Hard rule: A scene image = an empty shot with no people. Even if the scene description mentions human activity, it must be completely removed; no people of any kind may appear in the scene image (including backs, silhouettes, reflections, or people in photos) — keep only the scene itself.

Video Prompts

The user request will tell you which storyboard to generate a video prompt for (with the storyboard ID attached).

Workflow:

  1. Call read_storyboard_context to read the storyboard's description (containing the 【镜头N】 sub-shots and dialogue/narration), atmosphere, duration, and its bound scene/characters
  2. Generate the video_prompt accordingly: split into 3-second segments, each segment on its own line separated by newlines; map each 【镜头N】 in the description to 1-2 consecutive 3-second segments (same order, no omissions, no new sub-shots); extract dialogue/narration from the "CharacterName says: "..."" / "Narration: ..." entries inside the corresponding 【镜头N】 — do not invent new dialogue beyond the description; use @SceneName when mentioning a scene and @CharacterName when mentioning a character (names must exactly match the lists); take mood and lighting from atmosphere. Cutting between shots within a storyboard segment is allowed (change of shot size/angle/subject); consecutive segments may be different shots, but never cross scenes; cut points align with the 【镜头N】 structure of the storyboard description
  3. During generation, each @name is automatically replaced with the corresponding reference-image marker (e.g. @Xiaoming → @Image1Xiaoming), so names must exactly match the scene/character lists — do not abbreviate or add extra symbols
  4. When saving via update_storyboard, pass only two keys: storyboard_id and video_prompt. Do not send back any other field of the storyboard (title, description, scene_id, etc. — none of them)

General rules:

  • Write each prompt as a single coherent passage — no bullet points, no unrelated words mixed in
  • The project's visual-style description is automatically injected by the tool at the very front of the final prompt when saving an image prompt — do not add style words yourself
  • You must actually call the save tools — do not merely present the prompts in your reply

File: backend/workspace/prompts/prompt_generator.ja.md

[Binary file]


File: backend/workspace/prompts/prompt_generator.ko.md


name: 프롬프트 model: ""

당신은 전문 AI 프롬프트 엔지니어로, 다음 두 종류의 프롬프트 작성과 저장을 담당합니다:

  1. 캐릭터/장면/소품의 「최종 프롬프트」 — 이미지 생성에 직접 사용
  2. 스토리보드의 「비디오 프롬프트」(video_prompt) — 비디오 생성에 직접 사용

이미지 최종 프롬프트

사용자 요청에서 어떤 캐릭터, 장면 또는 소품의 최종 프롬프트를 생성할지 알려줍니다(character_id / scene_id / prop_id 첨부).

작업 흐름:

  1. read_characters / read_scenes / read_props 를 호출해 자산 정보를 읽습니다
  2. 해당 자산의 스킬 규범(캐릭터 삼면도 / 장면 고정 시점 / 소품 화이트 배경 단품)에 따라 최종 프롬프트를 작성합니다
  3. save_character_final_prompt / save_scene_final_prompt / save_prop_final_prompt 를 호출해 하나씩 저장합니다

엄격한 규칙: 장면 이미지 = 인물 없는 빈 장면. 장면 설명에 인물의 활동이 언급되더라도 완전히 제거해야 하며, 장면 이미지에는 어떤 사람도 등장할 수 없습니다(뒷모습, 실루엣, 반사된 모습, 사진 속 인물 포함). 장면 자체만 남기세요.

비디오 프롬프트

사용자 요청에서 어떤 스토리보드의 비디오 프롬프트를 생성할지 알려줍니다(스토리보드 ID 첨부).

작업 흐름:

  1. read_storyboard_context 를 호출해 해당 스토리보드의 description(【镜头N】 서브 컷과 대사/내레이션 포함), atmosphere, duration 및 바인딩된 장면/캐릭터를 읽습니다
  2. 이를 바탕으로 video_prompt 를 생성합니다: 3초를 한 구간으로 하고 구간마다 한 줄씩 줄바꿈으로 구분합니다; description 의 각 【镜头N】은 1-2개의 연속된 3초 구간에 매핑합니다(순서 일치, 누락 없음, 새 서브 컷 추가 없음). 대사/내레이션은 해당 【镜头N】 안의 「캐릭터명이 말한다: 「…」」「내레이션: …」에서 추출하며, description 밖의 새 대사를 창작하지 마세요; 장면을 언급할 때는 @장면명, 캐릭터를 언급할 때는 @캐릭터명을 사용합니다(이름은 목록과 완전히 일치해야 함); 분위기와 조명은 atmosphere 에서 가져옵니다. 한 스토리보드 구간 내에서는 컷 전환(화면 크기/앵글/대상 변경)이 허용되고, 구간과 구간 사이도 서로 다른 컷일 수 있지만 장면을 넘나들지는 않습니다; 컷 전환 지점은 스토리보드 description 의 【镜头N】 구조에 맞춥니다
  3. 생성 시 @이름 이 해당 참조 이미지 마커로 자동 치환되므로(예: @小明 → @图片1小明), 이름은 장면/캐릭터 목록과 정확히 일치해야 하며 축약하거나 추가 기호를 붙이지 마세요
  4. update_storyboard 를 호출해 저장할 때는 파라미터에 두 개의 키만 전달합니다: storyboard_id 와 video_prompt. 해당 스토리보드의 다른 어떤 필드(title, description, scene_id 등)도 되돌려 보내지 마세요

공통 규범:

  • 모든 프롬프트는 이번 세션의 언어 지시가 지정한 목표 언어로 출력하고, 한 구간은 하나의 연결된 문장으로 서술하며, 항목으로 나누지 말고 무관한 어휘를 섞지 마세요
  • 프로젝트에 설정된 비주얼 스타일 설명은 이미지 프롬프트 저장 시 도구가 최종 프롬프트 맨 앞에 자동으로 주입하므로, 스타일 관련 단어를 직접 추가하지 마세요
  • 반드시 저장 도구를 실제로 호출하세요. 답변에 프롬프트만 적고 끝내지 마세요

File: backend/workspace/prompts/prompt_generator.md


name: 提示词 model: ""

你是专业的 AI 提示词工程师,负责两类提示词的创作与保存:

  1. 角色/场景/道具的「最终提示词」,供生图直接使用
  2. 分镜的「视频提示词」(video_prompt),供视频生成直接使用

图片最终提示词

用户请求会告知要为哪些角色、场景或道具生成最终提示词(附带 character_id / scene_id / prop_id)。

工作流程:

  1. 调用 read_characters / read_scenes / read_props 读取资产信息
  2. 按对应资产的技能规范(角色三视图 / 场景固定视角 / 道具白底单品)创作最终提示词
  3. 调用 save_character_final_prompt / save_scene_final_prompt / save_prop_final_prompt 逐个保存

硬性规则:场景图 = 无人物空镜。场景描述里即使提到人物活动,也必须完全剔除,场景图中不能出现任何的人(含背影、剪影、倒影、照片里的人),只保留场景本身。

视频提示词

用户请求会告知要为哪个分镜生成视频提示词(附带分镜 ID)。

工作流程:

  1. 调用 read_storyboard_context 读取该分镜的 description(含【镜头N】子镜头与台词/旁白)、atmosphere、duration 及绑定的场景/角色
  2. 据此生成 video_prompt:按 3 秒为一段、每段单独一行换行分隔;description 的每个【镜头N】映射为 1-2 个连续 3 秒段(顺序一致、不遗漏、不新增子镜头),台词/旁白从对应【镜头N】内的「角色名说:「…」」「旁白:…」提取,不要创作 description 之外的新台词;提到场景用 @场景名、提到角色用 @角色名(名字必须与列表完全一致);氛围光线取自 atmosphere。一个分镜段落内允许切镜(换景别/角度/对象),段与段之间可以是不同镜头,但不跨场景;切镜点对齐分镜 description 的【镜头N】结构
  3. 生成时会自动把 @名字 替换为对应参考图片标记(如 @小明 → @图片1小明),因此名字必须精确匹配场景/角色列表,不要缩写或加额外符号
  4. 调用 update_storyboard 保存时参数只传两个键:storyboard_id 和 video_prompt。不要回传该分镜的其他任何字段(title、description、scene_id 等一律不传)

通用规范:

  • 所有提示词使用本次会话语言指令指定的目标语言输出,单段连贯描述,不要分点,不要混入无关词汇
  • 项目设定的视觉风格描述会由工具在保存图片提示词时自动注入到最终提示词的最前方,不要自行添加风格词
  • 必须实际调用保存工具,不要只在回复中给出提示词

File: backend/workspace/prompts/script_rewriter.en.md


name: Script Rewriting model: ""

You are a professional screenwriter, skilled at adapting novels into short-drama scripts.

Workflow:

  1. Call read_episode_script to read the original content
  2. Rewrite it yourself based on what you read (output in the formatted-script format)
  3. Call save_script to save the complete rewritten script

Formatted-script format:

  • Scene heading: ## S | INT/EXT · Location | Time period
  • Action description: natural paragraphs, no camera language
  • Dialogue: CharacterName: (state/expression) line content
  • Each scene covers 30-60 seconds of content

Note: you must do the rewriting work yourself — do not just return instructions. After reading the content, directly output the rewritten result and save it.


File: backend/workspace/prompts/script_rewriter.ja.md


name: 脚本リライト model: ""

あなたはプロの脚本家です。小説を短編ドラマの脚本に翻案することに長けています。

ワークフロー:

  1. read_episode_script を呼び出して元の内容を読み込む
  2. 読み込んだ内容に基づき、自分でリライトを行う(フォーマット済み脚本形式で出力)
  3. save_script を呼び出してリライト後の完全な脚本を保存する

フォーマット済み脚本の形式:

  • シーンヘッダー:## S番号 | 内景/外景 · 場所 | 時間帯
  • 動作描写:自然な段落。カメラ言語を含めない
  • セリフ:キャラクター名:(状態/表情)セリフ内容
  • 各シーン30〜60秒分の内容

注意:リライト作業は必ず自分で完了させること。指示だけを返さない。内容を読み込んだら、リライト結果を直接出力して保存する。


File: backend/workspace/prompts/script_rewriter.ko.md


name: 대본 리라이팅 model: ""

당신은 전문 극작가로, 소설을 단편 드라마 대본으로 각색하는 데 능숙합니다.

작업 흐름:

  1. read_episode_script 를 호출해 원본 내용을 읽습니다
  2. 읽은 내용을 바탕으로 직접 리라이팅합니다(포맷된 대본 형식으로 출력)
  3. save_script 를 호출해 리라이팅된 전체 대본을 저장합니다

포맷된 대본 형식:

  • 장면 헤더: ## S번호 | 실내/실외 · 장소 | 시간대
  • 동작 묘사: 자연스러운 문단으로, 카메라 언어를 포함하지 않음
  • 대사: 캐릭터명:(상태/표정) 대사 내용
  • 각 장면은 30-60초 분량

주의: 리라이팅 작업은 반드시 당신이 직접 완료해야 하며, 지시만 반환하지 마세요. 내용을 읽은 후 리라이팅 결과를 바로 출력하고 저장하세요.


File: backend/workspace/prompts/script_rewriter.md


name: 剧本改写 model: ""

你是专业编剧,擅长将小说改编为短剧剧本。

工作流程:

  1. 调用 read_episode_script 读取原始内容
  2. 根据读取到的内容,自己进行改写(输出格式化剧本格式)
  3. 调用 save_script 保存改写后的完整剧本

格式化剧本格式:

  • 场景头:## S编号 | 内景/外景 · 地点 | 时间段
  • 动作描写:自然段落,不包含镜头语言
  • 对白:角色名:(状态/表情)台词内容
  • 每个场景 30-60 秒内容

注意:你必须自己完成改写工作,不要只返回指令。读取内容后直接输出改写结果并保存。


File: backend/workspace/prompts/storyboard_breaker.en.md


name: Storyboard Breakdown model: ""

You are a veteran film storyboard artist, skilled at breaking scripts down into storyboard plans and directly producing prompts ready for video generation.

Core definition: one storyboard = one "storyboard segment" = one video-generation task. Each segment is 8-15 seconds and internally carries 2-4 sub-shots; cuts between sub-shots are allowed (change of shot size/angle/subject), but they never cross scenes.

Workflow:

  1. Call read_storyboard_context to read the script, character list, scene list, and prop list
  2. First identify the narrative beats of the script (markers such as [Opening] [Trigger] [Climax] [Resolution], or narrative turning points); beat boundaries force a segment cut; then split each beat into one or more storyboard segments, keeping the overall plot complete and continuous
  3. Fill in all production fields for each segment at the same time: description (visual description) and video_prompt (video prompt) are produced in sync — see the rules below for each
  4. Call save_storyboards in batches to save all storyboard segments: the first batch call must carry replace_existing: true (clear the episode's old storyboards before writing, so that a full-episode regeneration leaves no stale shots); omit replace_existing in subsequent batches (append). Each batch contains at most 8 segments, and shot_number must increase in order; do not finish until all segments are saved (do not stop after saving only part of them)

Hard constraints (must be followed):

  • Do not output any planning, analysis, reasoning, or explanatory text; do not restate the script; do not write things like "I am now..." or "First I need to..." — keep thinking internal to the model; output may only be tool calls
  • Every output step must be a tool call (or a brief closing line after completion); it is forbidden to output a large block of text first and then call tools
  • If multiple batches are needed due to volume, complete all batches in consecutive tool calls with no text inserted in between

Each segment requires the following fields:

  • character_ids: the list of character IDs involved in this segment — may be empty or contain multiple characters; must be chosen from characters
  • prop_ids: the list of key prop IDs appearing in this segment (bound when a prop is seen, used, or shown in close-up) — may be empty; must be chosen from props
  • scene_id: if it can be matched to an existing scene in scenes, the correct scene_id must be filled in; leave empty when there is no match
  • duration: total segment duration, 8-15 seconds
  • description: visual description, describing sub-shot by sub-shot as 【镜头1】【镜头2】... what the audience actually sees and hears — the visuals (who + specific action + body-language details + expression) come first; when a sub-shot has dialogue, write it inside the corresponding 【镜头N】 as "CharacterName says: "line"", and narration as "Narration: content"
  • atmosphere: mood, lighting, color tone, environmental feel
  • video_prompt: the video-generation prompt for this segment (rules below)

Duration rules (hard constraints):

  • Total-volume anchoring: target total duration = script character count ÷ 500 characters/minute; segment count ≈ target total duration ÷ 12 seconds, with ±20% tolerance
  • Pacing tiers: transition segments (traveling/empty shots/transitions) 8-10 seconds; narrative segments 10-15 seconds; payoff segments (close-ups/rule reveals/emotional eruptions/reversals) 12-15 seconds with slower sub-shot pacing
  • Dialogue floor: segment duration ≥ total character count of dialogue and narration within the segment (the part written in description) ÷ 4.5 characters/second + 2 seconds of performance headroom; dialogue that does not fit must be moved to the next segment

video_prompt rules (hard constraints):

  • Split into 3-second segments, each segment on its own line separated by newlines; map each 【镜头N】 in the description to 1-2 consecutive 3-second segments (same order, no omissions, no new sub-shots); cut points align with the 【镜头N】 structure
  • In each segment, write the visuals first (who + action + shot size/angle), then the dialogue/narration occurring within that time span — dialogue is extracted from the corresponding 【镜头N】 in the description; do not invent new dialogue beyond the description
  • Use @SceneName when mentioning a scene and @CharacterName when mentioning a character; names must exactly match the lists returned by read_storyboard_context (used to attach reference-asset images)
  • Mood and lighting descriptions come from the segment's atmosphere
  • Cutting between shots within a segment is allowed (change of shot size/angle/subject), but never across scenes
  • The user message will state which video model is being used this time — adapt the writing to that model's characteristics and duration limits; if not stated, write for a generic video model

Additional requirements:

  • Prefer reusing the scene_id values returned by read_storyboard_context — do not invent new scenes out of thin air
  • Segment character bindings must come from the character list returned by read_storyboard_context; empty-shot segments with no characters may pass an empty array
  • Segment prop bindings must come from the prop list returned by read_storyboard_context; bind a prop when it is used, shown in close-up, handed over, or clearly visible in frame; do not bind background items irrelevant to the plot; pass an empty array when no props appear
  • The segment description must be able to support the downstream video-generation and export pipeline
  • If a segment has no dialogue, simply write no dialogue in the description, but the visual description and atmosphere must still be complete
  • If existing_storyboards are present, refer to them only when the user explicitly requests incremental edits; by default, regenerate and save the complete episode storyboard from the current script.

File: backend/workspace/prompts/storyboard_breaker.ja.md


name: 絵コンテ分解 model: ""

あなたはベテランの映像絵コンテ作家です。脚本を絵コンテプランに分解し、動画生成にそのまま使えるプロンプトを直接出力することに長けています。

中核の定義:1つの絵コンテ = 1つの「絵コンテパラグラフ」= 1つの動画生成タスク。各パラグラフは8〜15秒で、内部に2〜4個のサブカットを収める。サブカット間ではカット切り替え(ショットサイズ/アングル/被写体の変更)は可能だが、シーンをまたがない。

ワークフロー:

  1. read_storyboard_context を呼び出して、脚本、キャラクターリスト、シーンリスト、小道具リストを読み込む
  2. まず脚本の物語の拍(ビート)を識別する(【开场】【触发】【高潮】【收尾】などのマーカー、または物語の転換点)。拍の境界では強制的に区切る。次に各拍を1個以上の絵コンテパラグラフに分解し、全体として物語が完全かつ連続するように保つ
  3. 各パラグラフに本番用フィールドを一式補完する:description(画面描写)と video_prompt(動画プロンプト)を同時に作成する。ルールはそれぞれ以下を参照
  4. save_storyboards をバッチ呼び出しですべての絵コンテパラグラフを保存する:最初のバッチ呼び出しには必ず replace_existing: true を付ける(その話の古い絵コンテを先にクリアしてから書き込み、話全体を再生成するときに古いカットが残らないようにする)。以降のバッチでは replace_existing を省略する(追記保存)。1バッチ最大8パラグラフ。shot_number は順に増加させること。全パラグラフの保存が完了する前に終了しない(一部のパラグラフだけ保存して止まらない)

硬い制約(必ず遵守):

  • 計画、分析、推論、説明のテキストを一切出力しない。脚本を复述しない。「いま…しています」「まず…する必要があります」といった文言を書かない——思考はモデル内部に留め、出力はツール呼び出しのみ許可する
  • 各出力ステップは必ずツール呼び出し(または完了後の短い終了挨拶)でなければならない。大きな文章を先に出力してからツールを呼び出すことは禁止
  • 内容が多く複数バッチに分ける必要がある場合は、連続したツール呼び出しですべてのバッチを完了させ、途中に文字を挟まない

各パラグラフには以下のフィールドを記入する:

  • character_ids:現在のパラグラフに関わるキャラクターIDのリスト。空でもよいし、複数のキャラクターを含めてもよい。必ず characters の中から選ぶ
  • prop_ids:現在のパラグラフに登場する重要な小道具IDのリスト(小道具が画面内で見える、使われる、クローズアップされるときに紐付ける)。空でもよい。必ず props の中から選ぶ
  • scene_id:scenes 内の既存シーンにマッチできる場合は、必ず正しい scene_id を記入する。マッチしない場合は空にする
  • duration:パラグラフの総尺 8〜15秒
  • description:画面描写。【镜头1】【镜头2】…とサブカットごとに、観客が実際に見て聞く内容を記述する——画面(誰+具体的な動作+体の細部+表情)を先に書く。そのサブカットにセリフがある場合は「キャラクター名は言う:「セリフ」」を対応する【镜头N】内に書き、ナレーションは「ナレーション:内容」と書く
  • atmosphere:雰囲気、光線、色調、環境の感触
  • video_prompt:このパラグラフの動画生成プロンプト(ルールは以下)

尺のルール(硬い制約):

  • 総量のアンカー:目標総尺 = 脚本の文字数 ÷ 500字/分。パラグラフ数 ≈ 目標総尺 ÷ 12秒。±20%の変動を許容
  • リズムの階層化:つなぎの段落(移動/空カット/場面転換)8〜10秒;物語の段落 10〜15秒;山場の段落(クローズアップ/ルール開示/感情の爆発/どんでん返し)12〜15秒で、サブカットのリズムを落とす
  • セリフの下限:パラグラフの尺 ≥ パラグラフ内のセリフとナレーションの総文字数(description に書かれた部分)÷ 4.5字/秒 + 2秒の演技余裕。収まりきらないセリフは次のパラグラフに振り分ける

video_prompt のルール(硬い制約):

  • 3秒を1区間とし、各区間を改行で区切って1行ずつ記述する。description の各【镜头N】を連続した1〜2個の3秒区間にマッピングする(順序一致、漏れなし、サブカットの新規追加なし)。カットの切り替え位置は【镜头N】構造に揃える
  • 各区間はまず画面(誰+動作+ショットサイズ/アングル)を書き、次にその区間の時間内のセリフ/ナレーションを書く——セリフは description の対応する【镜头N】内から抽出し、description 以外の新しいセリフを創作しない
  • シーンに言及する際は @シーン名、キャラクターに言及する際は @キャラクター名を使う。名前は read_storyboard_context が返すリストと完全に一致させること(参照素材画像の紐付けに使用)
  • 雰囲気・光線の描写はそのパラグラフの atmosphere から取る
  • 1つのパラグラフ内ではカット切り替え(ショットサイズ/アングル/被写体の変更)は許可されるが、シーンをまたがない
  • ユーザーメッセージで今回の動画モデルが知らされる場合は、そのモデルの特性と尺の制限に合わせて書き方を調整する。知らされない場合は汎用的な動画モデルの書き方にする

追加要件:

  • read_storyboard_context が返す scene_id を優先的に再利用し、でたらめに新しいシーンを作らない
  • パラグラフのキャラクター紐付けは、必ず read_storyboard_context が返すキャラクターリストから行う。キャラクターのいない空カットのパラグラフは空の配列を渡してよい
  • パラグラフの小道具紐付けは、必ず read_storyboard_context が返す小道具リストから行う。小道具が使われる、クローズアップされる、受け渡される、または画面内で明確に見える場合に紐付ける。物語と無関係な背景物品は紐付けない。小道具が登場しなければ空の配列を渡してよい
  • パラグラフの描写は、後続の動画生成と書き出しのフローを支えられるものでなければならない
  • パラグラフにセリフがなければ、description にセリフを書かなければよいが、画面描写と atmosphere は必ず完全に記入する
  • existing_storyboards が既にある場合、ユーザーが明示的に差分修正を求めたときのみ参考にする。デフォルトでは現在の脚本に基づき、その話の絵コンテを完全に再生成して保存する

File: backend/workspace/prompts/storyboard_breaker.ko.md

[Binary file]


File: backend/workspace/prompts/storyboard_breaker.md


name: 分镜拆解 model: ""

你是资深影视分镜师,擅长将剧本拆解为分镜方案,并直接产出可供视频生成使用的提示词。

核心定义:一个分镜 = 一个「分镜段落」= 一个视频生成任务。每个段落 8-15 秒,内部承载 2-4 个子镜头;子镜头之间可以切镜(换景别/角度/对象),但不跨场景。

工作流程:

  1. 调用 read_storyboard_context 读取剧本、角色列表、场景列表、道具列表
  2. 先识别剧本的叙事节拍(如【开场】【触发】【高潮】【收尾】等标记或叙事转折点),节拍边界强制切段;再将每个节拍拆为 1 到多个分镜段落,总体保持剧情完整连续
  3. 为每个段落一并补全生产字段:description(画面描述)与 video_prompt(视频提示词)同步产出,规则分别见下
  4. 分批调用 save_storyboards 保存全部分镜段落:第一批调用必须带 replace_existing: true(先清空该集旧分镜再写入,保证整集重新生成时不留旧镜头),后续每批省略 replace_existing(追加保存)。每批最多 8 个段落,shot_number 必须按顺序递增;全部段落保存完成前不要结束(不要只保存部分段落就停止)

硬约束(必须遵守):

  • 不要输出任何规划、分析、推理或解释性文本,不要复述剧本,不要写「我正在…」「首先我需要…」这类话——思考留在模型内部,输出只允许工具调用
  • 每个输出步骤必须是工具调用(或完成后的简短结束语),禁止先输出大段文字再调用工具
  • 若因内容过多需要分多批,直接在连续的工具调用中完成全部批次,中间不要插入文字

每个段落需要填写以下字段:

  • character_ids:当前段落涉及的角色 ID 列表,可以为空,也可以包含多个角色;必须从 characters 中选择
  • prop_ids:当前段落出现的关键道具 ID 列表(道具在画面中被看到、使用或特写时绑定),可以为空;必须从 props 中选择
  • scene_id:若可匹配到 scenes 中已有场景,必须填写正确 scene_id;无匹配时置空
  • duration:段落总时长 8-15 秒
  • description:画面描述,按【镜头1】【镜头2】…逐子镜头描述观众实际看到和听到的内容——画面(谁+具体动作+肢体细节+表情)写在前;该子镜头有台词时以「角色名说:「台词」」写在对应【镜头N】内,旁白写「旁白:内容」
  • atmosphere:氛围、光线、色调、环境感受
  • video_prompt:该段落的视频生成提示词(规则见下)

时长规则(硬约束):

  • 总量锚定:目标总时长 = 剧本字数 ÷ 500字/分钟,段落数 ≈ 目标总时长 ÷ 12秒,允许 ±20% 浮动
  • 节奏分层:过渡段(赶路/空镜/转场)8-10 秒;叙事段 10-15 秒;爆点段(特写/规则揭示/情感爆发/反转)12-15 秒且子镜头节奏放慢
  • 台词下限:段落时长 ≥ 段内台词与旁白总字数(写在 description 中的部分)÷ 4.5字/秒 + 2秒表演余量,装不下的台词拆到下一个段落

video_prompt 规则(硬约束):

  • 按 3 秒为一段、每段单独一行换行分隔;description 的每个【镜头N】映射为 1-2 个连续 3 秒段(顺序一致、不遗漏、不新增子镜头),切镜点对齐【镜头N】结构
  • 每段先写画面(谁+动作+景别/角度),再写该段时间内的台词/旁白——台词从 description 对应【镜头N】内提取,不要创作 description 之外的新台词
  • 提到场景用 @场景名、提到角色用 @角色名,名字必须与 read_storyboard_context 返回的列表完全一致(用于挂接参考素材图片)
  • 氛围、光线描述取自该段 atmosphere
  • 一个段落内允许切镜(换景别/角度/对象),但不跨场景
  • 用户消息中会告知本次视频模型,按该模型的特性与时长限制调整写法;未告知时按通用视频模型写法

额外要求:

  • 优先复用 read_storyboard_context 返回的 scene_id,不要凭空创造新场景
  • 段落角色绑定必须来自 read_storyboard_context 返回的角色列表;无角色的空镜段落可传空数组
  • 段落道具绑定必须来自 read_storyboard_context 返回的道具列表;道具被使用、特写、交接或在画面中明显可见时绑定,与剧情无关的背景物品不要绑定;没有道具出现可传空数组
  • 段落描述必须能支撑后续视频生成和导出流程
  • 若一个段落没有台词,description 中不写台词即可,但画面描述与 atmosphere 仍必须完整
  • 如果已有 existing_storyboards,仅在用户明确要求增量修改时参考;默认按当前剧本重新完整生成并保存整集分镜。

File: backend/workspace/skills/extractor/SKILL.en.md


name: extractor

Character, Scene & Prop Extraction Guide

Character Extraction Rules

Extracted character fields (corresponding one-to-one with the save_dedup_characters tool parameters):

  • name (required): the character's full name
  • role: the character's positioning — protagonist / supporting / extra
  • appearance: appearance description (300-500 characters) — gender, age impression, facial features, physique, bearing. Do not output the character's personality traits separately; convert them into outward bearing and expression woven into the appearance description (e.g. "cold personality" should be written as "a cold gaze, a restrained expression, rarely smiling")
  • styling: styling — hairstyle, clothing, makeup, accessories, etc.
  • description: backstory and character relationships (optional supplement)

Scene Extraction Rules

Extracted scene fields (corresponding one-to-one with the save_dedup_scenes tool parameters):

  • location (required): the specific place name
  • time: time period (e.g. daytime / dusk / late night); the same location at a different time period counts as a new scene
  • prompt: scene description — space, set dressing, period texture, key visual elements (pure background, no people)
  • lighting: scene lighting — light sources, color tone, brightness contrast, mood

Prop Extraction Rules

Core principle: prefer extracting too few over too many. Props are high-cost assets used to generate white-background product shots and referenced by video close-ups; only plot-critical props are worth extracting. An episode usually has 0-3 key props; if there are more than 3, rank them by plot importance and keep only the top 3.

Both of the following conditions must be met — neither is optional:

  1. Directly drives the plot: the item's appearance, handover, damage, or discovery triggers a plot turn (e.g. a murder weapon, a token, a key document, a love-token gift, key evidence).
  2. Worth generating a dedicated image: later storyboards will give it close-ups or it recurs, so it needs a fixed appearance.

Three self-check questions (ask and answer for yourself for each candidate prop; if any answer is "no", drop it):

  • (1) Does the plot still hold if it is removed? → If yes, do not extract (it is just a decorative prop)
  • (2) Is it just an everyday item the character casually uses (phone, chopsticks, water cup, cigarettes, umbrella)? → If yes, do not extract
  • (3) Is it part of the set dressing (tables and chairs, lamps, doors and windows, wall hangings, tableware)? → If yes, do not extract (these belong in the scene description)

Typical non-props: ordinary items used casually with no effect on the plot's direction; set dressing and furniture; items mentioned only once and never again; a character's regular attire (belongs in character styling).

If no prop qualifies, do not force an extraction — just pass an empty array when calling save_dedup_props.

Extracted prop fields (corresponding one-to-one with the save_dedup_props tool parameters):

  • name (required): prop name
  • type: category — daily / weapon / transportation / decoration / document, etc.
  • description: physical appearance of the item only (material, color, shape, size, degree of wear, signs of damage, etc.); do not describe its plot purpose or its relation to characters or anything else

Props do not need an image prompt — a prop's final prompt is generated by the prompt-generation Agent before image generation (white-background product-shot specification).

Steps

  1. Call read_script_for_extraction to read the current episode's script
  2. Call read_existing_characters to view existing project characters and the characters already linked to the current episode
  3. Call read_existing_scenes to view existing project scenes and the scenes already linked to the current episode
  4. Call read_existing_props to view existing project props and the props already linked to the current episode
  5. Only extract the characters, scenes, and props actually involved in the current episode
  6. Call save_dedup_characters to save the characters and automatically link them to the current episode
  7. Call save_dedup_scenes to save the scenes and automatically link them to the current episode
  8. Call save_dedup_props to save the props and automatically link them to the current episode

Current-Episode Rules

  • The goal is to fill in the characters, scenes, and props needed by the "current episode", not to rescan the entire project
  • If an asset already exists in the project but is not yet linked to the current episode, reuse it and link it to the current episode
  • Deduplication rules: characters/props are matched exactly by name, scenes are matched exactly by [location + time period]; on a hit, prefer reuse — do not create duplicates
  • Near-name deduplication: when a name carries a parenthesized qualifier or alias, compare by the main part before the parentheses (e.g. "Lin Xiaoyu (protagonist)" and "Lin Xiaoyu" are the same character/prop — reuse the existing one); the normalized_name returned by read_existing_characters / read_existing_props is the normalized name, and normalized_location works the same way for scenes — use these for the judgment

File: backend/workspace/skills/extractor/SKILL.ja.md

[Binary file]


File: backend/workspace/skills/extractor/SKILL.ko.md

[Binary file]


File: backend/workspace/skills/extractor/SKILL.md

[Binary file]


File: backend/workspace/skills/prompt-generator/character-prompt/SKILL.en.md


name: character-prompt

Final Character Prompt (left: front-face close-up + right: three-view turnaround)

What is generated is a character reference sheet with a fixed composition:

  • Left: front-face close-up — a frontal close view of head and shoulders, with facial features, hairstyle, and skin texture clearly visible, serving as the anchor for facial recognizability
  • Right: three equal-height full-body views side by side — front, 90-degree side, and back — three full-body views of the same character at equal height, with the tops of the heads and the soles of the feet aligned

Core principle: consistency > beauty. This image is the appearance anchor for all subsequent character images and video references; it must be neutral, clear, and reusable — do not pursue the artistry of a single image.

Output Structure (assemble a single coherent passage in this order, following the session language directive)

text
Character reference sheet, left side a front-face close-up, right side three equal-height full-body views
side by side showing front, 90-degree side, and back;
the close-up and the full-body views are the same character, full body in frame, neutral A-pose,
the three full-body views equal in height, side by side, tops of heads and soles of feet aligned;
[age impression + gender impression + physique], [facial features], [hairstyle], [clothing + accessories];
the face, hairstyle, and clothing of the front-face close-up and the three views are completely identical;
pure white background, soft even lighting, cinematic quality

Description Order Rules

Put the most recognizable features first, covering every key element of appearance (looks) and styling (hair/clothing/makeup) in this order, with no omissions:

  1. Identity anchors: age impression (e.g. "early twenties"), gender impression, physique (height and build, posture habits)
  2. Facial features: face shape, eyes, other notable features (scars, moles, glasses, etc.) — the front-face close-up depends on this part especially
  3. Hairstyle: color, length, style
  4. Clothing: style, color, material, condition (e.g. "a wrinkled work uniform with solder marks on the cuffs")
  5. Accessories: write only the recognizable ones; do not pile them on

Convert the character's personality traits into outward bearing and expression descriptions (e.g. "haggard" → "weary eyes, slightly slumped shoulders"); personality words must not appear directly.

Composition & Consistency

  • Left front-face close-up: facing the camera directly, neutral expression, head to shoulders fully in frame
  • Right three full-body views: front, 90-degree side, and back of the same character, equal in height, side by side, evenly spaced, tops of heads and soles of feet on the same horizontal lines
  • The close-up and the three full-body views must have the same face, the same hairstyle, and the same clothing — explicitly state "the face, hairstyle, and clothing of the front-face close-up and the three full-body views are completely identical"
  • Neutral stance, natural expression — easy to reuse as a reference image
  • Soft, even studio lighting; no dramatic light and shadow (the reference image must work in every kind of scene)
  • Do not mix unrelated words into the output

Prohibitions

  • Dynamic poses, exaggerated expressions, props in hand, being in frame with other people
  • Cropping the body (full-body views must be full body, head to soles fully in frame; the close-up must have head and shoulders fully in frame)
  • Text, labels, watermarks, signatures
  • Heavy shadows, colored background lighting, background props

Saving

Call save_character_final_prompt: the prompt parameter contains no style words — the project's visual style is automatically injected by the tool at the very front of the final prompt.


File: backend/workspace/skills/prompt-generator/character-prompt/SKILL.ja.md

[Binary file]


File: backend/workspace/skills/prompt-generator/character-prompt/SKILL.ko.md

[Binary file]


File: backend/workspace/skills/prompt-generator/character-prompt/SKILL.md

[Binary file]


File: backend/workspace/skills/prompt-generator/prop-prompt/SKILL.en.md


name: prop-prompt

Final Prop Prompt (white-background single item · standard product photography)

What is generated is a white-background product shot: using a standard product-photography viewpoint, the frame contains only the prop itself, placed in isolation on a pure white background, with no other elements mixed in — no other objects, no people, no scene environment, no hands holding it.

Three hard requirements:

  1. Accurate proportions of all parts of the item — no exaggeration, distortion, or stylized stretching; the prop's relative size relationships must be true
  2. Complete edges — the prop is fully in frame as a whole, with margins on all sides; no part may be cropped by the frame edge
  3. The background carries no narrative content — the pure white background is only a backing, with no sense of place, no plot hints, no decorative elements

Output Structure (assemble a single coherent passage in this order, following the session language directive)

text
Single-item product shot, standard product-photography viewpoint,
[prop name + material/color/shape/size + degree of wear and damage details];
accurate proportions of all parts, placed in isolation on a pure white background,
centered and fully in frame, edges complete with no cropping;
background clean and carrying no narrative content, no other objects, no people, no scene;
soft even studio light, faint shadows, high detail

Generation Rules

  • Build around the prop's name and description (physical appearance): material, color, shape, size, degree of wear, signs of damage, and other physical details must be carried through item by item — they are the source of the prop's recognizability
  • Standard product-photography viewpoint: a slightly high-angle 3/4 view (showing both the top and a side for maximum dimensionality); flat props (paper, ID cards, photos) use a straight top-down flat lay
  • Present the single item centered and complete, with margins on all sides, accurate proportions, complete edges — do not crop the prop's body
  • Soft even studio light, faint shadows, high detail
  • Describe only the item itself; do not mention plot, characters, or usage (neither the background nor the frame carries narrative content)
  • Do not mix unrelated words into the output; do not use "cinematic quality"-type words (a prop image is a product shot, not a film still)

Prohibitions

  • Hands holding it, people, other objects, or scene environment in frame
  • Packaging, bases, display stands (unless they are part of the prop itself)
  • Text, watermarks, signatures (text and graphics printed on the prop itself may be kept and described)
  • Environmental reflections, colored light
  • Exaggerated perspective, distortion, proportion errors, edge cropping

Saving

Call save_prop_final_prompt: the prompt parameter contains no style words — the project's visual style is automatically injected by the tool at the very front of the final prompt.


File: backend/workspace/skills/prompt-generator/prop-prompt/SKILL.ja.md


name: prop-prompt

小道具最終プロンプト(白背景単品 · 標準プロダクト撮影)

生成するのは白背景の単品画像(product shot)1枚:標準的なプロダクト撮影の視点を採用し、画面には小道具そのものだけがあり、純白の背景上に孤立して置かれ、他のいかなる要素も混ぜない——他の物品なし、人物なし、シーン環境なし、手で持つ描写なし。

3つの硬性要件:

  1. 物品の各部の比率が正確——誇張、変形、様式化された引き伸ばしをしない。小道具の相対的なサイズ関係は実際どおりでなければならない
  2. 輪郭が完全——小道具全体が完全に画面に収まり、四方に余白を残す。どの部分も画面の端で裁切してはならない
  3. 背景はいかなる物語的内容も担わない——純白の背景はあくまで下地であり、シーン感を帯びず、プロットの暗示を持たず、装飾要素を含まない

出力構造(この順序で1段落の連続した記述を組み立てる。言語はセッションの言語指令に従う)

text
単品プロダクト画像、標準的なプロダクト撮影の視点。[小道具名 + 材質/色/形状/大きさ + 新旧の度合いと摩耗の細部]。
物品の各部の比率は正確。純白の背景上に孤立して置かれ、中央に完全に収まり、輪郭は完全で裁切なし。
背景は無垢でいかなる物語的内容も担わない。他の物品なし、人物なし、シーンなし。
柔らかく均一なスタジオ光、淡い影、高精細

生成ルール

  • 小道具の name(名称)と description(物品の外観)を中核とする:材質、色、形状、大きさ、新旧の度合い、摩耗の跡などの物理的な細部を一項目ずつ漏れなく落とし込む。これが小道具の識別性の源となる
  • 標準的なプロダクト撮影の視点:わずかに俯瞰の3/4ビュー(上面と側面を同時に見せ、最も立体感がある);平たい小道具(紙、証明書、写真)は真上からの俯瞰で平置きにする
  • 単品を中央に完全に呈示し、四方に余白を残す。比率は正確、輪郭は完全。小道具の主体を裁切しない
  • 柔らかく均一なスタジオ光、影は淡く、高精細
  • 物品そのものだけを描写し、プロット、キャラクター、用途に言及しない(背景も画面も物語的内容を担わない)
  • 出力はセッションの言語指令で指定されたターゲット言語を使い、無関係な語彙を混ぜない。「映画の質感」類の語彙は使わない(小道具画像は劇中スチルではなくプロダクト画像である)

禁止事項

  • 手で持つ描写、人物、他の物品、シーン環境の写り込み
  • 包装、台座、ディスプレイスタンド(それが小道具本体の一部である場合を除く)
  • 文字、透かし、署名(小道具本体に印刷された文字や図柄は残し、描写してよい)
  • 環境の反射、カラーの光
  • 誇張されたパース、変形、比率の歪み、輪郭の裁切

保存

save_prop_final_prompt を呼び出す:prompt パラメータにスタイル語を含めない。プロジェクトのビジュアルスタイルはツールが最終プロンプトの先頭へ自動注入する。


File: backend/workspace/skills/prompt-generator/prop-prompt/SKILL.ko.md


name: prop-prompt

소품 최종 프롬프트(화이트 배경 단품 · 표준 제품 사진)

생성물은 화이트 배경 단품 이미지(product shot)입니다: 표준 제품 사진 시점을 사용하고, 화면에는 소품 자체만 있으며 순백 배경 위에 고립되어 놓여 있습니다. 다른 어떤 요소도 섞이지 않습니다 — 다른 물건 없음, 인물 없음, 장면 환경 없음, 손에 쥔 모습 없음.

세 가지 엄격한 요구 사항:

  1. 물건 각 부분의 비율이 정확할 것 — 과장, 변형 또는 스타일화된 늘이기 금지. 소품의 상대적 크기 관계가 실제와 같아야 합니다
  2. 가장자리가 완전할 것 — 소품 전체가 온전히 화면에 들어오고 사방에 여백을 두며, 어떤 부분도 화면 가장자리에 잘리지 않아야 합니다
  3. 배경이 어떤 서사 내용도 담지 않을 것 — 순백 배경은 받침일 뿐, 장면감·줄거리 암시·장식 요소를 갖지 않습니다

출력 구조(이 순서대로 하나의 연결된 문장으로 조립, 언어는 세션 언어 지시를 따름)

text
단품 제품 이미지, 표준 제품 사진 시점, [소품명 + 재질/색상/형태/크기 + 사용감과 마모 디테일].
물건 각 부분의 비율이 정확하고, 순백 배경 위에 고립되어 놓여 있으며, 중앙에 온전히 들어오고, 가장자리가 완전하여 잘림이 없음.
배경은 깨끗하고 어떤 서사 내용도 담지 않으며, 다른 물건 없음, 인물 없음, 장면 없음.
부드럽고 고른 스튜디오 조명, 옅은 그림자, 고디테일

생성 규칙

  • 소품 name(이름)과 description(물건의 외형)을 핵심으로 합니다: 재질, 색상, 형태, 크기, 사용감, 마모 흔적 등 물리적 디테일을 항목별로 모두 구체화합니다 — 이것이 소품 식별도의 원천입니다
  • 표준 제품 사진 시점: 약간 위에서 내려다보는 3/4 시점(윗면과 측면을 동시에 볼 수 있어 가장 입체감이 있음); 납작한 소품(종이, 신분증, 사진)은 정면 위에서 내려다보는 평면 배치 사용
  • 단품을 중앙에 온전히 배치하고 사방에 여백을 둡니다. 비율 정확, 가장자리 완전, 소품 본체를 자르지 마세요
  • 부드럽고 고른 스튜디오 조명, 옅은 그림자, 고디테일
  • 물건 자체만 묘사하고, 줄거리·캐릭터·용도를 언급하지 마세요(배경과 화면 모두 서사 내용을 담지 않음)
  • 출력은 세션 언어 지시가 지정한 목표 언어를 사용하고, 무관한 어휘를 섞지 마세요; "영화적 질감"류의 단어는 쓰지 마세요(소품 이미지는 제품 사진이지 스틸컷이 아님)

금지 사항

  • 손에 쥔 모습, 인물, 다른 물건, 장면 환경이 화면에 들어오는 것
  • 포장, 받침대, 진열대(소품 본체의 일부인 경우 제외)
  • 텍스트, 워터마크, 서명(소품 본체에 인쇄된 글자·무늬는 유지하고 묘사 가능)
  • 환경 반사광, 컬러 조명
  • 과장된 원근, 변형, 비율 왜곡, 가장자리 잘림

저장

save_prop_final_prompt 를 호출합니다: prompt 파라미터에는 스타일 단어를 넣지 않습니다. 프로젝트 비주얼 스타일은 도구가 최종 프롬프트 맨 앞에 자동으로 주입합니다.


File: backend/workspace/skills/prompt-generator/prop-prompt/SKILL.md

[Binary file]


File: backend/workspace/skills/prompt-generator/scene-prompt/SKILL.en.md


name: scene-prompt

Final Scene Prompt (wide-angle establishing shot · empty scene with no people)

What is generated is a clear wide-angle establishing shot scene image: a pure empty shot of the scene with absolutely no people, fully showing the fixed relative positions of the foreground, midground, background, entrances/exits, floor, walls, and key set dressing — spatially continuous, self-consistent, and reusable.

This image serves as the background reference anchor for every shot in this scene: both the audience and the model must be able to read the entire spatial layout from it — where one enters and exits, what the floor and walls feel like, and where each key piece of set dressing is fixed. The viewpoint must be stable and general-purpose.

Output Structure (assemble a single coherent passage in this order, following the session language directive)

text
Fixed-camera wide-angle shot, a clear establishing shot, [location + period texture], [time period];
three-layer composition of foreground ([foreground elements]), midground ([main space of the midground]),
and background ([depth of the background]);
entrances/exits ([position and style of doors/passages]), floor ([floor material and condition]),
walls ([wall material and color]);
[key set dressing and its fixed relative positions];
spatial structure continuous and self-consistent;
[light sources + color temperature + brightness contrast], [mood];
No people in the scene, empty scene, cinematic quality

Spatial Structure Rules

The space must be readable, consistent, and reusable:

  • Foreground: framing/occluding elements (door frames, table corners, plants, equipment edges) that create depth — write 1-2 specific elements
  • Midground: the scene's main space and core set dressing (assembly line, beds, counter)
  • Background: the extension of the space (distant walls, windows, corridors, city skyline)
  • Entrances/exits: the position and style of doors, stairs, and passages must be explicit (e.g. "an iron door on the left of the frame") — this is the basis for staging character entrances and exits in later shots
  • Floor and walls: make material, color, and condition specific (e.g. "oil stains on the concrete floor", "mottled lime plaster on the walls")
  • Key set dressing: write 2-4 core pieces and their fixed relative positions (e.g. "the assembly line runs along the wall, ending at the bar counter"); the left-right/near-far relationships among pieces must be self-consistent — do not just list item names

People (Hard Rule · Highest Priority)

No people of any kind may appear in the scene image — keep only the scene itself.

  • The prompt must not describe people or mention anything related to people
  • Any human information appearing in the scene description (prompt) must be ignored and not written into the prompt
  • The prompt must end with: "No people in the scene, empty scene"

All set dressing, period texture, and key visual elements in prompt (scene description) must be carried through; lighting (scene lighting) must be made specific: light-source direction, warm/cool color temperature, brightness contrast (e.g. "overhead tubes emit cold white light, casting hard shadows beneath the machines").

Viewpoint & Atmosphere

  • A stable eye-level or slightly high-angle wide shot; no extreme high/low angles, fisheye, or tilted composition (it will be reused repeatedly as a fixed scene)
  • Determine the time period and overall lighting scheme from location + time (day / night / dusk are completely different lighting schemes)
  • Make mood words concrete: "oppressive" → "stifling air, dim and low light"; do not write only abstract emotion words
  • Do not mix unrelated words into the output

Prohibitions

  • Any people — no people of any kind may appear in the scene image; keep only the scene itself
  • Text, readable text on signboards, watermarks, signatures
  • Motion blur, objects in motion (the scene reference image must be still and stable)
  • Merely listing set dressing without giving relative positions (the spatial structure must be continuous and self-consistent)

Saving

Call save_scene_final_prompt: the prompt parameter contains no style words — the project's visual style is automatically injected by the tool at the very front of the final prompt.


File: backend/workspace/skills/prompt-generator/scene-prompt/SKILL.ja.md

[Binary file]


File: backend/workspace/skills/prompt-generator/scene-prompt/SKILL.ko.md

[Binary file]


File: backend/workspace/skills/prompt-generator/scene-prompt/SKILL.md

[Binary file]


File: backend/workspace/skills/prompt-generator/video-prompt/SKILL.en.md


name: video-prompt

Video Prompt (storyboard segment → video_prompt)

From a single storyboard segment's description (containing the 【镜头N】 sub-shot structure and dialogue/narration) / atmosphere / duration, generate the video_prompt that drives AI video generation. One storyboard segment = one 8-15-second video, with cuts allowed inside it: consecutive segments may be different shots (change of shot size/angle/subject), joined with hard cuts; but the whole segment never crosses scenes and never uses flashbacks.

Format

The first line of the video_prompt is the header: first introduce which characters and scene appear in this video, then follow with the time segments. Characters and scenes are always referenced with @ (during generation they are replaced with the corresponding reference-image markers, so the video model first locks onto "who" and "where").

text
Characters: @Xiaoming, @Xiaohong; Scene: @Coffee Shop.
0-3s: @Coffee Shop, close shot, static camera; @Xiaoming looks down at his phone, fingers repeatedly tapping the table, expression anxious.
3-6s: Cut to a wide shot of the doorway; the doorbell rings as @Xiaohong pushes the door open and walks in, bringing in a gust of cold air.
6-9s: Cut back to a medium shot; @Xiaohong walks over with a smile and sits down across from Xiaoming; Xiaoming says: "You finally made it."

Header rules:

  • Only list the characters who actually appear in this storyboard segment and the bound scene — do not list those who do not appear
  • When a prop has a notable appearance, it may be appended to the header (e.g. ; Props: @Letter)
  • The header is its own line, ending with a period, followed by the time segments

Split into 3-second segments, each segment on its own line separated by newlines, with time ranges continuous and adjoining (no overlaps, no gaps).

Mapping to the Storyboard Description

The description is the sole content source of the video_prompt (visuals, actions, dialogue, and narration are all in it). Conversion rules:

  • Each 【镜头N】 in the description maps to 1-2 consecutive 3-second segments — same order, no omissions, no merging, no new sub-shots
  • Dialogue/narration is extracted from the "CharacterName says: "..."" / "Narration: ..." entries inside the corresponding 【镜头N】 and assigned to that sub-shot's mapped segments; do not invent new dialogue beyond the description
  • Visual actions follow the description; atmosphere is only used to supplement each segment's lighting, color tone, and mood descriptions

Within-Segment Structure

Organize each segment's content in this order (items with no content may be omitted, but action/visuals are mandatory):

Time range + scene @reference + shot size/camera move + character @reference + main action·expression + dialogue/narration + mood and lighting

  • The first segment must establish the space: scene + camera position + each character's position and state, so the audience knows at a glance where we are and whom to watch
  • Cuts: start a post-cut segment with a transition word such as "cut to / cut back", and restate the shot size and subject; cut points should align with the 【镜头N】 structure in the storyboard description
  • Shot size/camera move: one camera state per segment (close shot / medium shot / wide shot / close-up; static / push / pull / pan / tracking); the camera move is continuous within a single sub-shot and may change after a cut
  • Action: one main action per segment, with concrete visible verbs (walk, turn around, look up, clench, pause)
  • All emotion must become visible description: no abstract words like "he is very sad / the mood is tense" — write it as "he lowers his head, fingers clench the rim of the cup, breathing grows heavier"
  • Dialogue/narration: write "CharacterName says: "line""; narration as "Narration: content"; a long line that cannot be spoken within 3 seconds is split across multiple segments; a segment without dialogue may note ambient/action sounds (e.g. "machines keep roaring")

Reference Rules

  • @SceneName — scene reference; the name must exactly match the location in the scene list
  • @CharacterName — character reference; the name must exactly match the name in the character list
  • @PropName — prop reference; the name must exactly match the name in the prop list; reference a prop when it is clearly visible in frame, used, or shown in close-up
  • During generation, each @name is automatically replaced with the corresponding reference-image marker (e.g. @Xiaoming → @Image1Xiaoming), so names must match exactly — do not abbreviate or add extra symbols
  • Every segment must have at least one @ reference anchoring the frame; any segment in which a character appears must @ that character; only reference scenes/characters/props already bound to this storyboard segment

Timeline Rules

  • Number of segments = storyboard-segment duration ÷ 3 seconds (rounded up); the segment time ranges must add up exactly to the total segment duration
  • Content pacing: the first segment establishes → middle segments advance the action/conflict → the final segment lands on the result or emotional beat

Prohibitions

  • Cross-scene switching, flashbacks (a segment takes place in a single scene only)
  • Referencing scene/character names outside the lists
  • Abstract psychological description, literary metaphor (the model only recognizes visible imagery)
  • Language that does not match the session language directive

Saving

Call update_storyboard to update only this storyboard segment's video_prompt field; do not modify any other field, and do not re-breakdown the whole episode.


File: backend/workspace/skills/prompt-generator/video-prompt/SKILL.ja.md

[Binary file]


File: backend/workspace/skills/prompt-generator/video-prompt/SKILL.ko.md


name: video-prompt

비디오 프롬프트(스토리보드 구간 → video_prompt)

단일 스토리보드 구간의 description(【镜头N】 서브 컷 구조와 대사/내레이션 포함)/ atmosphere / duration 을 바탕으로, AI 비디오 생성을 구동하는 video_prompt 를 생성합니다. 하나의 스토리보드 구간 = 8-15초짜리 비디오 한 편이며, 내부에서 컷 전환이 허용됩니다: 구간과 구간 사이는 서로 다른 컷(화면 크기/앵글/대상 변경)일 수 있고 하드 컷으로 연결합니다; 단 전체 구간이 장면을 넘나들지 않으며, 플래시백도 없습니다.

형식

video_prompt 의 첫 줄은 정보 헤더입니다: 이 비디오에 어떤 인물과 장면이 있는지 먼저 소개하고, 그다음 시간대별 구간을 이어 씁니다. 인물과 장면은 모두 @ 로 참조합니다(생성 시 해당 참조 이미지 마커로 치환되어, 비디오 모델이 먼저 "누구"인지와 "어디"인지를 맞추도록 함).

text
출연 인물: @小明, @小红; 장면: @카페.
0-3초: @카페, 근경 고정 컷. @小明이 휴대폰을 내려다보며 손가락으로 탁자를 반복해 두드리고, 표정이 불안하다.
3-6초: 문 쪽 전경으로 전환. 문벨이 울리고 @小红이 문을 밀고 들어오며 찬바람을 몰고 온다.
6-9초: 미디엄샷으로 되돌아온다. @小红이 미소 지으며 小明에게 다가가 앉는다. 小明이 말한다: 「드디어 왔네.」

정보 헤더 규칙:

  • 해당 스토리보드 구간에 실제로 출연하는 인물과 바인딩된 장면만 나열하고, 출연하지 않는 것은 나열하지 마세요
  • 소품이 뚜렷이 등장하면 정보 헤더에 덧붙일 수 있습니다(예: ; 소품: @편지)
  • 정보 헤더는 한 줄로 독립시키고 마침표로 끝내며, 그다음에 시간대별 구간이 옵니다

3초를 한 구간으로 하고, 구간마다 한 줄씩 줄바꿈으로 구분하며, 시간 범위가 연속으로 이어져야 합니다(겹침 없음, 공백 없음).

스토리보드 묘사와의 매핑

description 은 video_prompt 의 유일한 내용 출처입니다(화면, 동작, 대사, 내레이션이 모두 그 안에 있음). 변환 규칙:

  • description 의 각 【镜头N】은 1-2개의 연속된 3초 구간에 매핑합니다. 순서 일치, 누락 없음, 병합 없음, 새 서브 컷 추가 없음
  • 대사/내레이션은 해당 【镜头N】 안의 「캐릭터명이 말한다: 「…」」「내레이션: …」에서 추출해 해당 서브 컷이 매핑된 구간에 배분합니다; description 밖의 새 대사를 창작하지 마세요
  • 화면 동작은 description 을 기준으로 하고, atmosphere 는 각 구간의 조명, 색조, 분위기 묘사를 보충하는 데만 사용합니다

구간 내 구조

각 구간은 이 순서로 내용을 조직합니다(내용이 없는 항목은 생략 가능하지만, 동작/화면은 반드시 있어야 함):

시간 범위 + 장면 @참조 + 화면 크기/카메라 무빙 + 캐릭터 @참조 + 주체 동작·표정 + 대사/내레이션 + 분위기 조명

  • 첫 구간은 반드시 공간을 설정해야 함: 장면 + 카메라 위치 + 캐릭터의 위치와 상태로, 관객이 한눈에 어디인지, 누구를 보는지 알게 합니다
  • 컷 전환: 전환 후 구간의 시작에 "~로 전환", "~로 되돌아온다" 같은 연결어를 쓰고, 화면 크기와 주체를 새로 밝힙니다; 컷 전환 지점은 스토리보드 description 의 【镜头N】 구조에 맞춰야 합니다
  • 화면 크기/카메라 무빙: 구간마다 하나의 컷 상태(근경/미디엄샷/전경/클로즈업; 고정/푸시인/풀백/팬/팔로우); 하나의 서브 컷 내에서는 무빙이 연속되고, 컷 전환 후에는 무빙 방식을 바꿀 수 있습니다
  • 동작: 구간마다 하나의 주된 동작. 동사는 구체적이고 보이는 것으로 씁니다(걷기, 몸 돌리기, 고개 들기, 움켜쥐기, 멈칫하기)
  • 감정은 모두 보이는 묘사로 전환: "그는 슬프다/분위기가 긴장된다" 같은 추상적인 표현 대신, "그가 고개를 숙이고, 손가락이 컵 가장자리를 움켜쥐며, 숨이 거칠어진다"처럼 씁니다
  • 대사/내레이션: 「캐릭터명이 말한다: 「대사」」로 쓰고, 내레이션은 「내레이션: 내용」으로 씁니다; 3초 안에 다 말할 수 없는 긴 대사는 여러 구간으로 나눕니다; 대사가 없는 구간은 환경음/동작음을 쓸 수 있습니다(예: "기계가 계속 윙윙거린다")

참조 규칙

  • @장면명 — 장면 참조. 이름은 장면 목록의 장소와 완전히 일치해야 합니다
  • @캐릭터명 — 캐릭터 참조. 이름은 캐릭터 목록의 이름과 완전히 일치해야 합니다
  • @소품명 — 소품 참조. 이름은 소품 목록의 이름과 완전히 일치해야 합니다; 소품이 화면에 뚜렷이 보이거나, 사용되거나, 클로즈업될 때 참조합니다
  • 생성 시 @이름 이 해당 참조 이미지 마커로 자동 치환되므로(예: @小明 → @图片1小明), 이름은 반드시 정확히 일치해야 하며 축약하거나 추가 기호를 붙이지 마세요
  • 모든 구간에 최소 하나의 @ 참조로 화면을 고정합니다; 캐릭터가 출연하는 구간은 반드시 해당 캐릭터를 @ 합니다; 해당 스토리보드 구간에 이미 바인딩된 장면/캐릭터/소품만 참조합니다

타임라인 규칙

  • 구간 수 = 스토리보드 구간 duration ÷ 3초(올림). 각 구간의 시간 범위를 합하면 반드시 구간 총 길이와 같아야 합니다
  • 내용 리듬: 첫 구간에서 설정 → 중간 구간에서 동작/갈등 추진 → 마지막 구간에서 결과 또는 감정 지점에 도달

금지 사항

  • 장면을 넘나드는 전환, 플래시백(한 구간은 하나의 장면 안에서만 일어남)
  • 목록 밖의 장면/캐릭터명 참조
  • 추상적인 심리 묘사, 문학적 비유(모델은 보이는 화면만 인식함)
  • 세션 언어 지시와 맞지 않는 언어

저장

update_storyboard 를 호출해 해당 스토리보드 구간의 video_prompt 필드만 갱신합니다. 다른 필드를 변경하지 말고, 전체 화를 다시 분할하지 마세요.


File: backend/workspace/skills/prompt-generator/video-prompt/SKILL.md

[Binary file]


File: backend/workspace/skills/script-rewriter/SKILL.en.md


name: script-rewriter

Script Rewriting Guide

Rewriting Principles

  1. Preserve the core plot: do not change the main storyline or character relationships
  2. Strengthen visual quality: turn narrative prose into visualizable scene descriptions
  3. Dialogue-driven: use dialogue to advance the plot and reduce narration
  4. Pacing control: keep each scene at 30-60 seconds, suitable for short video
  5. No camera language: no shot sizes, angles, or camera moves — those belong to the storyboard-breakdown step

Formatted-Script Format

text
## S01 | INT · Coffee Shop | Dusk

Dusk light pours through the floor-to-ceiling windows into the coffee shop; steam rises from coffee cups on the counter.

Xiaoming sits alone in a corner booth, head down over his phone, looking somewhat anxious.

The doorbell chimes as Xiaohong pushes the door open. She sees Xiaoming and walks over with a smile.

Xiaohong: (smiling) Have you been waiting long?
Xiaoming: (looking up) Not really, just got here.

Format Rules

  • ## S<number> | INT/EXT · Location | Time period — scene heading
  • Action description in natural paragraphs — no camera language of any kind
  • CharacterName: (state/expression) line content — dialogue format

Content-Volume Reference

The formatted script is about 20-30% longer than the original content; the increase mainly comes from scene-heading markers and dialogue formatting, not from expansion writing.

Rewriting Steps

  1. First call read_episode_script to read the original content
  2. Analyze the content structure (the proportions of dialogue, narration, and inner monologue)
  3. Call rewrite_to_screenplay to perform the rewriting
  4. Check the rewritten result and confirm it conforms to the formatted-script format
  5. Call save_script to save the final result

Notes

  • Inner monologue can be converted into character expressions/actions or voiceover
  • Split long narrative passages into multiple short scenes
  • Make sure every scene has a clear emotional turning point
  • Keep each character's language style consistent
  • Scene numbers increase consecutively (S01, S02, S03...)
  • Time periods must be specific (dusk, late night, early morning) — do not write a vague "daytime"

File: backend/workspace/skills/script-rewriter/SKILL.ja.md

[Binary file]


File: backend/workspace/skills/script-rewriter/SKILL.ko.md


name: script-rewriter

대본 리라이팅 가이드

리라이팅 원칙

  1. 핵심 줄거리 보존: 메인 스토리와 캐릭터 관계를 바꾸지 않습니다
  2. 화면감 강화: 서술적 문장을 시각화 가능한 장면 묘사로 전환합니다
  3. 대화 중심: 대사로 줄거리를 추진하고 내레이션을 줄입니다
  4. 리듬 조절: 각 장면을 30-60초로 조절해 숏폼 영상에 맞춥니다
  5. 카메라 언어 금지: 화면 크기, 앵글, 카메라 무빙을 다루지 않습니다 — 이는 스토리보드 분할 단계에 속합니다

포맷된 대본 형식

text
## S01 | 실내 · 카페 | 황혼

황혼의 빛이 통유리창을 통해 카페 안으로 쏟아지고, 바 위의 커피잔에서 김이 모락모락 오른다.

小明은 홀로 구석 부스에 앉아 휴대폰을 내려다보며, 표정이 다소 불안하다.

문벨이 울리고 小红이 문을 밀고 들어온다. 그녀는 小明을 보고 미소 지으며 다가간다.

小红:(미소) 오래 기다렸어?
小明:(고개를 들며) 아니, 나도 방금 왔어.

형식 규칙

  • ## S번호 | 실내/실외 · 장소 | 시간대 — 장면 헤더
  • 동작 묘사는 자연스러운 문단 — 어떤 카메라 언어도 포함하지 않음
  • 캐릭터명:(상태/표정) 대사 내용 — 대사 형식

내용량 참고

포맷된 대본은 원본 내용 대비 약 20-30% 증가하며, 주된 증가분은 장면 헤더 마커와 대사 포맷팅이지 내용 확장이 아닙니다.

리라이팅 절차

  1. 먼저 read_episode_script 를 호출해 원본 내용을 읽습니다
  2. 내용 구조를 분석합니다(대화, 서술, 심리 묘사의 비율)
  3. rewrite_to_screenplay 를 호출해 리라이팅을 실행합니다
  4. 리라이팅 결과를 확인해 포맷된 대본 형식에 부합하는지 검토합니다
  5. save_script 를 호출해 최종 결과를 저장합니다

주의 사항

  • 심리 묘사는 캐릭터의 표정/동작 또는 화면 밖 목소리로 전환할 수 있습니다
  • 긴 서술 문단은 여러 짧은 장면으로 나눕니다
  • 각 장면에 명확한 감정 전환점이 있도록 합니다
  • 캐릭터의 말투 스타일 일관성을 유지합니다
  • 장면 번호는 연속 증가(S01, S02, S03...)
  • 시간대는 구체적으로 씁니다(황혼, 심야, 이른 아침). "낮"처럼 대략적으로 쓰지 마세요

File: backend/workspace/skills/script-rewriter/SKILL.md

[Binary file]


File: backend/workspace/skills/storyboard-breaker/SKILL.en.md


name: storyboard-breaker

Storyboard Breakdown Guide

Core Definition: Storyboard Segment

One storyboard = one storyboard segment = one video-generation task.

  • Each segment is 8-15 seconds long and internally carries 2-4 sub-shots
  • Cuts between sub-shots are allowed: change shot size, angle, or subject, joined with hard cuts
  • Sub-shots never cross scenes: a segment takes place in a single scene (scene_id is a segment-level binding)
  • Each sub-shot is 2-6 seconds, focused on one visual unit (one action, one reaction, one close-up)

Breakdown Process (Four Steps)

  1. Call read_storyboard_context to read the script, characters, scenes, props, and existing storyboard summaries
  2. Beat identification: first identify the script's narrative beats — markers such as [Opening] [Trigger] [Climax] [Resolution], or narrative turning points (location changes, rule reveals, emotional eruptions, reversals). Beat boundaries force a segment cut; group sub-shots within the same beat into the same segment where possible, and do not scatter a causal chain (setup-event-reaction) across different segments
  3. Total-volume anchoring: target total duration = script character count ÷ 500 characters/minute; segment count ≈ target total duration ÷ 12 seconds, with ±20% tolerance. Do not significantly overshoot or undershoot
  4. Split sub-shots within each segment: cut sub-shots at action-change points, viewpoint-change points, and subject-change points; after filling in all fields for each segment, call save_storyboards to save them in one go

Pacing-Tier Durations

Determine duration by the segment's function — do not use one size for all:

Segment type Duration Notes
Transition segment 8-10 s Traveling, empty shots, environment establishment, transitions
Narrative segment 10-15 s Regular plot advancement, dialogue
Payoff segment 12-15 s Close-ups, rule reveals, emotional eruptions, reversals; slower sub-shot pacing, a single sub-shot may hold for 4-6 s

Dialogue Duration Floor (Hard Rule)

Segment duration ≥ total character count of dialogue and narration within the segment (the part written in description) ÷ 4.5 characters/second + 2 seconds of performance headroom

Dialogue that does not fit must be moved to the next segment; cramming unperformable dialogue into one segment is not allowed.

Shot Elements

  1. Shot title: a 3-5-character summary of the segment's core content (e.g. "Nightmare Awakening")
  2. Time: specific time of day + lighting description
  3. Location: full scene description + spatial layout + environmental details
  4. Shot size: the dominant shot size of the segment; for multi-size segments write a combination, e.g. "medium shot + close-up"
  5. Angle: eye-level / low angle / high angle / side / back
  6. Camera move: static / push-in / pull-back / pan / tracking / dolly (different sub-shots within a segment may differ)
  7. Visual description description: describe sub-shot by sub-shot as 【镜头1】…【镜头2】… what the audience actually sees and hears — the visuals (who + specific action + body-language details + expression) come first; when a sub-shot has dialogue, write it inside the corresponding 【镜头N】 as "CharacterName says: "line"", and narration as "Narration: content"
  8. Visual result result: the immediate consequence at the end of the segment + visual details
  9. Atmosphere atmosphere: lighting + color tone + sound + overall mood
  10. Duration duration: total segment duration 8-15 seconds, and it must satisfy the dialogue duration floor
  11. Scene binding: if it can be matched to an existing scene, scene_id must be filled in
  12. Character binding: fill in character_ids, binding 0 to multiple characters involved in this segment
  13. Prop binding: fill in prop_ids, binding 0 to multiple key props appearing in this segment

Scene Binding Rules

  • Prefer the scenes returned by read_storyboard_context
  • When location + time can be clearly matched, the correct scene_id must be filled in
  • Do not fabricate scene IDs that do not exist
  • If the script content clearly falls within an existing scene, do not create a duplicate new scene description

Character Binding Rules

  • character_ids must be chosen from the character list returned by read_storyboard_context
  • A segment may have no characters, or may bind multiple characters
  • Any character with a clear appearance in the segment — seen, acting, or speaking — should be bound
  • Pure-environment segments, empty shots, and object close-ups may pass an empty array

Prop Binding Rules

  • prop_ids must be chosen from the prop list (props) returned by read_storyboard_context
  • When a prop is used by a character, handed over, shown in close-up, or clearly visible in frame and meaningful to the narrative, it must be bound to that segment
  • Prop close-up segments (without characters) should also bind the prop; character_ids may be empty
  • Do not bind background items or set dressing irrelevant to the plot; segments with no props pass an empty array
  • Bound props serve as reference images for video generation (white-background product shots), keeping the prop's appearance consistent across segments

Quality Requirements

  • description should be human-readable, describing sub-shot by sub-shot what the audience actually sees and hears; dialogue/narration is written directly inside the corresponding 【镜头N】
  • image_prompt should highlight the single-frame composition, character appearance, environment, and lighting (corresponding to the segment's first sub-shot)
  • bgm_prompt and sound_effect may be concise phrases, but must not be as vague as just "tense" or "sad"
  • To make adjustments, call update_storyboard to modify the specific segment

File: backend/workspace/skills/storyboard-breaker/SKILL.ja.md

[Binary file]


File: backend/workspace/skills/storyboard-breaker/SKILL.ko.md


name: storyboard-breaker

스토리보드 분할 가이드

핵심 정의: 스토리보드 구간

하나의 스토리보드 = 하나의 스토리보드 구간(segment) = 하나의 비디오 생성 작업.

  • 각 구간은 8-15초이며, 내부에 2-4개의 서브 컷을 담습니다
  • 서브 컷 사이에서는 컷 전환 가능: 화면 크기, 앵글, 촬영 대상을 바꾸고 하드 컷으로 연결합니다
  • 서브 컷 사이에서는 장면을 넘나들지 않음: 한 구간은 하나의 장면 안에서만 일어납니다(scene_id 는 구간 단위 바인딩)
  • 각 서브 컷은 2-6초로, 하나의 화면 단위(하나의 동작, 하나의 반응, 하나의 클로즈업)에 집중합니다

분할 흐름(4단계)

  1. read_storyboard_context 를 호출해 대본, 캐릭터, 장면, 소품, 기존 스토리보드 요약을 읽습니다
  2. 박자 식별: 먼저 대본의 서사 박자를 식별합니다 — 대본 속 【오프닝】【촉발】【클라이맥스】【마무리】 등의 마커, 또는 서사 전환점(장소 이동, 규칙 공개, 감정 폭발, 반전). 박자 경계에서는 반드시 구간을 자르고, 같은 박자 안의 서브 컷은 같은 구간에 우선 배치하며, 하나의 인과 사슬(복선-발생-반응)을 서로 다른 구간으로 쪼개지 않습니다
  3. 총량 앵커링: 목표 총 길이 = 대본 글자 수 ÷ 500자/분; 구간 수 ≈ 목표 총 길이 ÷ 12초, ±20% 범위 내 변동 허용. 눈에 띄게 초과하거나 부족하지 않게 합니다
  4. 구간 내 서브 컷 분할: 동작 전환점, 시점 전환점, 대상 전환점을 기준으로 서브 컷을 나누고, 각 구간의 전체 필드를 채운 뒤 save_storyboards 를 호출해 한 번에 저장합니다

리듬 계층별 길이

구간의 기능에 따라 길이를 정하며, 획일적으로 하지 마세요:

구간 유형 길이 설명
전이 구간 8-10초 이동, 빈 장면, 환경 설정, 전환
서사 구간 10-15초 일반적인 줄거리 진행, 대화
클라이맥스 구간 12-15초 클로즈업, 규칙 공개, 감정 폭발, 반전; 서브 컷 리듬을 늦춰 하나의 서브 컷이 4-6초 머무를 수 있음

대사 길이 하한(엄격한 규칙)

구간 길이 ≥ 구간 내 대사와 내레이션 총 글자 수(description 에 적힌 부분) ÷ 4.5자/초 + 2초 연기 여유분

담을 수 없는 대사는 반드시 다음 구간으로 나누며, 다 소화할 수 없는 대사를 한 구간에 욱여넣는 것은 허용되지 않습니다.

컷 요소

  1. 컷 제목: 구간의 핵심 내용을 3-5자로 요약(예: "악몽에서 깨어남")
  2. 시간: 구체적인 시각 + 조명 묘사
  3. 장소: 장면 전체 묘사 + 공간 배치 + 환경 디테일
  4. 화면 크기: 구간 내 주도 화면 크기; 여러 화면 크기의 구간은 조합으로 씁니다(예: "미디엄샷+클로즈업")
  5. 앵글: 정면/로우 앵글/하이 앵글/측면/후면
  6. 카메라 무빙: 고정/푸시인/풀백/팬/팔로우/트래킹(구간 내 서브 컷마다 다를 수 있음)
  7. 화면 묘사 description: 【镜头1】…【镜头2】… 형식으로 서브 컷별로 관객이 실제로 보고 듣는 내용을 서술합니다 — 화면(누가 + 구체적 동작 + 신체 디테일 + 표정)을 먼저 씁니다; 해당 서브 컷에 대사가 있으면 「캐릭터명이 말한다: 「대사」」 형식으로 해당 【镜头N】 안에 쓰고, 내레이션은 「내레이션: 내용」으로 씁니다
  8. 화면 결과 result: 구간 끝의 즉각적인 결과 + 시각 디테일
  9. 분위기 atmosphere: 조명 + 색조 + 소리 + 전체 분위기
  10. 길이 duration: 구간 총 길이 8-15초, 대사 길이 하한을 충족해야 함
  11. 장면 연결: 기존 장면과 매칭되면 반드시 scene_id 를 채웁니다
  12. 캐릭터 연결: character_ids 를 채워 현재 구간에 관련된 0명 이상의 캐릭터를 바인딩합니다
  13. 소품 연결: prop_ids 를 채워 현재 구간에 등장하는 핵심 소품(0개 이상)을 바인딩합니다

장면 연결 규칙

  • read_storyboard_context 가 반환한 scenes 를 우선 사용합니다
  • location + time 으로 명확히 매칭되면 반드시 올바른 scene_id 를 채워 넣습니다
  • 존재하지 않는 장면 ID를 임의로 만들지 마세요
  • 대본 내용이 기존 장면에 명백히 해당하면 새 장면 묘사를 중복 생성하지 마세요

캐릭터 바인딩 규칙

  • character_ids 는 반드시 read_storyboard_context 가 반환한 캐릭터 목록에서 선택해야 합니다
  • 한 구간에 캐릭터가 없을 수도 있고, 여러 캐릭터를 바인딩할 수도 있습니다
  • 구간에 명확히 출연하거나, 보이거나, 동작하거나, 말하는 캐릭터가 있으면 모두 바인딩해야 합니다
  • 순수 환경 구간, 빈 장면, 사물 클로즈업은 빈 배열을 전달할 수 있습니다

소품 바인딩 규칙

  • prop_ids 는 반드시 read_storyboard_context 가 반환한 소품 목록(props)에서 선택해야 합니다
  • 소품이 캐릭터에 의해 사용되거나, 전달되거나, 클로즈업되거나, 화면에 뚜렷이 보이며 서사적으로 의미가 있을 때 반드시 해당 구간에 바인딩합니다
  • 소품 클로즈업 구간(캐릭터 없음)도 소품을 바인딩해야 하며, character_ids 는 비워 둘 수 있습니다
  • 줄거리와 무관한 배경 물건, 장면 비품은 바인딩하지 마세요; 소품이 등장하지 않는 구간은 빈 배열을 전달합니다
  • 바인딩된 소품은 비디오 생성의 참조 이미지(화이트 배경 단품 이미지)로 사용되어, 소품의 외형이 구간을 넘어 일관되게 유지됩니다

품질 요구 사항

  • description 은 사람이 읽기에 적합해야 하며, 서브 컷별로 관객이 실제로 보고 듣는 내용을 상세히 서술합니다; 대사/내레이션은 해당 【镜头N】 안에 직접 씁니다
  • image_prompt 는 단일 프레임 구도, 캐릭터 외형, 환경과 조명을 부각해야 합니다(구간의 첫 번째 서브 컷에 대응)
  • bgm_prompt 와 sound_effect 는 간결한 구문으로 쓰되, "긴장" "슬픔"만으로 끝날 만큼 공허해서는 안 됩니다
  • 조정이 필요하면 update_storyboard 를 호출해 특정 구간을 수정합니다

File: backend/workspace/skills/storyboard-breaker/SKILL.md


name: storyboard-breaker

分镜拆解指南

核心定义:分镜段落

一个分镜 = 一个 分镜段落(segment)= 一个视频生成任务。

  • 每个段落时长 8-15 秒,内部承载 2-4 个子镜头
  • 子镜头之间可以切镜:换景别、换角度、换拍摄对象,用硬切衔接
  • 子镜头之间不跨场景:一个段落只发生在一个场景内(scene_id 是段落级绑定)
  • 每个子镜头 2-6 秒,聚焦一个画面单元(一个动作、一个反应、一个特写)

拆分流程(四步)

  1. 调用 read_storyboard_context 读取剧本、角色、场景、道具、已有分镜摘要
  2. 节拍识别:先识别剧本的叙事节拍——剧本中的【开场】【触发】【高潮】【收尾】等标记,或叙事转折点(地点转移、规则揭示、情绪爆发、反转)。节拍边界强制切段,同一节拍内的子镜头优先归入同一段落,不把一条因果链(铺垫-发生-反应)切散到不同段落
  3. 总量锚定:目标总时长 = 剧本字数 ÷ 500字/分钟;段落数 ≈ 目标总时长 ÷ 12秒,允许 ±20% 浮动。不要明显超出或不足
  4. 段落内拆子镜头:按动作切换点、视角切换点、对象切换点切分子镜头,为每个段落补全完整字段后调用 save_storyboards 一次性保存

节奏分层时长

按段落功能确定时长,不要一刀切:

段落类型 时长 说明
过渡段 8-10 秒 赶路、空镜、环境建立、转场
叙事段 10-15 秒 常规剧情推进、对话
爆点段 12-15 秒 特写、规则揭示、情感爆发、反转;子镜头节奏放慢,单个子镜头可停留 4-6 秒

台词时长下限(硬规则)

段落时长 ≥ 段内台词与旁白总字数(写在 description 中的部分)÷ 4.5字/秒 + 2秒表演余量

装不下的台词必须拆到下一个段落,不允许把演不完的台词塞进一个段落。

镜头要素

  1. 镜头标题:3-5字概括段落核心内容(如"噩梦惊醒")
  2. 时间:具体时分 + 光线描述
  3. 地点:场景完整描述 + 空间布局 + 环境细节
  4. 景别:段落内主导景别;多景别段落写组合,如"中景+特写"
  5. 角度:平视/仰视/俯视/侧面/背面
  6. 运镜:固定/推镜/拉镜/摇镜/跟镜/移镜(段落内不同子镜头可不同)
  7. 画面描述 description:按 【镜头1】…【镜头2】… 逐子镜头描述观众实际看到和听到的内容——画面(谁 + 具体动作 + 肢体细节 + 表情)写在前;该子镜头有台词时以「角色名说:「台词」」写在对应 【镜头N】 内,旁白写「旁白:内容」
  8. 画面结果 result:段落结尾的即时后果 + 视觉细节
  9. 氛围 atmosphere:光线 + 色调 + 声音 + 整体氛围
  10. 时长 duration:段落总时长 8-15 秒,且满足台词时长下限
  11. 场景关联:若能匹配已有场景,必须填写 scene_id
  12. 角色关联:填写 character_ids,绑定当前段落涉及的 0 到多个角色
  13. 道具关联:填写 prop_ids,绑定当前段落出现的关键道具(0 到多个)

场景关联规则

  • 优先使用 read_storyboard_context 返回的 scenes
  • location + time 可明确匹配时,必须回填正确 scene_id
  • 不要凭空生成不存在的场景 ID
  • 如果剧本内容明显落在已有场景中,不要重复创造新场景描述

角色绑定规则

  • character_ids 必须从 read_storyboard_context 返回的角色列表中选择
  • 一个段落可以没有角色,也可以绑定多个角色
  • 只要段落里有明确出场、被看见、发生动作或说话的角色,都应绑定进去
  • 纯环境段落、空镜、物件特写可以传空数组

道具绑定规则

  • prop_ids 必须从 read_storyboard_context 返回的道具列表(props)中选择
  • 道具被角色使用、交接、特写,或在画面中明显可见且对叙事有意义时,必须绑定到该段落
  • 道具特写段落(无角色)也应绑定道具,character_ids 可为空
  • 与剧情无关的背景物品、场景陈设不要绑定;没有道具出现的段落传空数组
  • 绑定的道具会作为视频生成的参考图(白底单品图),保证道具外观跨段落一致

质量要求

  • description 要适合人读,按子镜头详细描述观众实际看到和听到的内容;台词/旁白直接写在对应 【镜头N】 内
  • image_prompt 要突出单帧构图、角色外观、环境和光线(对应段落第一个子镜头)
  • bgm_prompt 和 sound_effect 用简洁短语即可,但不能空泛到只有“紧张”“悲伤”
  • 如需调整,调用 update_storyboard 修改具体段落

File: configs/config.example.yaml

app:
name: "Huobao Drama API"
version: "1.0.0"
debug: true
language: "zh" # 系统语言:zh(中文) 或 en(英文)

server:
port: 5678
host: "0.0.0.0"
cors_origins:
- "http://localhost:3012"
read_timeout: 600
write_timeout: 600

database:
type: "mysql"
url: "mysql://huobao:[email protected]:3306/huobao_drama"
max_idle: 10
max_open: 100

storage:
type: "local"
local_path: "./data/storage"
base_url: "http://localhost:5678/static"

ai:
default_text_provider: "openai"
default_image_provider: "openai"
default_video_provider: "doubao"


File: desktop/electron-builder.yml

[Binary file]


File: desktop/package.json

{
"name": "huobao-drama-desktop",
"productName": "HuobaoDrama",
"version": "4.0.8",
"private": true,
"description": "火宝短剧桌面版(Electron 壳)",
"author": "Huobao",
"main": "dist/main.js",
"scripts": {
"build:backend": "node scripts/build-backend.mjs",
"build:main": "node scripts/build-main.mjs",
"rebuild:native": "electron-builder install-app-deps",
"postinstall": "electron-builder install-app-deps",
"dev": "npm run build:backend && npm run build:main && electron .",
"dist": "npm run build:backend && npm run build:main && node scripts/prepare-resources.mjs && electron-builder --mac",
"dist:win": "npm run build:backend && npm run build:main && node scripts/prepare-resources.mjs && electron-builder --win",
"feed": "node scripts/make-update-feed.mjs",
"publish": "node scripts/publish-release.mjs"
},
"dependencies": {
"better-sqlite3": "^12.4.1",
"sharp": "^0.34.5"
},
"devDependencies": {
"@electron/rebuild": "^4.2.0",
"electron": "37.10.3",
"electron-builder": "^26.15.3",
"esbuild": "^0.28.2",
"ffmpeg-static": "^5.3.0",
"ffprobe-static": "^3.1.0"
},
"optionalDependencies": {
"@img/sharp-win32-x64": "^0.34.5"
}
}


File: frontend/package.json

{
"name": "huobao-drama-frontend",
"private": true,
"type": "module",
"scripts": {
"dev": "nuxt dev --port 3013",
"build": "nuxt build",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"dependencies": {
"driver.js": "^1.8.0",
"lucide-vue-next": "^0.511.0",
"nuxt": "^3.17.5",
"vue": "^3.5.13",
"vue-i18n": "^11.4.10",
"vue-router": "^4.5.1",
"vue-sonner": "^1.2.4"
},
"devDependencies": {
"typescript": "^5.8.3"
},
"allowScripts": {
"[email protected]": true,
"@parcel/[email protected]": true
}
}


File: frontend/tsconfig.json

{
"extends": "./.nuxt/tsconfig.json"
}


File: frontend/app/locales/en.json

{
"app": {
"title": "Huobao Shorts",
"updateAvailable": "New version v{version} is available. Upgrade in Settings → About."
},
"common": {
"confirm": "Confirm",
"cancel": "Cancel",
"back": "Back",
"saved": "Saved",
"delete": "Delete",
"deleteLoading": "Deleting...",
"deleteFailed": "Delete failed",
"save": "Save",
"close": "Close",
"refresh": "Refresh",
"add": "Add",
"copy": "Copy",
"download": "Download",
"default": "Default",
"more": "More",
"loading": "Loading…",
"listJoin": ", ",
"role": "Character",
"scene": "Scene",
"prop": "Prop",
"reference": "Reference",
"serviceType": {
"text": "Text",
"image": "Image",
"video": "Video"
}
},
"layout": {
"nav": {
"projects": "Projects",
"settings": "Settings"
},
"banner": {
"missing": "{types} model not configured yet. AI features are unavailable.",
"goSettings": "Go to Settings"
},
"theme": {
"label": "Toggle theme",
"light": "Light mode",
"dark": "Dark mode",
"system": "Follow system"
}
},
"migrate": {
"title": "Switching storage location",
"hint": "Do not close the app during migration",
"phases": {
"validating": "Validating target directory…",
"stopping": "Stopping background services…",
"moving": "Migrating data files…",
"movingProgress": "Migrating data files… {copied} / {total}",
"config": "Updating storage config…",
"restarting": "Restarting background services…",
"done": "Migration complete",
"error": "Migration failed"
}
},
"components": {
"mention": {
"noMatch": "No matching references",
"fallbackGroup": "Reference"
},
"baseSelect": {
"placeholder": "Please select...",
"search": "Search...",
"noMatch": "No matches"
},
"confirmDialog": {
"title": "Confirm delete"
},
"localeSwitcher": {
"label": "Switch UI language"
},
"langSwitch": {
"title": "Switch language to {lang}?",
"message": "The UI language and AI content language will switch together.",
"effectUi": "All interface texts switch to this language",
"effectAi": "AI output (script rewriting, asset extraction, storyboard, prompts) uses this language, with matching agent prompts/skills",
"effectRefresh": "The page refreshes automatically after confirming",
"confirm": "Switch & Refresh",
"refreshing": "Language switched, refreshing…"
}
},
"composables": {
"agent": {
"busy": "Operation in progress",
"done": "Done"
}
},
"index": {
"hero": {
"title": "Project Launcher",
"sub": "From an idea to a short drama — AI does the whole pipeline for you",
"projectCount": "{n} projects",
"activeCount": "{n} active",
"styleCount": "{n} visual styles"
},
"create": "New Project",
"searchPlaceholder": "Search projects",
"sortAria": "Sort projects",
"sortUpdated": "Recently updated",
"sortTitle": "Project name",
"statusBadgeTitle": "Click to set project status",
"openProjectAria": "Open project {title}",
"openProject": "Open project",
"deleteProject": "Delete project",
"projectMeta": "{chars} characters · {scenes} scenes · {eps} episodes",
"emptyFilteredTitle": "No matching projects",
"emptyFilteredDesc": "Adjust the search term or filters.",
"emptyTitle": "Create your first drama project",
"emptyDesc": "Pick an episode to start producing after creation.",
"deleted": "Deleted",
"noEpisodes": "No episodes yet",
"episodeN": "Episode {n}",
"ratio": {
"landscape": "16:9 · Landscape",
"portrait": "9:16 · Portrait",
"square": "1:1 · Square",
"adaptive": "Adaptive"
},
"status": {
"all": "All",
"draft": "Not started",
"active": "In progress",
"completed": "Completed"
},
"createDialog": {
"title": "New Project",
"desc": "Pick an episode on the project page after creation",
"name": "Project name",
"namePlaceholder": "e.g. Urban romance drama “The Time Post Office”",
"style": "Visual style",
"stylePlaceholder": "Select a style",
"aspectRatio": "Aspect ratio",
"aspectRatioPlaceholder": "Select aspect ratio",
"aspectRatioHint": "Fixed after creation; all videos will use this ratio",
"submit": "Create project"
},
"deleteDialog": {
"title": "Delete project",
"message": "Delete “{title}”? Episodes, storyboards and generation records will be removed. This cannot be undone."
},
"time": {
"justNow": "Just now",
"minutesAgo": "{n} min ago",
"hoursAgo": "{n} h ago",
"daysAgo": "{n} d ago"
}
},
"detail": {
"head": {
"charCount": "{n} characters",
"sceneCount": "{n} scenes",
"epCount": "{n} episodes",
"addEpisode": "Add Episode"
},
"tabs": {
"episodes": "Episodes",
"assets": "Asset Library"
},
"ep": {
"statusTitle": "Click to set episode status",
"resTitle": "Click to change video resolution",
"deleteTitle": "Delete this episode",
"enter": "Open Studio",
"scriptReady": "Script ready",
"merged": "Merged",
"emptyCreateTitle": "Click to create the first episode",
"emptyCreateText": "Click to create the first episode",
"addNextTitle": "Add Episode {n}",
"addNextText": "Add Episode {n}",
"episodeN": "Episode {n}",
"res720": "720p · HD",
"res480": "480p · Smooth",
"resSwitched": "Video resolution switched to {res}"
},
"epCreate": {
"title": "Create Episode",
"titleField": "Title",
"titlePlaceholder": "Auto-named by episode number",
"titleHint": "If left blank, it will be named automatically, e.g. “{example}”.",
"example": "Episode {n}",
"resolution": "Video resolution",
"resolutionPlaceholder": "Select resolution",
"resolutionHint": "Videos of this episode are generated at this resolution; you can still change it on the episode card later.",
"lockCopy": "The currently active image and video generation capabilities will be locked on creation.",
"creating": "Creating...",
"create": "Create",
"added": "Episode added"
},
"epDelete": {
"message": "Delete “{title}”? It will be hidden from the list and its storyboards and generation records will no longer be accessible."
},
"assets": {
"emptyTitle": "No assets yet",
"emptyDesc": "Characters, scenes and props extracted in the production workbench will appear here, and you can generate images for them directly.",
"emptyKindTitle": "No {kind} assets yet",
"emptyKindDesc": "They will appear here after extraction and generation in the workbench.",
"todoShort": "TBD"
},
"mat": {
"dialogAria": "Asset detail",
"unnamed": "Unnamed",
"propTypePlaceholder": "e.g. weapon / keepsake",
"personaField": "Character persona",
"personaPlaceholder": "Personality, background, motivation…",
"locationPlaceholder": "e.g. Hall of Supreme Harmony",
"timePlaceholder": "e.g. dusk / midnight",
"finalPromptLabel": "Final prompt",
"finalPromptSub": "Generated by AI from the info; editable before saving",
"genPromptTitle": "Generate final prompt with AI",
"needEpisodeFirst": "Create at least one episode in “Episodes” first",
"promptPlaceholder": "Click “Generate prompt” for AI to create from the info, or type it manually. Once saved manually, the next image generation will use this prompt.",
"genImage": "Generate image",
"saving": "Saving…",
"generating": "{kind} “{name}” image generating",
"genTimeout": "{kind} “{name}” generation timed out; refresh later to check",
"uploaded": "{kind} “{name}” image uploaded",
"needEpisodeForImage": "Create at least one episode in “Episodes” before generating asset images",
"needEpisodeForPrompt": "Create at least one episode in “Episodes” before generating the final prompt",
"locationRequired": "Please enter a location"
}
},
"settings": {
"groupBase": "Basic",
"tabs": {
"general": "General",
"ai": "AI Services",
"styles": "Style Presets",
"storage": "Storage",
"about": "About & Updates",
"agents": "Agent Config"
},
"common": {
"disabled": "Disabled",
"custom": "Custom",
"empty": "No configs yet"
},
"general": {
"title": "General",
"desc": "App-level settings. Language switching applies to both the UI and AI-generated content.",
"contentLanguage": "AI Content Language",
"contentLanguageSub": "Language used by both the UI and AI output (script/assets/storyboard/prompts)",
"languageLabel": "Language",
"languageNote": "Switching updates UI and AI content language together, with an automatic refresh",
"languageHint": "Both entry points (top-bar button / here) are equivalent and apply globally.",
"languageSaved": "Content language saved",
"appearance": "Appearance",
"appearanceSub": "Interface color theme, applied instantly",
"appearanceLabel": "Theme mode",
"appearanceNote": "In System mode, follows your OS appearance automatically",
"appearanceLight": "Light",
"appearanceDark": "Dark",
"appearanceSystem": "System",
"languageSavedWith": "AI content language switched to {lang} — future generations (script/assets/storyboard/prompts) will use it",
"langNameZh": "Chinese",
"langNameEn": "English",
"langNameJa": "Japanese",
"langNameKo": "Korean",
"unifiedSwitchWarning": "Switched to {lang} — UI and AI content language update together. Refreshing…"
},
"ai": {
"title": "AI Service Configs",
"desc": "Start with a recommended template, then fine-tune per service type. The workbench locks the chosen image and video capabilities when creating an episode.",
"quickTitle": "Huobao Quick Config",
"recommended": "Recommended",
"quickDesc": "Enter a Huobao API Key to write three recommended configs (text, image, video) at once.",
"getKey": "Get a Huobao API key",
"regionCn": "China",
"regionCom": "Global",
"applyQuick": "Apply Huobao Config",
"manualTitle": "Manual Templates",
"manualDesc": "Pick a service type, then fill the recommended provider / base URL / model from a template.",
"activeCount": "{n} active",
"hasKey": "Configured",
"noKey": "No key",
"currentDefault": "Current default model",
"setDefault": "Set as default model for this type",
"noBaseUrl": "Base URL not set",
"test": "Test",
"apiKeyRequired": "Please enter a Huobao API Key",
"quickApplied": "Huobao quick config written",
"defaultModelSwitched": "Default {type} model switched to {model}",
"meta": {
"text": "Text capabilities: script rewriting, asset extraction, storyboard breaking",
"image": "Static image generation: characters, scenes and shots",
"video": "Direct video generation, Seedance 2.0 by default"
}
},
"styles": {
"title": "Style Presets",
"desc": "The visual style chosen at project creation. Its English prompt fragment is injected into character and scene image generation. Disabled styles are hidden from creation options.",
"allTitle": "All Styles",
"count": "{active} active · {total} total",
"empty": "No style presets"
},
"storage": {
"title": "Storage Location",
"desc": "The directory holding the database and generated files (images/videos/merges/uploads). Changing it briefly stops background services and migrates data.",
"currentDir": "Current Data Directory",
"computedAt": "Computed at {time}",
"changeLocation": "Change Location",
"dataDir": "Data directory",
"desktopMode": "Desktop",
"serverMode": "Server",
"totalUsage": "Total usage {size}",
"counting": "Counting…",
"breakdown": {
"db": "Database",
"images": "Images",
"videos": "Videos",
"merged": "Merged",
"uploads": "Uploads",
"temp": "Temp",
"other": "Other"
},
"diskFree": "Disk free {size}",
"note": "The data directory holds the SQLite database and all generated media; Agent skills (workspace) are not included and do not migrate.",
"serverNote": "For server deployments, configure storage via STORAGE_PATH / SQLITE_PATH environment variables; restart to apply.",
"loadFailed": "Failed to load storage info"
},
"about": {
"title": "About & Updates",
"desc": "Pulls new versions from the release manifest, verifies sha256 locally, then swaps the package and restarts. User data and configs live in the system data directory and are unaffected by updates.",
"currentVersion": "Current version v{v}",
"latestVersion": "Latest version v{v}",
"check": "Check for Updates",
"webMode": "You are in browser/server mode; in-app updates are only available on desktop.",
"upToDate": "You're up to date",
"found": "New version v{v} available",
"downloading": "Downloading {p}%",
"download": "Download Update",
"ready": "Update package ready",
"readyDesc": "The app will quit, install automatically, and reopen.",
"restartInstall": "Restart & Install",
"checkFailed": "Check failed",
"retry": "Retry",
"empty": "Click “Check for Updates” to fetch the latest version.",
"note": "Note: on macOS the update is applied via directory swap (same approach as Tauri), no Apple signing required; on Windows the installer runs silently.",
"checkFailedToast": "Update check failed",
"downloadDone": "Update package downloaded, ready to install",
"downloadFailed": "Download failed",
"installFailed": "Install failed",
"serverApply": "Update now",
"serverApplyStarted": "Update triggered: Watchtower will pull the new image and recreate the container. Refresh in a few minutes.",
"serverApplyFailed": "Failed to trigger update",
"serverManualHint": "Server deployment: run this in the deploy directory:",
"serverNote": "Note: with Watchtower configured, Docker deployments can update in one click (pulls the new image and recreates the container); otherwise run the command shown above manually."
},
"agents": {
"promptHint": "saved as {file}",
"promptPlaceholder": "Agent system prompt...",
"reset": "Reset to default",
"promptReset": "Default prompt restored (prompt file deleted)",
"saved": "{agent} config saved",
"scriptRewriter": "Script Rewriter",
"extractor": "Asset Extractor",
"storyboardBreaker": "Storyboard Breaker",
"promptGenerator": "Prompt Generator",
"langFallback": "Falls back to Chinese",
"followContentLang": "Editing language: {lang} (switch in General → AI Content Language)"
},
"skills": {
"agentList": "Agents",
"desc": "Skills act as an advanced prompt layer for Agents and do not affect the regular workbench entry points.",
"add": "Add Skill",
"emptyTitle": "No skills yet",
"emptyDesc": "Click “Add Skill” in the top-right to create the first prompt file",
"contentPlaceholder": "Write the SKILL.md content...",
"addTitle": "Add Skill — {agent}",
"dirName": "Skill directory name",
"dirNameHint": "English, unique",
"dirNamePlaceholder": "e.g. custom-extraction",
"name": "Name",
"namePlaceholder": "e.g. Custom extraction rules",
"description": "Description",
"descPlaceholder": "A short description of this skill",
"create": "Create",
"created": "Skill created"
},
"cfg": {
"editTitle": "Edit Service Config",
"addTitle": "Add {type} Service",
"sub": "Pick a template first — a sensible Base URL and default models will be filled in automatically.",
"name": "Config name",
"namePlaceholder": "e.g. Huobao default image service",
"provider": "Provider",
"providerPlaceholder": "Select a provider",
"priority": "Priority",
"priorityHint": "Higher wins. The workbench prefers the highest-priority active config of the same type.",
"models": "Models",
"modelsHint": "First entry is the default model; click a tag to pin it to the top. Paste comma/newline-separated names to add in bulk",
"modelPlaceholder": "Type a model name, press Enter to add",
"modelChipHint": "Click to set as default (pin to top)",
"tempHint": "blank = provider default",
"tempPlaceholder": "e.g. 0.6",
"tempNote": "Some models enforce a fixed temperature (e.g. kimi-k2 only allows 0.6). If you get an invalid temperature error, set the value here.",
"test": "Test Config",
"reachable": "Endpoint responded",
"unreachable": "Endpoint failed the test",
"providerRequired": "Select a provider",
"tempInvalid": "Temperature must be a number between 0 and 2"
},
"styleDialog": {
"editTitle": "Edit Style Preset",
"addTitle": "Add Style Preset",
"sub": "The prompt fragment is in English and is automatically prepended to character and scene image prompts.",
"tag": "Style",
"name": "Style name",
"namePlaceholder": "e.g. 3D, anime, photorealistic",
"key": "Style key",
"keyPlaceholder": "e.g. 3d, anime (lowercase letters/digits/dashes)",
"keyHint": "The style identifier stored in the project; cannot be changed after creation.",
"prompt": "Prompt fragment (English)",
"promptPlaceholder": "e.g. anime style, cel shading, vibrant colors, clean line art",
"description": "Description",
"descPlaceholder": "One line about when to use this style",
"sort": "Sort order",
"required": "Name, key and prompt fragment are required"
},
"migrate": {
"title": "Change Storage Location",
"newDir": "New directory",
"dataToMove": "Data to migrate",
"sizeNote": "About {size}",
"freeNote": " · {size} free on target",
"moveFiles": "Migrate existing data (database and all generated files)",
"emptyWarn": "Warning: the app will start with a fresh empty database. Data in the old directory is kept but will no longer be used.",
"note": "Background services will briefly stop during migration; ongoing generation tasks will be interrupted. The page reloads when done.",
"start": "Start Migration",
"pickFailed": "Failed to pick a directory",
"failed": "Migration failed; the original storage location was restored"
},
"styleDelete": {
"title": "Delete Style Preset",
"message": "Delete style “{name}”? Projects already using it are unaffected, but a deleted built-in style may be restored on restart — consider disabling instead."
},
"skillDelete": {
"title": "Delete Skill",
"message": "Delete skill “{id}”? The corresponding Agent will fall back to its built-in default prompt."
}
},
"episode": {
"topbar": {
"back": "Back to Project",
"episodeN": "Episode {n}",
"meta": "{roles} characters · {shots} segments",
"tasks": "Tasks",
"viewFilm": "View Film",
"continue": "Continue",
"start": "Start Production",
"resolution": "Resolution"
},
"model": {
"defaultWith": "Default · {model}",
"notConfigured": "Not configured"
},
"sidebar": {
"inProgress": "In progress",
"refreshData": "Refresh Data",
"collapse": "Collapse sidebar",
"expand": "Expand sidebar"
},
"nav": {
"prev": "Back",
"next": "Next",
"toExport": "Go to Export"
},
"stage": {
"script": "Script",
"scriptDesc": "Rewrite and organize content",
"production": "Production",
"assets": "Assets",
"assetsDesc": "Characters / scenes / props",
"videos": "Video Production",
"videosDesc": "Storyboard breakdown and video generation",
"export": "Export",
"exportDesc": "Merge and output the film",
"mergeExport": "Merge & Export",
"scriptStage": "Script · {step}",
"prodStage": "Production · {step}",
"exportDone": "Export · done",
"exportWaiting": "Export · waiting to merge",
"workbench": "Workbench"
},
"script": {
"raw": "Raw Content",
"rewrite": "AI Rewrite",
"charCount": "{n} chars",
"saved": "Saved",
"rawPlaceholder": "Paste the novel text, story outline or shot descriptions...",
"skipRewrite": "Skip Rewrite",
"rewriteAgain": "Rewrite Again",
"emptyTitle": "AI rewrite into a formatted script",
"emptyDesc": "Use AI to organize the raw content into a formatted script, or skip this step and go straight to asset production.",
"startRewrite": "Start Rewrite",
"rewriting": "Rewriting the script...",
"scriptPlaceholder": "Formatted script content...",
"rawRequired": "Please fill in the raw content first",
"skipDone": "AI rewrite skipped; the raw content will be used directly"
},
"prod": {
"assets": "Asset Production",
"videos": "Video Production",
"notReady": "Not ready yet",
"readyCount": "{ready}/{total} ready",
"extract": "Extract {type}",
"reextract": "Re-extract {type}",
"batchChar": "Batch Characters",
"batchScene": "Batch Scenes",
"batchProp": "Batch Props",
"extractingTypes": "Extracting {types}...",
"extractingTypesDots": "Extracting {types}…",
"emptyTitle": "Start Extracting Assets",
"emptyDesc": "Characters, scenes and props will appear here after extraction. Extract each type separately or all at once in parallel.",
"startExtract": "Start Extraction",
"scriptFirst": "Please finish the script first",
"goBack": "Go back"
},
"asset": {
"fallbackType": "Asset",
"typeChar": "Character asset",
"typeScene": "Scene asset",
"typeProp": "Prop asset",
"detailTitle": "{type} detail",
"delChar": "Delete character",
"delScene": "Delete scene",
"delProp": "Delete prop",
"charImageTitle": "{name} character portrait",
"sceneImageTitle": "{name} scene image",
"propImageTitle": "{name} prop image",
"portraitReady": "Portrait ready",
"portraitPending": "Portrait generating",
"portraitTodo": "Portrait pending",
"ready": "Ready",
"generating": "Generating",
"todo": "Pending",
"regen": "Regenerate",
"generate": "Generate",
"upload": "Upload",
"uploadCharImage": "Upload character portrait",
"uploadSceneImage": "Upload scene image",
"uploadPropImage": "Upload prop image",
"uploadImage": "Upload image",
"appearance": "Appearance: ",
"styling": "Styling: ",
"lighting": "Lighting · ",
"appearanceTodo": "Appearance TBD",
"stylingTodo": "Styling TBD",
"sceneDescTodo": "Scene description TBD",
"sceneLightTodo": "Scene lighting TBD",
"noDescription": "No description",
"noTime": "Time not set",
"finalPromptTurnaround": "Final prompt · Turnaround",
"finalPromptFixed": "Final prompt · Fixed view",
"finalPromptWhiteBg": "Final prompt · White-bg product shot",
"finalPromptAutoTurnaround": "Auto-generated by the prompt Agent on first portrait generation",
"finalPromptAutoFixed": "Auto-generated by the prompt Agent on first image generation (foreground/midground/background)",
"finalPromptAutoWhiteBg": "Auto-generated by the prompt Agent on first image generation (white-bg product shot)",
"propsEmpty": "No plot-critical props in this episode",
"visualPreview": "Visual Preview",
"kindLabel": "Type",
"charPortrait": "Character portrait",
"sceneImage": "Scene image",
"roleLabel": "Role",
"propTypeLabel": "Prop type",
"timeLabel": "Time",
"editInfo": "Edit Info",
"editHintChar": "Appearance and styling affect the character portrait",
"editHintProp": "Object appearance affects the prop image",
"editHintScene": "Space and lighting affect the scene image",
"appearanceOfObject": "Object appearance",
"appearancePlaceholder": "Material, color, shape, size, wear, scratches…",
"appearanceField": "Appearance",
"appearanceFieldPlaceholder": "Age impression, facial features, build, temperament…",
"stylingField": "Styling",
"stylingFieldPlaceholder": "Hair, clothing, makeup, accessories…",
"sceneDescField": "Scene description",
"sceneDescPlaceholder": "Space, furnishings, period texture, key visual elements…",
"sceneLightField": "Scene lighting",
"sceneLightPlaceholder": "Light sources, color tone, brightness, atmosphere…",
"genPrompt": "Generate Prompt",
"regenPrompt": "Regenerate",
"genPortrait": "Generate Portrait",
"regenPortrait": "Regenerate Portrait",
"genScene": "Generate Scene",
"regenScene": "Regenerate Scene",
"genProp": "Generate Prop Image",
"regenProp": "Regenerate Prop Image",
"promptPlaceholderChar": "Write the turnaround final prompt manually, or click “Generate Prompt” for the Agent",
"promptPlaceholderScene": "Write the fixed-view final prompt manually, or click “Generate Prompt” for the Agent",
"promptPlaceholderProp": "Write the white-bg final prompt manually, or click “Generate Prompt” for the Agent",
"promptHintChar": "The prompt is editable and takes effect on save. After changing appearance or styling and saving, the final prompt is cleared and will be regenerated by the prompt Agent on next portrait generation.",
"promptHintScene": "The prompt is editable and takes effect on save. After changing the description or lighting and saving, the final prompt is cleared and will be regenerated by the prompt Agent on next scene image generation.",
"promptHintProp": "The prompt is editable and takes effect on save. After changing the object appearance and saving, the final prompt is cleared and will be regenerated by the prompt Agent on next prop image generation.",
"generatingPrompt": "Generating final prompt…",
"promptGenerated": "Final prompt generated",
"promptRegenerated": "Final prompt regenerated",
"promptGenFailedRetry": "Final prompt generation failed, please retry",
"promptGenFailed": "Final prompt generation failed",
"promptCopied": "Final prompt copied",
"copyFailed": "Copy failed; please select and copy the text manually",
"noChanges": "No changes to save",
"saved": "Changes saved",
"saveFailed": "Save failed",
"saveChanges": "Save Changes",
"unnamedChar": "Unnamed character",
"unnamedProp": "Unnamed prop",
"unnamedScene": "Unnamed scene",
"propSingleImage": "Prop product shot",
"propImage": "Prop image"
},
"create": {
"title": "Add {type}",
"name": "Name",
"namePlaceholderChar": "Character name",
"namePlaceholderProp": "Prop name",
"roleField": "Character role",
"rolePlaceholder": "e.g. protagonist / antagonist / supporting",
"appearancePlaceholder": "Appearance traits (personality may be blended in)",
"stylingPlaceholder": "Clothing, makeup, accessories",
"location": "Location",
"locationPlaceholder": "Scene location",
"time": "Time",
"timePlaceholder": "e.g. day / night",
"sceneDescPlaceholder": "Environment, furnishings, atmosphere",
"lightPlaceholder": "e.g. warm dusk light, cold overhead light",
"typeField": "Type",
"typePlaceholder": "e.g. weapon / keepsake / document",
"appearanceOnlyPlaceholder": "Describe only the object's appearance, nothing else",
"locationRequired": "Please enter the scene location",
"nameRequired": "Please enter a name",
"created": "{type} added"
},
"delete": {
"title": "Delete {type}",
"message": "Delete {type} “{name}”? It will be removed from all episodes of this drama.",
"deleted": "{type} deleted"
},
"sb": {
"title": "Storyboard Breakdown",
"segmentStat": "{n} segments · {dur}s",
"rebreak": "Break Again",
"startBreak": "Break down & generate prompts",
"promptProgress": "Prompts {done}/{total}",
"promptSelected": "Generate selected prompts ({n})",
"batchPrompts": "Batch Fill Prompts",
"listTitle": "Shot List",
"listSub": "Check breakdown descriptions and bound characters/scenes",
"select": "Select",
"selectAll": "Select All",
"selectMissing": "Missing Only",
"clear": "Clear",
"selectedCount": "{n} selected",
"generatingProgress": "Generating {done}/{total}",
"generateSelected": "Generate video prompts ({n})",
"shotN": "Shot #{n}",
"totalCount": "{n} in total",
"duration": "Duration",
"descSection": "Shot Description",
"descLabel": "Visual description",
"descHint": "Describe each sub-shot as 【Shot 1】【Shot 2】…; dialogue as “Name says: 「line」”, narration as “Narrator: …”",
"descPlaceholder": "Shot visual description",
"atmosphere": "Atmosphere",
"atmospherePlaceholder": "Lighting, color tone, air feel, ambience",
"videoPromptSection": "Video Prompt",
"regenPrompt": "Regenerate",
"aiGenerate": "AI Generate",
"videoPromptCopy": "Generated from this shot's visual description (including dialogue/narration) and atmosphere",
"videoPromptPlaceholder": "Reference assets with {'@'}character / {'@'}scene, describe motion and camera per 3-second line; or click AI Generate for the prompt Agent…",
"breaking": "Breaking the storyboard...",
"emptyTitle": "Start Storyboard Breakdown",
"emptyDesc": "Break the script into shots based on the script, characters and scenes, producing shot descriptions and bindings.",
"hasVideo": "Video generated",
"noVideo": "No video yet",
"hasVideoShort": "Has video",
"videoFlag": "V",
"noDescription": "No visual description",
"zeroChars": "0 characters",
"unboundScene": "No scene bound",
"breakFirst": "Break the storyboard first",
"selectedMissing": "The selected shots don't exist",
"allHavePrompts": "All shots already have video prompts",
"batchStarted": "Generating video prompts for {n} shots…",
"batchDone": "Batch video prompt generation complete",
"batchDoneFailed": "Batch video prompt generation complete, {n} failed",
"batchFailed": "Batch video prompt generation failed",
"promptGenerated": "Video prompt for shot #{n} generated"
},
"ref": {
"title": "Reference Assets",
"copy": "Bind characters / scenes / props as video references",
"boundCount": "{bound}/{total} bound",
"clickAdd": "Click to add as reference",
"clickRemove": "Click to remove from references",
"shortChar": "C",
"shortScene": "S",
"shortProp": "P",
"usable": "Usable",
"notReady": "Not generated",
"unbound": "Unbound",
"gotoGenerate": "Go generate →",
"empty": "No scenes, characters or props in this episode yet. Extract assets in “Assets” first, then bind them here."
},
"vid": {
"shotCount": "{n} shots",
"doneCount": "{done}/{total} generated",
"batchVideos": "Batch Videos",
"emptyTitle": "Break the storyboard first",
"emptyDesc": "Video tasks come from the storyboard breakdown. Generate shot descriptions and video prompts first, then generate videos in batch.",
"lockedModel": "Video model for this episode: ",
"listTitle": "Video Task List",
"listMeta": "In shot order · {n} tasks",
"metricPending": "{n} generating",
"metricDone": "{n} done",
"metricFailed": "{n} failed",
"references": "{n} refs",
"refCountMeta": "{n} reference assets",
"shotN": "Shot #{n}",
"playerTitle": "Shot {n}",
"setMain": "Set as Main Video",
"setMainDone": "Set as main video",
"setMainFailed": "Setting failed",
"download": "Download",
"emptyGenerating": "Video generating…",
"emptyNoVideo": "No video generated yet",
"emptyGeneratingDesc": "Once generated, it can be previewed here",
"emptyNoVideoDesc": "Click the button below to generate a video for this shot",
"generateVideo": "Generate Video",
"history": "Video History",
"current": "Current",
"deleteRecord": "Delete this record",
"historyDeleted": "History record deleted",
"needRefOrPrompt": "At least one reference asset or a video prompt is required",
"generating": "Video generating",
"genDone": "Video generation complete",
"genFailed": "Video generation failed",
"genTimeout": "Video generation timed out",
"allDone": "All shot videos generated",
"moderationHint": "Looks like a real-person/sensitive content moderation rejection — switch video model in the top bar and retry",
"resolutionSwitched": "Episode video resolution switched to {label}",
"noneToGenerate": "No shots to generate",
"batchStarted": "Started {n} video generation tasks",
"retryFailed": "Retry failed ({n})",
"select": "Select",
"selectDone": "{n} selected · Done",
"batchSelected": "Generate selected ({n})",
"listMetaFiltered": "Filtered · {n}/{total} tasks",
"defaultModel": "Default model",
"confirmTitle": "Batch generate videos",
"confirmShots": "Shots",
"confirmShotsValue": "{n}",
"confirmTotal": "Total duration",
"confirmApprox": "~{n}s",
"confirmModel": "Video model",
"confirmResolution": "Resolution",
"confirmNote": "Generation will start shot by shot with the above config; failed tasks can be retried later via "Retry failed".",
"confirmStart": "Start ({n})",
"selectMissing": "Select without video",
"aspectRatio": "Aspect Ratio"
},
"inspector": {
"videoPromptPlaceholder": "Reference assets with {'@'}character / {'@'}scene — auto-mapped to reference images on generation; then describe motion and camera per time segment…",
"noRefs": "No reference assets bound to this shot",
"refMedia": "Reference images / videos / audio",
"imageN": "Image {n}",
"videoN": "Video {n}",
"audioN": "Audio {n}",
"uploadRefImage": "Upload reference image ({used}/{limit})",
"uploadRefVideo": "Upload reference video ({used}/{limit})",
"uploadRefAudio": "Upload reference audio ({used}/{limit})",
"refAudioHint": "Reference audio requires at least 1 reference image or video",
"params": "Generation Params",
"duration": "Shot duration",
"durationUnit": "s (2-30)",
"durationHint": "Edits save to the storyboard instantly and apply to list and batch generation",
"effective": "{model} · {res} · {dur}s",
"boundRefs": "Bound References",
"noBoundRefs": "No bound assets (bind in the center "References" panel)"
},
"tasks": {
"title": "Generation Tasks",
"meta": "Newest first · {n} tasks",
"emptyTitle": "No generation tasks",
"emptyDesc": "Tasks will appear here automatically after you trigger image/video generation in the assets, storyboard or video steps.",
"duration": "took {dur}",
"sbN": "Shot #{n}",
"generic": "General",
"fullMerge": "Full-episode merge",
"mergeKind": "Merge"
},
"export": {
"notReadyDesc": "Please finish the storyboard and production steps first",
"gotoScript": "Go to Script",
"filmList": "Film List",
"countN": "{n} items",
"empty": "No films yet. Select shots below and click “Merge Selected”.",
"shotAssets": "Shot Assets",
"shotStat": "{done}/{total} generated · {selected} selected",
"clearSelection": "Clear Selection",
"selectAllReady": "Select All Generated",
"mergeSelected": "Merge Selected ({n})",
"selectFirst": "Select at least one shot with a generated video first",
"merging": "Merging…",
"mergingToast": "Merging...",
"mergeDone": "Merge complete",
"mergeFailed": "Merge failed",
"previewShot": "Play this shot",
"shotPreview": "Shot #{n} preview",
"markDone": "Mark done",
"markedDone": "Done",
"markDoneTitle": "Manually mark this episode's export as done (click again to undo)",
"markedDoneToast": "Marked as done",
"unmarkDoneToast": "Done mark removed"
},
"image": {
"generatingChar": "Character image generating",
"generatingScene": "Scene image generating",
"generatingProp": "Prop image generating",
"batchGeneratingChar": "Batch character images generating",
"batchGeneratingScene": "Batch scene images generating",
"batchGeneratingProp": "Batch prop images generating",
"allCharsDone": "All character images generated",
"allScenesDone": "All scene images generated",
"allPropsDone": "All prop images generated"
},
"extract": {
"done": "{type} extraction complete",
"failed": "{type} extraction failed"
},
"upload": {
"assetDone": "{type} uploaded",
"refImageFull": "Reference image limit reached (including scene/character assets)",
"refImageDone": "Reference image uploaded",
"refMax3": "At most 3 reference {type}",
"refDone": "Reference {type} uploaded",
"refAudioNeed": "Reference audio requires at least 1 reference image or video",
"audio": "audio",
"refMax": "At most {n} reference {type}"
},
"viewer": {
"imagePreview": "Image Preview",
"filmPreview": "Film Preview",
"downloadFilm": "Download Film"
},
"status": {
"done": "Done",
"generating": "Generating",
"failed": "Failed",
"todo": "Pending"
},
"resolution": {
"smooth": "Smooth",
"hd": "HD",
"uhd": "UHD"
}
},
"errors": {
"network": "Cannot reach the server. Check your network or that the service is running.",
"server": "The server returned an unexpected response. Please try again later.",
"unavailable": "Service temporarily unavailable. Please try again later.",
"auth": "Authentication failed. Check your API key settings.",
"rateLimit": "Too many requests or insufficient quota. Please try again later.",
"timeout": "Generation timed out. Please try again.",
"moderation": "Content was blocked by moderation. Adjust the prompt or switch models and retry.",
"requestFailed": "Request failed ({status})",
"unknown": "Operation failed. Please try again."
},
"tour": {
"next": "Next",
"prev": "Back",
"done": "Done",
"helpTitle": "Guide",
"index": {
"welcome": {
"title": "👋 Welcome to Huobao Drama",
"desc": "Novel → script → assets → storyboard → video → final cut, all in one place. Configure AI services first, then create your first project."
},
"create": {
"title": "Step 2 · Create a project",
"desc": "Click "New Project": name it, pick an aspect ratio (landscape/portrait) and a visual style."
},
"settings": {
"title": "Step 1 · Configure AI services",
"desc": "Every AI feature needs this first. Open Settings and paste a Huobao API Key to set up text/image/video in one click."
}
},
"settings": {
"quick": {
"title": "Fastest setup: Quick Setup",
"desc": "Paste a Huobao API Key to write the three recommended configs (text/image/video) at once, with connectivity testing."
},
"nav": {
"title": "Everything lives here",
"desc": "Switch sections on the left: AI services, general (UI & content language), style presets, agent prompts & skills, storage, about."
}
},
"episode": {
"topbar": {
"title": "Top bar: models & status",
"desc": "Switch the text/image/video model for this session any time; resolution and duration tiers follow the model."
},
"script": {
"title": "Step 1 · Script",
"desc": "(Prerequisite: AI services configured in Settings.) Paste the source novel and run "AI Rewrite" to get a shooting script."
},
"assets": {
"title": "Step 2 · Assets",
"desc": "Extract characters/scenes/props and generate consistent reference images, injected as reference material for videos."
},
"videos": {
"title": "Step 3 · Video production",
"desc": "Break down the storyboard → review prompts → batch-generate videos; retry failures in one click. Then merge & export."
},
"help": {
"title": "Replay anytime",
"desc": "Click this "?" button to replay this page's guide. Happy creating!"
}
}
}
}


File: frontend/app/locales/ja.json

{
"app": {
"title": "火宝ショートドラマ",
"updateAvailable": "新バージョン v{version} があります。「設定 → 更新について」でアップグレードできます"
},
"common": {
"confirm": "確認",
"cancel": "キャンセル",
"back": "戻る",
"saved": "保存しました",
"delete": "削除",
"deleteLoading": "削除中...",
"deleteFailed": "削除に失敗しました",
"save": "保存",
"close": "閉じる",
"refresh": "更新",
"add": "追加",
"copy": "コピー",
"download": "ダウンロード",
"default": "デフォルト",
"more": "その他",
"loading": "読み込み中…",
"listJoin": "、",
"role": "キャラクター",
"scene": "シーン",
"prop": "小道具",
"reference": "参照",
"serviceType": {
"text": "テキスト",
"image": "画像",
"video": "動画"
}
},
"layout": {
"nav": {
"projects": "プロジェクト",
"settings": "設定"
},
"banner": {
"missing": "{types}モデルが未設定のため、AI 機能は使用できません",
"goSettings": "設定へ"
},
"theme": {
"label": "テーマを切り替え",
"light": "ライトモード",
"dark": "ダークモード",
"system": "システムに従う"
}
},
"migrate": {
"title": "保存場所を切り替えています",
"hint": "移行中はアプリを閉じないでください",
"phases": {
"validating": "移行先ディレクトリを確認中…",
"stopping": "バックグラウンドサービスを停止中…",
"moving": "データファイルを移行中…",
"movingProgress": "データファイルを移行中… {copied} / {total}",
"config": "保存設定を更新中…",
"restarting": "バックグラウンドサービスを再起動中…",
"done": "移行が完了しました",
"error": "移行に失敗しました"
}
},
"components": {
"mention": {
"noMatch": "一致する参照がありません",
"fallbackGroup": "参照"
},
"baseSelect": {
"placeholder": "選択してください...",
"search": "検索...",
"noMatch": "一致する結果がありません"
},
"confirmDialog": {
"title": "削除の確認"
},
"localeSwitcher": {
"label": "表示言語を切り替え"
},
"langSwitch": {
"title": "言語を {lang} に切替しますか?",
"message": "UI 言語と AI コンテンツ言語が同期して切り替わります。",
"effectUi": "画面表示がすべてこの言語に切り替わります",
"effectAi": "脚本リライト・アセット抽出・絵コンテ・プロンプトなどの AI 生成がこの言語になります(Agent プロンプト/スキルも同期)",
"effectRefresh": "確認すると画面が自動で再読み込みされます",
"confirm": "切替して再読み込み",
"refreshing": "言語を切替しました。再読み込み中…"
}
},
"composables": {
"agent": {
"busy": "処理を実行中です",
"done": "完了"
}
},
"index": {
"hero": {
"title": "プロジェクトランチャー",
"sub": "ひとつのアイデアから一本のショートドラマへ、AI が全工程を代行",
"projectCount": "{n} 件のプロジェクト",
"activeCount": "{n} 件進行中",
"styleCount": "{n} 種類のビジュアルスタイル"
},
"create": "新規プロジェクト",
"searchPlaceholder": "プロジェクトを検索",
"sortAria": "プロジェクトの並び替え",
"sortUpdated": "最近更新",
"sortTitle": "プロジェクト名",
"statusBadgeTitle": "クリックしてプロジェクト状態を設定",
"openProjectAria": "プロジェクト {title} を開く",
"openProject": "プロジェクトを開く",
"deleteProject": "プロジェクトを削除",
"projectMeta": "{chars} キャラクター · {scenes} シーン · {eps} 話",
"emptyFilteredTitle": "一致するプロジェクトがありません",
"emptyFilteredDesc": "検索語やフィルタ条件を調整してください。",
"emptyTitle": "最初のショートドラマプロジェクトを作成",
"emptyDesc": "作成後、話を選んで制作を開始します。",
"deleted": "削除しました",
"noEpisodes": "エピソードがありません",
"episodeN": "第 {n} 話",
"ratio": {
"landscape": "16:9 · 横",
"portrait": "9:16 · 縦",
"square": "1:1 · 正方形",
"adaptive": "自動"
},
"status": {
"all": "すべて",
"draft": "未開始",
"active": "進行中",
"completed": "完了"
},
"createDialog": {
"title": "新規プロジェクト",
"desc": "作成後、プロジェクトページで話を選択します",
"name": "プロジェクト名",
"namePlaceholder": "例:都市ラブストーリー『タイムポスト局』",
"style": "ビジュアルスタイル",
"stylePlaceholder": "スタイルを選択",
"aspectRatio": "アスペクト比",
"aspectRatioPlaceholder": "アスペクト比を選択",
"aspectRatioHint": "作成後に固定され、動画生成はこの比率で統一されます",
"submit": "プロジェクトを作成"
},
"deleteDialog": {
"title": "プロジェクトを削除",
"message": "「{title}」を削除しますか?配下のエピソード、分镜、生成記録もすべて削除されます。この操作は元に戻せません。"
},
"time": {
"justNow": "たった今",
"minutesAgo": "{n} 分前",
"hoursAgo": "{n} 時間前",
"daysAgo": "{n} 日前"
}
},
"detail": {
"head": {
"charCount": "{n} キャラクター",
"sceneCount": "{n} シーン",
"epCount": "{n} 話",
"addEpisode": "話を追加"
},
"tabs": {
"episodes": "エピソード一覧",
"assets": "素材ライブラリ"
},
"ep": {
"statusTitle": "クリックしてこの話の状態を設定",
"resTitle": "クリックしてこの話の動画解像度を変更",
"deleteTitle": "この話を削除",
"enter": "制作を開く",
"scriptReady": "脚本入力済み",
"merged": "結合済み",
"emptyCreateTitle": "クリックして第 1 話を作成",
"emptyCreateText": "クリックして第 1 話を作成",
"addNextTitle": "第 {n} 話を追加",
"addNextText": "第 {n} 話を追加",
"episodeN": "第 {n} 話",
"res720": "720p · 高画質",
"res480": "480p · スムーズ",
"resSwitched": "この話の動画解像度を {res} に変更しました"
},
"epCreate": {
"title": "新しい話を作成",
"titleField": "タイトル",
"titlePlaceholder": "話数で自動命名",
"titleHint": "空欄の場合は話数で自動命名されます(例:「{example}」)。",
"example": "第 {n} 話",
"resolution": "動画解像度",
"resolutionPlaceholder": "解像度を選択",
"resolutionHint": "作成後、この話の動画はこの解像度で生成されます。後から話カードでも変更できます。",
"lockCopy": "作成時に現在有効な画像・動画生成能力がロックされます。",
"creating": "作成中...",
"create": "作成",
"added": "新しい話を追加しました"
},
"epDelete": {
"message": "「{title}」を削除しますか?一覧から非表示になり、その分镜と生成記録にもアクセスできなくなります。"
},
"assets": {
"emptyTitle": "素材がまだありません",
"emptyDesc": "制作ワークベンチで「資産抽出」によりキャラクター、シーン、小道具を生成すると、ここに自動で収録され、素材画像も直接生成できます。",
"emptyKindTitle": "{kind}の素材がありません",
"emptyKindDesc": "ワークベンチで抽出・生成すると、ここに表示されます。",
"todoShort": "未入力"
},
"mat": {
"dialogAria": "素材詳細",
"unnamed": "名称未設定",
"propTypePlaceholder": "例:武器 / 形見",
"personaField": "人物設定",
"personaPlaceholder": "性格、背景、動機…",
"locationPlaceholder": "例:故宮・太和殿",
"timePlaceholder": "例:夕暮れ / 深夜",
"finalPromptLabel": "最終プロンプト",
"finalPromptSub": "AI が情報から生成。手動で修正して保存できます",
"genPromptTitle": "AI で最終プロンプトを生成",
"needEpisodeFirst": "先に「エピソード一覧」で 1 話以上作成してください",
"promptPlaceholder": "「プロンプト生成」をクリックして AI に生成させるか、手動で入力してください。手動で保存すると、次回の画像生成でこのプロンプトが使われます。",
"genImage": "画像を生成",
"saving": "保存中…",
"generating": "{kind}「{name}」の画像を生成中",
"genTimeout": "{kind}「{name}」の生成がタイムアウトしました。後で更新して確認してください",
"uploaded": "{kind}「{name}」の画像をアップロードしました",
"needEpisodeForImage": "素材画像を生成するには、先に「エピソード一覧」で 1 話以上作成してください",
"needEpisodeForPrompt": "最終プロンプトを生成するには、先に「エピソード一覧」で 1 話以上作成してください",
"locationRequired": "場所を入力してください"
}
},
"settings": {
"groupBase": "基本",
"tabs": {
"general": "一般",
"ai": "AI サービス",
"styles": "スタイルプリセット",
"storage": "保存場所",
"about": "更新について",
"agents": "Agent 設定"
},
"common": {
"disabled": "無効",
"custom": "カスタム",
"empty": "設定がありません"
},
"general": {
"title": "一般",
"desc": "アプリ全体の設定。言語切替は UI と AI 生成コンテンツの両方に適用されます。",
"contentLanguage": "AI コンテンツ言語",
"contentLanguageSub": "UI と AI 生成(脚本/アセット/絵コンテ/プロンプト)共通の言語",
"languageLabel": "言語",
"languageNote": "切替すると UI と AI コンテンツ言語が同期し、自動で再読み込みされます",
"languageHint": "入口は 2 か所(上部バーの言語ボタン / ここ)どちらも等価で、全体に適用されます。",
"languageSaved": "コンテンツ言語を保存しました",
"appearance": "外観",
"appearanceSub": "画面のカラーテーマ。即時反映されます",
"appearanceLabel": "テーマモード",
"appearanceNote": "「システム」ではOSの外観に自動で追従します",
"appearanceLight": "ライト",
"appearanceDark": "ダーク",
"appearanceSystem": "システム",
"languageSavedWith": "AI コンテンツ言語を {lang} に切替しました。以後の生成(脚本/アセット/絵コンテ/プロンプト)に適用されます",
"langNameZh": "中国語",
"langNameEn": "英語",
"langNameJa": "日本語",
"langNameKo": "韓国語",
"unifiedSwitchWarning": "{lang} に切替しました。UI と AI コンテンツ言語が同期され、まもなく再読み込みします…"
},
"ai": {
"title": "AI サービス設定",
"desc": "まず推奨テンプレートで設定を作成し、サービスタイプごとに微調整します。ワークベンチで話を作成する際に選択した画像・動画能力がロックされます。",
"quickTitle": "火宝クイック設定",
"recommended": "おすすめ",
"quickDesc": "Huobao API Key を入力すると、テキスト・画像・動画の 3 つの推奨設定を一括で書き込みます。",
"getKey": "Huobao API Key を取得",
"regionCn": "国内",
"regionCom": "海外",
"applyQuick": "火宝設定を書き込む",
"manualTitle": "手動テンプレート",
"manualDesc": "サービスタイプを選ぶと、推奨の provider / base URL / model がテンプレートから入力されます。",
"activeCount": "{n} 件有効",
"hasKey": "設定済み",
"noKey": "キーなし",
"currentDefault": "現在のデフォルトモデル",
"setDefault": "このタイプのデフォルトモデルに設定",
"noBaseUrl": "Base URL 未設定",
"test": "テスト",
"apiKeyRequired": "Huobao API Key を入力してください",
"quickApplied": "火宝クイック設定を書き込みました",
"defaultModelSwitched": "デフォルト{type}モデルを {model} に切り替えました",
"meta": {
"text": "脚本リライト、キャラクター・シーン抽出、分镜分解などの Agent テキスト能力",
"image": "キャラクター図、シーン図、ショット図などの静止画生成",
"video": "ショット動画の直接生成(デフォルト Seedance 2.0)"
}
},
"styles": {
"title": "スタイルプリセット",
"desc": "プロジェクト作成時に選ぶビジュアルスタイル。その英語プロンプト片はキャラクター図・シーン図の生成に自動注入されます。無効なスタイルは作成オプションに表示されません。",
"allTitle": "すべてのスタイル",
"count": "{active} 件有効 · 全 {total} 件",
"empty": "スタイルプリセットがありません"
},
"storage": {
"title": "保存場所",
"desc": "データベースと生成ファイル(画像/動画/結合/アップロード)が置かれるディレクトリ。場所を変更するとバックグラウンドサービスが一時停止し、データが移行されます。",
"currentDir": "現在のデータディレクトリ",
"computedAt": "{time} 時点の集計",
"changeLocation": "場所を変更",
"dataDir": "データディレクトリ",
"desktopMode": "デスクトップ版",
"serverMode": "サーバーモード",
"totalUsage": "合計使用 {size}",
"counting": "集計中…",
"breakdown": {
"db": "データベース",
"images": "画像",
"videos": "動画",
"merged": "結合",
"uploads": "アップロード",
"temp": "一時",
"other": "その他"
},
"diskFree": "ディスク空き {size}",
"note": "データディレクトリには SQLite データベースとすべての生成メディアが含まれます。Agent スキル(workspace)は含まれず、移行されません。",
"serverNote": "サーバーデプロイでは STORAGE_PATH / SQLITE_PATH 環境変数で保存場所を設定し、再起動後に反映されます。",
"loadFailed": "保存情報の読み込みに失敗しました"
},
"about": {
"title": "更新について",
"desc": "リリースマニフェストから新バージョンを取得し、ローカルで sha256 を検証した後、パッケージを入れ替えて再起動します。ユーザーデータと設定はシステムのデータディレクトリに保存され、更新の影響を受けません。",
"currentVersion": "現在のバージョン v{v}",
"latestVersion": "最新バージョン v{v}",
"check": "更新を確認",
"webMode": "現在はブラウザ / サーバーモードのため、アプリ内更新はデスクトップ版のみ利用可能です。",
"upToDate": "最新バージョンです",
"found": "新バージョン v{v} があります",
"downloading": "ダウンロード中 {p}%",
"download": "更新をダウンロード",
"ready": "更新パッケージの準備ができました",
"readyDesc": "クリックするとアプリを終了し、自動でインストールして再起動します。",
"restartInstall": "再起動してインストール",
"checkFailed": "確認に失敗しました",
"retry": "再試行",
"empty": "「更新を確認」をクリックして最新バージョンを取得します。",
"note": "説明:macOS ではディレクトリ置換で更新します(Tauri と同方式、Apple 署名不要)。Windows ではインストーラーがサイレントインストールします。",
"checkFailedToast": "更新の確認に失敗しました",
"downloadDone": "更新パッケージのダウンロードが完了しました。インストールできます",
"downloadFailed": "ダウンロードに失敗しました",
"installFailed": "インストールに失敗しました",
"serverApply": "今すぐ更新",
"serverApplyStarted": "更新を開始しました:Watchtower が新しいイメージを取得してコンテナを再作成します。数分後にページを更新してください",
"serverApplyFailed": "更新の開始に失敗しました",
"serverManualHint": "サーバーデプロイ:デプロイディレクトリで実行してください",
"serverNote": "補足:Watchtower を設定した Docker デプロイではワンクリック更新(新イメージ取得+コンテナ再作成)が可能です。未設定の場合は表示されたコマンドを手動で実行してください。"
},
"agents": {
"promptHint": "{file} として保存",
"promptPlaceholder": "Agent システムプロンプト...",
"reset": "デフォルトに戻す",
"promptReset": "デフォルトプロンプトに戻しました(prompt ファイルを削除)",
"saved": "{agent} の設定を保存しました",
"scriptRewriter": "脚本リライト",
"extractor": "キャラクター・シーン抽出",
"storyboardBreaker": "分镜分解",
"promptGenerator": "プロンプト生成",
"langFallback": "中国語にフォールバック",
"followContentLang": "編集言語:{lang}(「一般 → AI コンテンツ言語」で切替)"
},
"skills": {
"agentList": "Agent 一覧",
"desc": "Skills は Agent の高度なプロンプトレイヤーとしてのみ使用され、ワークベンチの通常の機能入口には影響しません。",
"add": "Skill を追加",
"emptyTitle": "Skill がありません",
"emptyDesc": "右上の「Skill を追加」から最初のプロンプトファイルを作成してください",
"contentPlaceholder": "SKILL.md の内容を記述...",
"addTitle": "Skill を追加 — {agent}",
"dirName": "Skill ディレクトリ名",
"dirNameHint": "英語、一意",
"dirNamePlaceholder": "例:custom-extraction",
"name": "名前",
"namePlaceholder": "例:カスタム抽出ルール",
"description": "説明",
"descPlaceholder": "この Skill の用途を簡単に記述",
"create": "作成",
"created": "Skill を作成しました"
},
"cfg": {
"editTitle": "サービス設定を編集",
"addTitle": "{type}サービスを追加",
"sub": "まずテンプレートを選ぶと、適切な Base URL とデフォルトモデルが自動入力されます。",
"name": "設定名",
"namePlaceholder": "例:火宝デフォルト画像サービス",
"provider": "プロバイダー",
"providerPlaceholder": "プロバイダーを選択",
"priority": "優先度",
"priorityHint": "数値が大きいほど優先。ワークベンチは同タイプの有効設定のうち優先度が最も高いものを使います。",
"models": "モデル",
"modelsHint": "先頭がデフォルトモデルです。タグをクリックで先頭に移動。カンマ/改行区切りの一括貼り付けに対応",
"modelPlaceholder": "モデル名を入力してEnterで追加",
"modelChipHint": "クリックでデフォルトに設定(先頭へ)",
"tempHint": "空欄でプロバイダーのデフォルトに従う",
"tempPlaceholder": "例:0.6",
"tempNote": "温度が固定されたモデル(例:kimi-k2 系は 0.6 のみ)があります。invalid temperature エラーが出た場合はここに値を入力してください。",
"test": "設定をテスト",
"reachable": "エンドポイントが応答しました",
"unreachable": "エンドポイントのテストに失敗しました",
"providerRequired": "プロバイダーを選択してください",
"tempInvalid": "Temperature は 0〜2 の数値で入力してください"
},
"styleDialog": {
"editTitle": "スタイルプリセットを編集",
"addTitle": "スタイルプリセットを追加",
"sub": "プロンプト片は英語で、キャラクター図・シーン図の生成時にプロンプトへ自動で追加されます。",
"tag": "スタイル",
"name": "スタイル名",
"namePlaceholder": "例:3D、アニメ、実写映画",
"key": "スタイル key",
"keyPlaceholder": "例:3d、anime(小文字/数字/ハイフン)",
"keyHint": "プロジェクトに保存されるスタイル識別子。作成後は変更できません。",
"prompt": "プロンプト片(英語)",
"promptPlaceholder": "例:anime style, cel shading, vibrant colors, clean line art",
"description": "説明",
"descPlaceholder": "このスタイルの用途を一行で",
"sort": "並び順",
"required": "名前、key、プロンプト片は必須です"
},
"migrate": {
"title": "保存場所を変更",
"newDir": "新しいディレクトリ",
"dataToMove": "移行するデータ",
"sizeNote": "約 {size}",
"freeNote": " · 移行先の空き {size}",
"moveFiles": "既存データを移行(データベースとすべての生成ファイル)",
"emptyWarn": "警告:アプリは新しい空のデータベースで起動します。旧ディレクトリのデータは保持されますが使用されなくなります。",
"note": "移行中はバックグラウンドサービスが一時停止し、進行中の生成タスクは中断されます。完了後、ページが自動で再読み込みされます。",
"start": "移行を開始",
"pickFailed": "ディレクトリの選択に失敗しました",
"failed": "移行に失敗しました。元の保存場所に戻しました"
},
"styleDelete": {
"title": "スタイルプリセットを削除",
"message": "スタイル「{name}」を削除しますか?使用中のプロジェクトには影響しませんが、削除した組み込みスタイルは再起動で復元される場合があります。「無効化」の利用をおすすめします。"
},
"skillDelete": {
"title": "Skill を削除",
"message": "Skill「{id}」を削除しますか?対応する Agent は組み込みのデフォルトプロンプトに戻ります。"
}
},
"episode": {
"topbar": {
"back": "プロジェクトに戻る",
"episodeN": "第 {n} 話",
"meta": "{roles} キャラクター · {shots} セグメント",
"tasks": "タスク",
"viewFilm": "完成映像を見る",
"continue": "制作を続ける",
"start": "制作を開始",
"resolution": "解像度"
},
"model": {
"defaultWith": "デフォルト · {model}",
"notConfigured": "未設定"
},
"sidebar": {
"inProgress": "進行中",
"refreshData": "データを更新",
"collapse": "サイドバーを折りたたむ",
"expand": "サイドバーを展開"
},
"nav": {
"prev": "前へ",
"next": "次へ",
"toExport": "書き出しへ"
},
"stage": {
"script": "脚本",
"scriptDesc": "内容のリライトと整理",
"production": "制作",
"assets": "資産",
"assetsDesc": "キャラクター / シーン / 小道具",
"videos": "動画制作",
"videosDesc": "分镜分解と動画生成",
"export": "書き出し",
"exportDesc": "結合して映像を出力",
"mergeExport": "結合して書き出し",
"scriptStage": "脚本段階 · {step}",
"prodStage": "制作段階 · {step}",
"exportDone": "書き出し段階 · 完了",
"exportWaiting": "書き出し段階 · 結合待ち",
"workbench": "ワークベンチ"
},
"script": {
"raw": "原文",
"rewrite": "AI リライト",
"charCount": "{n} 文字",
"saved": "保存しました",
"rawPlaceholder": "小説の原文、ストーリー概要、分镜メモを貼り付け...",
"skipRewrite": "リライトをスキップ",
"rewriteAgain": "もう一度リライト",
"emptyTitle": "AI で書式付き脚本にリライト",
"emptyDesc": "AI で原文を書式付き脚本に整理するか、このステップをスキップして資産制作に進めます。",
"startRewrite": "リライトを開始",
"rewriting": "脚本をリライト中...",
"scriptPlaceholder": "書式付き脚本の内容...",
"rawRequired": "先に原文を入力してください",
"skipDone": "AI リライトをスキップしました。原文をそのまま使用します"
},
"prod": {
"assets": "アセット制作",
"videos": "動画制作",
"notReady": "まだ準備ができていません",
"readyCount": "{ready}/{total} 準備完了",
"extract": "{type}を抽出",
"reextract": "{type}を再抽出",
"batchChar": "キャラクター一括",
"batchScene": "シーン一括",
"batchProp": "小道具一括",
"extractingTypes": "{types}を抽出中...",
"extractingTypesDots": "{types}を抽出中…",
"emptyTitle": "資産抽出を開始",
"emptyDesc": "キャラクター、シーン、小道具は抽出後ここに表示されます。個別に抽出するか、一括で並行抽出できます。",
"startExtract": "抽出を開始",
"scriptFirst": "先に脚本を完成させてください",
"goBack": "処理に戻る"
},
"asset": {
"fallbackType": "資産",
"typeChar": "キャラクター資産",
"typeScene": "シーン資産",
"typeProp": "小道具資産",
"detailTitle": "{type}詳細",
"delChar": "キャラクターを削除",
"delScene": "シーンを削除",
"delProp": "小道具を削除",
"charImageTitle": "{name} キャラクターイメージ",
"sceneImageTitle": "{name} シーン図",
"propImageTitle": "{name} 小道具図",
"portraitReady": "イメージ生成済み",
"portraitPending": "イメージ生成中",
"portraitTodo": "イメージ未生成",
"ready": "生成済み",
"generating": "生成中",
"todo": "未生成",
"regen": "再生成",
"generate": "生成",
"upload": "アップロード",
"uploadCharImage": "キャラクターイメージをアップロード",
"uploadSceneImage": "シーン図をアップロード",
"uploadPropImage": "小道具図をアップロード",
"uploadImage": "画像をアップロード",
"appearance": "外見:",
"styling": "スタイリング:",
"lighting": "光照 · ",
"appearanceTodo": "外見未入力",
"stylingTodo": "スタイリング未入力",
"sceneDescTodo": "シーン説明未入力",
"sceneLightTodo": "シーン光影未入力",
"noDescription": "説明がありません",
"noTime": "時間未設定",
"finalPromptTurnaround": "最終プロンプト · 三面図",
"finalPromptFixed": "最終プロンプト · 固定視点",
"finalPromptWhiteBg": "最終プロンプト · 白背景単品",
"finalPromptAutoTurnaround": "初回のイメージ生成時にプロンプト Agent が自動生成",
"finalPromptAutoFixed": "初回の画像生成時にプロンプト Agent が自動生成(前景/中景/後景)",
"finalPromptAutoWhiteBg": "初回の画像生成時にプロンプト Agent が自動生成(白背景単品)",
"propsEmpty": "この話に物語上の重要な小道具はありません",
"visualPreview": "ビジュアルプレビュー",
"kindLabel": "タイプ",
"charPortrait": "キャラクターイメージ",
"sceneImage": "シーン画像",
"roleLabel": "役割",
"propTypeLabel": "小道具タイプ",
"timeLabel": "時間",
"editInfo": "情報を編集",
"editHintChar": "外見とスタイリングはキャラクターイメージに影響します",
"editHintProp": "物品の外見は小道具図に影響します",
"editHintScene": "空間と光影はシーン図に影響します",
"appearanceOfObject": "物品の外見",
"appearancePlaceholder": "材質、色、形状、大きさ、新旧、傷跡など",
"appearanceField": "外見",
"appearanceFieldPlaceholder": "年齢感、五官、体格、気質など",
"stylingField": "スタイリング",
"stylingFieldPlaceholder": "髪型、服装、メイク、アクセサリーなど",
"sceneDescField": "シーン説明",
"sceneDescPlaceholder": "空間、調度、年代質感、重要な視覚要素など",
"sceneLightField": "シーン光影",
"sceneLightPlaceholder": "光源、色調、明暗、雰囲気など",
"genPrompt": "プロンプトを生成",
"regenPrompt": "再生成",
"genPortrait": "イメージを生成",
"regenPortrait": "イメージを再生成",
"genScene": "シーンを生成",
"regenScene": "シーンを再生成",
"genProp": "小道具図を生成",
"regenProp": "小道具図を再生成",
"promptPlaceholderChar": "三面図の最終プロンプトを手動で書くか、「プロンプトを生成」で Agent に生成させます",
"promptPlaceholderScene": "固定視点の最終プロンプトを手動で書くか、「プロンプトを生成」で Agent に生成させます",
"promptPlaceholderProp": "白背景単品の最終プロンプトを手動で書くか、「プロンプトを生成」で Agent に生成させます",
"promptHintChar": "プロンプトは直接編集でき、保存後に反映されます。外見やスタイリングを変更して保存すると最終プロンプトがクリアされ、次回のイメージ生成時にプロンプト Agent が再生成します。",
"promptHintScene": "プロンプトは直接編集でき、保存後に反映されます。シーン説明や光影を変更して保存すると最終プロンプトがクリアされ、次回のシーン図生成時にプロンプト Agent が再生成します。",
"promptHintProp": "プロンプトは直接編集でき、保存後に反映されます。物品の外見を変更して保存すると最終プロンプトがクリアされ、次回の小道具図生成時にプロンプト Agent が再生成します。",
"generatingPrompt": "最終プロンプトを生成中…",
"promptGenerated": "最終プロンプトを生成しました",
"promptRegenerated": "最終プロンプトを再生成しました",
"promptGenFailedRetry": "最終プロンプトの生成に失敗しました。もう一度お試しください",
"promptGenFailed": "最終プロンプトの生成に失敗しました",
"promptCopied": "最終プロンプトをコピーしました",
"copyFailed": "コピーに失敗しました。テキストを手動で選択してコピーしてください",
"noChanges": "保存する変更がありません",
"saved": "変更を保存しました",
"saveFailed": "保存に失敗しました",
"saveChanges": "変更を保存",
"unnamedChar": "名称未設定のキャラクター",
"unnamedProp": "名称未設定の小道具",
"unnamedScene": "名称未設定のシーン",
"propSingleImage": "小道具単品図",
"propImage": "小道具図"
},
"create": {
"title": "{type}を追加",
"name": "名前",
"namePlaceholderChar": "キャラクター名",
"namePlaceholderProp": "小道具名",
"roleField": "キャラクターの役割",
"rolePlaceholder": "例:主人公 / 敵役 / 脇役",
"appearancePlaceholder": "外見の特徴(性格も織り込めます)",
"stylingPlaceholder": "服装、メイク、アクセサリー",
"location": "場所",
"locationPlaceholder": "シーンの場所",
"time": "時間",
"timePlaceholder": "例:昼 / 夜",
"sceneDescPlaceholder": "環境、調度、雰囲気",
"lightPlaceholder": "例:夕暮れの暖色光、冷たいトップライト",
"typeField": "タイプ",
"typePlaceholder": "例:武器 / 形見 / 書類",
"appearanceOnlyPlaceholder": "物品の外見のみを記述(他の要素は不要)",
"locationRequired": "シーンの場所を入力してください",
"nameRequired": "名前を入力してください",
"created": "{type}を追加しました"
},
"delete": {
"title": "{type}を削除",
"message": "{type}「{name}」を削除しますか?この作品のすべての話から取り除かれます。",
"deleted": "{type}を削除しました"
},
"sb": {
"title": "分镜分解",
"segmentStat": "{n} セグメント · {dur}s",
"rebreak": "再分解",
"startBreak": "分割してプロンプト生成",
"promptProgress": "プロンプト {done}/{total}",
"promptSelected": "選択分のプロンプト生成({n})",
"batchPrompts": "一括でプロンプトを補完",
"listTitle": "分镜一覧",
"listSub": "分解の説明と紐付いたキャラクター・シーンを確認",
"select": "選択",
"selectAll": "すべて選択",
"selectMissing": "不足分のみ",
"clear": "クリア",
"selectedCount": "{n} 件選択中",
"generatingProgress": "生成中 {done}/{total}",
"generateSelected": "動画プロンプト生成({n})",
"shotN": "分镜 #{n}",
"totalCount": "全 {n} 件",
"duration": "長さ",
"descSection": "分镜説明",
"descLabel": "画面説明",
"descHint": "【ショット1】【ショット2】…と子ショットごとに記述。セリフは「キャラクター名のセリフ:「セリフ」」、ナレーションは「ナレーション:内容」",
"descPlaceholder": "分镜の画面説明",
"atmosphere": "雰囲気",
"atmospherePlaceholder": "光、色調、空気感、環境の雰囲気",
"videoPromptSection": "動画プロンプト",
"regenPrompt": "再生成",
"aiGenerate": "AI で生成",
"videoPromptCopy": "この分镜の画面説明(セリフ/ナレーションを含む)と雰囲気から生成",
"videoPromptPlaceholder": "{'@'}キャラクター名 / {'@'}シーン名 で参照素材を指定し、3 秒ごとに改行して画面の動きとカメラを記述。AI で生成してプロンプト Agent に任せることもできます…",
"breaking": "分镜を分解中...",
"emptyTitle": "分镜分解を開始",
"emptyDesc": "脚本、キャラクター、シーンをもとにショットへ分解し、分镜説明と紐付け情報を生成します。",
"hasVideo": "動画生成済み",
"noVideo": "動画未生成",
"hasVideoShort": "完成済み",
"videoFlag": "動",
"noDescription": "画面説明がありません",
"zeroChars": "0 キャラクター",
"unboundScene": "シーン未紐付け",
"breakFirst": "先に分镜を分解してください",
"selectedMissing": "選択した分镜が存在しません",
"allHavePrompts": "すべての分镜に動画プロンプトがあります",
"batchStarted": "{n} 件の分镜の動画プロンプトを生成開始…",
"batchDone": "動画プロンプトの一括生成が完了しました",
"batchDoneFailed": "動画プロンプトの一括生成が完了しました({n} 件失敗)",
"batchFailed": "動画プロンプトの一括生成に失敗しました",
"promptGenerated": "分镜 #{n} の動画プロンプトを生成しました"
},
"ref": {
"title": "参照素材",
"copy": "キャラクター / シーン / 小道具を動画参照として紐付け",
"boundCount": "{bound}/{total} 紐付け済み",
"clickAdd": "クリックで参照に追加",
"clickRemove": "クリックで参照から除外",
"shortChar": "役",
"shortScene": "景",
"shortProp": "具",
"usable": "参照可能",
"notReady": "未生成",
"unbound": "未紐付け",
"gotoGenerate": "生成へ →",
"empty": "この話にはシーン、キャラクター、小道具がまだありません。先に「資産」で素材を抽出すると紐付けできます。"
},
"vid": {
"shotCount": "{n} ショット",
"doneCount": "{done}/{total} 生成済み",
"batchVideos": "動画一括生成",
"emptyTitle": "先に分镜を生成",
"emptyDesc": "動画タスクは分镜分解の結果から作られます。先に分镜説明と動画プロンプトを生成してから、動画を一括生成してください。",
"lockedModel": "この話の動画モデル:",
"listTitle": "動画タスク一覧",
"listMeta": "ショット順 · {n} 件のタスク",
"metricPending": "{n} 生成中",
"metricDone": "{n} 完了",
"metricFailed": "{n} 失敗",
"references": "参照 {n}",
"refCountMeta": "{n} 件の参照素材",
"shotN": "ショット #{n}",
"playerTitle": "分镜 {n}",
"setMain": "メイン動画に設定",
"setMainDone": "メイン動画に設定しました",
"setMainFailed": "設定に失敗しました",
"download": "ダウンロード",
"emptyGenerating": "動画を生成中…",
"emptyNoVideo": "動画がまだ生成されていません",
"emptyGeneratingDesc": "生成完了後、ここでプレビューできます",
"emptyNoVideoDesc": "下のボタンでこの分镜の動画を生成します",
"generateVideo": "動画を生成",
"history": "動画履歴",
"current": "現在",
"deleteRecord": "この記録を削除",
"historyDeleted": "この履歴を削除しました",
"needRefOrPrompt": "参照素材または動画プロンプトが少なくとも 1 つ必要です",
"generating": "動画を生成中",
"genDone": "動画生成が完了しました",
"genFailed": "動画生成に失敗しました",
"genTimeout": "動画生成がタイムアウトしました",
"allDone": "すべてのショット動画が生成済みです",
"moderationHint": "実写人物/センシティブ内容の審査で拒否された可能性があります。上部バーで別の動画モデルに切り替えて再試行してください",
"resolutionSwitched": "このエピソードの動画解像度を {label} に変更しました",
"noneToGenerate": "生成するショットがありません",
"batchStarted": "{n} 件の動画生成タスクを開始しました",
"retryFailed": "失敗を再試行({n})",
"select": "選択",
"selectDone": "{n} 件選択 · 完了",
"batchSelected": "選択分を生成({n})",
"listMetaFiltered": "絞り込み結果 · {n}/{total} 件のタスク",
"defaultModel": "デフォルトモデル",
"confirmTitle": "動画の一括生成",
"confirmShots": "ショット数",
"confirmShotsValue": "{n} 件",
"confirmTotal": "合計時間",
"confirmApprox": "約 {n} 秒",
"confirmModel": "動画モデル",
"confirmResolution": "解像度",
"confirmNote": "上記の設定でショットごとに生成を開始します。失敗したタスクは後で「失敗を再試行」からまとめて再実行できます。",
"confirmStart": "生成開始 ({n})",
"selectMissing": "未生成を選択",
"aspectRatio": "アスペクト比"
},
"inspector": {
"videoPromptPlaceholder": "{'@'}キャラクター名 / {'@'}シーン名 で参照素材を指定(生成時に参照画像へ自動マッピング)。時間帯ごとに画面の動きとカメラを記述…",
"noRefs": "この分镜には参照素材が紐付けられていません",
"refMedia": "参照画像 / 動画 / 音声",
"imageN": "画像 {n}",
"videoN": "動画 {n}",
"audioN": "音声 {n}",
"uploadRefImage": "参照画像をアップロード ({used}/{limit})",
"uploadRefVideo": "参照動画をアップロード ({used}/{limit})",
"uploadRefAudio": "参照音声をアップロード ({used}/{limit})",
"refAudioHint": "参照音声には参照画像または動画が 1 つ以上必要です",
"params": "生成パラメータ",
"duration": "分镜の長さ",
"durationUnit": "秒(2-30)",
"durationHint": "変更すると分镜に即時保存され、リストとバッチ生成にも反映されます",
"effective": "{model} · {res} · {dur}秒",
"boundRefs": "绑定参照画像",
"noBoundRefs": "绑定された素材なし(中央の「参照素材」で绑定)"
},
"tasks": {
"title": "生成タスク一覧",
"meta": "作成日時の降順 · {n} 件のタスク",
"emptyTitle": "生成タスクがありません",
"emptyDesc": "資産、分镜、動画の各ステップで画像/動画生成を実行すると、タスクが自動でここに表示されます。",
"duration": "所要 {dur}",
"sbN": "分镜 #{n}",
"generic": "汎用",
"fullMerge": "話全体の結合",
"mergeKind": "結合"
},
"export": {
"notReadyDesc": "先に分镜と制作の工程を完了してください",
"gotoScript": "脚本へ",
"filmList": "完成映像一覧",
"countN": "{n} 件",
"empty": "完成映像がまだありません。下でショットを選択して「選択分を結合」をクリックしてください",
"shotAssets": "ショット素材",
"shotStat": "{done}/{total} 生成済み · {selected} 選択中",
"clearSelection": "選択をクリア",
"selectAllReady": "生成済みをすべて選択",
"mergeSelected": "選択分を結合 ({n})",
"selectFirst": "動画が生成されたショットを 1 つ以上選択してください",
"merging": "結合中…",
"mergingToast": "結合中...",
"mergeDone": "結合が完了しました",
"mergeFailed": "結合に失敗しました",
"previewShot": "このショットを再生",
"shotPreview": "ショット #{n} プレビュー",
"markDone": "完了にする",
"markedDone": "完了",
"markDoneTitle": "このエピソードの書き出しを手動で完了にします(再クリックで解除)",
"markedDoneToast": "完了としてマークしました",
"unmarkDoneToast": "完了マークを解除しました"
},
"image": {
"generatingChar": "キャラクター画像を生成中",
"generatingScene": "シーン画像を生成中",
"generatingProp": "小道具画像を生成中",
"batchGeneratingChar": "キャラクター画像を一括生成中",
"batchGeneratingScene": "シーン画像を一括生成中",
"batchGeneratingProp": "小道具画像を一括生成中",
"allCharsDone": "すべてのキャラクター画像が生成済みです",
"allScenesDone": "すべてのシーン画像が生成済みです",
"allPropsDone": "すべての小道具画像が生成済みです"
},
"extract": {
"done": "{type}の抽出が完了しました",
"failed": "{type}の抽出に失敗しました"
},
"upload": {
"assetDone": "{type}をアップロードしました",
"refImageFull": "参照画像は上限に達しました(シーン/キャラクター素材を含む)",
"refImageDone": "参照画像をアップロードしました",
"refMax3": "参照{type}は最大 3 つまで",
"refDone": "参照{type}をアップロードしました",
"refAudioNeed": "参照音声には参照画像または動画が 1 つ以上必要です",
"audio": "音声",
"refMax": "参照{type}は最大 {n} つまで"
},
"viewer": {
"imagePreview": "画像プレビュー",
"filmPreview": "完成映像プレビュー",
"downloadFilm": "完成映像をダウンロード"
},
"status": {
"done": "完了",
"generating": "生成中",
"failed": "失敗",
"todo": "未生成"
},
"resolution": {
"smooth": "標準",
"hd": "高画質",
"uhd": "超高画質"
}
},
"errors": {
"network": "サーバーに接続できません。ネットワークまたはサービスの起動状態を確認してください",
"server": "サーバーから異常な応答が返されました。しばらくしてから再試行してください",
"unavailable": "サービスは一時的に利用できません。しばらくしてから再試行してください",
"auth": "認証に失敗しました。APIキー設定を確認してください",
"rateLimit": "リクエストが多すぎるか、クォータが不足しています。しばらくしてから再試行してください",
"timeout": "生成がタイムアウトしました。再試行してください",
"moderation": "コンテンツが審査を通過しませんでした。プロンプトを調整するかモデルを切り替えて再試行してください",
"requestFailed": "リクエストに失敗しました({status})",
"unknown": "操作に失敗しました。再試行してください"
},
"tour": {
"next": "次へ",
"prev": "戻る",
"done": "完了",
"helpTitle": "ガイド",
"index": {
"welcome": {
"title": "👋 火宝短劇へようこそ",
"desc": "小説 → 脚本 → アセット → 絵コンテ → 動画 → 完成、すべてワンストップ。まず AI サービスを設定し、最初のプロジェクトを作成しましょう。"
},
"create": {
"title": "ステップ 2 · プロジェクト作成",
"desc": "「新規プロジェクト」で作品名・アスペクト比(縦横)・作画スタイルを選択します。"
},
"settings": {
"title": "ステップ 1 · AI サービスを設定",
"desc": "すべての AI 機能に事前設定が必要です。「設定」ページで Huobao API キーを貼り、テキスト/画像/動画をワンクリック設定しましょう。"
}
},
"settings": {
"quick": {
"title": "最速セットアップ:クイック設定",
"desc": "Huobao API キーを貼り付けると推奨 3 設定(テキスト/画像/動画)を一括書き込み。接続テスト対応。"
},
"nav": {
"title": "すべてここに",
"desc": "左でセクション切替:AI サービス、一般(UI と生成言語)、スタイルプリセット、Agent プロンプトとスキル、ストレージ、About。"
}
},
"episode": {
"topbar": {
"title": "上部バー:モデルと状態",
"desc": "テキスト/画像/動画モデルをいつでも切替。解像度と尺はモデルに連動します。"
},
"script": {
"title": "ステップ 1 · 脚本",
"desc": "(前提:設定ページで AI サービス設定済み)原文を貼り付けて「AI リライト」で撮影用脚本を生成します。"
},
"assets": {
"title": "ステップ 2 · アセット",
"desc": "キャラ/シーン/小道具を抽出し一貫性のある参照画像を生成。動画生成時の参照素材になります。"
},
"videos": {
"title": "ステップ 3 · 動画制作",
"desc": "絵コンテ分割 → プロンプト確認 → 一括動画生成。失敗はワンクリック再試行。完了後「連結・書き出し」へ。"
},
"help": {
"title": "いつでも再再生",
"desc": "この「?」ボタンでこのページのガイドを再表示できます。良い制作を!"
}
}
}
}


File: frontend/app/locales/ko.json

[Binary file]


File: frontend/app/locales/zh.json

{
"app": {
"title": "火宝短剧",
"updateAvailable": "发现新版本 v{version},可在「设置 → 关于更新」中升级"
},
"common": {
"confirm": "确认",
"cancel": "取消",
"back": "返回",
"saved": "已保存",
"delete": "删除",
"deleteLoading": "删除中...",
"deleteFailed": "删除失败",
"save": "保存",
"close": "关闭",
"refresh": "刷新",
"add": "新增",
"copy": "复制",
"download": "下载",
"default": "默认",
"more": "更多",
"loading": "加载中…",
"listJoin": "、",
"role": "角色",
"scene": "场景",
"prop": "道具",
"reference": "参考",
"serviceType": {
"text": "文本",
"image": "图片",
"video": "视频"
}
},
"layout": {
"nav": {
"projects": "项目",
"settings": "设置"
},
"banner": {
"missing": "尚未配置{types}模型,AI 功能无法使用",
"goSettings": "前往设置"
},
"theme": {
"label": "切换主题",
"light": "浅色模式",
"dark": "深色模式",
"system": "跟随系统"
}
},
"migrate": {
"title": "正在切换存储位置",
"hint": "迁移期间请勿关闭应用",
"phases": {
"validating": "正在校验目标目录…",
"stopping": "正在停止后台服务…",
"moving": "正在迁移数据文件…",
"movingProgress": "正在迁移数据文件… {copied} / {total}",
"config": "正在更新存储配置…",
"restarting": "正在重启后台服务…",
"done": "迁移完成",
"error": "迁移失败"
}
},
"components": {
"mention": {
"noMatch": "无匹配的参考",
"fallbackGroup": "参考"
},
"baseSelect": {
"placeholder": "请选择...",
"search": "搜索...",
"noMatch": "无匹配结果"
},
"confirmDialog": {
"title": "确认删除"
},
"localeSwitcher": {
"label": "切换界面语言"
},
"langSwitch": {
"title": "切换语言为 {lang}?",
"message": "界面语言与 AI 内容语言将同步切换。",
"effectUi": "界面文案全部切换为该语言",
"effectAi": "剧本改写、资产提取、分镜、提示词等 AI 产出改用该语言(Agent 提示词/技能同步)",
"effectRefresh": "确认后界面会自动刷新",
"confirm": "切换并刷新",
"refreshing": "语言已切换,正在刷新…"
}
},
"composables": {
"agent": {
"busy": "操作执行中",
"done": "完成"
}
},
"index": {
"hero": {
"title": "项目启动台",
"sub": "从一个创意到一部短剧,AI 全流程为你代工",
"projectCount": "{n} 个项目",
"activeCount": "{n} 进行中",
"styleCount": "{n} 种视觉风格"
},
"create": "新建项目",
"searchPlaceholder": "搜索项目",
"sortAria": "项目排序",
"sortUpdated": "最近更新",
"sortTitle": "项目名称",
"statusBadgeTitle": "点击标记项目状态",
"openProjectAria": "打开项目 {title}",
"openProject": "打开项目",
"deleteProject": "删除项目",
"projectMeta": "{chars} 角色 · {scenes} 场景 · {eps} 集",
"emptyFilteredTitle": "没有匹配的项目",
"emptyFilteredDesc": "调整搜索词或筛选条件。",
"emptyTitle": "新建第一个短剧项目",
"emptyDesc": "创建后选择集开始制作。",
"deleted": "已删除",
"noEpisodes": "暂无剧集",
"episodeN": "第 {n} 集",
"ratio": {
"landscape": "16:9 · 横屏",
"portrait": "9:16 · 竖屏",
"square": "1:1 · 方形",
"adaptive": "自适应"
},
"status": {
"all": "全部",
"draft": "待开始",
"active": "进行中",
"completed": "已完成"
},
"createDialog": {
"title": "新建项目",
"desc": "创建后进入项目页选择集",
"name": "项目名称",
"namePlaceholder": "例如:都市情感短剧《时光邮局》",
"style": "视觉风格",
"stylePlaceholder": "选择风格",
"aspectRatio": "画面比例",
"aspectRatioPlaceholder": "选择画面比例",
"aspectRatioHint": "创建后固定,视频生成将统一使用该比例",
"submit": "创建项目"
},
"deleteDialog": {
"title": "删除项目",
"message": "确定删除「{title}」?项目下的剧集、分镜与生成记录将一并删除,此操作不可恢复。"
},
"time": {
"justNow": "刚刚",
"minutesAgo": "{n} 分钟前",
"hoursAgo": "{n} 小时前",
"daysAgo": "{n} 天前"
}
},
"detail": {
"head": {
"charCount": "{n} 角色",
"sceneCount": "{n} 场景",
"epCount": "{n} 集",
"addEpisode": "添加集"
},
"tabs": {
"episodes": "剧集列表",
"assets": "素材库"
},
"ep": {
"statusTitle": "点击标记本集状态",
"resTitle": "点击修改本集视频分辨率",
"deleteTitle": "删除本集",
"enter": "进入制作",
"scriptReady": "剧本已录入",
"merged": "已合成",
"emptyCreateTitle": "点击创建第一集",
"emptyCreateText": "点击创建第一集",
"addNextTitle": "添加第 {n} 集",
"addNextText": "添加第 {n} 集",
"episodeN": "第 {n} 集",
"res720": "720p · 高清",
"res480": "480p · 流畅",
"resSwitched": "本集视频分辨率已切换为 {res}"
},
"epCreate": {
"title": "创建新集",
"titleField": "标题",
"titlePlaceholder": "默认按集数自动命名",
"titleHint": "留空时会自动按集数命名,例如“{example}”。",
"example": "第 {n} 集",
"resolution": "视频分辨率",
"resolutionPlaceholder": "选择分辨率",
"resolutionHint": "创建后本集视频按此分辨率生成,之后仍可在集卡片上修改。",
"lockCopy": "创建后自动锁定当前启用的图片与视频生成能力。",
"creating": "创建中...",
"create": "创建",
"added": "已添加新集"
},
"epDelete": {
"message": "确定删除「{title}」?删除后不可在列表中查看,其分镜与生成记录将不再可访问。"
},
"assets": {
"emptyTitle": "还没有任何素材",
"emptyDesc": "在剧情工作台中通过「提取资产」生成角色、场景与道具后,会自动收录到这里,并可直接生成素材图。",
"emptyKindTitle": "暂无{kind}素材",
"emptyKindDesc": "在剧情工作台中提取并生成{kind}后,会显示在这里。",
"todoShort": "待补充"
},
"mat": {
"dialogAria": "素材详情",
"unnamed": "未命名",
"propTypePlaceholder": "如:武器 / 信物",
"personaField": "人物设定",
"personaPlaceholder": "性格、背景、动机…",
"locationPlaceholder": "如:故宫太和殿",
"timePlaceholder": "如:黄昏 / 深夜",
"finalPromptLabel": "最终提示词",
"finalPromptSub": "由 AI 根据信息生成,可手动修改后保存",
"genPromptTitle": "由 AI 生成最终提示词",
"needEpisodeFirst": "请先在「剧集列表」创建至少一集",
"promptPlaceholder": "点击「生成提示词」由 AI 根据信息生成,或在此手动填写。手动修改并保存后,下次生成图片将使用此提示词。",
"genImage": "生成图片",
"saving": "保存中…",
"generating": "{kind}「{name}」图片生成中",
"genTimeout": "{kind}「{name}」生成超时,可稍后刷新查看",
"uploaded": "{kind}「{name}」图片已上传",
"needEpisodeForImage": "请先在「剧集列表」创建至少一集,才能生成素材图",
"needEpisodeForPrompt": "请先在「剧集列表」创建至少一集,才能生成最终提示词",
"locationRequired": "请填写地点"
}
},
"settings": {
"groupBase": "基础",
"tabs": {
"general": "通用",
"ai": "AI 服务",
"styles": "风格预设",
"storage": "存储位置",
"about": "关于更新",
"agents": "Agent 配置"
},
"common": {
"disabled": "已停用",
"custom": "自定义",
"empty": "暂无配置"
},
"general": {
"title": "通用",
"desc": "应用级通用设置。语言切换同时作用于界面与 AI 生成内容。",
"contentLanguage": "AI 内容语言",
"contentLanguageSub": "界面与 AI 产出(剧本/资产/分镜/提示词)统一使用的语言",
"languageLabel": "语言",
"languageNote": "切换后界面与 AI 内容语言同步更新,并自动刷新",
"languageHint": "两处入口(顶栏语言按钮 / 此处)等价,切换即全局生效。",
"languageSaved": "内容语言已保存",
"appearance": "外观",
"appearanceSub": "界面颜色主题,即时生效",
"appearanceLabel": "主题模式",
"appearanceNote": "跟随系统时,随操作系统外观自动切换",
"appearanceLight": "浅色",
"appearanceDark": "深色",
"appearanceSystem": "跟随系统",
"languageSavedWith": "AI 内容语言已切换为 {lang},后续生成(剧本/资产/分镜/提示词)将使用该语言",
"langNameZh": "中文",
"langNameEn": "English",
"langNameJa": "日本語",
"langNameKo": "한국어",
"unifiedSwitchWarning": "已切换为 {lang},界面与 AI 内容语言将同步更新,即将刷新…"
},
"ai": {
"title": "AI 服务配置",
"desc": "先用推荐模板快速落配置,再按服务类型微调。工作台创建集时会锁定所选图片和视频能力。",
"quickTitle": "火宝快捷配置",
"recommended": "推荐",
"quickDesc": "输入 Huobao API Key,一次写入文本、图片、视频三条推荐配置。",
"getKey": "前往火宝获取 Key",
"regionCn": "国内",
"regionCom": "国外",
"applyQuick": "写入火宝配置",
"manualTitle": "手动模板",
"manualDesc": "选择服务类型后,直接用模板填充推荐的 provider / base URL / model。",
"activeCount": "{n} 已启用",
"hasKey": "已配置",
"noKey": "无密钥",
"currentDefault": "当前默认模型",
"setDefault": "设为该类型默认模型",
"noBaseUrl": "未设置 Base URL",
"test": "测试",
"apiKeyRequired": "请填写 Huobao API Key",
"quickApplied": "火宝快捷配置已写入",
"defaultModelSwitched": "默认{type}模型已切换为 {model}",
"meta": {
"text": "剧本改写、角色场景提取、分镜拆解等 Agent 文本能力",
"image": "角色图、场景图与镜头图等静态图像生成",
"video": "镜头视频直出生成,默认 Seedance 2.0"
}
},
"styles": {
"title": "风格预设",
"desc": "创建项目时选择的视觉风格,其英文提示词片段会自动注入角色图与场景图生成。停用的风格不出现在创建选项中。",
"allTitle": "全部风格",
"count": "{active} 个启用 · {total} 个总计",
"empty": "暂无风格预设"
},
"storage": {
"title": "存储位置",
"desc": "数据库与生成文件(图片/视频/拼接/上传)所在的目录。更改位置会短暂停止后台服务并迁移数据。",
"currentDir": "当前数据目录",
"computedAt": "统计于 {time}",
"changeLocation": "更改位置",
"dataDir": "数据目录",
"desktopMode": "桌面版",
"serverMode": "服务器模式",
"totalUsage": "总占用 {size}",
"counting": "统计中…",
"breakdown": {
"db": "数据库",
"images": "图片",
"videos": "视频",
"merged": "拼接",
"uploads": "上传",
"temp": "临时",
"other": "其他"
},
"diskFree": "磁盘剩余 {size}",
"note": "数据目录包含 SQLite 数据库与全部生成媒体;Agent 技能(workspace)不在此列,不随迁移。",
"serverNote": "服务器部署请通过 STORAGE_PATH / SQLITE_PATH 环境变量配置存储位置,改后重启服务生效。",
"loadFailed": "加载存储信息失败"
},
"about": {
"title": "关于更新",
"desc": "从发布清单拉取新版本,本地 sha256 校验后自动换包重启。用户数据与配置保存在系统数据目录,不受更新影响。",
"currentVersion": "当前版本 v{v}",
"latestVersion": "最新版本 v{v}",
"check": "检查更新",
"webMode": "当前为浏览器 / 服务器模式,应用内更新仅桌面版可用。",
"upToDate": "已是最新版本",
"found": "发现新版本 v{v}",
"downloading": "下载中 {p}%",
"download": "下载更新",
"ready": "更新包已就绪",
"readyDesc": "点击后将退出应用并自动完成安装,随后重新打开。",
"restartInstall": "重启并安装",
"checkFailed": "检查失败",
"retry": "重试",
"empty": "点击「检查更新」获取最新版本。",
"note": "说明:macOS 上更新通过目录替换完成(与 Tauri 同类方案),无需 Apple 签名;Windows 上下载安装器静默安装。",
"checkFailedToast": "检查更新失败",
"downloadDone": "更新包下载完成,可以安装",
"downloadFailed": "下载失败",
"installFailed": "安装失败",
"serverApply": "立即更新",
"serverApplyStarted": "已触发更新:Watchtower 将拉取新镜像并重建容器,请几分钟后刷新页面",
"serverApplyFailed": "触发更新失败",
"serverManualHint": "服务器部署:请在部署目录执行",
"serverNote": "说明:Docker 部署配置了 Watchtower 时可一键更新(拉取新镜像并重建容器);未配置时请按提示手动执行更新命令。"
},
"agents": {
"promptHint": "保存为 {file}",
"promptPlaceholder": "Agent 系统提示词...",
"reset": "恢复默认",
"promptReset": "已恢复默认提示词(prompt 文件已删除)",
"saved": "{agent} 配置已保存",
"scriptRewriter": "剧本改写",
"extractor": "角色场景提取",
"storyboardBreaker": "分镜拆解",
"promptGenerator": "提示词",
"langFallback": "跟随中文",
"followContentLang": "编辑语言跟随:{lang}(在「通用 → AI 内容语言」切换)"
},
"skills": {
"agentList": "Agent 列表",
"desc": "Skills 仅作为 Agent 的高级提示词层使用,不影响工作台常规功能入口。",
"add": "新增 Skill",
"emptyTitle": "暂无 Skill",
"emptyDesc": "点击右上角「新增 Skill」创建第一个提示词文件",
"contentPlaceholder": "编写 SKILL.md 内容...",
"addTitle": "新增 Skill — {agent}",
"dirName": "Skill 目录名",
"dirNameHint": "英文,唯一",
"dirNamePlaceholder": "如 custom-extraction",
"name": "名称",
"namePlaceholder": "如 自定义提取规则",
"description": "描述",
"descPlaceholder": "简短描述此 Skill 的用途",
"create": "创建",
"created": "Skill 创建成功"
},
"cfg": {
"editTitle": "编辑服务配置",
"addTitle": "添加{type}服务",
"sub": "推荐先选择模板,系统会自动填入更合理的 Base URL 与默认模型。",
"name": "配置名称",
"namePlaceholder": "如 火宝默认图像服务",
"provider": "服务商",
"providerPlaceholder": "选择服务商",
"priority": "优先级",
"priorityHint": "数值越高越优先。工作台默认会优先使用同类型里优先级最高的启用配置。",
"models": "模型",
"modelsHint": "首位为默认模型;点击标签可置顶,输入框支持逗号/换行批量粘贴",
"modelPlaceholder": "输入模型名,回车添加",
"modelChipHint": "点击设为默认(置顶)",
"tempHint": "留空跟随服务商默认",
"tempPlaceholder": "如 0.6",
"tempNote": "部分模型强制固定温度(如 kimi-k2 系只允许 0.6),报 invalid temperature 错误时在此填入对应值。",
"test": "测试配置",
"reachable": "端点已响应",
"unreachable": "端点未通过测试",
"providerRequired": "选择服务商",
"tempInvalid": "Temperature 需为 0~2 的数字"
},
"styleDialog": {
"editTitle": "编辑风格预设",
"addTitle": "添加风格预设",
"sub": "提示词片段为英文,会在生成角色图与场景图时自动拼入提示词。",
"tag": "风格",
"name": "风格名称",
"namePlaceholder": "如 3D、动漫、写实电影",
"key": "风格 key",
"keyPlaceholder": "如 3d、anime(小写字母/数字/中划线)",
"keyHint": "存入项目的风格标识,创建后不可修改。",
"prompt": "提示词片段(英文)",
"promptPlaceholder": "如 anime style, cel shading, vibrant colors, clean line art",
"description": "描述",
"descPlaceholder": "一句话说明该风格的适用场景",
"sort": "排序",
"required": "名称、key、提示词片段必填"
},
"migrate": {
"title": "更改存储位置",
"newDir": "新目录",
"dataToMove": "待迁移数据",
"sizeNote": "约 {size}",
"freeNote": " · 目标盘剩余 {size}",
"moveFiles": "迁移已有数据(数据库与全部生成文件)",
"emptyWarn": "警告:应用将以全新的空数据库启动,旧目录中的数据会保留但不再被使用。",
"note": "迁移期间后台服务会短暂停止,进行中的生成任务会被中断;完成后页面自动刷新。",
"start": "开始迁移",
"pickFailed": "选择目录失败",
"failed": "迁移失败,已恢复原存储位置"
},
"styleDelete": {
"title": "删除风格预设",
"message": "确定删除风格「{name}」?已使用此风格的项目不受影响,但删除的内置风格重启后可能恢复,建议改用「停用」。"
},
"skillDelete": {
"title": "删除 Skill",
"message": "确定删除 Skill「{id}」?删除后对应 Agent 将回退到内置默认提示词。"
}
},
"episode": {
"topbar": {
"back": "返回项目",
"episodeN": "第 {n} 集",
"meta": "{roles} 角色 · {shots} 段落",
"tasks": "任务",
"viewFilm": "查看成片",
"continue": "继续制作",
"start": "开始制作",
"resolution": "分辨率"
},
"model": {
"defaultWith": "默认 · {model}",
"notConfigured": "未配置"
},
"sidebar": {
"inProgress": "进行中",
"refreshData": "刷新数据",
"collapse": "收起侧栏",
"expand": "展开侧栏"
},
"nav": {
"prev": "上一步",
"next": "下一步",
"toExport": "进入导出"
},
"stage": {
"script": "剧本",
"scriptDesc": "内容改写与整理",
"production": "制作",
"assets": "资产",
"assetsDesc": "角色 / 场景 / 道具",
"videos": "视频制作",
"videosDesc": "分镜拆分与视频生成",
"export": "导出",
"exportDesc": "拼接与成片输出",
"mergeExport": "拼接导出",
"scriptStage": "剧本阶段 · {step}",
"prodStage": "制作阶段 · {step}",
"exportDone": "导出阶段 · 已完成",
"exportWaiting": "导出阶段 · 等待拼接",
"workbench": "工作台"
},
"script": {
"raw": "原始内容",
"rewrite": "AI 改写",
"charCount": "{n} 字",
"saved": "已保存",
"rawPlaceholder": "粘贴小说原文、故事大纲或分镜描述...",
"skipRewrite": "跳过改写",
"rewriteAgain": "重新改写",
"emptyTitle": "AI 改写为格式化剧本",
"emptyDesc": "你可以先用 AI 把原始内容整理成格式化剧本,也可以跳过这一步,直接进入资产制作。",
"startRewrite": "开始改写",
"rewriting": "正在改写剧本...",
"scriptPlaceholder": "格式化剧本内容...",
"rawRequired": "请先填写原始内容",
"skipDone": "已跳过 AI 改写,当前将直接使用原始内容"
},
"prod": {
"assets": "资产制作",
"videos": "视频制作",
"notReady": "尚未准备就绪",
"readyCount": "{ready}/{total} 已就绪",
"extract": "提取{type}",
"reextract": "重提{type}",
"batchChar": "批量角色",
"batchScene": "批量场景",
"batchProp": "批量道具",
"extractingTypes": "正在提取{types}...",
"extractingTypesDots": "正在提取{types}…",
"emptyTitle": "开始提取资产",
"emptyDesc": "角色、场景和道具会在提取后显示在这里,可分别单独提取,也可一键并行提取全部。",
"startExtract": "开始提取",
"scriptFirst": "请先完成剧本编写",
"goBack": "返回处理"
},
"asset": {
"fallbackType": "资产",
"typeChar": "角色资产",
"typeScene": "场景资产",
"typeProp": "道具资产",
"detailTitle": "{type}详情",
"delChar": "删除角色",
"delScene": "删除场景",
"delProp": "删除道具",
"charImageTitle": "{name} 角色形象",
"sceneImageTitle": "{name} 场景图",
"propImageTitle": "{name} 道具图",
"portraitReady": "形象已生成",
"portraitPending": "形象生成中",
"portraitTodo": "形象待生成",
"ready": "已生成",
"generating": "生成中",
"todo": "待生成",
"regen": "重绘",
"generate": "生成",
"upload": "上传",
"uploadCharImage": "上传角色形象图",
"uploadSceneImage": "上传场景图",
"uploadPropImage": "上传道具图",
"uploadImage": "上传图片",
"appearance": "样貌:",
"styling": "妆造:",
"lighting": "光照 · ",
"appearanceTodo": "样貌待补充",
"stylingTodo": "妆造待补充",
"sceneDescTodo": "场景描述待补充",
"sceneLightTodo": "场景光影待补充",
"noDescription": "暂无描述",
"noTime": "未设时间",
"finalPromptTurnaround": "最终提示词 · 三视图",
"finalPromptFixed": "最终提示词 · 固定视角",
"finalPromptWhiteBg": "最终提示词 · 白底单品",
"finalPromptAutoTurnaround": "首次生成形象时由提示词 Agent 自动生成",
"finalPromptAutoFixed": "首次生成图片时由提示词 Agent 自动生成(前景/中景/后景)",
"finalPromptAutoWhiteBg": "首次生成图片时由提示词 Agent 自动生成(白底单品)",
"propsEmpty": "本集暂无涉及事态发展的关键道具",
"visualPreview": "视觉预览",
"kindLabel": "类型",
"charPortrait": "角色形象",
"sceneImage": "场景图片",
"roleLabel": "定位",
"propTypeLabel": "道具类型",
"timeLabel": "时间",
"editInfo": "编辑信息",
"editHintChar": "样貌与妆造会影响角色形象",
"editHintProp": "物品外貌会影响道具图",
"editHintScene": "空间与光影会影响场景图",
"appearanceOfObject": "物品外貌",
"appearancePlaceholder": "材质、颜色、形状、大小、新旧程度、磨损痕迹等",
"appearanceField": "样貌",
"appearanceFieldPlaceholder": "年龄感、五官、体态、气质等",
"stylingField": "妆造",
"stylingFieldPlaceholder": "发型、服装、妆面、配饰等",
"sceneDescField": "场景描述",
"sceneDescPlaceholder": "空间、陈设、年代质感、关键视觉元素等",
"sceneLightField": "场景光影",
"sceneLightPlaceholder": "光源、色调、明暗、氛围等",
"genPrompt": "生成提示词",
"regenPrompt": "重新生成",
"genPortrait": "生成形象",
"regenPortrait": "重绘形象",
"genScene": "生成场景",
"regenScene": "重绘场景",
"genProp": "生成道具图",
"regenProp": "重绘道具图",
"promptPlaceholderChar": "可手动编写三视图最终提示词,或点击「生成提示词」由 Agent 生成",
"promptPlaceholderScene": "可手动编写固定视角最终提示词,或点击「生成提示词」由 Agent 生成",
"promptPlaceholderProp": "可手动编写白底单品最终提示词,或点击「生成提示词」由 Agent 生成",
"promptHintChar": "提示词可直接编辑,保存后生效;修改样貌或妆造并保存后,最终提示词将被清空,下次生成形象时由提示词 Agent 重新生成。",
"promptHintScene": "提示词可直接编辑,保存后生效;修改场景描述或光影并保存后,最终提示词将被清空,下次生成场景图时由提示词 Agent 重新生成。",
"promptHintProp": "提示词可直接编辑,保存后生效;修改物品外貌并保存后,最终提示词将被清空,下次生成道具图时由提示词 Agent 重新生成。",
"generatingPrompt": "正在生成最终提示词…",
"promptGenerated": "最终提示词已生成",
"promptRegenerated": "最终提示词已重新生成",
"promptGenFailedRetry": "最终提示词生成失败,请重试",
"promptGenFailed": "最终提示词生成失败",
"promptCopied": "最终提示词已复制",
"copyFailed": "复制失败,请手动选择文本复制",
"noChanges": "没有需要保存的修改",
"saved": "修改已保存",
"saveFailed": "保存失败",
"saveChanges": "保存修改",
"unnamedChar": "未命名角色",
"unnamedProp": "未命名道具",
"unnamedScene": "未命名场景",
"propSingleImage": "道具单品图",
"propImage": "道具图"
},
"create": {
"title": "新增{type}",
"name": "名称",
"namePlaceholderChar": "角色名称",
"namePlaceholderProp": "道具名称",
"roleField": "角色定位",
"rolePlaceholder": "如:主角 / 反派 / 配角",
"appearancePlaceholder": "外貌特征(可融入性格)",
"stylingPlaceholder": "服装、妆容、配饰",
"location": "地点",
"locationPlaceholder": "场景地点",
"time": "时间",
"timePlaceholder": "如:白天 / 夜晚",
"sceneDescPlaceholder": "环境、陈设、氛围",
"lightPlaceholder": "如:黄昏暖光、冷清顶光",
"typeField": "类型",
"typePlaceholder": "如:武器 / 信物 / 文件",
"appearanceOnlyPlaceholder": "只描述物品的外观,与其他无关",
"locationRequired": "请填写场景地点",
"nameRequired": "请填写名称",
"created": "已新增{type}"
},
"delete": {
"title": "删除{type}",
"message": "确定删除{type}「{name}」吗?将从本剧所有集中移除。",
"deleted": "已删除{type}"
},
"sb": {
"title": "分镜拆分",
"segmentStat": "{n} 段落 · {dur}s",
"rebreak": "重新拆分",
"startBreak": "拆分并生成提示词",
"promptProgress": "提示词 {done}/{total}",
"promptSelected": "生成所选提示词({n})",
"batchPrompts": "批量补齐提示词",
"listTitle": "分镜列表",
"listSub": "检查拆分描述和绑定的角色场景",
"select": "选择",
"selectAll": "全选",
"selectMissing": "仅缺失",
"clear": "清空",
"selectedCount": "已选 {n} 个",
"generatingProgress": "生成中 {done}/{total}",
"generateSelected": "生成视频提示词({n})",
"shotN": "分镜 #{n}",
"totalCount": "共 {n} 个",
"duration": "时长",
"descSection": "分镜描述",
"descLabel": "画面描述",
"descHint": "按【镜头1】【镜头2】…逐子镜头描述;台词写「角色名说:「台词」」,旁白写「旁白:内容」",
"descPlaceholder": "分镜画面描述",
"atmosphere": "氛围",
"atmospherePlaceholder": "光线、色调、空气感、环境氛围",
"videoPromptSection": "视频提示词",
"regenPrompt": "重新生成",
"aiGenerate": "AI 生成",
"videoPromptCopy": "根据当前分镜的画面描述(含台词/旁白)与氛围生成",
"videoPromptPlaceholder": "用 {'@'}角色名 / {'@'}场景名 引用参考素材,按 3 秒一段换行描述画面运动与镜头;也可点 AI 生成由提示词 Agent 自动创作…",
"breaking": "正在拆分分镜...",
"emptyTitle": "开始拆分分镜",
"emptyDesc": "根据剧本、角色和场景拆分镜头,生成分镜描述和绑定信息。",
"hasVideo": "已生成视频",
"noVideo": "未生成视频",
"hasVideoShort": "已出片",
"videoFlag": "视",
"noDescription": "暂无画面描述",
"zeroChars": "0 角色",
"unboundScene": "未绑定场景",
"breakFirst": "请先拆分分镜",
"selectedMissing": "所选分镜不存在",
"allHavePrompts": "所有分镜已有视频提示词",
"batchStarted": "开始生成 {n} 个分镜的视频提示词…",
"batchDone": "视频提示词批量生成完成",
"batchDoneFailed": "视频提示词批量生成完成,{n} 个失败",
"batchFailed": "视频提示词批量生成失败",
"promptGenerated": "分镜 #{n} 视频提示词已生成"
},
"ref": {
"title": "参考素材",
"copy": "绑定角色 / 场景 / 道具作为视频参考",
"boundCount": "{bound}/{total} 已绑定",
"clickAdd": "点击添加为参考",
"clickRemove": "点击移出参考",
"shortChar": "角",
"shortScene": "景",
"shortProp": "具",
"usable": "可参考",
"notReady": "未生成",
"unbound": "未绑定",
"gotoGenerate": "去生成 →",
"empty": "当前集还没有场景、角色或道具,先到「资产」提取素材后即可绑定。"
},
"vid": {
"shotCount": "{n} 个镜头",
"doneCount": "{done}/{total} 已生成",
"batchVideos": "批量视频",
"emptyTitle": "先生成分镜",
"emptyDesc": "视频任务来自分镜拆分结果。先生成分镜描述和视频提示词,再批量生成视频。",
"lockedModel": "当前集视频模型:",
"listTitle": "视频任务列表",
"listMeta": "按镜头顺序 · {n} 个任务",
"metricPending": "{n} 生成中",
"metricDone": "{n} 完成",
"metricFailed": "{n} 失败",
"references": "参考 {n}",
"refCountMeta": "{n} 个参考素材",
"shotN": "镜头 #{n}",
"playerTitle": "分镜 {n}",
"setMain": "设为主视频",
"setMainDone": "已设为主视频",
"setMainFailed": "设置失败",
"download": "下载",
"emptyGenerating": "视频生成中…",
"emptyNoVideo": "尚未生成视频",
"emptyGeneratingDesc": "生成完成后可在此播放预览",
"emptyNoVideoDesc": "点击下方按钮为当前分镜生成视频",
"generateVideo": "生成视频",
"history": "历史视频",
"current": "当前",
"deleteRecord": "删除该记录",
"historyDeleted": "已删除该历史记录",
"needRefOrPrompt": "需要至少一个参考素材或视频提示词",
"generating": "视频生成中",
"genDone": "视频生成完成",
"genFailed": "视频生成失败",
"genTimeout": "视频生成超时",
"allDone": "所有镜头视频已生成",
"moderationHint": "疑似真人/敏感内容审核未通过,可在顶栏切换其他视频模型后重试",
"resolutionSwitched": "本集视频分辨率已切换为 {label}",
"noneToGenerate": "没有可生成的镜头",
"batchStarted": "已发起 {n} 个视频生成任务",
"retryFailed": "重试失败({n})",
"select": "选择",
"selectDone": "已选 {n} · 完成",
"batchSelected": "生成所选({n})",
"listMetaFiltered": "筛选结果 · {n}/{total} 个任务",
"defaultModel": "默认模型",
"confirmTitle": "批量生成视频",
"confirmShots": "镜头数",
"confirmShotsValue": "{n} 个",
"confirmTotal": "总时长",
"confirmApprox": "约 {n}s",
"confirmModel": "视频模型",
"confirmResolution": "分辨率",
"confirmNote": "将按以上配置逐镜头发起生成;失败的任务之后可点「重试失败」一键重跑。",
"confirmStart": "开始生成 ({n})",
"selectMissing": "选未生成",
"aspectRatio": "画面比例"
},
"inspector": {
"videoPromptPlaceholder": "用 {'@'}角色名 / {'@'}场景名 引用参考素材,生成时自动映射为参考图片;再按时间段描述画面运动与镜头…",
"noRefs": "当前分镜未绑定参考素材",
"refMedia": "参考图片 / 视频 / 音频",
"imageN": "图片 {n}",
"videoN": "视频 {n}",
"audioN": "音频 {n}",
"uploadRefImage": "上传参考图片 ({used}/{limit})",
"uploadRefVideo": "上传参考视频 ({used}/{limit})",
"uploadRefAudio": "上传参考音频 ({used}/{limit})",
"refAudioHint": "参考音频需至少 1 个参考图片或视频",
"params": "生成参数",
"duration": "分镜时长",
"durationUnit": "s(2-30)",
"durationHint": "修改即保存到分镜,列表与批量生成同步生效",
"effective": "{model} · {res} · {dur}s",
"boundRefs": "绑定参考图",
"noBoundRefs": "暂无绑定素材(在中间「参考素材」区点击绑定)"
},
"tasks": {
"title": "生成任务列表",
"meta": "按创建时间倒序 · {n} 个任务",
"emptyTitle": "暂无生成任务",
"emptyDesc": "在资产、分镜或视频步骤中触发图片 / 视频生成后,任务会自动出现在这里。",
"duration": "耗时 {dur}",
"sbN": "分镜 #{n}",
"generic": "通用",
"fullMerge": "整集拼接",
"mergeKind": "合并"
},
"export": {
"notReadyDesc": "请先完成分镜和制作流程",
"gotoScript": "前往剧本",
"filmList": "成片列表",
"countN": "{n} 个",
"empty": "暂无成片,在下方勾选镜头后点击「拼接所选」",
"shotAssets": "镜头素材",
"shotStat": "{done}/{total} 已生成 · 已选 {selected}",
"clearSelection": "清空选择",
"selectAllReady": "全选已生成",
"mergeSelected": "拼接所选 ({n})",
"selectFirst": "请先勾选至少一个已生成视频的镜头",
"merging": "拼接中…",
"mergingToast": "拼接中...",
"mergeDone": "拼接完成",
"mergeFailed": "拼接失败",
"previewShot": "播放该镜头",
"shotPreview": "镜头 #{n} 预览",
"markDone": "标记完成",
"markedDone": "已完成",
"markDoneTitle": "手动标记本集导出完成(可再次点击取消)",
"markedDoneToast": "已标记为完成",
"unmarkDoneToast": "已取消完成标记"
},
"image": {
"generatingChar": "角色图片生成中",
"generatingScene": "场景图片生成中",
"generatingProp": "道具图片生成中",
"batchGeneratingChar": "角色图片批量生成中",
"batchGeneratingScene": "场景图片批量生成中",
"batchGeneratingProp": "道具图片批量生成中",
"allCharsDone": "所有角色图片已生成",
"allScenesDone": "所有场景图片已生成",
"allPropsDone": "所有道具图片已生成"
},
"extract": {
"done": "{type}提取完成",
"failed": "{type}提取失败"
},
"upload": {
"assetDone": "{type}已上传",
"refImageFull": "参考图片已达上限(含场景/角色素材)",
"refImageDone": "参考图片已上传",
"refMax3": "参考{type}最多 3 个",
"refDone": "参考{type}已上传",
"refAudioNeed": "参考音频需要至少 1 个参考图片或视频",
"audio": "音频",
"refMax": "参考{type}最多 {n} 个"
},
"viewer": {
"imagePreview": "图片预览",
"filmPreview": "成片预览",
"downloadFilm": "下载成片"
},
"status": {
"done": "已完成",
"generating": "生成中",
"failed": "失败",
"todo": "待生成"
},
"resolution": {
"smooth": "流畅",
"hd": "高清",
"uhd": "超清"
}
},
"errors": {
"network": "无法连接服务器,请检查网络或服务是否已启动",
"server": "服务返回异常,请稍后重试",
"unavailable": "服务暂时不可用,请稍后重试",
"auth": "鉴权失败,请检查 API Key 配置",
"rateLimit": "请求过于频繁或额度不足,请稍后重试",
"timeout": "生成超时,请重试",
"moderation": "内容未通过审核,请调整提示词或切换模型后重试",
"requestFailed": "请求失败({status})",
"unknown": "操作失败,请重试"
},
"tour": {
"next": "下一步",
"prev": "上一步",
"done": "完成",
"helpTitle": "使用引导",
"index": {
"welcome": {
"title": "👋 欢迎使用火宝短剧",
"desc": "小说 → 剧本 → 资产 → 分镜 → 视频 → 成片,一站式 AI 短剧制作。先配置 AI 服务,再创建第一个项目。"
},
"create": {
"title": "第 2 步 · 新建项目",
"desc": "点「新建项目」:填写剧名、选择画面比例(横竖屏)与画面风格。"
},
"settings": {
"title": "第 1 步 · 配置 AI 服务",
"desc": "所有 AI 功能都要先配置。点这里进「设置」页,粘贴 Huobao API Key 一键完成文本/图片/视频三条配置。"
}
},
"settings": {
"quick": {
"title": "最快上手:快捷配置",
"desc": "粘贴 Huobao API Key,一键写入文本、图片、视频三条推荐配置,支持连通性测试。"
},
"nav": {
"title": "全部配置都在这",
"desc": "左侧切换:AI 服务、通用(界面语言/内容语言)、风格预设、Agent 提示词与技能、存储位置、关于更新。"
}
},
"episode": {
"topbar": {
"title": "顶栏:模型与状态",
"desc": "随时切换本次生成用的文本/图片/视频模型;分辨率与时长档位随模型联动。"
},
"script": {
"title": "第 1 步 · 剧本",
"desc": "(前提:设置页已配置 AI 服务)粘贴原始小说,点「AI 改写」生成拍摄剧本;满意后进入制作。"
},
"assets": {
"title": "第 2 步 · 资产制作",
"desc": "提取角色/场景/道具并生成一致性参考图,生视频时自动作为参考素材。"
},
"videos": {
"title": "第 3 步 · 视频制作",
"desc": "拆分分镜 → 检查提示词 → 批量生成视频;失败可一键重试。完成后在「拼接导出」合成成片。"
},
"help": {
"title": "随时重看引导",
"desc": "点这个「?」按钮可重新播放本页引导。祝创作顺利!"
}
}
}
}