feat: migrate TTS generation to frontend to utilize local browser proxy

This commit is contained in:
2026-08-01 11:55:31 +08:00
parent 1d0c0e0703
commit 5e600bb75d
3 changed files with 121 additions and 45 deletions
+48 -40
View File
@@ -857,14 +857,48 @@
}
async function _generateSingleTTS(text, reference_id) {
const res = await fetch('/api/tts/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text, reference_id, model: TTS_MODEL })
});
const data = await res.json();
if (!data.success) throw new Error(data.message);
return data;
try {
// Client-side fetch to use local browser's proxy
const fishRes = await fetch('https://api.fish.audio/v1/tts', {
method: 'POST',
headers: {
'Authorization': 'Bearer 233f3a9bcc204b20a1979d59d33cc649',
'Content-Type': 'application/json'
},
body: JSON.stringify({
text: text,
reference_id: reference_id,
model: TTS_MODEL,
format: "wav"
})
});
if (!fishRes.ok) {
let msg = 'Fish Audio API Error';
try { msg = await fishRes.text(); } catch(e){}
throw new Error(`[${fishRes.status}] ${msg}`);
}
const audioBlob = await fishRes.blob();
// Upload the blob to the server as a temporary file
const formData = new FormData();
formData.append('audio', audioBlob, 'temp.wav');
const uploadRes = await fetch('/api/tts/upload_temp', {
method: 'POST',
body: formData
});
const data = await uploadRes.json();
if (!data.success) throw new Error(data.message);
return data;
} catch (err) {
if (err.name === 'TypeError' && err.message === 'Failed to fetch') {
throw new Error('网络请求失败或跨域被拦截(CORS)。如果启用了本地代理,请确保浏览器能够通过代理正常访问外网接口。');
}
throw err;
}
}
async function _importSingleAudio(code, zhTemp, jaTemp) {
@@ -1141,46 +1175,20 @@
status.textContent = "Generating Chinese audio...";
try {
// Generate Chinese via Server-Side Proxy
const resZh = await fetch('/api/tts/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
text: zhText,
reference_id: ZH_REFERENCE_ID,
model: TTS_MODEL
})
});
const dataZh = await resZh.json();
if (!dataZh.success) throw new Error("ZH TTS failed: " + dataZh.message);
// Generate Chinese via Client-Side Fetch
const dataZh = await _generateSingleTTS(zhText, ZH_REFERENCE_ID);
status.textContent = "Generating Japanese audio...";
// Generate Japanese via Server-Side Proxy
const resJa = await fetch('/api/tts/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
text: jaText,
reference_id: JA_REFERENCE_ID,
model: TTS_MODEL
})
});
const dataJa = await resJa.json();
if (!dataJa.success) throw new Error("JA TTS failed: " + dataJa.message);
// Generate Japanese via Client-Side Fetch
const dataJa = await _generateSingleTTS(jaText, JA_REFERENCE_ID);
// Success
zhTempFile = dataZh.tempName;
jaTempFile = dataJa.jaTempName || dataJa.enTempName || dataJa.tempName;
jaTempFile = dataJa.tempName;
document.getElementById('zh-audio').src = dataZh.url;
document.getElementById('en-audio').src = dataJa.jaUrl || dataJa.enUrl || dataJa.url;
document.getElementById('en-audio').src = dataJa.url;
document.getElementById('preview-section').style.display = 'block';
status.textContent = "Generation complete!";