File size: 8,043 Bytes
b3b0b53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
const plugin = requirePlugin("WechatSI");
const pluginManager = plugin.getRecordRecognitionManager();
const nativeRecorderManager = wx.getRecorderManager();

Page({
    data: {
        languages: {
            'zh': { name: '中文', flag: 'cn', code: 'zh_CN', usePlugin: true },
            'en': { name: 'English', flag: 'us', code: 'en_US', usePlugin: true },
            'ja': { name: '日本語', flag: 'jp', code: 'ja_JP', usePlugin: false },
            'ko': { name: '한국어', flag: 'kr', code: 'ko_KR', usePlugin: false }
        },
        langCodes: ['zh', 'en', 'ja', 'ko'],
        sourceLang: 'zh',
        targetLang: 'en',
        transcript: '',
        outputText: '',
        isRecording: false,
        hfSpaceUrl: 'https://dazaozi-wechat-translator-app.hf.space',
        currentManagerType: null // 'plugin' or 'native'
    },

    onLoad: function () {
        this.initializeLanguages();
        this.initPluginManager();
        this.initNativeRecorderManager();
    },

    // --- Language Selection Logic (Simplified) ---
    initializeLanguages: function () {
        const { languages, sourceLang, targetLang } = this.data;
        this.setData({
            sourceLanguages: Object.keys(languages).map(key => ({ ...languages[key], langCode: key, selected: key === sourceLang })),
            targetLanguages: Object.keys(languages).map(key => ({ ...languages[key], langCode: key, selected: key === 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 with Detailed Error Logging ---
    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) { return this.setData({ transcript: '识别结果为空' }); }
            this.setData({ transcript: res.result });
            const { sourceLang, targetLang } = this.data;
            const isPluginTarget = this.data.languages[targetLang].usePlugin;
            if (isPluginTarget) {
                this.translateViaPlugin(res.result);
            } else {
                this.translateViaHfBridge(res.result, sourceLang, targetLang);
            }
        };
        pluginManager.onError = (res) => this.setData({ isRecording: false, transcript: `插件错误: ${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: `原生录音失败: ${res.errMsg}` });
    },

    // --- Main Record Button Handler ---
    handleRecordToggle: function() {
        if (this.data.isRecording) {
            this.stopRecording();
            return;
        }
        // Check permissions before starting a new recording
        wx.getSetting({
            success: (res) => {
                if (!res.authSetting['scope.record']) {
                    wx.authorize({
                        scope: 'scope.record',
                        success: this.startRecording,
                        fail: () => wx.showToast({ title: '您拒绝了录音权限', icon: 'none' })
                    });
                } else {
                    this.startRecording();
                }
            },
            fail: () => wx.showToast({ title: '无法获取权限设置', icon: 'none' })
        });
    },

    startRecording: function () {
        const { sourceLang, languages } = this.data;
        const shouldUsePlugin = languages[sourceLang].usePlugin;
        const managerType = shouldUsePlugin ? 'plugin' : 'native';

        this.setData({ isRecording: true, currentManagerType: managerType });

        if (shouldUsePlugin) {
            pluginManager.start({ lang: languages[sourceLang].code, translate: false });
        } else {
            nativeRecorderManager.start({ format: 'mp3', sampleRate: 16000, numberOfChannels: 1 });
        }
    },

    stopRecording: function () {
        if (this.data.currentManagerType === 'native') {
            nativeRecorderManager.stop();
        } else {
            pluginManager.stop();
        }
    },

    // --- Translation Logic ---
    translateViaPlugin: function(text) {
        const { sourceLang, targetLang, languages } = this.data;
        if (sourceLang === targetLang) { return this.setData({ outputText: text }); }
        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: `插件翻译失败: ${res.retcode}` }); }
            },
            fail: (err) => 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识别请求失败' })
            });
        }});
    },

    translateViaHfBridge: function(text, source, target) {
        if (source === target) { return this.setData({ outputText: text }); }
        this.setData({ outputText: '翻译中 (HF)...' });
        this.translateViaHF(text, source, target, (result) => {
            if (result) { this.setData({ outputText: result }); }
        });
    },

    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 { this.setData({ outputText: `HF翻译失败: ${res.data.error || '未知错误'}` }); callback(null); }
            },
            fail: () => { this.setData({ outputText: 'HF翻译请求失败' }); callback(null); }
        });
    }
});