
本文参考三合卓学OPC项目记录了一套基于开源工具构建的数字人直播自动化系统的部署过程。系统涵盖内容批量生成、视频自动化合成、多平台推流分发三个核心模块,旨在解决单人运营者在内容产出效率和直播执行成本上的技术瓶颈。文章详细记录了系统架构设计、各模块的实现代码、部署步骤以及30天运行数据,为计划自建自动化内容生产管线的开发者提供参考。
本系统采用“内容生产”与“直播分发”并行的双线架构,两条线通过统一的选题库和话术模板进行串联:
选题库 → [内容生产管线] → 脚本/素材 → [视频合成] → 素材库
↓
统一IP定位与话术体系
↓
数字人直播系统 → RTMP推流 → 多平台分发各层职责:
本方案完全基于开源工具实现,无需商业软件授权:
模块 | 工具 | 用途 |
|---|---|---|
流程编排 | Python 3.10+ | 调度各模块执行 |
脚本生成 | OpenAI API (GPT-4o-mini) | 批量生成视频脚本和直播话术 |
语音合成 | Edge TTS | 将文本转为语音 |
视频合成 | moviepy + FFmpeg | 合成含字幕的数字人视频 |
直播推流 | FFmpeg | RTMP推流至各平台 |
数据存储 | SQLite | 记录内容和直播数据 |
定时调度 | Windows Task Scheduler / cron | 定时触发生产与推送任务 |
选题库采用JSON格式存储,包含内容方向、目标平台、标签等信息:
{
"topics": [
{
"id": "T001",
"category": "劳动纠纷",
"question": "公司单方面降薪是否合法",
"target_platform": ["抖音", "视频号"],
"tags": ["劳动法", "职场权益"],
"publish_frequency": "每周2次"
}
]
}import json
from openai import OpenAI
client = OpenAI(api_key="your_api_key")
def generate_batch_scripts(topics: list, platform: str = "general") -> list:
"""批量生成短视频脚本"""
results = []
for topic in topics:
prompt = f"""
请根据以下话题生成一个60秒短视频脚本。
话题:{topic['question']}
分类:{topic.get('category', '')}
目标平台:{platform}
要求:
1. 三段式结构:开场提问→核心解答→结尾引导
2. 开场用反常识提问或数据对比抓住注意力
3. 核心部分分3个要点,每点不超过2句话
4. 结尾引导点赞、评论或关注
5. 输出JSON格式:{{"opening": "", "core": "", "closing": ""}}
"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"},
temperature=0.8
)
script = json.loads(response.choices[0].message.content)
script["topic_id"] = topic["id"]
script["category"] = topic.get("category", "")
results.append(script)
return resultsimport asyncio
import edge_tts
from moviepy.editor import ImageClip, AudioFileClip, CompositeVideoClip, TextClip
import os
async def batch_synthesize(scripts: list, output_dir: str):
"""批量合成语音"""
semaphore = asyncio.Semaphore(5)
async def synthesize_one(text: str, path: str):
async with semaphore:
tts = edge_tts.Communicate(text, "zh-CN-XiaoxiaoNeural")
await tts.save(path)
tasks = []
for i, script in enumerate(scripts):
full_text = script["opening"] + script["core"] + script["closing"]
path = os.path.join(output_dir, f"audio_{i}.wav")
tasks.append(synthesize_one(full_text, path))
await asyncio.gather(*tasks)
def batch_compose_videos(scripts: list, audio_dir: str, avatar_path: str, output_dir: str):
"""批量合成视频"""
for i, script in enumerate(scripts):
audio_path = os.path.join(audio_dir, f"audio_{i}.wav")
output_path = os.path.join(output_dir, f"video_{i}.mp4")
audio = AudioFileClip(audio_path)
duration = audio.duration
avatar = ImageClip(avatar_path).set_duration(duration).resize(height=1080)
full_text = script["opening"] + script["core"] + script["closing"]
sentences = [s for s in full_text.split("。") if s.strip()]
if not sentences:
sentences = [full_text]
segment_duration = duration / len(sentences)
subtitle_clips = []
for j, sentence in enumerate(sentences):
clip = TextClip(
sentence + "。",
fontsize=38,
color='white',
stroke_color='black',
stroke_width=2,
method='caption',
size=(avatar.w * 0.85, None)
).set_start(j * segment_duration).set_duration(segment_duration)
subtitle_clips.append(clip)
final = CompositeVideoClip([avatar, *subtitle_clips])
final = final.set_audio(audio)
final.write_videofile(output_path, codec='libx264', audio_codec='aac', fps=24)
print(f"已生成:{output_path}")测试条件:10条脚本,平均每条250字,使用上述批量处理方案
指标 | 数据 |
|---|---|
脚本生成耗时 | 约8秒(API调用) |
语音合成耗时 | 约11秒(并发5) |
视频合成耗时 | 约35分钟(单条约3.5分钟) |
人工修改率 | 约15%(审核脚本质量) |
单日产能(8小时) | 约120条完整视频 |
直播话术采用结构化模板,按时间轴分段:
{
"session_name": "法律知识科普",
"duration_minutes": 30,
"segments": [
{"time": "0-3min", "type": "开场", "template": "欢迎来到直播间,今天我们来聊一个大家都很关心的问题..."},
{"time": "3-20min", "type": "核心内容", "template": "关于{topic},很多朋友都问过我..."},
{"time": "20-27min", "type": "互动", "template": "如果你也遇到了类似的情况,欢迎在评论区留言..."},
{"time": "27-30min", "type": "结尾", "template": "感谢大家的观看,我们下期再见..."}
]
}配置文件stream_config.json包含各平台的推流地址和排期:
{
"platforms": [
{
"name": "抖音",
"rtmp_url": "rtmp://push.douyin.com/live",
"stream_key": "your_stream_key",
"schedule": "19:00-20:00",
"enabled": true
},
{
"name": "视频号",
"rtmp_url": "rtmp://push.weixin.qq.com/live",
"stream_key": "your_stream_key",
"schedule": "20:30-21:30",
"enabled": true
}
]
}import subprocess
import time
import json
from datetime import datetime
class AutoStream:
def __init__(self, config_path: str):
with open(config_path, 'r') as f:
self.config = json.load(f)
self.running = {}
def start_stream(self, platform: dict, video_path: str, duration_seconds: int = 3600):
"""启动单个平台推流"""
url = f"{platform['rtmp_url']}/{platform['stream_key']}"
cmd = [
"ffmpeg",
"-re",
"-stream_loop", "-1",
"-i", video_path,
"-c", "copy",
"-f", "flv",
"-reconnect", "1",
"-reconnect_at_eof", "1",
"-reconnect_streamed", "1",
"-reconnect_delay_max", "5",
"-t", str(duration_seconds),
url
]
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
self.running[platform['name']] = {
"process": process,
"start_time": datetime.now(),
"platform": platform['name']
}
print(f"[{datetime.now()}] 推流已启动:{platform['name']}")
def stop_all(self):
"""停止所有推流"""
for name, info in self.running.items():
info["process"].terminate()
print(f"[{datetime.now()}] 已停止:{name}")
self.running.clear()
def get_status(self):
"""获取运行状态"""
status = {}
for name, info in self.running.items():
elapsed = (datetime.now() - info["start_time"]).seconds
status[name] = {
"status": "running",
"elapsed_minutes": elapsed // 60
}
return status在Windows下创建定时任务,每日自动执行:
# 创建每日推流任务
schtasks /create /tn "AutoStream_Daily" /tr "python C:\stream\auto_stream.py" /sc daily /st 19:00指标 | 数据 |
|---|---|
单场推流时长 | 30至60分钟 |
推流成功率 | 96%(30场测试,1场因网络中断) |
自动重连恢复率 | 100%(中断后自动重连) |
AI互动应答延迟 | 约0.5至2秒(基于预设知识库) |
用户平均停留时长 | 约2.5分钟 |
CREATE TABLE content_distribution (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content_id TEXT,
platform TEXT,
title TEXT,
publish_time TEXT,
views INTEGER DEFAULT 0,
likes INTEGER DEFAULT 0,
comments INTEGER DEFAULT 0,
shares INTEGER DEFAULT 0,
status TEXT
);
CREATE TABLE live_sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
platform TEXT,
start_time TEXT,
end_time TEXT,
duration_minutes INTEGER,
peak_viewers INTEGER,
total_messages INTEGER,
status TEXT
);def check_distribution_status(days: int = 7) -> dict:
"""检查最近N天的内容分发状态"""
cursor = conn.cursor()
cursor.execute("""
SELECT platform, COUNT(*) as total,
SUM(CASE WHEN status = 'published' THEN 1 ELSE 0 END) as published
FROM content_distribution
WHERE publish_time >= date('now', ?)
GROUP BY platform
""", (f'-{days} days',))
results = {}
for row in cursor.fetchall():
results[row[0]] = {
"total": row[1],
"published": row[2],
"sync_rate": round(row[2] / row[1] * 100, 1)
}
return results指标 | 数据 |
|---|---|
累计生成脚本 | 约120条 |
累计合成视频 | 约105条 |
内容工厂日产能 | 约12条/天 |
人工审核修改率 | 约18% |
视频合成成功率 | 93.3% |
指标 | 数据 |
|---|---|
累计推流场次 | 28场 |
单场平均时长 | 32分钟 |
推流成功率 | 96.4% |
覆盖平台数 | 2个(抖音、视频号) |
各平台同步成功率 | 100% |
工作项 | 日均耗时 |
|---|---|
选题策划与脚本审核 | 约25分钟 |
视频合成监控 | 约15分钟 |
推流状态检查 | 约10分钟 |
数据记录与汇总 | 约10分钟 |
日均合计 | 约60分钟 |
# 安装Python依赖
pip install openai edge-tts moviepy opencv-python
# 验证FFmpeg
ffmpeg -version本文涉及的所有代码和配置文件均已归档,包含以下材料:
复现所需资源:
免责声明:本文所有技术方案仅供学习参考。各平台政策可能随时更新,推流前请自行核实最新规则。使用开源工具前请阅读并遵守各软件的许可证条款。文中所有代码需根据自身环境调整参数后使用。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。