AKIRA
Finalize all local changes
b3b0b53
raw
history blame
7.31 kB
const plugin = requirePlugin('WechatSI');
const innerAudioContext = wx.createInnerAudioContext();
const pluginManager = plugin.getRecordRecognitionManager();
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'],
sourceLang: 'zh',
targetLang: 'en',
transcript: '',
outputText: '',
isRecording: false,
sourceLanguages: [],
targetLanguages: [],
hfSpaceUrl: 'https://dazaozi-wechat-translator-app.hf.space',
currentRecordMode: '' // 'plugin' or 'custom'
},
onLoad: function () {
this.initializeLanguages();
this.customRecorderManager = wx.getRecorderManager();
this.initCustomRecorderManager();
this.initPluginRecorderManager();
},
// --- Language Selection Logic ---
initializeLanguages: function () {
const { langCodes, languages, sourceLang, targetLang } = this.data;
this.setData({
sourceLanguages: langCodes.map(c => ({ ...languages[c], langCode: c, selected: c === sourceLang })),
targetLanguages: langCodes.map(c => ({ ...languages[c], langCode: c, selected: c === targetLang }))
});
},
selectSourceLanguage: function(e) { this.setData({ sourceLang: e.currentTarget.dataset.langCode }, this.initializeLanguages); },
selectTargetLanguage: function(e) { this.setData({ targetLang: e.currentTarget.dataset.langCode }, this.initializeLanguages); },
swapLanguages: function() {
this.setData({
sourceLang: this.data.targetLang,
targetLang: this.data.sourceLang,
transcript: this.data.outputText,
outputText: this.data.transcript
}, this.initializeLanguages);
},
// --- Recording Logic ---
startRecording: function () {
const { sourceLang, targetLang } = this.data;
const isChineseEnglish = (sourceLang === 'zh' && targetLang === 'en') || (sourceLang === 'en' && targetLang === 'zh');
this.setData({ isRecording: true, transcript: '正在聆听...', outputText: '' });
if (isChineseEnglish) {
this.setData({ currentRecordMode: 'plugin' });
pluginManager.start({ lang: this.data.languages[sourceLang].code, translate: true, lto: this.data.languages[targetLang].code });
} else {
this.setData({ currentRecordMode: 'custom' });
this.customRecorderManager.start({ duration: 60000, sampleRate: 16000, numberOfChannels: 1, encodeBitRate: 96000, format: 'mp3' });
}
},
stopRecording: function () {
if (this.data.currentRecordMode === 'plugin') {
pluginManager.stop();
} else if (this.data.currentRecordMode === 'custom') {
this.customRecorderManager.stop();
}
this.setData({ isRecording: false });
},
// --- Result Handlers ---
initPluginRecorderManager: function() {
pluginManager.onRecognize = (res) => {
this.setData({ transcript: res.result });
};
// CORRECTED: Use onTranslate to get translation results
pluginManager.onTranslate = (res) => {
this.setData({ outputText: res.result });
};
pluginManager.onStop = (res) => {
this.setData({ transcript: res.result, outputText: res.translateResult });
};
pluginManager.onError = (res) => {
this.setData({ transcript: '微信插件识别失败', outputText: res.msg });
};
},
initCustomRecorderManager: function() {
this.customRecorderManager.onStop = (res) => {
if (res.tempFilePath) {
this.uploadAudioForASR(res.tempFilePath);
} else { this.setData({ transcript: '录音文件创建失败' }); }
};
this.customRecorderManager.onError = () => {
this.setData({ transcript: '语音识别出错' });
};
},
// --- Custom Translation Flow (for non-CN/EN pairs) ---
uploadAudioForASR: function (filePath) {
this.setData({ transcript: '正在识别 (1/3)...' });
const fileSystemManager = wx.getFileSystemManager();
fileSystemManager.readFile({ filePath, encoding: 'base64', success: (res) => {
wx.request({
url: `${this.data.hfSpaceUrl}/api/asr`,
method: 'POST',
header: { 'Content-Type': 'application/json' },
data: { "audio_data_uri": `data:audio/mp3;base64,${res.data}` },
timeout: 60000,
success: (asrRes) => {
if (asrRes.statusCode === 200 && asrRes.data.transcript) {
const transcript = asrRes.data.transcript;
this.setData({ transcript });
// Start the full-backend translation bridge
this.fullBackendBridge(transcript, this.data.sourceLang, this.data.targetLang);
} else { this.setData({ transcript: 'HF识别失败' }); }
},
fail: () => { this.setData({ transcript: 'HF识别请求失败' }); }
});
}});
},
fullBackendBridge: function(text, sourceLang, targetLang) {
// Step 1: Translate source (e.g., JA) to English via HF
this.setData({ outputText: '翻译中 (2/3)..' });
this.translateViaHF(text, sourceLang, 'en', (englishResult) => {
if (englishResult) {
// Step 2: Translate English result to final target (e.g., ZH) via HF
this.setData({ outputText: '翻译中 (3/3)..' });
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) {
if (callback) {
callback(res.data.translated_text);
} else {
this.setData({ outputText: res.data.translated_text });
}
} else {
this.setData({ outputText: `HF翻译失败 (${sourceLang}->${targetLang})` });
if (callback) callback(null); // Signal failure
}
},
fail: () => {
this.setData({ outputText: `HF翻译请求失败 (${sourceLang}->${targetLang})` });
if (callback) callback(null); // Signal failure
}
});
}
});