Revert "feat: switch to client-side fetch for Fish Audio API to bypass server network restrictions"
This reverts commit dedb37e22b.
This commit is contained in:
@@ -857,48 +857,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function _generateSingleTTS(text, reference_id) {
|
async function _generateSingleTTS(text, reference_id) {
|
||||||
try {
|
const res = await fetch('/api/tts/generate', {
|
||||||
// Client-side fetch to use local browser's proxy
|
|
||||||
const fishRes = await fetch('https://api.fish.audio/v1/tts', {
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: { 'Content-Type': 'application/json' },
|
||||||
'Authorization': 'Bearer 233f3a9bcc204b20a1979d59d33cc649',
|
body: JSON.stringify({ text, reference_id, model: TTS_MODEL })
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
text: text,
|
|
||||||
reference_id: reference_id,
|
|
||||||
model: TTS_MODEL,
|
|
||||||
format: "wav"
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
const data = await res.json();
|
||||||
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);
|
if (!data.success) throw new Error(data.message);
|
||||||
return data;
|
return data;
|
||||||
} catch (err) {
|
|
||||||
if (err.name === 'TypeError' && err.message === 'Failed to fetch') {
|
|
||||||
throw new Error('网络跨域拦截(CORS)或连接失败。请确保你的浏览器已开启 CORS Unblock 插件,并且本地代理工作正常!');
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _importSingleAudio(code, zhTemp, jaTemp) {
|
async function _importSingleAudio(code, zhTemp, jaTemp) {
|
||||||
@@ -1034,9 +1000,9 @@
|
|||||||
const jaData = await _generateSingleTTS(task.en, JA_REFERENCE_ID);
|
const jaData = await _generateSingleTTS(task.en, JA_REFERENCE_ID);
|
||||||
|
|
||||||
task.zhTempName = zhData.tempName;
|
task.zhTempName = zhData.tempName;
|
||||||
task.jaTempName = jaData.tempName;
|
task.jaTempName = jaData.jaTempName || jaData.enTempName || jaData.tempName;
|
||||||
task.zhUrl = zhData.url;
|
task.zhUrl = zhData.url;
|
||||||
task.jaUrl = jaData.url;
|
task.jaUrl = jaData.jaUrl || jaData.enUrl || jaData.url;
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -1175,20 +1141,46 @@
|
|||||||
status.textContent = "Generating Chinese audio...";
|
status.textContent = "Generating Chinese audio...";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Generate Chinese via Client-Side Fetch
|
// Generate Chinese via Server-Side Proxy
|
||||||
const dataZh = await _generateSingleTTS(zhText, ZH_REFERENCE_ID);
|
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);
|
||||||
|
|
||||||
status.textContent = "Generating Japanese audio...";
|
status.textContent = "Generating Japanese audio...";
|
||||||
|
|
||||||
// Generate Japanese via Client-Side Fetch
|
// Generate Japanese via Server-Side Proxy
|
||||||
const dataJa = await _generateSingleTTS(jaText, JA_REFERENCE_ID);
|
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);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
zhTempFile = dataZh.tempName;
|
zhTempFile = dataZh.tempName;
|
||||||
jaTempFile = dataJa.tempName;
|
jaTempFile = dataJa.jaTempName || dataJa.enTempName || dataJa.tempName;
|
||||||
|
|
||||||
document.getElementById('zh-audio').src = dataZh.url;
|
document.getElementById('zh-audio').src = dataZh.url;
|
||||||
document.getElementById('en-audio').src = dataJa.url;
|
document.getElementById('en-audio').src = dataJa.jaUrl || dataJa.enUrl || dataJa.url;
|
||||||
|
|
||||||
document.getElementById('preview-section').style.display = 'block';
|
document.getElementById('preview-section').style.display = 'block';
|
||||||
status.textContent = "Generation complete!";
|
status.textContent = "Generation complete!";
|
||||||
|
|||||||
@@ -322,51 +322,6 @@
|
|||||||
.replaceAll("'", "'");
|
.replaceAll("'", "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _generateTTSLocal(text, reference_id) {
|
|
||||||
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)或连接失败。请确保你的浏览器已开启 CORS Unblock 插件,并且本地代理工作正常!');
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function composeTempBroadcast() {
|
async function composeTempBroadcast() {
|
||||||
const text = document.getElementById("tb_text").value.trim();
|
const text = document.getElementById("tb_text").value.trim();
|
||||||
if (!text) {
|
if (!text) {
|
||||||
@@ -376,18 +331,15 @@
|
|||||||
document.getElementById("btn_publish").disabled = true;
|
document.getElementById("btn_publish").disabled = true;
|
||||||
document.getElementById("btn_compose").disabled = true;
|
document.getElementById("btn_compose").disabled = true;
|
||||||
document.getElementById("build_badge").textContent = "合成中…";
|
document.getElementById("build_badge").textContent = "合成中…";
|
||||||
setStatus("合成临时广播中(1/2: 生成语音)…");
|
setStatus("合成临时广播中…");
|
||||||
try {
|
try {
|
||||||
// 1. 本地生成 TTS 并上传获得临时文件名
|
const resp = await fetch("/api/temp-broadcast/compose", {
|
||||||
const ttsData = await _generateTTSLocal(text, ZH_REFERENCE_ID);
|
|
||||||
|
|
||||||
setStatus("合成临时广播中(2/2: 服务端混音)…");
|
|
||||||
// 2. 告诉服务端进行混音合并
|
|
||||||
const resp = await fetch("/api/temp-broadcast/build", {
|
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
contentTempName: ttsData.tempName,
|
text,
|
||||||
|
reference_id: ZH_REFERENCE_ID,
|
||||||
|
model: TTS_MODEL,
|
||||||
prefixName: "lsts"
|
prefixName: "lsts"
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2464,25 +2464,6 @@ async function generateTtsWavToTemp(text, reference_id, model = DEFAULT_TTS_MODE
|
|||||||
return { tempName, tempPath, url: `/uploads/${tempName}` };
|
return { tempName, tempPath, url: `/uploads/${tempName}` };
|
||||||
}
|
}
|
||||||
|
|
||||||
app.post('/api/tts/upload_temp', upload.single('audio'), (req, res) => {
|
|
||||||
try {
|
|
||||||
if (!req.file) return res.status(400).json({ success: false, message: 'No audio file uploaded' });
|
|
||||||
|
|
||||||
const tempName = `temp_${Date.now()}_${Math.floor(Math.random() * 1000)}.wav`;
|
|
||||||
const tempPath = path.join(uploadDir, tempName);
|
|
||||||
|
|
||||||
fs.renameSync(req.file.path, tempPath);
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
tempName: tempName,
|
|
||||||
url: `/uploads/${tempName}`
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
res.status(500).json({ success: false, message: e.message });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/api/tts/generate', express.json(), async (req, res) => {
|
app.post('/api/tts/generate', express.json(), async (req, res) => {
|
||||||
const text = String(req.body?.text || '').trim();
|
const text = String(req.body?.text || '').trim();
|
||||||
const reference_id = String(req.body?.reference_id || '').trim();
|
const reference_id = String(req.body?.reference_id || '').trim();
|
||||||
|
|||||||
Reference in New Issue
Block a user