wechat-translator-app / pages /index /index_v22_old.js
AKIRA
Finalize all local changes
b3b0b53
const plugin = requirePlugin("WechatSI");
const pluginManager = plugin.getRecordRecognitionManager(); // For CN/EN ASR
const nativeRecorderManager = wx.getRecorderManager(); // For JA/KO Recording
Page({
data: {
languages: {
'zh': { name: '中文', flag: 'cn', code: 'zh_CN', native: false },
'en': { name: 'English', flag: 'us', code: 'en_US', native: false },
'ja': { name: '日本語', flag: 'jp', code: 'ja_JP', native: true },
'ko': { name: '한국어', flag: 'kr', code: 'ko_KR', native: true }
},
langCodes: ['zh', 'en', 'ja', 'ko'],
sourceLang: 'zh',
targetLang: 'en',
transcript: '',
outputText: '',
isRecording: false,
sourceLanguages: [],
targetLanguages: [],
hfSpaceUrl: 'https://dazaozi-wechat-translator-app.hf.space',
currentManager: null // 'plugin' or 'native'
},
onLoad: function () {
this.initializeLanguages();
this.initPluginManager();
this.initNativeRecorderManager();
},
// --- 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);
},
// --- Manager Initializations ---
initPluginManager: function () {
pluginManager.onStart = () => this.setData({ transcript: '正在聆听 (插件)...', outputText: '' });
pluginManager.onRecognize = (res) => this.setData({ transcript: res.result });
pluginManager.onStop = (res) => {
this.setData({ isRecording: false });
if (!res.result) {
this.setData({ transcript: '识别结果为空', outputText: '' });
return;
}
this.setData({ transcript: res.result });
const { sourceLang, targetLang } = this.data;
const isChineseEnglishPair = (sourceLang === 'zh' || sourceLang === 'en') && (targetLang === 'zh' || targetLang === 'en');
if (isChineseEnglishPair) {
this.translateViaPlugin(res.result);
} else {
this.translateViaHfBridge(res.result, sourceLang, targetLang);
}
};
pluginManager.onError = (res) => this.setData({ isRecording: false, transcript: '插件识别失败', outputText: res.msg });
},
initNativeRecorderManager: function () {
nativeRecorderManager.onStart = () => this.setData({ transcript: '正在聆听 (原生)...', outputText: '' });
nativeRecorderManager.onStop = (res) => {
this.setData({ isRecording: false });
if (res.tempFilePath) {
this.uploadAudioForASR(res.tempFilePath);
} else {
this.setData({ transcript: '录音文件获取失败' });
}
};
nativeRecorderManager.onError = (res) => this.setData({ isRecording: false, transcript: '原生录音失败', outputText: res.errMsg });
},
// --- Recording Logic ---
startRecording: function () {
const { sourceLang, languages } = this.data;
const shouldUseNative = languages[sourceLang].native;
this.setData({ isRecording: true, currentManager: shouldUseNative ? 'native' : 'plugin' });
if (shouldUseNative) {
nativeRecorderManager.start({ format: 'mp3', sampleRate: 16000, numberOfChannels: 1 });
} else {
pluginManager.start({ lang: languages[sourceLang].code, translate: false });
}
},
stopRecording: function () {
if (this.data.currentManager === 'native') {
nativeRecorderManager.stop();
} else {
pluginManager.stop();
}
},
// --- Translation Flows ---
translateViaPlugin: function(text) {
const { sourceLang, targetLang, languages } = this.data;
if (sourceLang === targetLang) {
this.setData({ outputText: text });
return;
}
this.setData({ outputText: '翻译中 (插件)...' });
plugin.translate({
lfrom: languages[sourceLang].code,
lto: languages[targetLang].code,
content: text,
success: (res) => {
if (res.retcode === 0) {
this.setData({ outputText: res.result });
} else {
this.setData({ outputText: '插件翻译失败' });
}
},
fail: () => this.setData({ outputText: '插件翻译接口调用失败' })
});
},
uploadAudioForASR: function (filePath) {
this.setData({ transcript: '正在识别 (HF)...' });
wx.getFileSystemManager().readFile({
filePath,
encoding: 'base64',
success: (res) => {
wx.request({
url: `${this.data.hfSpaceUrl}/api/asr`,
method: 'POST',
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 });
this.translateViaHfBridge(transcript, this.data.sourceLang, this.data.targetLang);
} else {
this.setData({ transcript: 'HF识别失败', outputText: asrRes.data.error || '' });
}
},
fail: () => this.setData({ transcript: 'HF识别请求失败' })
});
},
fail: () => this.setData({ transcript: '读取录音文件失败' })
});
},
translateViaHfBridge: function(text, source, target) {
this.setData({ outputText: '翻译中 (HF)...' });
if (source === target) {
this.setData({ outputText: text });
return;
}
this.translateViaHF(text, source, target, (result) => {
if (result) {
this.setData({ outputText: result });
}
// Error message is set within translateViaHF
});
},
translateViaHF: function(text, sourceLang, targetLang, callback) {
wx.request({
url: `${this.data.hfSpaceUrl}/api/translate`,
method: 'POST',
data: { "text": text, "source_lang": sourceLang, "target_lang": targetLang },
timeout: 45000,
success: (res) => {
if (res.statusCode === 200 && res.data.translated_text) {
callback(res.data.translated_text);
} else {
const errorMsg = res.data.error || `HF翻译失败`;
this.setData({ outputText: errorMsg });
callback(null);
}
},
fail: () => {
this.setData({ outputText: `HF翻译请求失败` });
callback(null);
}
});
}
});