fix: complete subtitle overlay pipeline
This commit is contained in:
parent
0be2b552ea
commit
7fda977e9d
@ -126,6 +126,9 @@ JZAO外置盘: 产物存放地,不是状态主控。
|
||||
| 固定道具合成路线 | ✅ 已建立 | `video-ai-system/plans/script-to-screen/EP01-LOCKED-PROP-COMPOSITING-ROUTE.hdlp` |
|
||||
| 苏白+牌匾合成小样 | 🟡 技术通过·位置失败 | `video-ai-system/outputs/tests/TEST-COMP-001-SUBAI-PLAQUE-OVERLAY-RUN-001-REPORT.hdlp` |
|
||||
| 牌匾固定贴图 | ✅ PNG已生成 | `video-ai-system/assets/props/PROP-TDZ-PLAQUE/texture/tdz-plaque-texture.png` |
|
||||
| 字幕渲染合成 | ✅ RUN-001通过 | `video-ai-system/outputs/tests/TEST-SUBTITLE-001-RUN-001-REPORT.hdlp` |
|
||||
| 苏白TTS配音 | ✅ 工程测试通过 | `video-ai-system/outputs/tests/TEST-TTS-001-SUBAI-RUN-001-REPORT.hdlp` |
|
||||
| 模型/成本路线 | ✅ 已建立 | `video-ai-system/knowledge/D144-MODEL-COST-ROUTE.hdlp` |
|
||||
| 广告牌资产 | ✅ 草案 | `video-ai-system/assets/props/PROP-FREE-AD-BOARD/manifest.hdlp` |
|
||||
| 广告牌文字贴图 | ✅ PNG已生成 | `video-ai-system/assets/props/PROP-FREE-AD-BOARD/texture/free-ad-board-texture.png` |
|
||||
| 百宗会场景资产 | ✅ 草案 | `video-ai-system/assets/envs/ENV-002-Baizonghui/manifest.hdlp` |
|
||||
|
||||
@ -38,6 +38,7 @@ Subtitle Renderer · 字幕渲染引擎
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@ -71,6 +72,27 @@ DEFAULT_STYLE = {
|
||||
"video_height": 1920,
|
||||
}
|
||||
|
||||
CHINESE_FONT_CANDIDATES = [
|
||||
"/System/Library/Fonts/PingFang.ttc",
|
||||
"/System/Library/Fonts/Hiragino Sans GB.ttc",
|
||||
"/System/Library/Fonts/STHeiti Medium.ttc",
|
||||
"/System/Library/Fonts/Supplemental/Songti.ttc",
|
||||
"/System/Library/Fonts/Supplemental/Kaiti.ttc",
|
||||
"/Library/Fonts/Arial Unicode.ttf",
|
||||
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
||||
]
|
||||
|
||||
|
||||
def load_font(font_size: int):
|
||||
for font_path in CHINESE_FONT_CANDIDATES:
|
||||
if not os.path.isfile(font_path):
|
||||
continue
|
||||
try:
|
||||
return ImageFont.truetype(font_path, font_size)
|
||||
except Exception:
|
||||
continue
|
||||
return ImageFont.load_default()
|
||||
|
||||
|
||||
def render_subtitle_png(
|
||||
text: str,
|
||||
@ -99,13 +121,7 @@ def render_subtitle_png(
|
||||
|
||||
# 字体(使用系统字体)
|
||||
font_size = style.get("font_size", 36)
|
||||
try:
|
||||
font = ImageFont.truetype("/System/Library/Fonts/PingFang.ttc", font_size)
|
||||
except:
|
||||
try:
|
||||
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", font_size)
|
||||
except:
|
||||
font = ImageFont.load_default()
|
||||
font = load_font(font_size)
|
||||
|
||||
# 计算文本尺寸
|
||||
bbox = draw.textbbox((0, 0), text, font=font)
|
||||
@ -215,53 +231,63 @@ def burn_subtitles_to_video(
|
||||
print("[ERROR] 没有字幕数据")
|
||||
return False
|
||||
|
||||
# 生成 FFmpeg 复杂滤镜表达式
|
||||
# 思路:为每个字幕 PNG 创建带有时序的 overlay
|
||||
# 简化版:使用 subtitles 滤镜(需要 FFmpeg 编译时启用)
|
||||
#
|
||||
# 由于本机 FFmpeg 无 subtitles 滤镜,改用 drawtext 方案
|
||||
# 如果 drawtext 也不可用,则生成带透明度的 PNG 序列,用 overlay 滤镜
|
||||
if not os.path.isfile(video_path):
|
||||
print(f"[ERROR] 视频文件不存在:{video_path}")
|
||||
return False
|
||||
|
||||
print("[INFO] 生成字幕叠加滤镜脚本...")
|
||||
os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
|
||||
|
||||
# 简化方案:生成所有字幕 PNG 后,用 FFmpeg 的 overlay 滤镜
|
||||
# 为每个时间段启用对应的 PNG
|
||||
# 这需要用 FFmpeg 的 `enable` 表达式
|
||||
ordered_subs = [subtitles[k] for k in sorted(subtitles.keys())]
|
||||
cmd = ["ffmpeg", "-y", "-i", video_path]
|
||||
for sub in ordered_subs:
|
||||
cmd.extend(["-i", sub["png"]])
|
||||
|
||||
filter_complex = []
|
||||
input_count = 1 # 第0个输入是视频
|
||||
margin_bottom = DEFAULT_STYLE["margin_bottom"]
|
||||
chains = []
|
||||
previous = "[0:v]"
|
||||
|
||||
for idx, sub in subtitles.items():
|
||||
png_path = sub["png"]
|
||||
for i, sub in enumerate(ordered_subs, start=1):
|
||||
start_sec = sub["start"] / 1000.0
|
||||
end_sec = sub["end"] / 1000.0
|
||||
scaled = f"[s{i}]"
|
||||
out = f"[v{i}]"
|
||||
chains.append(f"[{i}:v]scale={video_width}:-1{scaled}")
|
||||
chains.append(
|
||||
f"{previous}{scaled}"
|
||||
f"overlay=x=0:y=H-h-{margin_bottom}:"
|
||||
f"enable='between(t,{start_sec:.3f},{end_sec:.3f})'{out}"
|
||||
)
|
||||
previous = out
|
||||
|
||||
# 添加 PNG 输入
|
||||
filter_complex.append(f"[1:v]scale={video_width}:-1[png{idx}]")
|
||||
# 简化:直接用一条命令处理所有字幕(实际应该用动态叠加)
|
||||
filter_complex = ";".join(chains)
|
||||
cmd.extend([
|
||||
"-filter_complex", filter_complex,
|
||||
"-map", previous,
|
||||
"-map", "0:a?",
|
||||
"-c:v", "libx264",
|
||||
"-pix_fmt", "yuv420p",
|
||||
"-c:a", "copy",
|
||||
"-shortest",
|
||||
output_path,
|
||||
])
|
||||
|
||||
input_count += 1
|
||||
print("[INFO] 开始合成字幕到视频...")
|
||||
try:
|
||||
result = subprocess.run(cmd, check=False, capture_output=True, text=True)
|
||||
except FileNotFoundError:
|
||||
print("[ERROR] 未找到 ffmpeg")
|
||||
return False
|
||||
|
||||
# 实际实现:用一条简单的 FFmpeg 命令测试
|
||||
# 这里先输出一个简化版:把第一条字幕叠加上去
|
||||
first_png = list(subtitles.values())[0]["png"]
|
||||
if result.returncode != 0:
|
||||
print("[ERROR] FFmpeg 合成失败")
|
||||
print(result.stderr[-2000:])
|
||||
return False
|
||||
|
||||
cmd = (
|
||||
f'ffmpeg -i "{video_path}" -i "{first_png}" '
|
||||
f'-filter_complex "[0:v][1:v] overlay=0:(H-h) [out]" '
|
||||
f'-map "[out]" -c:a copy "{output_path}" -y'
|
||||
)
|
||||
|
||||
print(f"[INFO] FFmpeg 命令:{cmd}")
|
||||
|
||||
# 实际应该用更准确的方案,这里先输出架构
|
||||
print(f"\n[INFO] 字幕合成需要更复杂的 FFmpeg 滤镜表达式。")
|
||||
print(f"[INFO] 建议方案:")
|
||||
print(f" 1. 使用 FFmpeg 的 `drawtext` 滤镜(需要重新编译 FFmpeg)")
|
||||
print(f" 2. 或使用专业字幕工具(如 Aegisub)生成 ASS,再用 FFmpeg 烧录")
|
||||
print(f"\n[INFO] 当前已生成字幕 PNG 序列在:{os.path.dirname(first_png)}")
|
||||
print(f"[INFO] 可手动用 FFmpeg 或视频编辑软件合成。")
|
||||
if os.path.isfile(output_path) and os.path.getsize(output_path) > 0:
|
||||
print(f"[OK] 字幕已合成到视频:{output_path}")
|
||||
return True
|
||||
|
||||
print(f"[ERROR] 输出视频未生成:{output_path}")
|
||||
return False
|
||||
|
||||
|
||||
@ -308,7 +334,9 @@ def main():
|
||||
|
||||
# 如果指定了视频,则合成
|
||||
if args.video and args.output:
|
||||
burn_subtitles_to_video(args.video, subtitles, args.output, args.video_width, args.video_height)
|
||||
ok = burn_subtitles_to_video(args.video, subtitles, args.output, args.video_width, args.video_height)
|
||||
if not ok:
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\n[OK] 字幕 PNG 序列已生成:{output_dir}")
|
||||
print(f"[INFO] 共 {len(subtitles)} 条字幕")
|
||||
|
||||
240
video-ai-system/knowledge/D144-MODEL-COST-ROUTE.hdlp
Normal file
240
video-ai-system/knowledge/D144-MODEL-COST-ROUTE.hdlp
Normal file
@ -0,0 +1,240 @@
|
||||
# D144 · 视频AI模型与成本路线
|
||||
|
||||
> HLDP://video-ai-system/knowledge/D144-MODEL-COST-ROUTE
|
||||
> 类型: 模型选型 · 成本路线 · 需持续更新
|
||||
> 日期: 2026-06-24
|
||||
> 铸渊 ICE-GL-ZY001
|
||||
|
||||
---
|
||||
|
||||
## 当前事实
|
||||
|
||||
```
|
||||
用户观看TEST-LINE/TEST-PROP系列后反馈:
|
||||
“这是少有的符合标准的质量了,还蛮有感觉的,现在就是差字幕渲染了。”
|
||||
```
|
||||
|
||||
因此:
|
||||
|
||||
```
|
||||
画面主线暂不换掉火山/Seedance。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 当前出图/视频来源
|
||||
|
||||
已实测:
|
||||
|
||||
```
|
||||
图片:
|
||||
- 之前有火山Seedream生成/候选图。
|
||||
- JZAO anchors里也有可用参考图。
|
||||
|
||||
视频:
|
||||
- 当前高质量测试样本来自火山方舟 Seedance 2.0。
|
||||
- TEST-LINE-001: 苏白说台词画面基础部分通过。
|
||||
- TEST-PROP-001 RUN-001: 天道宗牌匾特写通过。
|
||||
- TEST-PROP-001 RUN-002: 苏白+牌匾复合参考图同场失败。
|
||||
```
|
||||
|
||||
结论:
|
||||
|
||||
```
|
||||
火山/Seedance负责高质量短镜头生成。
|
||||
文字道具不交给模型自由生成,改为固定贴图/合成层。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 成本分层
|
||||
|
||||
### A层 · 正片候选镜头
|
||||
|
||||
用途:
|
||||
|
||||
```
|
||||
角色近景
|
||||
关键表演
|
||||
牌匾特写
|
||||
需要商用质感的镜头
|
||||
```
|
||||
|
||||
模型:
|
||||
|
||||
```
|
||||
火山 Seedance 2.0 Pro/当前JIMENG_MODEL
|
||||
```
|
||||
|
||||
策略:
|
||||
|
||||
```
|
||||
只在资产/字幕/音频/构图预检通过后生成。
|
||||
每个技术路线最多2次,不连续抽卡。
|
||||
```
|
||||
|
||||
### B层 · 低成本测试镜头
|
||||
|
||||
用途:
|
||||
|
||||
```
|
||||
构图试验
|
||||
节奏试验
|
||||
远景/过场
|
||||
无角色口型镜头
|
||||
```
|
||||
|
||||
候选:
|
||||
|
||||
```
|
||||
Seedance 2.0 Mini
|
||||
```
|
||||
|
||||
官方价格页/搜索索引显示:
|
||||
|
||||
```
|
||||
720P: 0.5元/秒
|
||||
1080P: 1元/秒
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
```
|
||||
正式调用前必须在控制台/模型列表验证API是否开放。
|
||||
低价不等于可替代正片主镜头。
|
||||
```
|
||||
|
||||
来源:
|
||||
|
||||
```
|
||||
https://www.volcengine.com/docs/82379/1544106
|
||||
```
|
||||
|
||||
### C层 · 开源/本地后期
|
||||
|
||||
用途:
|
||||
|
||||
```
|
||||
字幕
|
||||
混音
|
||||
简单音效
|
||||
文字道具贴图
|
||||
基础配音测试
|
||||
```
|
||||
|
||||
工具:
|
||||
|
||||
```
|
||||
subtitle-renderer.py
|
||||
tts-engine.py / Edge-TTS
|
||||
FFmpeg
|
||||
svg-to-png.py
|
||||
```
|
||||
|
||||
策略:
|
||||
|
||||
```
|
||||
尽量本地完成,不花模型钱。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 声音路线
|
||||
|
||||
### 角色对白
|
||||
|
||||
当前:
|
||||
|
||||
```
|
||||
Edge-TTS可生成苏白测试对白。
|
||||
免费、速度快、适合节奏/字幕/混音联调。
|
||||
```
|
||||
|
||||
风险:
|
||||
|
||||
```
|
||||
Edge-TTS声线未必达到最终商用角色声线。
|
||||
不能解决口型,只解决音频。
|
||||
```
|
||||
|
||||
升级候选:
|
||||
|
||||
```
|
||||
豆包语音TTS / 声音复刻 / 其他商用TTS
|
||||
```
|
||||
|
||||
豆包语音官方计费页显示:
|
||||
|
||||
```
|
||||
豆包语音合成模型2.0: 约3元/万字符。
|
||||
```
|
||||
|
||||
来源:
|
||||
|
||||
```
|
||||
https://www.volcengine.com/docs/6561/1359370
|
||||
https://www.volcengine.com/docs/6561/2528925
|
||||
```
|
||||
|
||||
### 口型
|
||||
|
||||
当前:
|
||||
|
||||
```
|
||||
Seedance可生成“看起来在开口”的画面基础。
|
||||
但未由独立对白音频驱动,不算真正口型解决。
|
||||
```
|
||||
|
||||
路线:
|
||||
|
||||
```
|
||||
1. Edge-TTS/豆包TTS生成角色对白。
|
||||
2. 视频改口型或本地Wav2Lip驱动画面嘴型。
|
||||
3. 与字幕时间轴对齐。
|
||||
```
|
||||
|
||||
来源:
|
||||
|
||||
```
|
||||
https://www.volcengine.com/docs/86081/1804521
|
||||
https://www.volcengine.com/docs/85128/1462623
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配乐路线
|
||||
|
||||
当前:
|
||||
|
||||
```
|
||||
BGM生成器尚未开发。
|
||||
```
|
||||
|
||||
短期:
|
||||
|
||||
```
|
||||
先用免版权/自建素材库 + FFmpeg混音。
|
||||
第一集测试阶段不优先花钱买音乐API。
|
||||
```
|
||||
|
||||
中期:
|
||||
|
||||
```
|
||||
开发 bgm-generator.py:
|
||||
- 开源MusicGen可做探索。
|
||||
- 若本机无GPU或质量不够,再评估商用音乐API。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 当前推荐
|
||||
|
||||
```
|
||||
画面: 火山Seedance继续主线;Mini只做低成本测试。
|
||||
出图: 继续保留Seedream/已有JZAO参考图;最终角色资产要补多角度。
|
||||
配音: Edge-TTS先跑通工程闭环;商用声线再评估豆包语音。
|
||||
口型: 不能靠旁白,必须接音频驱动口型路线。
|
||||
字幕: 本地PNG+FFmpeg合成,已跑通。
|
||||
配乐: 先自建/免版权/本地生成,后续看质量再接商用模型。
|
||||
```
|
||||
|
||||
@ -112,6 +112,9 @@ preview-003: 暂不生成。
|
||||
| 固定道具合成路线 | ✅ | `plans/script-to-screen/EP01-LOCKED-PROP-COMPOSITING-ROUTE.hdlp` |
|
||||
| 苏白+牌匾合成小样 | 🟡 技术通过·位置失败 | `outputs/tests/TEST-COMP-001-SUBAI-PLAQUE-OVERLAY-RUN-001-REPORT.hdlp` |
|
||||
| 牌匾固定贴图 | ✅ PNG已生成 | `assets/props/PROP-TDZ-PLAQUE/texture/tdz-plaque-texture.png` |
|
||||
| 字幕渲染合成 | ✅ RUN-001通过 | `outputs/tests/TEST-SUBTITLE-001-RUN-001-REPORT.hdlp` |
|
||||
| 苏白TTS配音 | ✅ 工程测试通过 | `outputs/tests/TEST-TTS-001-SUBAI-RUN-001-REPORT.hdlp` |
|
||||
| 模型/成本路线 | ✅ 已建立 | `knowledge/D144-MODEL-COST-ROUTE.hdlp` |
|
||||
| 广告牌资产 | ✅ 草案 | `assets/props/PROP-FREE-AD-BOARD/manifest.hdlp` |
|
||||
| 广告牌文字贴图 | ✅ PNG已生成 | `assets/props/PROP-FREE-AD-BOARD/texture/free-ad-board-texture.png` |
|
||||
| 百宗会场景资产 | ✅ 草案 | `assets/envs/ENV-002-Baizonghui/manifest.hdlp` |
|
||||
@ -202,6 +205,9 @@ preview-003: 暂不生成。
|
||||
- [x] 建立工程合成/固定贴图路线解决E1-SHOT03牌匾同场 → `plans/script-to-screen/EP01-LOCKED-PROP-COMPOSITING-ROUTE.hdlp`
|
||||
- [x] 生成 PROP-TDZ-PLAQUE 固定文字贴图PNG → `assets/props/PROP-TDZ-PLAQUE/texture/tdz-plaque-texture.png`
|
||||
- [x] 执行 TEST-COMP-001 RUN-001: 苏白底片+固定牌匾合成 → 技术通过但位置失败
|
||||
- [x] 修复字幕管线: SRT→PNG→FFmpeg overlay合成 → `outputs/tests/TEST-SUBTITLE-001-RUN-001-REPORT.hdlp`
|
||||
- [x] 测试苏白Edge-TTS工程配音 → `outputs/tests/TEST-TTS-001-SUBAI-RUN-001-REPORT.hdlp`
|
||||
- [x] 建立模型/成本路线 → `knowledge/D144-MODEL-COST-ROUTE.hdlp`
|
||||
- [ ] 生成E1-SHOT03专用苏白底片: 上方/身后预留牌匾空间
|
||||
- [ ] 执行 TEST-PROP-001 RUN-003: 广告牌PNG文字贴图上镜追踪测试
|
||||
- [ ] 生成或确认 CHAR-003-SuBai 批准参考图
|
||||
|
||||
@ -0,0 +1,71 @@
|
||||
# TEST-SUBTITLE-001 · 字幕渲染 RUN-001报告
|
||||
|
||||
> HLDP://video-ai-system/outputs/tests/TEST-SUBTITLE-001-RUN-001-REPORT
|
||||
> 类型: 字幕PNG渲染 + FFmpeg合成测试
|
||||
> 日期: D144 · 2026-06-24 11:54 CST
|
||||
> 铸渊 ICE-GL-ZY001
|
||||
|
||||
---
|
||||
|
||||
## 输入
|
||||
|
||||
```
|
||||
srt: /tmp/guanghulab-d144-test/subai.srt
|
||||
base_video: /Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/视频/zai-fu-fei-xiu-xian/ep01/tests/TEST-COMP-001-SUBAI-PLAQUE-OVERLAY-RUN-001.mp4
|
||||
output: /Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/视频/zai-fu-fei-xiu-xian/ep01/tests/TEST-SUBTITLE-001-SUBAI-RUN-001.mp4
|
||||
```
|
||||
|
||||
实际输出:
|
||||
|
||||
```
|
||||
/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/视频/zai-fu-fei-xiu-xian/ep01/tests/TEST-SUBTITLE-001-SUBAI-RUN-001.mp4
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 修复内容
|
||||
|
||||
```
|
||||
subtitle-renderer.py:
|
||||
- 原 burn_subtitles_to_video 只是占位,未真正合成多条字幕。
|
||||
- D144修复为 PNG输入 + overlay enable 分时叠加。
|
||||
- 修复中文字体加载,优先使用 macOS 中文字体。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 测试结果
|
||||
|
||||
```
|
||||
PNG渲染: PASS
|
||||
FFmpeg合成: PASS
|
||||
中文字体: PASS
|
||||
字幕可读: PASS
|
||||
```
|
||||
|
||||
观察:
|
||||
|
||||
```
|
||||
字幕位置位于底部偏上,适合竖屏短剧。
|
||||
黑色半透明底可读性够。
|
||||
当前样式可作为测试默认,不是最终商用字幕包装。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 裁决
|
||||
|
||||
```
|
||||
status: PASS_FOR_PIPELINE_TEST
|
||||
approved_for: 后续EP01测试样片字幕烧录
|
||||
not_approved_for: 最终商用字幕样式
|
||||
```
|
||||
|
||||
下一步:
|
||||
|
||||
```
|
||||
1. 把EP01每句原文台词转成正式SRT。
|
||||
2. 对角色对白音频做时长校准。
|
||||
3. 字幕按音频时间轴烧录。
|
||||
4. 建立商用字幕样式: 字体、描边、底色、位置、安全区。
|
||||
```
|
||||
@ -0,0 +1,48 @@
|
||||
# TEST-TTS-001 · 苏白配音 RUN-001报告
|
||||
|
||||
> HLDP://video-ai-system/outputs/tests/TEST-TTS-001-SUBAI-RUN-001-REPORT
|
||||
> 类型: Edge-TTS角色对白测试
|
||||
> 日期: D144 · 2026-06-24 11:53 CST
|
||||
> 铸渊 ICE-GL-ZY001
|
||||
|
||||
---
|
||||
|
||||
## 输入
|
||||
|
||||
```
|
||||
text: 未来的天下第一宗!天道宗开门收徒啦!
|
||||
character: 苏白
|
||||
voice: zh-CN-XiaoxiaoNeural
|
||||
rate: +5%
|
||||
pitch: +0Hz
|
||||
output: /tmp/guanghulab-d144-test/subai-line.mp3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 探针
|
||||
|
||||
```
|
||||
codec: mp3
|
||||
sample_rate: 24000Hz
|
||||
channels: 1
|
||||
duration: 4.248s
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 裁决
|
||||
|
||||
```
|
||||
status: PASS_FOR_PIPELINE_TEST
|
||||
approved_for: 字幕/混音/对白节奏联调
|
||||
not_approved_for: 最终商用声线
|
||||
```
|
||||
|
||||
结论:
|
||||
|
||||
```
|
||||
Edge-TTS可作为免费工程配音线,先跑通角色对白、字幕、混音闭环。
|
||||
最终商用声线仍需与豆包语音/声音复刻做A/B测试。
|
||||
```
|
||||
|
||||
4
video-ai-system/requirements-video-ai.txt
Normal file
4
video-ai-system/requirements-video-ai.txt
Normal file
@ -0,0 +1,4 @@
|
||||
edge-tts>=7.2.8
|
||||
pysrt>=1.1.2
|
||||
cairosvg>=2.9.0
|
||||
Pillow>=12.2.0
|
||||
Loading…
x
Reference in New Issue
Block a user