P/
PromptTools
選單
資產庫
指令組合
產生指令包
管理資料
Skill asset
編輯 Skill
Skill 是完整資料夾資產;建立後可逐一加入腳本、參考文件、範本、圖片與子資料夾。
Skill 名稱
唯一代稱
簡短說明
主要分類
未分類
標籤
SKILL.md
五種工具預設適用
--- name: gemini-live-translation description: 即時語音翻譯技能包:利用 Gemini 3.5 Live 模型進行雙面板即時翻譯,含聲波視覺化、解耦的模組化架構、支援多語言。 --- # Gemini Live 即時語音翻譯技能 完全解耦、可重複使用的 ASP.NET Web Forms 實作,提供 **Gemini 3.5 Live 實時翻譯** + **可視化聲波** + **多語言支援**。 ## 功能 - **雙面板即時翻譯**:原文(左)→ 翻譯結果(右) - **聲波視覺化**:實時麥克風音量條形圖與語音活動檢測 - **完全解耦的模組設計**:核心引擎無 DOM 依賴,可獨立測試與重複使用 - **多語言自動偵測**:源語言自動識別;目標語言可切換 - **傳統中文翻譯修正**:確保繁體中文(zh-TW)輸出,非簡體 - **透明的錯誤處理**:後台令牌更新失敗無告示,翻譯持續進行 ## 模組架構 ### 核心層(零 DOM) | 模組 | 職責 | 備註 | |------|------|------| | `gemini-live-core.js` | 事件驅動引擎:token 取得、WebSocket、音訊擷取、重連 | 完全無 DOM 依賴,可注入配置 | | `gemini-live-audio-utils.js` | 純函數音訊工具:重採樣、PCM 轉換、Base64 編碼 | 已有單元測試 (tests/audio-utils.test.js) | | `gemini-live-audio-worklet.js` | Web Audio Worklet:麥克風 PCM 捕捉(16 kHz) | 在主線程外執行,無干擾 | ### 視覺化層 | 模組 | 職責 | 備註 | |------|------|------| | `gemini-live-waveform.js` | 獨立的聲波條形圖/曲線渲染器 | 可選擇性掛接;0 依賴 | ### UI 適配器層 | 模組 | 職責 | 備註 | |------|------|------| | `gemini-live-client.js` | DOM 綁定、事件訂閱、caption 轉譯 | 薄層;所有業務邏輯在 core 中 | ### 後端層 | 檔案 | 職責 | |------|------| | `App_Code/GeminiLiveOptions.cs` | 配置管理(API 金鑰、模型、token 有效期)| | `App_Code/GeminiLiveLanguages.cs` | 語言註冊表(BCP-47 碼 + Gemini API 碼映射)| | `App_Code/GeminiLiveTokenService.cs` | 短期令牌生成、翻譯配置嵌入 | | `Api/GeminiLiveToken.ashx.cs` | HTTP token 端點 | | `Content/gemini-live.css` | 雙面板 + 聲波樣式 | ## 整合步驟 ### 1. 複製檔案到專案 ``` 你的 ASP.NET Web Forms 專案 ├── Scripts/ │ ├── gemini-live-audio-utils.js │ ├── gemini-live-audio-worklet.js │ ├── gemini-live-waveform.js │ ├── gemini-live-core.js │ └── gemini-live-client.js ├── App_Code/ │ ├── GeminiLiveOptions.cs │ ├── GeminiLiveLanguages.cs │ └── GeminiLiveTokenService.cs ├── Api/ │ ├── GeminiLiveToken.ashx │ └── GeminiLiveToken.ashx.cs ├── Content/ │ └── gemini-live.css └── (你的頁面) └── LiveTranscription.aspx / .aspx.cs ``` 所有檔案使用 **UTF-8 with BOM** 編碼(尤其是包含中文的 `.cs` 檔,PowerShell 7 的 `Out-File -Encoding utf8` 可能不產出 BOM,需用 `System.Text.UTF8Encoding($true)` 確保檔首為 `EF BB BF`)。 ### 2. Web.config 配置 ```xml <configuration> <appSettings> <!-- Gemini Live 設定 --> <add key="GeminiLive.ApiKey" value="YOUR_GEMINI_API_KEY_HERE" /> <add key="GeminiLive.Model" value="gemini-3.5-live-translate-preview" /> <add key="GeminiLive.TokenUses" value="2" /> <add key="GeminiLive.TokenExpireMinutes" value="30" /> <add key="GeminiLive.NewSessionExpireMinutes" value="5" /> <add key="GeminiLive.RequireAuthenticatedUser" value="false" /> <add key="GeminiLive.ShowTokenErrors" value="false" /> </appSettings> </configuration> ``` ### 3. ASPX 頁面標記 ```html <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="LiveTranscription.aspx.cs" Inherits="YourNamespace.LiveTranscription" %> <!DOCTYPE html> <html lang="zh-Hant"> <head runat="server"> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>即時語音翻譯</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" /> <link href="Content/gemini-live.css" rel="stylesheet" /> </head> <body> <form id="form1" runat="server"> <main class="container py-4"> <section class="live-shell"> <header class="live-header"> <div class="live-header-titles"> <h1 class="live-title">即時語音翻譯</h1> <div class="live-status"> <span id="statusDot" class="status-dot"></span> <span id="connectionStatus">尚未連線</span> </div> </div> <div class="live-actions"> <button id="btnStart" type="button" class="btn btn-primary btn-lg"> <span class="btn-icon">●</span> 開始 </button> <button id="btnStop" type="button" class="btn btn-outline-secondary btn-lg" disabled> 停止 </button> </div> </header> <div class="language-bar"> <div class="language-field"> <label for="sourceLanguage">偵測語言(說話)</label> <select id="sourceLanguage" class="form-select"></select> </div> <div class="language-arrow" aria-hidden="true">→</div> <div class="language-field"> <label for="targetLanguage">翻譯語言(輸出)</label> <select id="targetLanguage" class="form-select"></select> </div> </div> <div id="systemNotice" class="alert alert-warning py-2 d-none" role="status"></div> <!-- 聲波視覺化容器 --> <div id="waveformWrap" class="waveform-wrap d-none"> <span class="waveform-mic" aria-hidden="true">🎙</span> <canvas id="waveform" class="waveform-canvas" aria-label="語音聲波"></canvas> </div> <!-- 雙面板字幕區域 --> <div class="caption-grid"> <div class="caption-col caption-col--source"> <div class="caption-col-head"> <span class="caption-badge">原文</span> <span id="sourceLangLabel" class="caption-lang">-</span> </div> <div id="sourcePanel" class="caption-panel" aria-live="polite"> <div id="sourceFinal" class="caption-final"></div> <div id="sourceInterim" class="caption-interim"></div> <div id="sourcePlaceholder" class="caption-placeholder">等待語音輸入…</div> </div> </div> <div class="caption-col caption-col--target"> <div class="caption-col-head"> <span class="caption-badge caption-badge--target">翻譯</span> <span id="targetLangLabel" class="caption-lang">-</span> </div> <div id="targetPanel" class="caption-panel" aria-live="polite"> <div id="targetFinal" class="caption-final"></div> <div id="targetInterim" class="caption-interim"></div> <div id="targetPlaceholder" class="caption-placeholder">翻譯結果將顯示於此…</div> </div> </div> </div> </section> </main> </form> <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> <script src="Scripts/gemini-live-audio-utils.js"></script> <script src="Scripts/gemini-live-waveform.js"></script> <script src="Scripts/gemini-live-core.js"></script> <script src="Scripts/gemini-live-client.js"></script> </body> </html> ``` ### 4. Code-Behind (LiveTranscription.aspx.cs) ```csharp using System; using System.Collections.Generic; using System.Web.Script.Serialization; using System.Web.UI; namespace YourNamespace { public partial class LiveTranscription : Page { protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { RegisterLiveConfigScript(); } } private void RegisterLiveConfigScript() { var languages = GeminiLiveLanguages.All; var langList = new List<object>(); foreach (var lang in languages) { langList.Add(new { code = lang.Code, displayName = lang.DisplayName }); } var serializer = new JavaScriptSerializer(); var config = new { csrfToken = GetCsrfToken(), languages = langList, defaultSourceLanguage = "auto", defaultTargetLanguage = "zh-Hant" }; var json = serializer.Serialize(config); var script = string.Format( "window.GeminiLiveConfig = {0};", json ); ClientScript.RegisterClientScriptBlock( GetType(), "GeminiLiveConfig", script, addScriptTags: true ); } private string GetCsrfToken() { const string TokenKey = "GeminiLiveCsrfToken"; var token = Session[TokenKey] as string; if (string.IsNullOrEmpty(token)) { token = Guid.NewGuid().ToString(); Session[TokenKey] = token; } return token; } } } ``` ## 模組自訂與擴展 ### 自訂聲波外觀 ```javascript // 在 gemini-live-client.js 之前插入 <script> // 自訂聲波顏色與樣式 window.GeminiLiveWaveformConfig = { style: 'line', // 'bars' | 'line' color: '#ff6b6b', idleColor: '#ccc', activityThreshold: 0.04 }; </script> ``` ### 自訂語言清單 在 `App_Code/GeminiLiveLanguages.cs` 中編輯 `GetAll()` 方法,新增或移除語言項。確認 API 碼對應正確(中文例:`zh-Hant` → `zh-TW`;`zh-Hans` → `zh-CN`)。 ### 監聽核心事件(無 UI 依賴) ```javascript // 可在任何地方訂閱 core 事件,無需 DOM: var core = window.GeminiLiveClient.core; core.on('source', function(e) { console.log('Source text:', e.text, 'Final:', e.final); }); core.on('audionode', function(e) { // 掛接自訂的音訊分析器 var analyser = e.audioContext.createAnalyser(); e.node.connect(analyser); }); ``` ## 故障排除 | 問題 | 原因 | 解決 | |------|------|------| | "只有 Content 控制項…" 錯誤 | ASPX 檔 BOM 不正確或編碼非 UTF-8 | 確保檔首 3 byte 為 `EF BB BF`(UTF-8 BOM) | | 翻譯為簡體中文 | targetLanguageCode 使用 script tag(zh-Hant)而非 API 碼(zh-TW) | API 層自動映射;檢查 GeminiLiveLanguages.cs 的 ApiCode | | "憑證刷新失敗" 告示 | 非致命的背景令牌更新失敗 | 已修正:現在默默記錄;翻譯持續進行 | | 無聲音輸入 | 麥克風權限拒絕或 AudioContext 未就緒 | 檢查瀏覽器麥克風權限;確保 https 或 localhost | ## 技術細節 ### 令牌流程 1. `POST /Api/GeminiLiveToken.ashx` → 後端驗證 CSRF、語言選項 2. `GeminiLiveTokenService.CreateTokenAsync()` 構建 `translationConfig` 嵌入 `generationConfig` 3 REST POST 到 Google 獲得短期 token(~30 分鐘) 4. WebSocket URL:`wss://...?access_token={token}` **關鍵**:`translationConfig` 必須在 `generationConfig` **內部**,並使用 API 碼(zh-TW/zh-CN),非 BCP-47 script tag。 ### 音訊管線 ``` 麥克風 → MediaStreamAudioSourceNode → AudioWorklet (gemini-live-audio-worklet.js) ↓ 16 kHz PCM 1600-sample 塊 ↓ floatTo16BitPcmBytes ↓ bytesToBase64 ↓ WebSocket realtimeInput.audio ``` 視覺化可插接 `MediaStreamAudioSourceNode` 無阻礙捕捉(Analyser 不消耗信號)。 ### 重連與恢復 - 異常斷線 → 指數退避重試(基數 300ms,最多 10 秒 + 隨機 0-300ms) - 短期令牌消耗 → 自動重新取得 - 目標語言變更 → 令牌失效,重新連線 - `sessionResumption` 句柄:如支援,自動恢復上下文 ## 安全考量 - **API 金鑰**:存放在 Web.config appSetting,不外洩至客戶端 - **CSRF token**:Session-based,每次令牌請求驗證 - **認證**:可配置 `RequireAuthenticatedUser` 強制登入 - **錯誤揭露**:`ShowTokenErrors` 控制錯誤細節洩漏程度 ## 授權與許可 此技能包提供的程式碼模板供 ASP.NET Web Forms 應用整合 Gemini Live API 之用。使用本技能包時,確保: 1. 遵守 Google Gemini API 的服務條款 2. 獲得使用者麥克風與地理位置的明確同意 3. 在隱私政策中揭露音訊處理方式 ## 變更歷史 | 版本 | 日期 | 變更 | |------|------|------| | 1.0 | 2024-Jan | 初版:解耦架構、聲波視覺化、傳統中文修正 | --- **下一步**:複製 `assets/` 內的檔案至你的專案,按上述步驟整合,編譯並測試。如有問題,檢查 Web.config 配置與檔案編碼。
必須包含 YAML frontmatter 的 name 與 description。
修改說明
保存完整 Skill 版本
取消