聊天視窗

從零到偶像:生成式 AI 與虛擬人物的跨域實踐 - 第 7 章

第 7 章:內容創作工作流與自動化

發布於 2026-03-02 22:27

# 第 7 章 內容創作工作流與自動化 在本章中,我們將把前面幾章所建構的 **角色定位、視覺形象、聲音人格** 具體落實到 **日常內容產出與即時互動** 的完整工作流。讀者將學會如何使用生成式 AI 自動撰寫腳本、即時回應粉絲訊息,並將這些素材無縫串接至 **Discord / Telegram 機器人** 以及 **OBS** 直播系統,達成「全自動」的虛擬偶像運營管線。 --- ## 7.1 內容創作全景圖 ```mermaid graph LR A[概念腳本] --> B[文本生成 LLM] B --> C[情感標記 & SSML] C --> D[語音 TTS / 歌曲 DiffSinger] D --> E[多媒體合成 (VFX + 2D/3D) ] E --> F[OBS Live Output] F --> G[觀眾互動 (Discord/Telegram Bot)] G --> H[即時回應生成] H --> B ``` 如上圖所示,**內容創作循環** 包含三大環節: 1. **腳本生成** – 以大型語言模型 (LLM) 產出劇本、直播腳本或短視頻文案。 2. **多模態合成** – 文本 → SSML → TTS/歌聲 → 視覺渲染 → OBS 輸出。 3. **即時互動** – 機器人捕捉粉絲訊息 → 情感分析 → 生成回覆 → TTS 回放。 本章將針對每個環節提供 **工具選型、實作步驟、最佳實踐**,並示範完整的 **自動化 pipeline**。 --- ## 7.2 腳本生成:從概念到文本 ### 7.2.1 為什麼使用 LLM? - **多樣性**:同一主題可快速生成多種敘事風格。 - **可控性**:透過 **Prompt Engineering**、**Few‑Shot** 範例與 **Function Calling**(如 OpenAI function calling)可限制輸出格式。 - **成本效益**:使用 **Open‑Source**(如 Llama‑3、Mistral)或 **雲端服務**(OpenAI GPT‑4o、Claude 3.5)依需求切換。 ### 7.2.2 Prompt 基礎模板 ```text [角色設定] - 姓名:{{name}} - 年齡:{{age}} - 人格特徵:{{personality}} - 語氣:{{tone}} [任務描述] 請以 {{tone}} 的語氣,為 {{event}} 撰寫一段 150~200 字的直播開場白,內容需包含以下三個要點: 1. 歡迎新粉絲 2. 簡短介紹本次活動主題 3. 呼籲觀眾在聊天室互動 [回覆格式] {{ "script": "...", "keywords": ["...","..."] }} ``` > **Tip**:將 `{{keywords}}` 作為後續情感控制或字幕自動生成的依據。 ### 7.2.3 使用 Python 呼叫 OpenAI API(示例) ```python import openai, json, os def generate_script(prompt: str, model: str = "gpt-4o-mini") -> dict: response = openai.ChatCompletion.create( model=model, messages=[{"role": "system", "content": "You are a creative assistant for a virtual idol."}, {"role": "user", "content": prompt}], temperature=0.7, response_format={"type": "json_object"} ) return json.loads(response.choices[0].message.content) # 範例 Prompt prompt = """[角色設定]\n- 姓名:星瀾\n- 年齡:18\n- 人格特徵:活潑、好奇、帶點神祕感\n- 語氣:甜美且帶有輕微的電子音效\n\n[任務描述]\n請以甜美的語氣,為即將舉行的《星光音樂會》撰寫一段 180 字的直播開場白,內容需包含以下三個要點:\n1. 歡迎新粉絲\n2. 簡短介紹本次活動主題\n3. 呼籲觀眾在聊天室互動\n\n[回覆格式]\n{{\n "script": "...",\n "keywords": ["...","..."]\n}}""" result = generate_script(prompt) print(result["script"]) ``` --- ## 7.3 多模態合成:文本 → SSML → TTS / 歌聲 ### 7.3.1 SSML 與情感標記 **SSML(Speech Synthesis Markup Language)** 能夠在文字中嵌入語速、音高、情緒等指令,讓 TTS 輸出更貼合角色設定。以下是一段範例: ```xml <speak version="1.0" xmlns="https://www.w3.org/2001/10/synthesis" xml:lang="zh-TW"> <prosody rate="+10%" pitch="+5%"> 大家好,我是 <emphasis level="moderate">星瀾</emphasis>! </prosody> <break time="500ms"/> <prosody rate="-5%" pitch="-3%" volume="soft"> 今晚,我們將一起踏上星光之旅… </prosody> </speak> ``` > **技巧**:將腳本中的 **關鍵字**(如 `{{emotion}}`)映射為 SSML `<prosody>` 參數,實現 **情感可編程**。 ### 7.3.2 TTS 引擎選型 | 類型 | 代表模型 | 開源/商用 | 特色 | 適合情境 | |------|----------|----------|------|----------| | 神經網路 TTS | **VITS**、**FastSpeech 2** | 開源 | 高品質、可自訂聲線 | 角色說話、劇本朗讀 | | 商業雲端 | **Azure Neural Speech**、**Google WaveNet**、**OpenAI Text-to-Speech (TTS‑o1)** | 商用 | 多語言、情感參數化 | 需要 SLA、低延遲直播 | | 歌聲合成 | **DiffSinger**、**so‑vits‑svc** | 開源 | 音高與音色分離、可轉換風格 | 虛擬歌手演唱 | > **實務建議**:將 **VITS LoRA** 微調後作為主力 TTS,備援使用 **Azure** 以確保高可用性。 ### 7.3.3 端到端合成腳本(Python) ```python import json, subprocess from pathlib import Path # 1. 讀取 LLM 產出的腳本與關鍵字 with open("script.json", "r", encoding="utf-8") as f: data = json.load(f) script = data["script"] keywords = data["keywords"] # 2. 依關鍵字插入情感 SSML(簡易映射) emotion_map = { "歡迎": "<prosody rate='+5%'>", "驚喜": "<prosody pitch='+10%'>", "柔和": "<prosody volume='soft'>" } ssml_body = script for kw in keywords: if kw in emotion_map: ssml_body = f"{emotion_map[kw]}{ssml_body}</prosody>" ssml = f"<speak>{ssml_body}</speak>" Path("output.ssml").write_text(ssml, encoding="utf-8") # 3. 呼叫本地 VITS(假設使用 vits_infer.py) subprocess.run(["python", "vits_infer.py", "--ssml", "output.ssml", "--out", "tts.wav"]) ``` --- ## 7.4 OBS 與多媒體輸出 ### 7.4.1 OBS 基礎架構 1. **來源 (Source)**: - **音訊來源**:TTS、歌聲檔 (`tts.wav` / `song.wav`)。 - **視訊來源**:Live2D、3D avatar、預先渲染的動畫。 2. **場景 (Scene)**:將音訊與視訊組合成 **直播畫面**,可預設「開場」「表演」「互動」等多個場景。 3. **插件**: - **OBS WebSocket**:允許外部腳本遠端控制場景切換與音量。 - **StreamElements / Streamlabs**:即時彈幕、禮物特效。 ### 7.4.2 用 Python 控制 OBS(示例) ```python import websockets, json, asyncio OBS_HOST = "ws://localhost:4455" PASSWORD = "your_obs_password" async def obs_request(msg: dict): async with websockets.connect(OBS_HOST) as ws: # 認證 await ws.send(json.dumps({"op": 1, "d": {"rpcVersion": 1, "authentication": PASSWORD}})) await ws.recv() # 讀取回應 # 發送指令 await ws.send(json.dumps({"op": 6, "d": msg})) return await ws.recv() # 切換到表演場景 payload = { "requestType": "SetCurrentProgramScene", "requestData": {"sceneName": "Performance"} } asyncio.run(obs_request(payload)) ``` > **注意**:OBS WebSocket 需要在 OBS 「工具 → WebSocket Server」中啟用,並設置密碼。 --- ## 7.5 即時互動:Discord / Telegram 機器人 ### 7.5.1 為什麼選擇 Discord / Telegram? - **即時性**:WebSocket 連線維持低延遲。 - **豐富的 API**:訊息、表情、按鈕、語音頻道皆可程式化。 - **社群成熟**:許多粉絲已在這兩平台活躍。 ### 7.5.2 Bot 基礎架構圖 ```mermaid sequenceDiagram participant User as 粉絲 participant Bot as Bot (Discord/Telegram) participant LLM as LLM 生成回覆 participant TTS as TTS 引擎 participant OBS as OBS (WebSocket) User->>Bot: 發送文字訊息 Bot->>LLM: 文字→Prompt LLM-->>Bot: JSON 回覆 Bot->>TTS: 文字→SSML TTS-->>Bot: 音檔 Bot->>OBS: 播放音檔 + 切換互動場景 Bot-->>User: 文字或語音回覆 ``` ### 7.5.3 Discord Bot 範例(Python + discord.py) ```python import discord, json, openai, asyncio, websockets from pathlib import Path intents = discord.Intents.default() intents.message_content = True bot = discord.Client(intents=intents) # 1. LLM 產生回覆 async def generate_reply(message: str) -> dict: prompt = f"你是虛擬偶像星瀾,請以甜美且帶點電子音的語氣回覆以下訊息:{message}" resp = await openai.ChatCompletion.acreate( model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}], temperature=0.8, response_format={"type": "json_object"} ) return json.loads(resp.choices[0].message.content) # 2. 呼叫本地 TTS(VITS LoRA) async def synthesize(text: str, filename: str = "reply.wav"): ssml = f"<speak>{text}</speak>" Path("tmp.ssml").write_text(ssml, encoding="utf-8") proc = await asyncio.create_subprocess_exec( "python", "vits_infer.py", "--ssml", "tmp.ssml", "--out", filename, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) await proc.communicate() return filename # 3. 觸發 OBS 切換場景並播放音檔 async def play_in_obs(audio_path: str): async with websockets.connect("ws://localhost:4455") as ws: await ws.send(json.dumps({"op":1,"d":{"rpcVersion":1,"authentication":"your_obs_password"}})) await ws.recv() # 切換至互動場景 await ws.send(json.dumps({"op":6,"d":{"requestType":"SetCurrentProgramScene","requestData":{"sceneName":"Interaction"}}})) await ws.recv() # 更新音訊來源(假設已有 Audio Source 名稱為 'Voice') await ws.send(json.dumps({"op":6,"d":{"requestType":"SetSourceSettings","requestData":{"sourceName":"Voice","sourceSettings":{"local_file":audio_path}}}})) await ws.recv() @bot.event async def on_message(message: discord.Message): if message.author.bot: return # 只回覆指令前綴 "!" 以免濫用 if not message.content.startswith("!"): return user_text = message.content[1:].strip() reply_json = await generate_reply(user_text) reply_text = reply_json.get("reply", "…") audio_file = await synthesize(reply_text) await play_in_obs(audio_file) # 同時回傳文字版給粉絲 await message.channel.send(reply_text) bot.run("YOUR_DISCORD_BOT_TOKEN") ``` > **重點說明**: > - 使用 **OpenAI function calling** 可保證回覆結構化,減少後處理錯誤。 > - Audio source 需在 OBS 預先設定為 **Media Source**,允許外部腳本指定本地檔案路徑。 > - 為防止濫用,建議在 **Discord 伺服器** 加入 **Rate‑limit** 或 **權限檢查**。 ### 7.5.4 Telegram Bot(python‑telegram‑bot)簡易實作 ```python from telegram import Update from telegram.ext import ApplicationBuilder, CommandHandler, MessageHandler, filters, ContextTypes import openai, json, asyncio, subprocess, websockets async def reply(update: Update, context: ContextTypes.DEFAULT_TYPE): user_msg = update.message.text # LLM 產生回覆 resp = await openai.ChatCompletion.acreate( model="gpt-4o-mini", messages=[{"role": "user", "content": f"你是星瀾,請以甜美語氣回覆:{user_msg}"}], response_format={"type": "json_object"}) reply_json = json.loads(resp.choices[0].message.content) reply_text = reply_json.get("reply", "…") # TTS 合成(使用本地腳本) ssml = f"<speak>{reply_text}</speak>" Path("tmp.ssml").write_text(ssml, encoding="utf-8") subprocess.run(["python", "vits_infer.py", "--ssml", "tmp.ssml", "--out", "reply.wav"]) # OBS 播放 async with websockets.connect("ws://localhost:4455") as ws: await ws.send(json.dumps({"op":1,"d":{"rpcVersion":1,"authentication":"your_obs_password"}})) await ws.recv() await ws.send(json.dumps({"op":6,"d":{"requestType":"SetCurrentProgramScene","requestData":{"sceneName":"Interaction"}}})) await ws.recv() await ws.send(json.dumps({"op":6,"d":{"requestType":"SetSourceSettings","requestData":{"sourceName":"Voice","sourceSettings":{"local_file":"reply.wav"}}}})) await ws.recv() # 回傳文字給使用者 await update.message.reply_text(reply_text) app = ApplicationBuilder().token("YOUR_TELEGRAM_BOT_TOKEN").build() app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, reply)) app.run_polling() ``` --- ## 7.6 完整自動化管線:從腳本生成到直播上線 ### 7.6.1 條件與前置設定 | 項目 | 推薦方案 | 版本/設定說明 | |------|----------|----------------| | 作業系統 | Ubuntu 22.04 LTS | 支援 GPU 驅動 (CUDA 12) | | GPU | NVIDIA RTX 4090 | 至少 24GB 記憶體,適用 VITS LoRA、DiffSinger | | LLM 服務 | OpenAI GPT‑4o / 本地 Mistral‑7B‑Instruct + llama‑cpp | 依需求選擇雲端或本地 | | TTS 引擎 | VITS‑LoRA (自訂聲線) + Azure TTS 作備援 | 兩者互補 | | 直播平台 | YouTube Live / Twitch | | 互動平台 | Discord (官方伺服器) + Telegram 群組 | | OBS | 29.x + OBS‑WebSocket 5.1 | | 任務排程 | **Cron** + **systemd** 服務 | 確保腳本在系統啟動時自動運行 | ### 7.6.2 Pipeline 程式碼概覽(master.py) ```python # master.py – 完整自動化工作流入口 import asyncio, json, datetime, os from pathlib import Path from utils import ( llm_generate, # LLM 產生腳本 ssml_wrap, # 產生 SSML tts_synthesize, # VITS LoRA 合成 obs_control, # OBS WebSocket 控制 discord_bot, # 啟動 Discord Bot telegram_bot # 啟動 Telegram Bot ) async def daily_script_job(): """每日凌晨 02:00 自動產出當日直播腳本並推送至 OBS 場景""" now = datetime.datetime.now().strftime("%Y-%m-%d") prompt = f"為 {now} 的《星光音樂會》產生 5 分鐘的開場腳本,請回傳 JSON,包含 'script' 與 'keywords'。" data = await llm_generate(prompt) script, kw = data["script"], data["keywords"] # 保存腳本供機器人使用 Path("today_script.json").write_text(json.dumps(data, ensure_ascii=False), encoding="utf-8") # 生成 SSML 並 TTS ssml = ssml_wrap(script, kw) await tts_synthesize(ssml, out_path="opening.wav") # OBS 切換至 Opening 場景並播放 await obs_control.set_scene("Opening") await obs_control.play_audio("opening.wav") print("[INFO] 今日開場腳本已上線") async def main(): # 啟動即時互動機器人(背景任務) asyncio.create_task(discord_bot.run()) asyncio.create_task(telegram_bot.run()) # 每日排程 while True: now = datetime.datetime.now() if now.hour == 2 and now.minute == 0: await daily_script_job() await asyncio.sleep(60) # 每分鐘檢查一次 if __name__ == "__main__": asyncio.run(main()) ``` > `utils` 內部實作即為第 7.3、7.4、7.5 小節的函式,將各模組解耦,便於未來替換模型或平台。 ### 7.6.3 部署與監控 1. **建立 systemd 服務** (`/etc/systemd/system/virtual_idol.service`) ```ini [Unit] Description=Virtual Idol Automation Service After=network.target [Service] Type=simple User=idol_user WorkingDirectory=/home/idol_user/virtual_idol ExecStart=/usr/bin/python3 /home/idol_user/virtual_idol/master.py Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target ``` - `systemctl enable --now virtual_idol` 即可自動啟動。 2. **日誌**:使用 `journalctl -u virtual_idol -f` 觀察即時輸出。 3. **健康檢查**:可在 `cron` 內加入 `curl -s http://localhost:8000/health`(在 `master.py` 加一個簡易 FastAPI 健康端點),讓監控系統(如 Prometheus + Grafana)即時通知服務異常。 --- ## 7.7 常見問題與最佳實踐 | 問題 | 可能原因 | 解決方案 | |------|----------|----------| | **Bot 回覆延遲 > 5 秒** | LLM 請求超時、GPU 資源不夠 | 調整 `temperature`、使用 `max_tokens` 限制;升級 GPU 或使用雲端推理服務。 | | **OBS 音訊不同步** | Media Source 緩衝策略不當 | 在 OBS 設定 `Media Source` → `Restart playback when source becomes active` 並關閉 `Show nothing when playback ends`。 | | **Discord Bot 被限速** | 訊息過於頻繁、未加 Rate‑limit | 使用 `discord.ext.commands.CooldownMapping` 或自行在 `on_message` 加入時間戳檢查。 | | **TTS 音質失真** | LoRA 微調資料不足或過度擬合 | 擴充語音資料集至至少 **30 分鐘**,使用 **AdamW** 小學習率微調,並在訓練後使用 **EMA** 平滑模型。 | | **語意偏離角色設定** | Prompt 未明確限定角色語調 | 在每次 LLM 呼叫前加入 **System Prompt**:`You are star‑idol "星瀾" ...`,並使用 **function calling** 強制輸出 JSON。 | ### 7.7.1 安全與隱私 - **Token 管理**:所有 API 金鑰、Discord/Telegram Bot Token、OBS 密碼皆放置於環境變數或 **Vault**,不要硬編碼於程式。 - **頻率限制**:對外部 LLM / TTS 服務設定每日/每秒上限,防止意外帳單暴增。 - **資料合規**:若收集粉絲文字訊息做模型微調,必須取得明確同意並在隱私政策中說明用途。 --- ## 7.8 小結 本章提供了 **從概念腳本到全自動直播** 的完整技術藍圖,核心流程可概括為: 1. **LLM 產生結構化腳本**(Prompt Engineering + Function Calling)。 2. **情感化 SSML + LoRA‑VITS/TTS** 產出自然語音,或 DiffSinger 產出歌曲。 3. **OBS WebSocket** 讓音視訊自動切換、播放、特效同步。 4. **Discord / Telegram Bot** 捕捉粉絲即時訊息,回饋文字與語音,形成閉環互動。 5. **系統化部署**(systemd、健康檢查、日誌)確保 24/7 穩定運行。 透過本章的實作範例與最佳實踐,讀者即可在自己的虛擬偶像專案中快速建立 **自動化內容創作管線**,即使在高流量直播期間,也能保持即時、個性化且高品質的粉絲互動,為後續的 **品牌運營與商業變現** 打下堅實基礎。