ai_co_discuss 0.3.49 → 0.3.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/runner/tts_providers.mjs +9 -5
- package/web/modern.css +1 -1
- package/web/modern.js +833 -775
package/package.json
CHANGED
package/runner/tts_providers.mjs
CHANGED
|
@@ -17,6 +17,8 @@ const VOLC_MESSAGES = {
|
|
|
17
17
|
};
|
|
18
18
|
const ALIYUN_SOCKET = 'wss://dashscope.aliyuncs.com/api-ws/v1/inference';
|
|
19
19
|
const ALIYUN_MODEL = 'cosyvoice-v3-flash';
|
|
20
|
+
// Its default answered 160 kbps (measured 2026-11-04); 64 kbps (8 KB/s, as Volcengine) keeps a 300-character answer under the 1 MiB relay limit.
|
|
21
|
+
const ALIYUN_BIT_RATE = 64;
|
|
20
22
|
// Aliyun and Azure answer 24 kHz mono MP3, so trailing silence is appended as silent frames of that format.
|
|
21
23
|
const SAMPLE_RATE = 24000;
|
|
22
24
|
// One silent MPEG-2 Layer III frame (24 kHz, 32 kbps, mono): a header and zeroed side info, 576 samples = 24 ms.
|
|
@@ -64,13 +66,13 @@ const voices = (list) => list.map(([id, label]) => ({ id, label }));
|
|
|
64
66
|
*/
|
|
65
67
|
export const TTS_PROVIDERS = [
|
|
66
68
|
{ id: 'volcengine', label: '火山引擎', key_base_url: 'https://openspeech.bytedance.com', console_url: 'https://console.volcengine.com/speech/new',
|
|
67
|
-
note: '
|
|
69
|
+
note: '约 3 元/万字,语音输入共用此 Key', voices: voices(VOLC_VOICES),
|
|
68
70
|
default_speaker: 'zh_female_vv_uranus_bigtts', context: true, region: false, voice_input: true },
|
|
69
71
|
{ id: 'aliyun', label: '阿里云百炼', key_base_url: 'https://dashscope.aliyuncs.com', console_url: 'https://bailian.console.aliyun.com/?tab=model#/api-key',
|
|
70
|
-
note: '
|
|
72
|
+
note: '约 2 元/万字(汉字计 2 字符)', voices: voices(ALIYUN_VOICES),
|
|
71
73
|
default_speaker: 'longxiaochun_v3', context: false, region: false, voice_input: false },
|
|
72
74
|
{ id: 'azure', label: 'Azure', key_base_url: 'https://tts.speech.microsoft.com', console_url: 'https://portal.azure.com/#create/Microsoft.CognitiveServicesSpeechServices',
|
|
73
|
-
note: '
|
|
75
|
+
note: '每月免费约 25 万字,超出约 2 元/万字', voices: voices(AZURE_VOICES),
|
|
74
76
|
default_speaker: 'zh-CN-XiaoxiaoNeural', context: false, region: true, voice_input: false },
|
|
75
77
|
];
|
|
76
78
|
|
|
@@ -147,14 +149,16 @@ function aliyun_speak({ key, text, speaker, rate, silence }, open) {
|
|
|
147
149
|
const finish = (error, value) => {
|
|
148
150
|
if (settled) return;
|
|
149
151
|
settled = true; clearTimeout(timer);
|
|
150
|
-
|
|
152
|
+
// A close without a status code is never answered by the service, which then holds the connection open.
|
|
153
|
+
try { socket.close(1000); } catch { /* Already closed. */ }
|
|
151
154
|
if (error) reject(error); else resolve(value);
|
|
152
155
|
};
|
|
153
156
|
const timer = setTimeout(() => finish(new Error('语音合成请求超时,请检查网络后重试')), TTS_TIMEOUT_MS);
|
|
154
157
|
const send = (action, payload) => socket.send(JSON.stringify({ header: { action, task_id, streaming: 'duplex' }, payload }));
|
|
155
158
|
socket.binaryType = 'arraybuffer';
|
|
156
159
|
socket.onopen = () => send('run-task', { task_group: 'audio', task: 'tts', function: 'SpeechSynthesizer', model: ALIYUN_MODEL, input: {},
|
|
157
|
-
parameters: { text_type: 'PlainText', voice: speaker, format: 'mp3', sample_rate: SAMPLE_RATE, rate: 1 + rate / 100,
|
|
160
|
+
parameters: { text_type: 'PlainText', voice: speaker, format: 'mp3', sample_rate: SAMPLE_RATE, bit_rate: ALIYUN_BIT_RATE, rate: 1 + rate / 100,
|
|
161
|
+
word_timestamp_enabled: true } });
|
|
158
162
|
socket.onmessage = ({ data }) => {
|
|
159
163
|
if (typeof data !== 'string') { chunks.push(Buffer.from(data)); return; }
|
|
160
164
|
const { header = {}, payload = {} } = JSON.parse(data);
|