mirror of
https://github.com/calesthio/OpenMontage.git
synced 2026-08-15 05:04:42 +08:00
Clean up Kling official PR artifacts
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
BIN
diagram.png
BIN
diagram.png
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.8 KiB |
@@ -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
@@ -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 tool(video_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。
|
||||
@@ -1,464 +0,0 @@
|
||||
# 可灵官方 API 集成阶段 2:Omni、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. 工作流 A:Omni 深度接入
|
||||
|
||||
阶段 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. 工作流 B:Elements 引用 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. 工作流 C:Account 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. 工作流 D:Callback 支持
|
||||
|
||||
阶段 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 记录
|
||||
|
||||
如果传入 callback,ToolResult 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 消费路径的端点默认不接。
|
||||
@@ -1,561 +0,0 @@
|
||||
# 可灵官方 API 集成阶段 3:TTS、音效、数字人、口型与视频特效
|
||||
|
||||
状态:已按本阶段边界完成 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 测试
|
||||
|
||||
覆盖:
|
||||
|
||||
- 如果接入现有 capability,registry 能发现音效 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 中误选特效、口型、音效工具。
|
||||
- 付费调用默认不进 CI,live QA 需要显式环境变量开启。
|
||||
- 所有新增工具遵守 OpenMontage 的 BaseTool 契约、artifact 路径和项目目录约定。
|
||||
- fal.ai Kling 和 official Kling 在 provider 命名、文档、skill 和 selector 使用上清楚分离。
|
||||
- 未新增 pipeline、stage、canonical artifact 或未设计的新 capability。
|
||||
@@ -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():
|
||||
|
||||
Reference in New Issue
Block a user