Clean up Kling official PR artifacts

This commit is contained in:
xucailiang
2026-07-07 15:34:23 +08:00
parent 1471ef47c3
commit 8e1128400b
9 changed files with 10 additions and 3408 deletions

View File

@@ -69,7 +69,7 @@ Local image references may be normalized through `tools/_kling/media.py`. Local
Image Omni accepts `image_list[]` with official `image` values. Prompt placeholders such as `<<<image_1>>>` must map stably to the provided image order. If the prompt already contains placeholders, validate that the referenced images exist and do not insert duplicates.
## Phase 3 Capability Boundaries
## Capability Boundaries
TTS, avatar, and lip sync are provider additions to existing OpenMontage capabilities. Audio effects and video effects are official Kling endpoints, but they are not registered as default OpenMontage tools until a pipeline has a stable capability slot for them.
@@ -148,7 +148,7 @@ Local video paths must not be silently uploaded through fal.ai or any other prov
## Audio Effects And Video Effects
Official Kling audio effects (`/v1/audio/text-to-audio`, `/v1/audio/video-to-audio`) and video effects (`/v1/videos/effects`) are intentionally not default OpenMontage selector tools in Phase 3. Record the non-mapping reason in docs/tests instead of registering tools that current pipelines might misuse.
Official Kling audio effects (`/v1/audio/text-to-audio`, `/v1/audio/video-to-audio`) and video effects (`/v1/videos/effects`) are intentionally not default OpenMontage selector tools. Record the non-mapping reason in docs/tests instead of registering tools that current pipelines might misuse.
## Elements Helper

View File

@@ -1,456 +0,0 @@
---
name: video-toolkit
description: Create professional videos autonomously using Codex-video-toolkit — AI voiceovers, image generation, music, talking heads, and Remotion rendering.
metadata:
openclaw:
emoji: "🎬"
skillKey: "video-toolkit"
os: ["darwin", "linux"]
requires:
bins: ["node", "python3", "ffmpeg", "npm"]
---
# Video Toolkit
Create professional explainer videos from a text brief. The toolkit uses open-source AI models on cloud GPUs (Modal or RunPod) for voiceover, image generation, music, and talking head animation. Remotion (React) handles composition and rendering.
## CRITICAL: Toolkit Path
The toolkit lives at a fixed path. **ALWAYS `cd` here before running any tool command.**
```bash
TOOLKIT=~/.openclaw/workspace/Codex-video-toolkit
cd $TOOLKIT
```
**NEVER run tool commands from inside a project directory.** Tools resolve paths relative to the toolkit root.
## Setup
### Step 1: Check Current State
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
python3 tools/verify_setup.py
```
If everything shows `[x]`, skip to "Quick Test" below. Otherwise continue setup.
### Step 2: Install Python Dependencies
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
pip3 install --break-system-packages -r tools/requirements.txt
```
Note: `--break-system-packages` is needed on Debian/Ubuntu with managed Python (PEP 668). Safe inside containers.
### Step 3: Configure Cloud GPU Endpoints
The toolkit needs cloud GPU endpoint URLs in `.env`. Check if `.env` exists and has Modal endpoints:
```bash
cat ~/.openclaw/workspace/Codex-video-toolkit/.env | grep MODAL
```
If Modal endpoints are configured, you're ready. If not, **ask the user to provide Modal endpoint URLs** or set up Modal:
```bash
pip3 install --break-system-packages modal
python3 -m modal setup # Opens browser for authentication
# Deploy each tool — capture the endpoint URL from output
cd ~/.openclaw/workspace/Codex-video-toolkit
modal deploy docker/modal-qwen3-tts/app.py
modal deploy docker/modal-flux2/app.py
modal deploy docker/modal-music-gen/app.py
modal deploy docker/modal-sadtalker/app.py
modal deploy docker/modal-image-edit/app.py
modal deploy docker/modal-upscale/app.py
modal deploy docker/modal-propainter/app.py
modal deploy docker/modal-ltx2/app.py # Requires: modal secret create huggingface-token HF_TOKEN=hf_...
```
**LTX-2 prerequisite:** Before deploying LTX-2, create a HuggingFace secret and accept the [Gemma 3 license](https://huggingface.co/google/gemma-3-12b-it-qat-q4_0-unquantized):
```bash
modal secret create huggingface-token HF_TOKEN=hf_your_read_access_token
```
Add each URL to `.env`:
```
MODAL_QWEN3_TTS_ENDPOINT_URL=https://...modal.run
MODAL_FLUX2_ENDPOINT_URL=https://...modal.run
MODAL_MUSIC_GEN_ENDPOINT_URL=https://...modal.run
MODAL_SADTALKER_ENDPOINT_URL=https://...modal.run
MODAL_IMAGE_EDIT_ENDPOINT_URL=https://...modal.run
MODAL_UPSCALE_ENDPOINT_URL=https://...modal.run
MODAL_DEWATERMARK_ENDPOINT_URL=https://...modal.run
MODAL_LTX2_ENDPOINT_URL=https://...modal.run
```
Optional but recommended — Cloudflare R2 for reliable file transfer:
```
R2_ACCOUNT_ID=...
R2_ACCESS_KEY_ID=...
R2_SECRET_ACCESS_KEY=...
R2_BUCKET_NAME=video-toolkit
```
### Step 4: Verify and Quick Test
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
python3 tools/verify_setup.py
```
All tools should show `[x]`. Then run a quick test to confirm the GPU pipeline works:
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
python3 tools/qwen3_tts.py --text "Hello, this is a test." --speaker Ryan --tone warm --output /tmp/video-toolkit-test.mp3 --cloud modal
```
If you get a valid .mp3 file, setup is complete. If it fails, check:
- `.env` has the correct `MODAL_QWEN3_TTS_ENDPOINT_URL`
- Run `python3 tools/verify_setup.py --json` and check `modal_tools` for which endpoints are missing
**Cost:** Modal includes $30/month free compute. A typical 60s video costs $1-3.
---
## Creating a Video
### Step 1: Create Project
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
cp -r templates/product-demo projects/PROJECT_NAME
cd projects/PROJECT_NAME
npm install
```
Templates: `product-demo` (marketing/explainer), `sprint-review`, `sprint-review-v2` (composable scenes).
### Step 2: Write Config
Edit `projects/PROJECT_NAME/src/config/demo-config.ts`:
```typescript
export const demoConfig: ProductDemoConfig = {
product: {
name: 'My Product',
tagline: 'What it does in one line',
website: 'example.com',
},
scenes: [
{ type: 'title', durationSeconds: 9, content: { headline: '...', subheadline: '...' } },
{ type: 'problem', durationSeconds: 14, content: { headline: '...', problems: ['...', '...'] } },
{ type: 'solution', durationSeconds: 13, content: { headline: '...', highlights: ['...', '...'] } },
{ type: 'stats', durationSeconds: 12, content: { stats: [{value: '99%', label: '...'}, ...] } },
{ type: 'cta', durationSeconds: 10, content: { headline: '...', links: ['...'] } },
],
audio: {
backgroundMusicFile: 'audio/bg-music.mp3',
backgroundMusicVolume: 0.12,
},
};
```
Scene types: `title`, `problem`, `solution`, `demo`, `feature`, `stats`, `cta`.
**Duration rule:** Estimate `durationSeconds` as `ceil(word_count / 2.5) + 2`. You will adjust this after generating audio in Step 4.
### Step 3: Write Voiceover Script
Create `projects/PROJECT_NAME/VOICEOVER-SCRIPT.md`:
```markdown
## Scene 1: Title (9s, ~17 words)
Build videos with AI. The product name toolkit makes it easy.
## Scene 2: Problem (14s, ~30 words)
The problem statement goes here. Keep it punchy and relatable.
```
**Word budget per scene:** `(durationSeconds - 2) * 2.5` words. The -2 accounts for 1s audio delay + 1s padding.
### Step 4: Generate Assets
**CRITICAL: All commands below MUST be run from the toolkit root, not the project directory.**
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
```
#### 4a. Background Music
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
python3 tools/music_gen.py \
--preset corporate-bg \
--duration 90 \
--output projects/PROJECT_NAME/public/audio/bg-music.mp3 \
--cloud modal
```
Presets: `corporate-bg`, `upbeat-tech`, `ambient`, `dramatic`, `tension`, `hopeful`, `cta`, `lofi`.
#### 4b. Voiceover (per-scene)
Generate ONE .mp3 file PER SCENE. Do NOT generate a single voiceover file.
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
# Scene 01
python3 tools/qwen3_tts.py \
--text "The voiceover text for scene one." \
--speaker Ryan --tone warm \
--output projects/PROJECT_NAME/public/audio/scenes/01.mp3 \
--cloud modal
# Scene 02
python3 tools/qwen3_tts.py \
--text "The voiceover text for scene two." \
--speaker Ryan --tone warm \
--output projects/PROJECT_NAME/public/audio/scenes/02.mp3 \
--cloud modal
# ... repeat for each scene
```
**Speakers:** `Ryan`, `Aiden`, `Vivian`, `Serena`, `Uncle_Fu`, `Dylan`, `Eric`, `Ono_Anna`, `Sohee`
**Tones:** `neutral`, `warm`, `professional`, `excited`, `calm`, `serious`, `storyteller`, `tutorial`
For voice cloning (needs a reference recording):
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
python3 tools/qwen3_tts.py \
--text "Text to speak" \
--ref-audio assets/voices/reference.m4a \
--ref-text "Exact transcript of the reference audio" \
--output projects/PROJECT_NAME/public/audio/scenes/01.mp3 \
--cloud modal
```
#### 4c. Scene Images
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
python3 tools/flux2.py \
--prompt "Dark tech background with blue geometric grid, cinematic lighting" \
--width 1920 --height 1080 \
--output projects/PROJECT_NAME/public/images/title-bg.png \
--cloud modal
```
Image presets (use `--preset` instead of `--prompt --width --height`):
`title-bg`, `problem`, `solution`, `demo-bg`, `stats-bg`, `cta`, `thumbnail`, `portrait-bg`
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
python3 tools/flux2.py \
--preset title-bg \
--output projects/PROJECT_NAME/public/images/title-bg.png \
--cloud modal
```
#### 4d. Video Clips — B-Roll & Animated Backgrounds (optional)
Generate AI video clips for b-roll cutaways, animated slide backgrounds, or intro/outro sequences:
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
# B-roll clip from text
python3 tools/ltx2.py \
--prompt "Aerial drone shot over a European city at golden hour, cinematic wide angle" \
--output projects/PROJECT_NAME/public/videos/broll-europe.mp4 \
--cloud modal
# Animate a slide/screenshot (image-to-video)
python3 tools/ltx2.py \
--prompt "Gentle particle effects, soft ambient light shifts, very slight camera drift" \
--input projects/PROJECT_NAME/public/images/title-bg.png \
--output projects/PROJECT_NAME/public/videos/animated-title.mp4 \
--cloud modal
# Abstract intro/outro background
python3 tools/ltx2.py \
--prompt "Dark moody abstract background with flowing blue light streaks, bokeh particles, cinematic" \
--output projects/PROJECT_NAME/public/videos/intro-bg.mp4 \
--cloud modal
```
Use in Remotion compositions with `<OffthreadVideo>`:
```tsx
<OffthreadVideo src={staticFile('videos/broll-europe.mp4')} />
```
**LTX-2 rules:**
- Max ~8 seconds per clip (193 frames at 24fps). Default is ~5s (121 frames).
- Width/height must be divisible by 64. Default: 768x512.
- ~$0.20-0.25 per clip, ~2.5 min generation time.
- Cold start ~60-90s. Subsequent clips on warm GPU are faster.
- Generated audio is ambient only — use voiceover/music tools for speech and music.
- ~30% of generations may have training data artifacts (logos/text). Re-run with `--seed` to vary.
#### 4e. Talking Head Narrator (optional)
Generate a presenter portrait, then animate per-scene clips:
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
# 1. Generate portrait
python3 tools/flux2.py \
--prompt "Professional presenter portrait, clean style, dark background, facing camera, upper body" \
--width 1024 --height 576 \
--output projects/PROJECT_NAME/public/images/presenter.png \
--cloud modal
# 2. Generate per-scene narrator clips (one per scene, NOT one long video)
python3 tools/sadtalker.py \
--image projects/PROJECT_NAME/public/images/presenter.png \
--audio projects/PROJECT_NAME/public/audio/scenes/01.mp3 \
--preprocess full --still --expression-scale 0.8 \
--output projects/PROJECT_NAME/public/narrator-01.mp4 \
--cloud modal
# Repeat for each scene that needs a narrator
```
**SadTalker rules — follow these exactly:**
- **ALWAYS** use `--preprocess full` (default `crop` outputs a square, wrong aspect ratio)
- **ALWAYS** use `--still` (reduces head movement, looks professional)
- **ALWAYS** generate per-scene clips (6-15s each), NEVER one long video
- Processing: ~3-4 min per 10s of audio on Modal A10G
- `--expression-scale 0.8` keeps expressions subtle (range 0.0-1.5)
#### 4e. Image Editing (optional)
Create scene variants from existing images:
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
python3 tools/image_edit.py \
--input projects/PROJECT_NAME/public/images/title-bg.png \
--prompt "Make it darker with red tones, more ominous" \
--output projects/PROJECT_NAME/public/images/problem-bg.png \
--cloud modal
```
#### 4f. Upscaling (optional)
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
python3 tools/upscale.py \
--input projects/PROJECT_NAME/public/images/some-image.png \
--output projects/PROJECT_NAME/public/images/some-image-4x.png \
--scale 4 --cloud modal
```
### Step 5: Sync Timing
**ALWAYS do this after generating voiceover.** Audio duration differs from estimates.
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit
for f in projects/PROJECT_NAME/public/audio/scenes/*.mp3; do
echo "$(basename $f): $(ffprobe -v error -show_entries format=duration -of csv=p=0 "$f")s"
done
```
Update each scene's `durationSeconds` in `demo-config.ts` to: `ceil(actual_audio_duration + 2)`.
Example: if `01.mp3` is 6.8s, set scene 1 `durationSeconds` to `9` (ceil(6.8 + 2) = 9).
### Step 6: Review Still Frames
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit/projects/PROJECT_NAME
npx remotion still src/index.ts ProductDemo --frame=100 --output=/tmp/review-scene1.png
npx remotion still src/index.ts ProductDemo --frame=400 --output=/tmp/review-scene2.png
```
Check: text truncation, animation timing, narrator PiP positioning, background contrast.
### Step 7: Render
```bash
cd ~/.openclaw/workspace/Codex-video-toolkit/projects/PROJECT_NAME
npm run render
```
**Output:** `out/ProductDemo.mp4`
---
## Composition Patterns
### Per-Scene Audio
Use per-scene audio with a 1-second delay (`from={30}` = 30 frames = 1s at 30fps):
```tsx
<Sequence from={30}>
<Audio src={staticFile('audio/scenes/01.mp3')} volume={1} />
</Sequence>
```
### Per-Scene Narrator PiP
```tsx
<Sequence from={30}>
<OffthreadVideo
src={staticFile('narrator-01.mp4')}
style={{ width: 320, height: 180, objectFit: 'cover' }}
muted
/>
</Sequence>
```
**ALWAYS use `<OffthreadVideo>`, NEVER `<video>`.** Remotion requires its own component for frame-accurate rendering.
### Transitions
```tsx
import { TransitionSeries, linearTiming } from '@remotion/transitions';
import { fade } from '@remotion/transitions/fade';
import { glitch } from '../../../lib/transitions/presentations/glitch';
import { lightLeak } from '../../../lib/transitions/presentations/light-leak';
```
**NEVER import from `lib/transitions` barrel** — import custom transitions from `lib/transitions/presentations/` directly.
---
## Error Recovery
| Problem | Solution |
|---------|----------|
| Tool command fails with "No module named..." | Run `pip3 install --break-system-packages -r tools/requirements.txt` from toolkit root |
| "MODAL_*_ENDPOINT_URL not configured" | Check `.env` has the endpoint URL. Run `python3 tools/verify_setup.py` |
| SadTalker output is square/cropped | You forgot `--preprocess full`. Re-run with that flag |
| Audio too short/long for scene | Re-run Step 5 (sync timing) and update config |
| `npm run render` fails | Make sure you're in the project dir, not toolkit root. Run `npm install` first |
| "Cannot find module" in Remotion | Check import paths. Custom components use `../../../lib/` relative paths |
| Cold start timeout on Modal | First call after idle takes 30-120s. Retry once — second call uses warm GPU |
---
## Cost Estimates (Modal)
| Tool | Typical Cost | Notes |
|------|-------------|-------|
| Qwen3-TTS | ~$0.01/scene | ~20s per scene on warm GPU |
| FLUX.2 | ~$0.01/image | ~3s warm, ~30s cold |
| ACE-Step | ~$0.02-0.05 | Depends on duration |
| SadTalker | ~$0.05-0.20/scene | ~3-4 min per 10s audio |
| Qwen-Edit | ~$0.03-0.15 | ~8 min cold start (25GB model) |
| RealESRGAN | ~$0.005/image | Very fast |
| LTX-2.3 | ~$0.20-0.25/clip | ~2.5 min per 5s clip, A100-80GB |
**Total for a 60s video:** ~$1-3 depending on scenes and narrator clips.
Modal Starter plan: $30/month free compute. Apps scale to zero when idle.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -398,16 +398,16 @@ All config is validated via Pydantic models in `lib/config_model.py`.
| `VIDEO_GEN_LOCAL_ENABLED` | local video tools | Enable local GPU generation |
| `VIDEO_GEN_LOCAL_MODEL` | wan, hunyuan, ltx, cogvideo | Select local model |
Kling Official Phase 2 adds deeper Omni reference support inside the existing
`kling_official_video` and `kling_official_image` providers. Elements and Account
Usage live under `tools/_kling/` as internal helpers for element ID references and
low-frequency account diagnostics; they are not separate pipeline stages,
selectors, or generated-asset capabilities.
Kling Official support stays inside the existing provider and capability model.
`kling_official_video` and `kling_official_image` handle Classic, Turbo, and Omni
request shapes, while Elements and Account Usage live under `tools/_kling/` as
internal helpers for element ID references and low-frequency account diagnostics;
they are not separate pipeline stages, selectors, or generated-asset capabilities.
Kling Official Phase 3 adds provider tools only where OpenMontage already has a
Kling Official also adds provider tools only where OpenMontage already has a
matching capability slot: `kling_tts` for `tts`, plus `kling_avatar` and
`kling_lip_sync` for `avatar`. Official Kling audio effects and video effects are
not registered as tools yet because current pipelines do not define stable
not registered as tools because current pipelines do not define stable
`sound_effects` or `video_effects` capability routing.
---

File diff suppressed because it is too large Load Diff

View File

@@ -1,784 +0,0 @@
# 可灵官方 API 集成阶段 1核心视频与图像 Provider
状态:实施指导文档。
来源:从 `docs/kling-official-integration-plan.md` 拆分而来。本阶段合并原计划中的 P0「准备与保护」和 P1「核心视频与图像」。
执行顺序:必须先完成本文件,再进入 `docs/kling-official-phase-2-omni-operations.md`
## 1. 阶段目标
本阶段的目标是让可灵官方 API 以正式 provider 形式接入 OpenMontage 的工具系统,先交付两个可用能力:
| 能力 | 文件 | tool name | provider | capability |
|------|------|-----------|----------|------------|
| 官方视频生成 | `tools/video/kling_official_video.py` | `kling_official_video` | `kling_official` | `video_generation` |
| 官方图像生成 | `tools/graphics/kling_official_image.py` | `kling_official_image` | `kling_official` | `image_generation` |
本阶段完成后OpenMontage 应能通过 registry 自动发现这两个工具,并通过 `video_selector` / `image_selector` 在用户指定 `preferred_provider="kling_official"` 时选中官方直连路径。
本阶段不要求完整接入音频、TTS、数字人、口型、视频特效、元素管理和账户用量。这些能力只在后续阶段评估只有能自然落入现有 OpenMontage capability 或作为 provider 内部 helper 的部分才接入。
本阶段是 provider 接入,不是新增 OpenMontage 功能面。现有 pipeline、stage director、selector、artifact schema 和 checkpoint 规则保持不变。
## 2. 不可变规则
实施时必须遵守以下规则:
- 本阶段只覆盖 Kling official API。Volcengine Jimeng/即梦不属于本计划Jimeng 的鉴权、provider 命名、环境变量、签名 client 和模型枚举都必须单独设计,不能混进这些可灵官方工具。
- 不改 pipeline 体系。官方可灵第一阶段只新增 BaseTool provider不新增 pipeline不重写已有 pipeline manifest。
- 不改 pipeline stage 顺序,不新增 canonical artifact不新增 orchestrator 状态。
- 不覆盖 `tools/video/kling_video.py`。该文件是现有 fal.ai Kling provider行为必须保持不变。
- 官方 provider 必须统一使用 `provider="kling_official"`,不能复用 `provider="kling"`,否则 selector 无法稳定区分 fal.ai 网关和官方直连。
- 第一阶段只实现 API Key 鉴权:`Authorization: Bearer <KLING_API_KEY>`。AK/SK JWT 不进入本阶段。
- 所有官方可灵工具都必须声明 `dependencies = ["env:KLING_API_KEY"]`,使 `provider_menu_summary()` 能自动生成 setup offer。
- `KLING_API_BASE_URL` 是可选覆盖项,默认值应为 `https://api-singapore.klingai.com`
- 所有付费官方可灵 provider 必须重写 `estimate_cost()`,不能继承 `BaseTool.estimate_cost()``0.0` 默认值。
- 所有官方可灵 provider 的 `agent_skills` 必须包含新建的 `kling-official` skill。视频工具还必须保留通用视频提示 skill例如 `ai-video-gen`
- 实施前必须重新抽取当前官方文档 schema chunk并固化为测试 fixture。不能直接把原总计划中的 chunk 文件名当作当前事实。
- 官方视频工具的 input schema 不得暴露顶层 `image_url` 字段,避免 `video_selector` 误触发 fal.ai 的图片上传逻辑。
- 所有远端生成结果必须下载到 OpenMontage 的输出路径或项目 artifacts 中,不能只返回官方临时 URL。
- CI 默认不能打真实可灵付费 API。真实调用必须通过显式环境变量开启。
## 3. Pipeline 调用链
本阶段必须接入现有调用链,而不是创造新的编排路径:
```text
pipeline stage director
-> selector toolvideo_selector / image_selector
-> registry.get_by_capability(...)
-> kling_official_* provider
-> tools/_kling client/parser/media helper
-> Kling official API
-> ToolResult + artifacts
-> stage canonical artifact
-> checkpoint
```
实施含义:
- pipeline 只看到 `video_generation` / `image_generation` capability不感知官方可灵协议细节。
- stage director 仍按现有方式调用 selector 或具体 tool不写可灵专用编排。
- selector 只做 provider selection 和通用参数转发,不承担可灵 payload 构造。
- 官方 API 协议差异只存在于 `kling_official_video``kling_official_image``tools/_kling/` helper。
- 所有生成文件仍写入 stage 传入的 `output_path` 或项目目录,不写 repo root。
- 如果用户选择官方可灵proposal/preflight 只说明 provider/model/cost不改变 pipeline。
## 4. 准备与保护
开始写代码前先完成这些检查:
1. 创建实现分支,建议使用 `codex/` 前缀,例如 `codex/kling-official-phase-1`
2. 查看工作区状态,确认不会覆盖用户已有改动。
3. 确认 Python 依赖可用,尤其是 HTTP 客户端依赖。优先复用仓库现有依赖;若新增依赖,必须同步依赖文件和文档。
4. 阅读这些本地文件以确认当前实现契约:
- `tools/base_tool.py`
- `tools/tool_registry.py`
- `tools/video/video_selector.py`
- `tools/graphics/image_selector.py`
- `tools/video/kling_video.py`
- `tools/video/_shared.py`
5. 不开始实现 provider直到 schema fixture 刷新完成。
## 5. 官方 Schema Fixture
官方文档是 SPA正文和 OpenAPI schema 会被拆进懒加载 chunk。同一个 build id 下资源文件名也可能变化,因此必须在实施时重新定位当前文档资源。
建议新增 fixture 路径:
```text
tests/fixtures/kling_official/schema_snapshot.json
```
fixture 至少包含:
```json
{
"build_id": "...",
"source_urls": ["..."],
"chunk_names": ["..."],
"extracted_at": "YYYY-MM-DDTHH:MM:SSZ",
"endpoints": {},
"models": {},
"task_statuses": {},
"result_paths": {},
"core_field_enums": {}
}
```
必须固化的核心信息:
- API base URL 默认值和可覆盖环境变量。
- Classic 任务状态:`submitted``processing``succeed``failed`
- Turbo 任务状态:`submitted``processing``succeeded``failed`
- Classic 创建 ID 路径:`data.task_id`
- Turbo 创建 ID 路径:`data.id`
- Classic 结果路径:`data.task_result.videos[]``data.task_result.images[]`
- Turbo 结果路径:`data[0].outputs[]`
- 第一阶段要支持的视频模型枚举。
- 第一阶段要支持的图像模型枚举。
- `aspect_ratio``duration``resolution``mode``sound` 等核心字段枚举。
测试要求:
- 如果当前官方 HTML 的 build id、入口 chunk 或核心 schema 与 fixture 不一致,测试应提示先刷新 fixture。
- 测试不应依赖原计划中的旧 chunk 文件名。
- fixture 是实现依据之一,不是替代错误处理和 runtime 验证的借口。
## 6. 共享可灵 Client
新增目录:
```text
tools/_kling/
├── __init__.py
├── client.py
├── errors.py
├── media.py
└── schemas.py
```
### 6.1 `client.py`
最低接口:
```python
class KlingClient:
def __init__(self, api_key=None, base_url=None, session=None): ...
def post(self, path: str, payload: dict[str, Any]) -> dict[str, Any]: ...
def get(self, path: str, params: dict[str, Any] | None = None) -> dict[str, Any]: ...
def download(self, url: str, output_path: Path, timeout: int = 180) -> Path: ...
```
任务接口:
```python
def create_classic_task(path: str, payload: dict[str, Any]) -> str: ...
def poll_classic(path: str, task_id: str, result_key: str, timeout_seconds: int, poll_interval: float) -> list[dict]: ...
def create_turbo(path: str, payload: dict[str, Any]) -> str: ...
def poll_turbo(task_id: str, timeout_seconds: int, poll_interval: float) -> list[dict]: ...
```
实现规则:
-`KLING_API_KEY` 读取默认 API Key。
-`KLING_API_BASE_URL` 读取可选 base URL未设置时使用 `https://api-singapore.klingai.com`
- 所有请求都发送 `Authorization: Bearer <key>`
- 所有 JSON 请求都发送明确的 JSON headers。
- HTTP 非 2xx 时尝试解析 JSON 中的 `code``message``request_id`;如果不是 JSON保留响应文本片段。
- 业务 `code != 0` 时抛出 `KlingAPIError`
- 下载方法负责创建父目录,返回最终 `Path`
### 6.2 `errors.py`
新增:
```python
class KlingAPIError(Exception):
code: str | int | None
message: str
request_id: str | None
http_status: int | None
```
新增:
```python
def is_retryable_kling_error(error: KlingAPIError) -> bool: ...
```
错误处理规则:
| HTTP | 业务码 | 含义 | 行为 |
|------|--------|------|------|
| 401 | 1000-1004 | 鉴权失败或 token 无效 | 不重试,提示 `KLING_API_KEY` / Authorization |
| 429 | 1101/1102 | 欠费、资源包耗尽或过期 | 不重试,提示账户或资源包 |
| 403 | 1103 | 接口或模型无权限 | 不重试,提示模型权限 |
| 400 | 1200/1201 | 参数非法 | 不重试,暴露官方 message |
| 404 | 1202/1203 | method/resource/model 无效 | 不重试,标记实现或模型配置问题 |
| 429 | 1302 | 请求过快 | 可有限退避重试 |
| 429 | 1303 | 并发或 QPS 超资源包限制 | 可有限退避重试,错误文案必须说明并发槽 |
| 400 | 1301 | 内容安全策略 | 不重试,提示修改输入 |
| 500/503/504 | 5000-5002 | 服务端错误、维护、积压超时 | 可有限退避重试 |
退避规则:
- 只对 `1302``1303``5000``5001``5002` 做有限重试。
- 不对鉴权、余额、权限、参数、安全策略错误重试。
- 重试耗尽后保留最后一次官方错误信息。
### 6.3 `schemas.py`
放置轻量常量和 dataclass
- Classic/Turbo 协议枚举。
- Classic/Turbo 状态常量。
- 第一阶段模型枚举。
- `ClassicTaskResult``TurboTaskResult` 等轻量解析结果。
不要写“猜字段”的通用任务解析器。Classic 和 Turbo 的字段名、状态值、结果路径不同,必须分开解析。
### 6.4 `media.py`
实现:
- `strip_data_uri_prefix(value)`:去掉 `data:image/...;base64,` 等前缀。
- `image_file_to_raw_base64(path)`:本地图片转 raw base64。
- `normalize_image_input(url=None, path=None)`URL 直接返回 URL本地路径转 raw base64。
- 下载图片/音频/视频到 output path 的共用 helper。
第一阶段可以先把这些 helper 放在 `tools/_kling/media.py`。不要为了抽象过早修改现有 fal.ai 工具。
## 7. 官方视频 Provider
新增:
```text
tools/video/kling_official_video.py
```
基础契约:
```python
class KlingOfficialVideo(BaseTool):
name = "kling_official_video"
version = "0.1.0"
tier = ToolTier.GENERATE
capability = "video_generation"
provider = "kling_official"
stability = ToolStability.EXPERIMENTAL
execution_mode = ExecutionMode.SYNC
determinism = Determinism.STOCHASTIC
runtime = ToolRuntime.API
dependencies = ["env:KLING_API_KEY"]
agent_skills = ["ai-video-gen", "kling-official"]
```
### 7.1 支持范围
| OpenMontage operation | `api_family` | 官方协议 | 端点 |
|-----------------------|--------------|----------|------|
| `text_to_video` | `classic` | Classic | `/v1/videos/text2video` |
| `image_to_video` | `classic` | Classic | `/v1/videos/image2video` |
| `text_to_video` | `turbo` | Turbo | `/text-to-video/kling-3.0-turbo` |
| `image_to_video` | `turbo` | Turbo | `/image-to-video/kling-3.0-turbo` |
| `text_to_video` | `omni` | Classic Omni | `/v1/videos/omni-video` |
| `image_to_video` | `omni` | Classic Omni | `/v1/videos/omni-video` |
| `reference_to_video` | `omni` | Classic Omni | `/v1/videos/omni-video` |
`video_selector` 的标准 operation 仍是 `text_to_video``image_to_video``reference_to_video``rank`。Turbo 和 Omni 不应变成 selector 层的新 operation而应通过 `api_family` 选择。
直接调用 provider 时可以兼容 `operation="omni_video"` 作为别名,但 selector 路径不要依赖这个别名。
### 7.2 Input Schema 规则
建议字段:
```python
{
"required": ["prompt"],
"properties": {
"prompt": {"type": "string"},
"operation": {"enum": ["text_to_video", "image_to_video", "reference_to_video"], "default": "text_to_video"},
"api_family": {"enum": ["classic", "turbo", "omni"], "default": "classic"},
"model_name": {
"enum": [
"kling-v1",
"kling-v1-5",
"kling-v1-6",
"kling-v2-master",
"kling-v2-1",
"kling-v2-1-master",
"kling-v2-5-turbo",
"kling-v2-6",
"kling-v3",
"kling-video-o1",
"kling-v3-omni"
],
"default": "kling-v3"
},
"duration": {"enum": ["3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"], "default": "5"},
"aspect_ratio": {"enum": ["16:9", "9:16", "1:1"], "default": "16:9"},
"resolution": {"enum": ["720p", "1080p"], "default": "720p"},
"mode": {"enum": ["std", "pro", "4k"], "default": "std"},
"sound": {"enum": ["on", "off"], "default": "off"},
"negative_prompt": {"type": "string"},
"reference_image_url": {"type": "string"},
"reference_image_path": {"type": "string"},
"reference_tail_image_url": {"type": "string"},
"reference_tail_image_path": {"type": "string"},
"image_list": {"type": "array"},
"video_list": {"type": "array"},
"element_list": {"type": "array"},
"camera_control": {"type": "object"},
"watermark": {"type": "boolean", "default": False},
"callback_url": {"type": "string"},
"external_task_id": {"type": "string"},
"output_path": {"type": "string"}
}
}
```
强制规则:
- 不暴露顶层 `image_url`
- 使用 `reference_image_url` / `reference_image_path` 表达首帧。
- 使用 `reference_tail_image_url` / `reference_tail_image_path` 表达尾帧。
- `reference_image_path` 在工具内部转 raw base64不能走 fal.ai 上传。
- `model_variant` 可以兼容老参数,但内部主字段应是 `model_name`
- `model_name` enum 必须来自当前 schema fixture。上面的枚举是阶段 1 初始范围;如果官方 schema 更新,先更新 fixture 和 contract 测试,再更新 input schema。
- `supports` 至少声明:
```python
{
"text_to_video": True,
"image_to_video": True,
"reference_to_video": True,
"reference_image": True,
"negative_prompt": True,
"aspect_ratio": True
}
```
### 7.3 Payload Builder 规则
Classic 文生视频:
- 端点:`POST /v1/videos/text2video`
- 发送 `model_name``prompt``negative_prompt``sound``cfg_scale``mode``camera_control``aspect_ratio``duration``watermark_info``callback_url``external_task_id` 等官方支持字段。
- 默认 `model_name` 建议为 `kling-v3`
Classic 图生视频:
- 端点:`POST /v1/videos/image2video`
- 必须有 `reference_image_url``reference_image_path`
- 将输入转换成官方字段 `image`
- 支持尾帧时使用官方字段 `image_tail`
- 不要盲目发送 `aspect_ratio`,除非当前 schema 明确支持。
Turbo 文生视频:
- 端点:`POST /text-to-video/kling-3.0-turbo`
- payload 结构为 `prompt``settings``options`
- `duration` 必须从字符串转成 int。
- `settings.resolution` 支持 `720p` / `1080p`
- `settings.aspect_ratio` 支持 `16:9` / `9:16` / `1:1`
Turbo 图生视频:
- 端点:`POST /image-to-video/kling-3.0-turbo`
- payload 使用 `contents[]`
- prompt 用 `{ "type": "prompt", "text": "..." }`
- 首帧 URL 用 `{ "type": "first_frame", "url": "..." }`
- 如果本地图片转成 raw base64 后当前官方 schema 不支持,必须给出清晰错误或先上传到可访问 URL不要静默走 fal.ai。
- 不要盲目发送 `aspect_ratio`,除非当前 schema 明确支持。
Video Omni
- 端点:`POST /v1/videos/omni-video`
- 第一阶段只要求基础 `prompt``image_list``video_list``element_list``sound``mode``aspect_ratio``duration` 可用。
- 深度多参考、多镜头 helper 放到第二阶段。
### 7.4 输出规则
成功后:
- 下载第一个无水印 `url``output_path`
- 返回 `provider="kling_official"`
- 返回 `model`Classic/Omni 用 `model_name`Turbo 可用 `kling-3.0-turbo`
- 返回 `task_id``operation``api_family``output_path`
- 将远端 URL、下载路径、任务 ID 放入 `artifacts``data`,便于复现。
- 对视频调用 `tools/video/_shared.py::probe_output(output_path)`
失败时:
- 参数错误返回可理解的 ToolResult error不要让 KeyError、IndexError 泄漏。
- 官方错误要保留 `code``message``request_id`
- `1303` 并发错误文案必须包含“并发/资源包限制”。
### 7.5 成本估算
必须实现:
```python
def estimate_cost(self, params: dict[str, Any]) -> float: ...
```
要求:
- 默认 paid 输入不能返回静默 `0.0`
- 如果官方价格无法稳定映射美元,返回保守估算,并在 dry-run 或结果 metadata 中写入 `cost_estimate_confidence="low"`
- 成功的 paid ToolResult 必须写入 `cost_usd``cost_usd` 应来自同一个 `estimate_cost()` 逻辑;如果后续 Account Usage 能提供实际用量,可在阶段 2 以后用实际用量校正。
- 默认不启用 `4k``sound="on"`、批量、多结果等高成本能力。
- proposal/preflight 展示成本时必须说明官方可灵是 paid API。
### 7.6 Registry Metadata
视频 provider 必须补齐 registry/provider menu 可见的元数据:
- `best_for`:说明官方可灵直连适合哪些视频生成场景。
- `not_good_for`:说明不适合的场景,例如本地离线、免费生成、非可灵模型能力。
- `install_instructions`:说明配置 `KLING_API_KEY`,不要硬编码过期 URL。
- `fallback_tools`:列出可替代的视频 provider例如现有 fal.ai Kling 或其它视频生成工具;只作为候选,不允许静默切换。
- `supports`:至少包含文生视频、图生视频、参考输入、负向提示、宽高比能力。
- `resource_profile` / `retry_policy`:如果 BaseTool 契约已有对应字段,按 API 远端生成和长轮询任务填写。
- `idempotency_key_fields`:至少考虑 `prompt``operation``api_family``model_name``reference_image_url/path``duration``aspect_ratio`
- `side_effects`:标记为 paid remote generation避免 proposal/preflight 把调用当作免费本地操作。
## 8. 官方图像 Provider
新增:
```text
tools/graphics/kling_official_image.py
```
基础契约:
```python
class KlingOfficialImage(BaseTool):
name = "kling_official_image"
version = "0.1.0"
tier = ToolTier.GENERATE
capability = "image_generation"
provider = "kling_official"
runtime = ToolRuntime.API
dependencies = ["env:KLING_API_KEY"]
agent_skills = ["kling-official"]
```
### 8.1 支持范围
| image_selector 语义 | `api_family` | 官方端点 |
|--------------------|--------------|----------|
| `generation_mode=generate` | `generation` | `/v1/images/generations` |
| `generation_mode=edit` 或有图片输入 | `generation` | `/v1/images/generations`,填 `image``image_reference` |
| `generation_mode=generate/edit` | `omni` | `/v1/images/omni-image` |
`image_selector` 的标准 operation 仍是 `generate``rank`。Omni 不应变成 selector 层的新 operation应通过 `api_family=omni` 表达。
### 8.2 Input Schema 规则
建议字段:
```python
{
"required": ["prompt"],
"properties": {
"prompt": {"type": "string"},
"negative_prompt": {"type": "string"},
"operation": {"enum": ["generate"], "default": "generate"},
"generation_mode": {"enum": ["generate", "edit"], "default": "generate"},
"api_family": {"enum": ["generation", "omni"], "default": "generation"},
"model_name": {
"enum": [
"kling-v1",
"kling-v1-5",
"kling-v2",
"kling-v2-new",
"kling-v2-1",
"kling-v3",
"kling-image-o1",
"kling-v3-omni"
],
"default": "kling-v3"
},
"image_url": {"type": "string"},
"image_path": {"type": "string"},
"image_urls": {"type": "array", "items": {"type": "string"}},
"image_paths": {"type": "array", "items": {"type": "string"}},
"image_reference": {"enum": ["subject", "face"]},
"image_fidelity": {"type": "number", "default": 0.5},
"human_fidelity": {"type": "number", "default": 0.45},
"resolution": {"enum": ["1k", "2k", "4k"], "default": "1k"},
"aspect_ratio": {"enum": ["16:9", "9:16", "1:1", "4:3", "3:4", "3:2", "2:3", "21:9", "auto"], "default": "16:9"},
"n": {"type": "integer", "default": 1},
"result_type": {"enum": ["single", "series"], "default": "single"},
"series_amount": {"type": "string"},
"element_list": {"type": "array"},
"watermark": {"type": "boolean", "default": False},
"callback_url": {"type": "string"},
"external_task_id": {"type": "string"},
"output_path": {"type": "string"}
}
}
```
图像工具可以暴露 `image_url` / `image_path`,因为 `image_selector` 没有 fal.ai 自动上传逻辑。
`model_name` enum 必须来自当前 schema fixture。上面的枚举覆盖普通图像生成和 Image Omni 的第一阶段范围;如果官方 schema 更新,先更新 fixture 和 contract 测试,再更新 input schema。
`supports` 至少声明:
```python
{
"text_to_image": True,
"image_edit": True,
"negative_prompt": True,
"aspect_ratio": True
}
```
### 8.3 Payload Builder 规则
图像生成:
- 端点:`POST /v1/images/generations`
- 必填 `prompt`
- 支持 `negative_prompt``image``image_reference``image_fidelity``human_fidelity``element_list``resolution``n``aspect_ratio`
- `prompt` 长度要遵守官方限制;超限应在调用前报参数错误。
图像编辑:
-`generation_mode=edit` 或存在 `image_url` / `image_path` 时走同一 generation 端点。
- `image_url` 直接填官方 `image`
- `image_path` 转 raw base64 后填官方 `image`
- `image_reference` 只允许官方枚举,例如 `subject``face`
Image Omni
- 端点:`POST /v1/images/omni-image`
- 支持 `image_list``element_list``resolution``result_type``n``series_amount``aspect_ratio`
- 第一阶段只要求基础可用;复杂多图引用 helper 放到第二阶段。
### 8.4 输出规则
成功后:
- 下载 `data.task_result.images[]` 中的图片。
- `data.output_path` 指向第一张图片。
- 如果 `n > 1``result_type="series"``artifacts` 必须返回全部图片路径。
- 根据响应 Content-Type 或 URL 推断扩展名;无法判断时默认 `.png`
- 返回 `provider``model``task_id``api_family``output_path`
失败时:
- 保留官方 `code``message``request_id`
- 参数错误应清楚说明是 prompt、参考图、分辨率、数量还是权限问题。
### 8.5 成本估算
同视频 provider
- 必须重写 `estimate_cost()`
- 默认 paid 输入不能静默返回 `0.0`
- `n > 1``2k/4k``series` 应提高估算。
- 估算不确定时记录 `cost_estimate_confidence="low"`
- 成功的 paid ToolResult 必须写入 `cost_usd``cost_usd` 应来自同一个 `estimate_cost()` 逻辑;如果后续 Account Usage 能提供实际用量,可在阶段 2 以后用实际用量校正。
### 8.6 Registry Metadata
图像 provider 必须补齐 registry/provider menu 可见的元数据:
- `best_for`说明官方可灵适合主体一致性、角色参考、Omni 多参考图等场景。
- `not_good_for`:说明不适合的场景,例如本地离线、免费生成、非可灵模型能力。
- `install_instructions`:说明配置 `KLING_API_KEY`,不要硬编码过期 URL。
- `fallback_tools`:列出可替代图像 provider只作为候选不允许静默切换。
- `supports`:至少包含文生图、图像编辑、负向提示、宽高比能力。
- `resource_profile` / `retry_policy`:如果 BaseTool 契约已有对应字段,按 API 远端生成和长轮询任务填写。
- `idempotency_key_fields`:至少考虑 `prompt``api_family``model_name``image_url/path``aspect_ratio``resolution``n`
- `side_effects`:标记为 paid remote generation避免 proposal/preflight 把调用当作免费本地操作。
## 9. Selector 衔接
原则:新增官方可灵 provider 不应要求重写 selector。`video_selector``image_selector` 已经通过 registry 自动发现 provider本阶段优先只新增 provider 和 contract 测试。
不要为了可灵专用字段改 selector 的核心选择逻辑。只有当字段属于跨 provider 的通用参数,且现有 selector 会丢弃该字段时,才允许补充 selector schema 或透传列表。
`video_selector` 当前应继续使用这些通用字段:
- `prompt`
- `operation`
- `preferred_provider`
- `allowed_providers`
- `aspect_ratio`
- `duration`
- `reference_image_path`
- `reference_image_url`
- `output_path`
`image_selector` 当前应继续使用这些通用字段:
- `prompt`
- `negative_prompt`
- `generation_mode`
- `image_url`
- `image_path`
- `image_urls`
- `image_paths`
- `preferred_provider`
- `allowed_providers`
- `aspect_ratio`
- `resolution`
- `n`
- `output_path`
要求:
- `api_family``model_name``sound``watermark``image_reference` 等可灵专用参数优先放在 provider input_schema 中,通过直接调用 provider 或 selector 的普通透传进入 provider。
- 如果 selector 当前已经透传未知字段,不要仅为“可发现性”改 selector。
- 如果必须改 selector只能做 provider-neutral 的最小透传;不得加入可灵专用分支。
- 不能破坏其他 provider 的选择和调用。
- `video_selector``preferred_provider="kling_official"` 时必须选中官方视频工具。
- `image_selector``preferred_provider="kling_official"` 时必须选中官方图像工具。
- `reference_image_path` 不能触发 `upload_image_fal()`
## 10. 文档和 Skill 更新
本阶段必须同步更新:
```text
.env.example
README.md
docs/PROVIDERS.md
docs/ARCHITECTURE.md
.agents/skills/ai-video-gen/SKILL.md
skills/creative/video-gen-prompting.md
skills/INDEX.md
.agents/skills/kling-official/SKILL.md
```
具体要求:
- `.env.example` 增加 `KLING_API_KEY=``KLING_API_BASE_URL=`
- `README.md` provider key 列表加入官方可灵。
- `docs/PROVIDERS.md` 新增 “Kling Official” 小节。
- `docs/PROVIDERS.md` 明确 fal.ai Kling 和 official Kling 是两个路径。
- `docs/ARCHITECTURE.md` API key 映射表加入 `KLING_API_KEY`
- `.agents/skills/ai-video-gen/SKILL.md` metadata `env_any` 加入 `KLING_API_KEY`
- `skills/creative/video-gen-prompting.md` 增加官方可灵适用场景和参数注意事项。
- `skills/INDEX.md` 让后续 agent 能发现 `kling-official`
- 新增 `.agents/skills/kling-official/SKILL.md`,覆盖鉴权、任务协议、错误处理、参数、成本治理和提示注意事项。
## 11. 测试要求
新增或更新以下测试。
### 11.1 Client 测试
建议文件:
```text
tests/contracts/test_kling_official_client.py
```
覆盖:
- 未设置 `KLING_API_KEY` 时工具不可用。
- 设置 `KLING_API_KEY` 后 headers 是 `Authorization: Bearer ...`
- base URL 默认 `https://api-singapore.klingai.com`
- `KLING_API_BASE_URL` 可以覆盖。
- `code != 0``KlingAPIError`,保留 `code``message``request_id`
- `code=1303` 被识别为可重试并发错误。
- Classic create 解析 `data.task_id`
- Classic poll 成功解析 `data.task_result.videos/images/audios[]`
- Turbo create 解析 `data.id`
- Turbo poll 成功解析 `data[0].outputs[]`
- schema fixture 包含必需字段。
### 11.2 视频 Provider 测试
建议文件:
```text
tests/contracts/test_kling_official_video.py
```
覆盖:
- registry 能发现 `kling_official_video`
- `capability="video_generation"`
- `provider="kling_official"`
- input schema 不包含顶层 `image_url`
- `operation=text_to_video, api_family=classic` 构造 `/v1/videos/text2video` payload。
- `operation=image_to_video, api_family=classic` 使用 `reference_image_url/path` 构造官方 `image` 字段。
- `operation=text_to_video, api_family=turbo` 构造 `prompt/settings/options`
- `operation=image_to_video, api_family=turbo` 构造 `contents[]`
- `operation=reference_to_video, api_family=omni` 构造 `video_list[]` 或基础参考输入。
- 成功后下载视频、返回 artifact、调用 `probe_output`
- `video_selector``preferred_provider="kling_official"` 能选中官方工具。
- `reference_image_path` 不触发 `upload_image_fal()`
- `agent_skills` 包含 `kling-official`
- 默认 paid 输入的 `estimate_cost()` 不返回静默 `0.0`
### 11.3 图像 Provider 测试
建议文件:
```text
tests/contracts/test_kling_official_image.py
```
覆盖:
- registry 能发现 `kling_official_image`
- `capability="image_generation"`
- `provider="kling_official"`
- generate payload 使用 `/v1/images/generations`
- edit payload 将 `image_path` 转 raw base64。
- `api_family=omni` payload 使用 `/v1/images/omni-image``image_list[]`
- 多图片结果全部写入 artifacts。
- `image_selector``preferred_provider="kling_official"` 能选中官方工具。
- `agent_skills` 包含 `kling-official`
- 默认 paid 输入的 `estimate_cost()` 不返回静默 `0.0`
### 11.4 文档和 Skill 测试
若仓库已有相关 contract 测试,补充:
- provider catalog 包含 `kling_official`
- docs provider table 包含 `KLING_API_KEY`
- `.agents/skills/ai-video-gen/SKILL.md` metadata `env_any` 包含 `KLING_API_KEY`
- `.agents/skills/kling-official/SKILL.md` 存在。
- 官方可灵 provider 的 `agent_skills` 引用 `kling-official`
### 11.5 Live QA
真实调用只允许显式开启:
```bash
RUN_KLING_LIVE_TESTS=1 KLING_API_KEY=... pytest tests/qa/test_kling_official_live.py
```
live smoke 限制:
- 文生图 1 张。
- 文生视频最短时长 3s 或 5s。
- 不跑批量。
- 不跑 4k。
- 不默认开声音。
## 12. 阶段验收清单
阶段 1 完成前逐项确认:
- `registry.support_envelope()` 能看到 `kling_official_video`
- `registry.support_envelope()` 能看到 `kling_official_image`
- 未设置 `KLING_API_KEY` 时两个工具状态为 `UNAVAILABLE`
- setup offer 指向 `KLING_API_KEY`
- 设置 `KLING_API_KEY` 时两个工具状态为 `AVAILABLE`
- `video_selector` 可通过 `preferred_provider="kling_official"` 选中官方视频工具。
- `image_selector` 可通过 `preferred_provider="kling_official"` 选中官方图像工具。
- selector 没有新增可灵专用选择分支;如有 selector 改动,必须是 provider-neutral 的最小透传。
- `tools/video/kling_video.py` fal.ai 版本行为不变。
- 官方视频工具没有顶层 `image_url` schema。
- Classic 和 Turbo 两套 parser 均有 fixture 覆盖。
- schema fixture 已按当前官方 HTML/chunk 重新抽取。
- 两个官方 provider 的 `agent_skills` 都包含 `kling-official`
- 两个官方 provider 都实现非默认 `estimate_cost()`
- 两个官方 provider 的 paid 成功结果都写入 `ToolResult.cost_usd`
- 两个官方 provider 都补齐 `best_for``not_good_for``install_instructions``fallback_tools``supports` 等 registry metadata。
- 图像多结果 artifacts 有测试覆盖。
- README、docs、skill 明确 fal.ai Kling 与 official Kling 的差异。
- 相关 contract 测试通过。
## 13. 完成后进入下一阶段
只有当本阶段验收清单全部完成后,才能进入第二阶段:
```text
docs/kling-official-phase-2-omni-operations.md
```
第二阶段会在本阶段 client、parser、provider 基础上增强 Omni、Elements、Account Usage 和 Callback。

View File

@@ -1,464 +0,0 @@
# 可灵官方 API 集成阶段 2Omni、Elements、账户用量与 Callback
状态:实施指导文档。
来源:从 `docs/kling-official-integration-plan.md` 拆分而来。本阶段对应原计划中的 P2「Omni、元素、账户、callback」。
执行顺序:必须在 `docs/kling-official-phase-1-core.md` 完成并验收后执行。本阶段完成后再进入 `docs/kling-official-phase-3-media-avatar-effects.md`
## 1. 阶段目标
本阶段不再解决“官方可灵能否被 OpenMontage 调用”的基础问题,而是在阶段 1 的视频、图像 provider 和共享 client 基础上增强同一个可灵官方 provider
- 深化 Video Omni / Image Omni 支持。
- 增加 Elements 引用能力,但默认作为 `kling_official_video` / `kling_official_image` 的内部 helper不新增 OpenMontage 管理功能。
- 增加 Account Usage 账户用量读取能力,但默认作为 provider preflight/错误诊断 helper不新增常规 pipeline 工具。
- 规范 callback 透传和 artifacts 记录。
这些能力提高的是官方可灵 provider 的参数覆盖和诊断质量,不应该改变 OpenMontage 现有 pipeline、selector、stage artifact 或 checkpoint 流程。
## 2. 进入条件
开始本阶段前必须确认:
- 阶段 1 验收清单已完成。
- `tools/_kling/` client、errors、media、schemas 已存在并有测试覆盖。
- `kling_official_video``kling_official_image` 已能被 registry 发现。
- `preferred_provider="kling_official"` 对视频和图像 selector 均可用。
- schema fixture 已按当前官方文档刷新。
- 付费成本估算不再静默返回 `0.0`
- fal.ai 版 `kling_video` 行为未被改变。
如果上述任一条件不满足,先回到阶段 1 修复。
## 3. 不可变规则
本阶段必须遵守:
- 不新增 pipeline。仍通过现有 provider/selector/capability 体系接入。
- 不新增 OpenMontage capability。阶段 2 的能力都挂在阶段 1 已有的 `video_generation` / `image_generation` provider 内部。
- 不更改 `provider="kling_official"` 命名。
- 不把 Elements 做成普通生成 provider也不新增 `asset_management` capability。
- 不把 callback 作为默认执行路径。当前仍以 polling 为主callback 是高级透传能力。
- Account Usage 不进入生产 pipeline stage不进 selector它只是 `tools/_kling` 下的可选诊断 helper。官方 QPS 限制为低频接口,必须做本地节流或缓存。
- Omni 深度能力必须建立在阶段 1 的 `api_family=omni` 上,不新增 selector 层 operation。
- 高成本 Omni、多参考、多元素调用必须进入成本估算。
- Omni 付费调用的成功 ToolResult 必须继续写入 `cost_usd`。如果 Account Usage 能返回可核对的实际用量,应把估算成本和实际用量的校正结果记录到 ToolResult data 或项目 artifacts。
- 所有远端结果、元素 ID、任务 ID、引用关系必须写入 artifacts 或 ToolResult data便于复现。
- 如果官方 schema 有变化,先更新 fixture 和测试,再改实现。
## 4. 工作流 AOmni 深度接入
阶段 1 只要求基础 Omni 可用。本阶段要让 Omni 能真正承担复杂参考输入。
### 4.1 Video Omni 增强范围
目标端点:
```text
POST /v1/videos/omni-video
GET /v1/videos/omni-video/{id}
GET /v1/videos/omni-video?pageNum=1&pageSize=30
```
增强字段:
- `image_list[].image_url`
- `image_list[].type`,例如 `first_frame``end_frame`
- `video_list[].video_url`
- `video_list[].refer_type`,例如 `feature``base`
- `video_list[].keep_original_sound`
- `element_list[].element_id`
- `multi_shot`
- `shot_type`
- `multi_prompt`
- `sound`
- `mode`
- `aspect_ratio`
- `duration`
实现要求:
-`kling_official_video` 中把 Omni payload builder 拆成独立 helper避免塞进 `execute()`
- 支持 URL 和本地文件输入的标准化。本地图片仍由 `tools/_kling/media.py` 转换;本地视频如果官方只接受 URL必须明确报错或要求用户提供可访问 URL不能静默上传到 fal.ai。
- `operation=reference_to_video` 时,必须明确要求至少一种参考输入:图片、视频或 element。
- `video_list` 中的 `refer_type` 必须保留官方枚举,不要随意翻译成内部枚举后丢失原值。
- `keep_original_sound` 默认应保守设置为 `no` 或不发送,避免无意保留参考视频声音。
- `sound="on"` 属于高成本/高差异输出能力,默认不启用。
- `mode="4k"` 默认不启用。
### 4.2 Image Omni 增强范围
目标端点:
```text
POST /v1/images/omni-image
GET /v1/images/omni-image/{id}
GET /v1/images/omni-image?pageNum=1&pageSize=30
```
增强字段:
- `image_list[].image`
- `element_list[].element_id`
- `resolution`
- `result_type`
- `n`
- `series_amount`
- `aspect_ratio`
- prompt 中的 `<<<image_1>>>` 引用语法
实现要求:
- 提供 prompt reference helper把用户输入的多图参考稳定映射为 `<<<image_1>>>``<<<image_2>>>` 等。
- helper 必须返回映射 metadata例如第几个引用对应哪个 URL/path。
- 如果用户 prompt 已经包含 `<<<image_1>>>`,不要重复插入;应校验引用数量和 `image_list` 是否一致。
- `result_type="series"``series_amount` 必须进入成本估算。
- `resolution="4k"` 默认不启用。
- `aspect_ratio="auto"` 只在官方当前 schema 支持时发送。
### 4.3 多镜头 `multi_prompt`
多镜头能力要做成明确结构,不要把用户自然语言拆分后随意发送。
建议 schema
```python
"multi_prompt": {
"type": "array",
"items": {
"type": "object",
"properties": {
"prompt": {"type": "string"},
"duration": {"type": "string"},
"camera_control": {"type": "object"},
"image_refs": {"type": "array"},
"element_refs": {"type": "array"}
},
"required": ["prompt"]
}
}
```
规则:
- `multi_shot=true` 时,普通 `prompt` 是否生效以官方 schema 为准;如果官方标注无效,不要同时依赖它。
- `shot_type` 必须为官方枚举,例如 `customize``intelligence`
- 多镜头 payload builder 要有单元测试覆盖。
- 多镜头默认不在 selector 自动路径启用,除非用户明确传入。
### 4.4 Omni 输出处理
输出规则:
- 仍下载最终媒体到本地 output path。
- 如果官方返回多个媒体,全部写入 artifacts。
- ToolResult data 至少包含:
- `task_id`
- `api_family="omni"`
- `operation`
- `model`
- `output_path`
- `remote_outputs`
- `references_used`
- `element_ids`
- 对视频继续调用 `probe_output()`
- 对图像继续推断文件扩展名,默认 `.png`
## 5. 工作流 BElements 引用 Helper
Elements 是 Video Omni 和 Image Omni 的官方参数能力。本阶段只把它作为官方可灵 provider 的内部引用 helper目的是让 `element_list[].element_id` 可以被视频/图像 provider 正确传入和记录。
不要在本阶段把 Elements 产品化成独立 OpenMontage 管理功能。
### 5.1 建议文件
建议只新增底层 helper
```text
tools/_kling/elements.py
```
不建议新增 `tools/kling_elements.py`。只有当已有 pipeline 或用户工作流明确需要独立元素管理入口时,才另开设计文档讨论。
### 5.2 支持范围
本阶段的 Elements 范围只服务 `element_list[].element_id` 引用、校验和 metadata 记录。允许封装的端点应保持只读或引用校验:
```text
GET /v1/general/advanced-custom-elements/{id}
GET /v1/general/advanced-custom-elements
GET /v1/general/advanced-presets-elements
```
明确不在本阶段实现:
```text
POST /v1/general/advanced-custom-elements
POST /v1/general/delete-elements
```
原因:创建/删除 element 是素材管理功能不是“新增可灵官方供应商”的必要路径。若后续确实需要元素生命周期管理必须单独设计用户入口、权限、artifact 生命周期和 pipeline 使用方式,不能混在本阶段 provider 增强里。
### 5.3 Helper 契约
helper 不继承 `BaseTool`,不进入 registry不进入 selector。
建议函数:
| helper | 用途 |
|--------|------|
| `normalize_element_list(...)` | 校验并标准化传给视频/图像 provider 的 `element_list` |
| `get_custom_element(...)` | 可选查询单个自定义元素,用于校验用户传入的 element id |
| `list_preset_elements(...)` | 可选列出官方预设元素,供诊断或文档使用 |
输入规则:
- provider 接收 `element_list` 时,只负责校验结构、透传给官方 API、记录 metadata。
- 不在默认路径创建或删除 element。
- 如果后续确实需要创建/删除 element必须单独设计不混在本阶段 provider 接入里。
- 对 preset elements 只读。
输出规则:
- 在 ToolResult data 中记录本次使用的 `element_ids`
- 如查询过 element 详情,将 element metadata 写入项目 artifacts便于复现。
- 如果官方查询响应是异步任务,使用共享 Classic parser 或新增专用 parser不要猜字段。
### 5.4 Artifacts 约定
建议在项目中记录:
```text
projects/<project-name>/artifacts/kling_elements.json
```
结构建议:
```json
{
"provider": "kling_official",
"elements": [
{
"element_id": 123,
"kind": "character",
"name": "main-presenter",
"source": "...",
"created_at": "...",
"task_id": "...",
"reusable": true
}
]
}
```
## 6. 工作流 CAccount Usage 诊断
Account Usage 用于官方可灵 provider 的 setup/preflight 和错误诊断,不是生产生成能力,不进入 pipeline stage。
### 6.1 建议文件
建议只新增底层 helper
```text
tools/_kling/account.py
```
不建议新增 `tools/kling_account_usage.py`。如果后续需要用户显式运行账户诊断,再单独设计工具入口。
### 6.2 支持端点
目标端点:
```text
GET /account/costs
```
字段:
- `start_time`
- `end_time`
- `resource_pack_name`
### 6.3 使用场景
必须支持:
- provider setup/preflight 中检查资源包或余额可见性。
- 捕获 `1101` / `1102` 后提供更清楚的账户诊断。
- 在用户要求排查“为什么可灵不能生成”时提供低成本诊断。
不要求:
- 每次生成前都调用账户用量接口。
- 在 CI 中调用真实账户接口。
### 6.4 节流和缓存
规则:
- 官方 Account Usage QPS 低,必须本地节流。
- 同一进程内相同参数短时间重复查询应使用缓存。
- 如果被节流,返回“最近一次缓存结果”或清楚说明需要稍后重试。
- 不允许为了诊断在短时间内循环打账户接口。
### 6.5 输出
如果 helper 被 provider 调用ToolResult data 建议包含:
- `resource_pack_subscribe_infos`
- `queried_range`
- `cached`
- `throttle_status`
- `provider="kling_official"`
- 如果用于校正生成成本,记录 `reconciled_cost_usd``cost_source` 和关联的 `task_id` 或时间窗口。
如果官方返回余额结构随资源包变化,保留原始字段,并给出轻量归一化摘要。
## 7. 工作流 DCallback 支持
阶段 2 只要求 callback 透传和记录,不要求实现完整 callback receiver。
### 7.1 Provider 参数
视频、图像、Omni、后续音频工具都应接受
```python
"callback_url": {"type": "string"}
```
并按官方 schema 放入对应字段:
- Classic顶层 `callback_url`
- Turbo`options.callback_url`
- 其他端点按当前 fixture 确认。
### 7.2 默认执行模式
默认仍然是 polling
- 工具创建任务。
- 工具轮询任务到终态。
- 工具下载结果。
- 工具返回 ToolResult。
即使传入 `callback_url`,当前工具也不应立即假设 callback receiver 会写入 artifacts除非 receiver 已明确存在并通过测试。
### 7.3 Artifacts 记录
如果传入 callbackToolResult data 应记录:
- `callback_url`
- `callback_requested=true`
- `polling_used=true`
- `task_id`
如果后续实现 receiver可追加
- `callback_received_at`
- `callback_payload_path`
- `callback_status`
### 7.4 失败处理
- callback URL 无效时,优先在调用前做基本 URL 校验。
- 官方 callback 投递失败不应影响 polling 结果,只要 polling 成功。
- 如果 polling 失败但 callback 成功,必须能从 artifacts 找到 callback payload。
## 8. 文档和 Skill 更新
本阶段更新:
```text
docs/PROVIDERS.md
docs/ARCHITECTURE.md
.agents/skills/kling-official/SKILL.md
skills/INDEX.md
docs/kling-official-integration-plan.md
```
要求:
- `docs/PROVIDERS.md` 增加 Omni 深度能力、Elements、Account Usage 的说明。
- `docs/ARCHITECTURE.md` 标明 Elements 和 Account Usage 只是可灵官方 provider 的内部引用/helper 与诊断能力,不是生成 pipeline 或独立产品功能。
- `.agents/skills/kling-official/SKILL.md` 增加 Omni 引用语法、多参考输入、元素 ID 引用和 callback 注意事项。
- `skills/INDEX.md` 仅标出 Elements/Account Usage 作为 `kling_official` helper 的用途,不新增 capability 分类。
- 原总计划如果继续保留,应标注阶段 2 已拆分到本文件。
## 9. 测试要求
### 9.1 Omni 测试
覆盖:
- Video Omni 多 `image_list` payload。
- Video Omni `video_list` payload。
- Video Omni `element_list` payload。
- `reference_to_video` 无参考输入时报参数错误。
- `multi_prompt` payload。
- `sound="on"``mode="4k"` 成本估算提高或标记高成本。
- Image Omni 多图引用 prompt helper。
- prompt 中已有 `<<<image_1>>>` 时不重复插入。
- `result_type="series"` 多结果 artifacts。
### 9.2 Elements 测试
覆盖:
- Elements helper 不进入 registry。
- Elements helper 不挂到普通 `video_generation` / `image_generation` selector 路径。
- `element_list` 标准化和校验。
- 查询元素 payload。
- preset list payload。
- 默认路径不创建/删除 element。
- element metadata 写入 artifacts。
### 9.3 Account Usage 测试
覆盖:
- endpoint、参数和 Authorization header。
- QPS 节流。
- 相同查询缓存。
- `1101` / `1102` 错误后能触发诊断 helper 或输出建议。
- Account Usage helper 不进入 registry/selector。
- CI 默认不打真实账户接口。
### 9.4 Callback 测试
覆盖:
- Classic callback_url 顶层透传。
- Turbo callback_url 放入 `options.callback_url`
- ToolResult 记录 `callback_requested``polling_used`
- callback URL 基本校验。
## 10. 阶段验收清单
阶段 2 完成前逐项确认:
- Video Omni 支持多图、多视频、元素引用。
- Image Omni 支持多图引用和 series 输出。
- Omni prompt reference helper 有测试覆盖。
- 多镜头 `multi_prompt` 有测试覆盖。
- Elements helper 存在并能记录 element metadata。
- Elements helper 不进入 registry/selector。
- Account Usage helper 存在。
- Account Usage helper 不进入 registry/selector。
- Account Usage 有节流和缓存测试。
- callback_url 能在 Classic/Turbo/Omni 路径正确透传。
- callback 当前仍以 polling 为默认执行路径。
- 成本估算覆盖多参考、多结果、4k、声音等高成本参数。
- Omni paid 成功结果继续写入 `ToolResult.cost_usd`Account Usage 可用时能记录校正信息。
- 文档和 `kling-official` skill 已更新。
- 阶段 1 的视频/图像基础测试仍通过。
## 11. 完成后进入下一阶段
只有当本阶段验收清单全部完成后,才能进入第三阶段:
```text
docs/kling-official-phase-3-media-avatar-effects.md
```
第三阶段会评估可灵官方在现有 OpenMontage capability 中还能补哪些 provider。没有现有 capability 或 pipeline 消费路径的端点默认不接。

View File

@@ -1,561 +0,0 @@
# 可灵官方 API 集成阶段 3TTS、音效、数字人、口型与视频特效
状态:已按本阶段边界完成 OpenMontage provider 接入;真实可灵 API 调用仍需显式 live QA 或人工端到端测试。
来源:从 `docs/kling-official-integration-plan.md` 拆分而来。本阶段对应原计划中的 P3「音频、TTS、数字人、口型、特效」。
执行顺序:必须在以下两个阶段完成后执行:
1. `docs/kling-official-phase-1-core.md`
2. `docs/kling-official-phase-2-omni-operations.md`
## 1. 阶段目标
本阶段目标是在已有 OpenMontage capability 中继续增加 `kling_official` provider 覆盖,而不是新增产品功能:
- 可灵 TTS接入现有 `tts` capability 和 `tts_selector`
- 可灵数字人:作为可选 provider 工具接入现有 `avatar` capability不自动替代 `talking_head.py`
- 可灵口型:作为可选 provider 工具接入现有 `avatar` capability与已有 `lip_sync.py` 并存,不自动替代本地口型工具。
- 可灵音效:仅当能自然映射到现有 `music_generation` 或已有音频后期流程时才接;默认不新增 `sound_effects` capability。
- 可灵视频特效:默认不接入普通 `video_generation`,除非已有 pipeline 明确消费该类 operation默认不新增 `video_effects` capability。
本阶段的重点是“给已有槽位增加可灵官方供应商”,不是把官方 API 的所有端点都产品化。
当前实现记录:
- 已新增 `tools/audio/kling_tts.py`,注册到 `tts` capability并可由 `tts_selector` 通过 `preferred_provider="kling_official"` 选中。
- 已新增 `tools/avatar/kling_avatar.py`,注册到 `avatar` capability与本地 `talking_head.py` 并存。
- 已新增 `tools/avatar/kling_lip_sync.py`,注册到 `avatar` capability与本地 `lip_sync.py` 并存,并保留多人脸人工确认出口。
- 未新增 `kling_audio``kling_effects`,避免为当前 pipeline 引入未设计的 `sound_effects` / `video_effects` 能力面。
- 已更新 `docs/PROVIDERS.md``docs/ARCHITECTURE.md``README.md``skills/INDEX.md``.agents/skills/kling-official/SKILL.md` 和 contract tests。
注意:仓库当前只有 `tts_selector``image_selector``video_selector` 三类 selector没有 `avatar_selector``avatar-spokesperson``localization-dub` pipeline 目前通过 manifest/director 显式列出 `talking_head` / `lip_sync`。因此 `kling_avatar` / `kling_lip_sync` 被 registry 发现并不等于现有 avatar pipeline 会自动消费它们。如需让现有 pipeline 使用,只能在对应 pipeline 的 `tools_available``optional_tools` 和 stage director tool plan 中做最小供应商选项更新,不新增 stage、canonical artifact 或新的 selector。
## 2. 进入条件
开始前必须确认:
- 阶段 1 的官方视频和图像 provider 已完成并验收。
- 阶段 2 的 Omni、Elements helper、Account Usage helper、Callback 已完成并验收。
- `tools/_kling/` client 能复用到音频、头像、口型和特效端点。
- `kling-official` skill 已覆盖任务协议、错误处理、成本治理和 Omni 引用。
- 当前官方 schema fixture 已刷新,并包含本阶段端点的核心字段。
- CI 仍默认不打真实可灵 API。
## 3. 全局规则
本阶段新增的每个工具都必须遵守:
- 继承 `BaseTool`
- 使用 `provider="kling_official"`
- 声明 `dependencies = ["env:KLING_API_KEY"]`
- 声明 `runtime = ToolRuntime.API`
- `agent_skills` 至少包含 `kling-official`,并按能力补充对应 Layer 3 skill。
- 显式实现 `estimate_cost()`,不能静默返回 `0.0`
- 成功的 paid ToolResult 必须写入 `cost_usd`。如果阶段 2 的 Account Usage 能提供实际用量,可记录估算成本和实际用量的校正信息。
- 所有远端结果必须下载到本地 output path 或项目 artifacts。
- ToolResult 必须包含 `task_id``provider``model``operation``output_path` 或等价字段。
- 官方错误必须保留 `code``message``request_id`
- 真实 API 测试必须由显式环境变量开启。
Selector 规则:
- TTS 可以接入 `tts_selector`
- 音效不要伪装成长音乐生成,除非 capability 暂时只能挂到 `music_generation`,且 `best_for/not_good_for` 必须写清楚。
- 数字人和口型可以挂到 `avatar` capability但仓库当前没有 `avatar_selector`。现有 avatar pipeline 是显式工具槽位模式,不能假设新增 provider 会自动被 pipeline 选择。
- 如果要让 `avatar-spokesperson``localization-dub` 使用 `kling_avatar` / `kling_lip_sync`,必须按现有 pipeline 规范显式更新 manifest 和 director skill 的工具选择规则;这只能是供应商选项更新,不能新增流程。
- 视频特效不应挂到普通 `video_generation` 自动选择路径。
- 本阶段默认不新增 capability。若确实需要 `sound_effects``video_effects` 这类新 capability必须另写设计文档并说明对应 pipeline、selector、artifact 和用户入口;不能混在“新增可灵供应商”任务里。
## 4. 工作流 A可灵 TTS
### 4.1 建议文件
```text
tools/audio/kling_tts.py
```
### 4.2 Tool 契约
建议:
```python
class KlingTTS(BaseTool):
name = "kling_tts"
version = "0.1.0"
tier = ToolTier.GENERATE
capability = "tts"
provider = "kling_official"
runtime = ToolRuntime.API
dependencies = ["env:KLING_API_KEY"]
agent_skills = ["kling-official", "text-to-speech"]
```
### 4.3 API 范围
目标端点:
```text
POST /v1/audio/tts
GET /v1/audio/tts/{id}
```
核心字段:
- `text`
- `voice_id`
- `voice_language`,例如 `zh``en`
- `voice_speed`
结果路径:
```text
data.task_result.audios[]
```
### 4.4 实现要求
- 接入 `tts_selector`,确保 `preferred_provider="kling_official"` 可选中。
- `text` 必填,并在调用前做长度校验。
- `voice_language` 使用官方枚举,不要用自由文本。
- `voice_speed` 做范围校验。
- 如果没有传 `voice_id`,要么使用官方默认,要么返回清晰错误;不要硬编码不存在的 voice。
- 输出音频必须下载到 `output_path`
- 如果返回多个音频,全部写入 artifacts`data.output_path` 指向第一条。
- 记录 `voice_id``voice_language``voice_speed`
### 4.5 测试
覆盖:
- registry 能发现 `kling_tts`
- `capability="tts"`
- `provider="kling_official"`
- `tts_selector` 可通过 `preferred_provider="kling_official"` 选中。
- payload 字段正确。
- 成功结果下载音频。
- `agent_skills` 包含 `kling-official`
- `estimate_cost()` 不静默返回 `0.0`
## 5. 工作流 B可灵音效
### 5.1 建议文件
```text
tools/audio/kling_audio.py
```
### 5.2 Capability 决策
实施前必须做一次“是否接入现有能力槽位”的决策:
| 选择 | 适用情况 | 要求 |
|------|----------|------|
| 接入 `music_generation` | 官方返回内容能满足现有音乐/音频生成 stage 的消费方式 | `best_for/not_good_for` 必须写明它偏音效,不是长音乐生成 |
| 暂不接入 | 端点更像短音效或视频后期声音,不符合现有 pipeline 消费方式 | 只在 `kling-official` skill 和后续计划中记录,不新增工具 |
推荐:默认暂不接入,除非现有 pipeline 明确需要该 provider。不要在本阶段新增 `sound_effects` capability。
### 5.3 API 范围
文生音效:
```text
POST /v1/audio/text-to-audio
GET /v1/audio/text-to-audio/{id}
```
核心字段:
- `prompt`
- `duration`
视频生音效:
```text
POST /v1/audio/video-to-audio
GET /v1/audio/video-to-audio/{id}
```
核心字段:
- `video_id``video_url`
- `sound_effect_prompt`
- `bgm_prompt`
- `asmr_mode`
结果路径:
```text
data.task_result.audios[]
```
视频生音效也可能返回 videos必须按当前 schema fixture 处理。
### 5.4 实现要求
- 使用 `operation` 区分 `text_to_audio``video_to_audio`
- 如果接入 `music_generation`,必须保证现有音乐 stage 能消费输出;否则不要接入 registry只保留在官方 skill/后续计划里。
- `text_to_audio` 必须有 `prompt`
- `video_to_audio` 必须有 `video_id``video_url`
- 如果输入本地视频而官方只接受 URL必须明确要求 URL 或先实现官方支持的上传路径;不能静默使用其它 provider。
- 输出音频必须下载到本地。
- 如果返回视频,也要下载并放入 artifacts。
- `duration` 必须进入成本估算。
- `asmr_mode`、bgm、长时长属于更高成本/更强效果差异参数,默认不启用。
### 5.5 测试
覆盖:
- 如果接入现有 capabilityregistry 能发现音效 provider。
- 如果暂不接入,文档明确“不接入当前 registry”的理由。
- `text_to_audio` payload。
- `video_to_audio` payload。
- 无必需输入时报参数错误。
- 多音频 artifacts。
- 如返回视频,视频 artifacts。
- 不被普通 TTS 或普通音乐流程误选;如果无法保证,则不接入 registry。
- `estimate_cost()` 不静默返回 `0.0`
## 6. 工作流 C可灵数字人
### 6.1 建议文件
```text
tools/avatar/kling_avatar.py
```
### 6.2 Tool 契约
建议:
```python
class KlingAvatar(BaseTool):
name = "kling_avatar"
version = "0.1.0"
tier = ToolTier.GENERATE
capability = "avatar"
provider = "kling_official"
runtime = ToolRuntime.API
dependencies = ["env:KLING_API_KEY"]
agent_skills = ["kling-official", "avatar-video"]
```
### 6.3 API 范围
目标端点:
```text
POST /v1/videos/avatar/image2video
GET /v1/videos/avatar/image2video/{id}
```
核心字段:
- `image`
- `audio_id``sound_file`
- `prompt`
- `mode`,例如 `std``pro`
结果路径:
```text
data.task_result.videos[]
```
### 6.4 实现要求
- 与本地 `talking_head.py` 并存,不替代本地工具。
- 官方工具适合云端高质量数字人;本地工具适合无 API 成本、离线可控。
- 不修改 `talking_head.py` 的行为,不把 `kling_avatar` 包装成 `talking_head` 的内部分支。
- 如果需要在 `avatar-spokesperson` 中启用,只在现有 pipeline 的工具列表和 director 决策里增加一个可选供应商路径;不改变 scene_plan、asset_manifest 或 checkpoint 契约。
- 输入头像图片可接受 URL 或本地路径;本地路径按官方要求转 raw base64 或报清晰错误。
- 音频可以使用 `audio_id``sound_file`,具体字段按当前 schema fixture。
- `mode="pro"` 进入成本估算。
- 输出视频必须下载到本地,并调用 `probe_output()`
- ToolResult 记录头像来源、音频来源、模式、任务 ID。
### 6.5 测试
覆盖:
- registry 能发现 `kling_avatar`
- `capability="avatar"`
- payload 使用头像和音频字段。
- 缺少头像或音频时报参数错误。
- 成功后下载视频并 probe。
- 与本地 `talking_head.py` 不冲突。
- 若更新了 `avatar-spokesperson`,测试或文档必须证明它是显式选择 `kling_avatar`,不是靠 registry 自动替换 `talking_head`
- `estimate_cost()` 不静默返回 `0.0`
## 7. 工作流 D可灵口型
### 7.1 建议文件
```text
tools/avatar/kling_lip_sync.py
```
### 7.2 流程
口型生成至少分两步:
1. 识别人脸:
```text
POST /v1/videos/identify-face
```
输入:
- `video_id``video_url`
输出:
- `data.session_id`
- face 信息列表
2. 生成口型:
```text
POST /v1/videos/advanced-lip-sync
GET /v1/videos/advanced-lip-sync/{id}
```
输入:
- `session_id`
- `face_choose[]`
- `audio_id``sound_file`
输出:
```text
data.task_result.videos[]
```
### 7.3 Tool 契约
建议:
```python
class KlingLipSync(BaseTool):
name = "kling_lip_sync"
version = "0.1.0"
tier = ToolTier.GENERATE
capability = "avatar"
provider = "kling_official"
runtime = ToolRuntime.API
dependencies = ["env:KLING_API_KEY"]
agent_skills = ["kling-official", "avatar-video"]
```
### 7.4 人脸选择规则
口型 face 选择可能影响输出人物,必须保留人工确认出口。
规则:
- 如果用户明确传入 `face_id``face_choose`,直接使用。
- 如果未传入,工具可以返回 face list 并要求上层确认。
- 如果实现自动选择,只能作为显式参数启用,例如 `auto_select_face=True`
- 自动策略应选择最大或最居中的 face并在 ToolResult 中记录选择理由。
- 不允许在多人视频中静默选择第一张脸。
### 7.5 Artifacts
建议记录:
```text
projects/<project-name>/artifacts/kling_lip_sync_faces.json
```
内容:
- `session_id`
- face list
- 每个 face 的位置、大小、置信度等官方字段
- 选中的 face
- 选择方式:`user_selected``auto_selected`
### 7.6 实现要求
- 识别人脸和生成口型可以是同一个工具的不同 operation也可以拆 helper。
- `identify_face` operation 可以只返回 face list不生成视频。
- `advanced_lip_sync` operation 必须有 `session_id` 和音频输入。
- 一站式 operation 可以执行识别、选择、生成,但多人场景必须遵守人工确认规则。
- 不修改 `lip_sync.py` 的行为,不把 `kling_lip_sync` 包装成 `lip_sync` 的内部分支。
- 如果需要在 `localization-dub``avatar-spokesperson` 中启用,只在现有 pipeline 的工具列表和 director 决策里增加一个可选供应商路径;不改变 artifact schema 或 stage 顺序。
- 输出视频下载到本地,并调用 `probe_output()`
- 成本估算要覆盖识别和生成两个步骤。
### 7.7 测试
覆盖:
- `identify_face` payload。
- face list 解析。
- 无 face 时报清晰错误。
- 多 face 未启用自动选择时不静默继续。
- `auto_select_face=True` 时记录选择理由。
- `advanced_lip_sync` payload。
- 成功后下载视频并 probe。
- 若更新了 `localization-dub``avatar-spokesperson`,测试或文档必须证明它是显式选择 `kling_lip_sync`,不是靠 registry 自动替换 `lip_sync`
- `estimate_cost()` 不静默返回 `0.0`
## 8. 工作流 E可灵视频特效
### 8.1 建议文件
```text
tools/video/kling_effects.py
```
### 8.2 Capability 决策
视频特效不是普通 text-to-video也不是通用 image-to-video。
本阶段默认不接入 `kling_effects`,原因是现有 `video_selector` 的标准 operation 是 `text_to_video``image_to_video``reference_to_video``rank`,视频特效没有稳定的 pipeline 消费路径。
只有满足以下条件时才允许接入:
- 已有 pipeline 或 stage 明确需要视频特效 operation。
- 已定义该 operation 如何进入 stage artifact。
- 不新增普通视频生成选择分支。
- 不让 `video_selector``text_to_video` / `image_to_video` / `reference_to_video` 中自动选择它。
不要在本阶段新增 `video_effects` capability。若确实需要应另写设计文档。
### 8.3 API 范围
目标端点:
```text
POST /v1/videos/effects
GET /v1/videos/effects/{id}
```
核心字段:
- `effect_scene`
- `input.image`
- `input.images`
结果路径:
```text
data.task_result.videos[]
```
### 8.4 实现要求
默认不实现。若满足上面的接入条件:
- 使用 `operation="video_effect"` 或更具体的 effect operation。
- `effect_scene` 必须是官方枚举或 fixture 中记录的有效值。
- 必须有输入图片,除非官方某个 effect 明确不需要。
- 支持单图和多图输入。
- 本地图片转 raw base64 或按官方要求处理。
- 输出视频下载到本地,并调用 `probe_output()`
- `best_for` 写清楚它适合特效模板,不适合普通视频生成。
- `not_good_for` 写清楚不要用于普通叙事视频、解释器视频、连续镜头生成。
### 8.5 测试
覆盖:
- 如果实现registry 路由方式被文档和测试固化。
- 如果不实现,阶段验收中明确记录“不接入当前 registry”的理由。
- 普通 `video_selector` text_to_video 不会误选 `kling_effects`
- effect payload。
- 缺少图片或 effect_scene 时报参数错误。
- 成功后下载视频并 probe。
- `estimate_cost()` 不静默返回 `0.0`
## 9. 文档和 Skill 更新
本阶段更新:
```text
docs/PROVIDERS.md
docs/ARCHITECTURE.md
README.md
skills/INDEX.md
.agents/skills/kling-official/SKILL.md
```
要求:
- `docs/PROVIDERS.md` 增加已接入的 TTS、数字人、口型 provider音效和特效若不接入只记录为官方 API 未映射端点。
- `docs/ARCHITECTURE.md` 只标明现有 capability 的 provider 扩展;不要描述未落地的新 capability。
- `README.md` provider key 列表不重复,只保留 `KLING_API_KEY` / `KLING_API_BASE_URL` 说明。
- `skills/INDEX.md` 能让 agent 发现对应能力。
- 若让现有 avatar pipeline 消费 `kling_avatar` / `kling_lip_sync`,对应 `pipeline_defs/``skills/pipelines/...` 只记录供应商选择规则,不新增 pipeline 阶段或 canonical artifact。
- `.agents/skills/kling-official/SKILL.md` 增加:
- TTS voice 参数注意事项。
- 音效 prompt 注意事项,以及默认不新增 `sound_effects` capability 的原因。
- 数字人头像/音频输入注意事项。
- 口型 face 选择规则。
- 视频特效默认不接入普通 `video_generation` 的警告。
## 10. 测试总要求
新增或更新:
```text
tests/contracts/test_kling_tts.py
tests/contracts/test_kling_avatar.py
tests/contracts/test_kling_lip_sync.py
```
可选测试:
- 如果 `kling_audio` 接入现有 capability新增 `tests/contracts/test_kling_audio.py`
- 如果 `kling_effects` 有明确 pipeline 消费路径并被实现,新增 `tests/contracts/test_kling_effects.py`
本阶段默认不新增 capability。如果后续单独设计了新 capability该设计必须自带 registry、provider menu、selector 或非 selector 路由测试。
Live QA 必须显式开启:
```bash
RUN_KLING_LIVE_TESTS=1 KLING_API_KEY=... pytest tests/qa/test_kling_official_live.py
```
live smoke 限制:
- 每类能力只跑最小调用。
- 不跑批量。
- 不默认使用高成本模式。
- 不在 CI 默认开启。
## 11. 阶段验收清单
阶段 3 完成前逐项确认:
- `kling_tts` 存在并接入 `tts_selector`
- `kling_audio` 只有在能映射到现有 capability 时才存在;否则验收记录为“暂不接入,避免新增功能面”。
- `kling_avatar` 存在,并与本地 `talking_head.py` 并存;除非现有 pipeline 显式加入它,否则不要求 pipeline 自动消费。
- `kling_lip_sync` 存在,并保留 face 人工选择出口;除非现有 pipeline 显式加入它,否则不要求 pipeline 自动消费。
- `kling_effects` 默认不存在;若存在,必须证明不会被普通视频生成误选,并说明对应 pipeline 消费路径。
- 每个新增工具都声明 `provider="kling_official"`
- 每个新增工具都声明 `dependencies = ["env:KLING_API_KEY"]`
- 每个新增工具都包含 `agent_skills = ["kling-official", ...]` 或等价配置。
- 每个新增工具都实现非默认 `estimate_cost()`
- 每个新增 paid 工具的成功 ToolResult 都写入 `cost_usd`
- 每个新增工具都有 contract 测试。
- 真实 API 测试默认不进 CI。
- 文档、skill、provider table 已更新。
- 阶段 1 和阶段 2 的测试仍通过。
## 12. 全项目完成标准
三阶段全部完成后OpenMontage 的可灵官方 API 集成应达到:
- 官方可灵每个主要能力族都有明确实现或不接入理由。
- 视频、图像和已接入现有 OpenMontage capability 的 TTS、数字人、口型等能力有实现和测试未接入端点有清楚的不接入理由。
- selector 或现有 stage routing 不会在不适合的 operation 中误选特效、口型、音效工具。
- 付费调用默认不进 CIlive QA 需要显式环境变量开启。
- 所有新增工具遵守 OpenMontage 的 BaseTool 契约、artifact 路径和项目目录约定。
- fal.ai Kling 和 official Kling 在 provider 命名、文档、skill 和 selector 使用上清楚分离。
- 未新增 pipeline、stage、canonical artifact 或未设计的新 capability。

View File

@@ -371,7 +371,7 @@ def test_architecture_env_mapping_includes_kling_official():
assert "`KLING_API_BASE_URL` | kling_official_video, kling_official_image, kling_tts, kling_avatar, kling_lip_sync" in architecture
assert "Elements and Account" in architecture
assert "not separate pipeline stages" in architecture
assert "Kling Official Phase 3 adds provider tools only where OpenMontage already has a" in architecture
assert "Kling Official also adds provider tools only where OpenMontage already has a" in architecture
def test_ai_video_skill_metadata_and_new_skill_link():