AI视频生成:文生视频、图生视频、视频生视频、模型选择。 用于根据提示或参考生成短视频片段(例如:雨中猫的5秒片段、动画化这张照片、重新风格化这个视频)。
video
在Starchild上,所有视频生成请求都使用此技能。
核心原则: 调用提供的脚本。不要重新实现代理/计费/上传逻辑。
1. 文生视频(最常见)
⚠️ 执行上下文——请先阅读。
下面的代码块是Python,不是shell命令。Starchild的bash工具
运行/bin/bash -c,它无法解析exec(open(...))——直接粘贴到
bash命令中会失败,报错syntax error near unexpected token 'open'。
此外,python3 -c中的exec(open(...))会因NameError: __file__失败,
因为脚本使用__file__进行路径解析。通过bash工具调用时,请使用
python3 - <<'EOF'配合from exports import:python3 - <<'EOF' import sys sys.path.insert(0, "skills/video") from generate_video import generate_video result = generate_video( prompt="A cinematic drone shot over snowy mountains at sunrise", model="balanced", duration=5, ) print(result) EOFheredoc(
<<'EOF')保留所有引号和换行——无需转义。
注意:video技能没有exports.py——直接从generate_video导入。
exec(open('skills/video/generate_video.py').read())
result = generate_video(
prompt="A cinematic drone shot over snowy mountains at sunrise",
model="balanced", # "budget" | "balanced" | "premium"
duration=5,
)
# result -> {"success": True, "cost": 0.70, "video_url": "...", "local_path": "output/videos/..."}
generate_video自动执行:提交→轮询→获取结果→将mp4下载到output/videos/。
向用户交付结果——重要
切勿将原始video_url(例如https://*.fal.media/.../*.mp4)交给用户。 fal使用Content-Security-Policy: sandbox; default-src 'none'提供这些文件,这意味着:
- 在浏览器中打开链接会显示空白页面(不会触发内联播放器)。
- 通过
<video>/<iframe>嵌入会被CSP阻止。 - 没有
Content-Disposition: attachment头,因此浏览器也不会自动下载。 - URL侧的调整(查询参数、
?download=1等)无法解决此问题——只有服务器端更改头才能解决,而我们无法控制fal的CDN。
唯一可靠的面向用户的交付路径是已下载的本地文件:
- 使用
result["local_path"](例如output/videos/xxx.mp4)——generate_video成功时始终下载。 - 告知用户文件已保存到
output/videos/<filename>,并可在工作区文件面板/文件浏览器中查看。 - 在Web渠道上,也将其内联嵌入,以便用户在聊天中预览:
(或链接为[video](output/videos/<filename>.mp4)——工作区直接提供这些文件,并带有正确的头)。 - 在Telegram/微信上:通过
send_to_telegram(file_path="output/videos/...", message_type="video")或send_to_wechat(file_path="output/videos/...", message_type="video")发送文件。
如果下载失败(缺少local_path)——重新获取:
curl -L -o output/videos/<filename>.mp4 "<video_url>"
然后交付本地路径。仍然不要将原始fal URL作为主要交付物提供给用户。
2. 图生视频/视频生视频(参考素材)
fal.ai需要参考素材作为公共HTTPS URL。fal存储上传需要您的密钥当前没有的Serverless权限。可靠的方式是通过已发布的Starchild预览公开素材。
标准流程
- 使用
publish_asset.py将素材放入或复制到output/fal_assets/。 - 确保名为
fal-assets的预览正在运行并已发布(一次性设置,见§3)。 - 构建公共URL为
<preview_base>/<filename>。 - 调用
generate_video(... image_url=public_url)。
# 步骤1:将本地图片发布到素材文件夹
exec(open('skills/video/publish_asset.py').read())
asset = publish_local('/path/to/your/photo.jpg')
# 或:publish_from_url('https://example.com/photo.jpg')
filename = asset['filename']
# 步骤2:与预览的公共基础URL结合(见§3)
public_url = f"https://community.iamstarchild.com/<user_slug>-fal-assets/{filename}"
# 步骤3:图生视频
exec(open('skills/video/generate_video.py').read())
result = generate_video(
prompt="gentle cinematic camera push-in",
model="balanced",
duration=5,
image_url=public_url,
)
当提供image_url时,generate_video自动将模型路径从*/text-to-video重写为*/image-to-video。相同的方法适用于视频生视频模型——传递mp4 URL即可。
素材约束(由publish_asset.py强制执行)
- 图片:
.jpg .jpeg .png .webp .gif .bmp,最大10 MB - 视频:
.mp4 .mov .webm .mkv .m4v,最大100 MB - 超出此范围的任何内容在发布前都会被拒绝
3. 一次性fal-assets公共预览设置
每个工作区运行一次。预览会跨会话保持运行。
# 3.1 确保素材文件夹存在并包含占位索引
import os, pathlib
pathlib.Path('output/fal_assets').mkdir(parents=True, exist_ok=True)
if not os.path.exists('output/fal_assets/index.html'):
open('output/fal_assets/index.html', 'w').write(
'<!doctype html><html><body><h1>fal asset host</h1></body></html>'
)
# 3.2 启动预览
preview(action='serve', dir='output/fal_assets', title='fal-assets')
# 3.3 发布到公共URL
preview(action='publish', preview_id='<id from step 3.2>', slug='fal-assets', title='fal-assets')
# → 公共基础:https://community.iamstarchild.com/<user_slug>-fal-assets/
发布后,公共基础URL可重复用于未来的每个图生视频/视频生视频任务。放入output/fal_assets/的文件立即可通过<base>/<filename>访问——无需重新发布。
验证:
curl -sI https://community.iamstarchild.com/<user_slug>-fal-assets/<filename>
# 预期:HTTP/2 200, content-type: image/* or video/*
如果preview(action='serve')返回No available ports in pool,询问用户哪个现有预览可以停止以释放端口——切勿静默终止。
4. 模型选择
| 层级 | 模型 | 每5秒成本 | 备注 |
|---|---|---|---|
| budget | fal-ai/wan/v2.5/text-to-video |
$0.25 | 最快、最便宜;适合提示迭代 |
| balanced | alibaba/happy-horse/text-to-video |
$0.70 | 默认;最佳唇形同步,适用于大多数用例 |
| premium | bytedance/seedance-2.0/fast/text-to-video |
$1.20 | 最佳运动+相机方向 |
| mini | bytedance/seedance-2.0/mini/text-to-video |
$0.36 (480p) / $0.77 (720p) | 最便宜的Seedance;按分辨率分层,无1080p。时长必须是字符串("5",不是5或"5s")——见下面的陷阱 |
| — | xai/grok-imagine-video/v1.5/image-to-video |
每5秒$0.41 (480p) / $0.71 (720p) | 仅图生视频(单个必需的image_url,无image_urls);+$0.01输入图片附加费已包含在估算中。⚠️ resolution="1080p"在模式上有效,但上游没有公布价格——代理以400拒绝并关闭 |
| — | fal-ai/kling-video/v3/turbo/standard/text-to-video |
每5秒$0.56 | Kling v3 Turbo Standard,固定$0.112/s;.../turbo/pro/... = $0.14/s ($0.70/5s);.../v3/4k/... = $0.42/s ($2.10/5s)。所有都有i2v变体 |
| — | alibaba/happy-horse/v1.1/text-to-video |
每5秒$0.70 (720p) / $0.90 (1080p) | v1.1有自己的1080p层级**$0.18/s**(不是v1.0的2×规则);还有/image-to-video、/reference-to-video |
⚠️ Happy Horse默认分辨率上游为1080p(v1.0和v1.1):省略resolution会按1080p层级计费(v1.1 5s = $0.90;v1.0 ref2v 5s = $1.40)。显式传递resolution="720p"以获得更便宜的费率。无效的分辨率值会被代理以400拒绝。
参考视频(alibaba/happy-horse/reference-to-video、.../v1.1/reference-to-video):传递image_urls=[...](1–9个公共HTTP(S) URL的列表)——不是单个image_url参数。generate_video()验证数量和URL方案,并提交image_urls负载字段。
通过将完整模型ID传递给generate_video(model=...)来覆盖。图生视频变体通过将text-to-video替换为image-to-video自动派生。
定价详情和模型注册表位于generate_video.py::estimate_cost。
5. 轮询现有请求
exec(open('skills/video/poll_status.py').read())
result = poll_video("019ded6c-d871-7290-bbf1-ddc6993f8958")
当之前的generate_video调用超时或您只有request_id时使用。
6. 提供的脚本
generate_video.py— 提交→轮询→下载。处理文生视频和图生视频。publish_asset.py— 将本地文件(或下载远程URL)复制到output/fal_assets/,以便通过fal-assets预览提供。poll_status.py— 通过request_id恢复轮询,完成后下载结果。
7. 故障排除
| 问题 | 修复 |
|---|---|
image_url must be a public HTTP(S) URL |
使用publish_asset.py + fal-assets预览,然后传递公共URL |
No available ports in pool(预览服务) |
询问用户要停止哪个预览;不要自动终止 |
downstream_service_error after COMPLETED |
参考素材主机在渲染过程中失败——重新编码/调整大小为16:9,重新发布,重试 |
HTTP 402 insufficient_credits |
充值余额;提交时预扣费用 |
HTTP 403 endpoint_not_allowed |
sc-proxy只允许批准的fal视频端点;从模型表中选择一个 |
生成上游FAILED |
缩短提示,删除不常见的标记,在更改模型前重试一次 |
HTTP 422 literal_error on duration (Seedance Mini) |
Mini要求duration为字符串("5"、"10"、"auto"),不是整数也不是"5s"。当model包含seedance-2.0/mini时,generate_video()自动编码此问题——仅当您手动构建请求体时才会遇到。其他Seedance变体接受整数/"5s"。 |
任务卡在IN_PROGRESS超过15分钟 |
保存request_id,稍后使用poll_status.py恢复 |
| 用户报告fal.media链接“显示空白”/“空白页面” | 预期行为——fal使用CSP: sandbox; default-src 'none'提供。交付result["local_path"]处的本地文件,而不是原始URL(见§1)。 |
8. 基础设施(参考)
- 调用者 →
sc-proxy→queue.fal.run(和api.fal.ai)→ fal模型提供商 - 所有请求必须包含
Authorization: Key fake-falai-key-12345(代理注入真实的FAL_KEY) - 提交时预扣费。轮询/结果调用免费。
- 允许的端点:注册模型的视频文生视频/图生视频/视频生视频/编辑视频。其他任何内容返回
403 endpoint_not_allowed。 - 最终mp4位于
https://*.fal.media/...——公共CDN,下载无需认证。
9. 维护
- 添加新模型→在
generate_video.py::estimate_cost和transparent-proxy/apis/falai.py::_VIDEO_PRICING中注册价格。 - 本技能有意不使用fal存储上传进行素材托管:生产环境的
FAL_KEY缺少Serverless权限。在情况改变之前,继续使用基于预览的方法。






