Spaces:
Sleeping
Sleeping
| const plugin = requirePlugin("WechatSI"); | |
| const manager = plugin.getRecordRecognitionManager(); // Only one manager | |
| Page({ | |
| data: { | |
| languages: { | |
| 'zh': { name: '中文', flag: 'cn', code: 'zh_CN' }, | |
| 'en': { name: 'English', flag: 'us', code: 'en_US' }, | |
| 'ja': { name: '日本語', flag: 'jp', code: 'ja_JP' }, | |
| 'ko': { name: '한국어', flag: 'kr', code: 'ko_KR' } | |
| }, | |
| langCodes: ['zh', 'en', 'ja', 'ko'], // Use short codes for internal logic | |
| sourceLang: 'zh', | |
| targetLang: 'en', | |
| transcript: '', | |
| outputText: '', | |
| isRecording: false, | |
| sourceLanguages: [], | |
| targetLanguages: [], | |
| hfSpaceUrl: 'https://dazaozi-wechat-translator-app.hf.space' | |
| }, | |
| onLoad: function () { | |
| this.initializeLanguages(); | |
| this.initRecordManager(); | |
| }, | |
| // --- Language Selection Logic --- | |
| initializeLanguages: function () { | |
| const { langCodes, languages, sourceLang, targetLang } = this.data; | |
| this.setData({ | |
| sourceLanguages: langCodes.map(c => ({ | |
| langCode: c, | |
| name: languages[c].name, | |
| flag: languages[c].flag, | |
| selected: c === sourceLang | |
| })), | |
| targetLanguages: langCodes.map(c => ({ | |
| langCode: c, | |
| name: languages[c].name, | |
| flag: languages[c].flag, | |
| selected: c === targetLang | |
| })) | |
| }); | |
| }, | |
| selectSourceLanguage: function (e) { | |
| const newSourceLang = e.currentTarget.dataset.langCode; | |
| this.setData({ sourceLang: newSourceLang }, this.initializeLanguages); | |
| }, | |
| selectTargetLanguage: function (e) { | |
| const newTargetLang = e.currentTarget.dataset.langCode; | |
| this.setData({ targetLang: newTargetLang }, this.initializeLanguages); | |
| }, | |
| swapLanguages: function () { | |
| const { sourceLang, targetLang } = this.data; | |
| this.setData({ | |
| sourceLang: targetLang, | |
| targetLang: sourceLang, | |
| transcript: this.data.outputText, | |
| outputText: this.data.transcript | |
| }, this.initializeLanguages); | |
| }, | |
| // --- Recorder Manager Initialization (Single Manager Mode) --- | |
| initRecordManager: function () { | |
| manager.onStart = () => { | |
| this.setData({ transcript: '正在聆听...', outputText: '' }); | |
| }; | |
| manager.onRecognize = (res) => { | |
| // Only update transcript for plugin-handled ASR (CN/EN) | |
| const { sourceLang } = this.data; | |
| if (sourceLang === 'zh' || sourceLang === 'en') { | |
| this.setData({ transcript: res.result }); | |
| } | |
| }; | |
| manager.onStop = (res) => { | |
| this.setData({ isRecording: false }); | |
| const { sourceLang, targetLang } = this.data; | |
| const isChineseEnglish = (sourceLang === 'zh' && targetLang === 'en') || (sourceLang === 'en' && targetLang === 'zh'); | |
| if (isChineseEnglish) { | |
| // Mode 1: Plugin handles both ASR and Translation | |
| if (res.result) { | |
| this.setData({ transcript: res.result, outputText: res.translateResult || '' }); | |
| } else { | |
| this.setData({ transcript: '识别结果为空', outputText: '' }); | |
| } | |
| } else { | |
| // Mode 2: Plugin handles ASR (if CN/EN), then HF handles translation | |
| if (res.result) { // res.result is the ASR result from plugin | |
| this.setData({ transcript: res.result }); | |
| this.fullBackendBridge(res.result, this.data.sourceLang, this.data.targetLang); | |
| } else { | |
| this.setData({ transcript: '识别结果为空' }); | |
| } | |
| } | |
| }; | |
| manager.onError = (res) => { | |
| this.setData({ isRecording: false, transcript: '识别失败', outputText: res.msg }); | |
| }; | |
| }, | |
| startRecording: function () { | |
| const { sourceLang, targetLang } = this.data; | |
| const isChineseEnglish = (sourceLang === 'zh' && targetLang === 'en') || (sourceLang === 'en' && targetLang === 'zh'); | |
| this.setData({ isRecording: true }); | |
| // CRITICAL: Check if source language is supported by plugin for ASR | |
| if (sourceLang !== 'zh' && sourceLang !== 'en') { | |
| wx.showToast({ | |
| title: '当前源语言不支持语音输入', | |
| icon: 'none' | |
| }); | |
| this.setData({ isRecording: false, transcript: '请选择中文或英文作为源语言' }); | |
| return; | |
| } | |
| if (isChineseEnglish) { | |
| // Use plugin for ASR and Translation | |
| manager.start({ | |
| lang: this.data.languages[sourceLang].code, | |
| trans_lang: this.data.languages[targetLang].code, | |
| }); | |
| } else { | |
| // Use plugin for ASR only, then HF for translation | |
| manager.start({ | |
| lang: this.data.languages[sourceLang].code, | |
| // No trans_lang here, as HF will handle translation | |
| }); | |
| } | |
| }, | |
| stopRecording: function () { | |
| manager.stop(); | |
| }, | |
| // --- HF Bridge Translation Flow (for non-CN/EN pairs) --- | |
| fullBackendBridge: function(text, sourceLang, targetLang) { | |
| this.setData({ outputText: '翻译中 (1/2)..' }); // Simplified steps | |
| // Step 1: Translate source (e.g., ZH) to English via HF | |
| this.translateViaHF(text, sourceLang, 'en', (englishResult) => { | |
| if (englishResult) { | |
| // Step 2: Translate English result to final target (e.g., JA) via HF | |
| this.setData({ outputText: '翻译中 (2/2)..' }); | |
| this.translateViaHF(englishResult, 'en', targetLang, (finalResult) => { | |
| if (finalResult) { | |
| this.setData({ outputText: finalResult }); | |
| } | |
| }); | |
| } | |
| }); | |
| }, | |
| translateViaHF: function(text, sourceLang, targetLang, callback) { | |
| wx.request({ | |
| url: `${this.data.hfSpaceUrl}/api/translate`, | |
| method: 'POST', | |
| header: { 'Content-Type': 'application/json' }, | |
| data: { "text": text, "source_lang": sourceLang, "target_lang": targetLang }, | |
| timeout: 30000, | |
| success: (res) => { | |
| if (res.statusCode === 200 && res.data.translated_text) { | |
| callback(res.data.translated_text); | |
| } else { | |
| this.setData({ outputText: `HF翻译失败 (${sourceLang}->${targetLang})` }); | |
| callback(null); | |
| } | |
| }, | |
| fail: () => { | |
| this.setData({ outputText: `HF翻译请求失败 (${sourceLang}->${targetLang})` }); | |
| callback(null); | |
| } | |
| }); | |
| } | |
| }); |