From eec6286a587e76db1446e8fefbbaa3254366e717 Mon Sep 17 00:00:00 2001 From: Wxw-Gu Date: Tue, 25 Aug 2026 15:08:58 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=A0=B7=E5=BC=8F,=20?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E6=8E=A5=E5=8F=A3=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../text-to-speech-settings-service.ts | 36 +++++++++++--- .../src/components/FirstUseWelcome.tsx | 2 +- .../components/export/ExportPreviewPanel.tsx | 2 +- .../features/agent-hub/AgentHubWorkspace.tsx | 30 +++++++++--- .../settings/pages/TextToSpeechPage.tsx | 1 + src/renderer/src/styles/export.scss | 4 ++ src/renderer/src/styles/reports-core.scss | 34 ++++++++++--- tests/component/agent-hub-controls.test.tsx | 17 +++++++ tests/component/export-preview-panel.test.tsx | 3 +- .../text-to-speech-settings-service.test.ts | 48 +++++++++++++++++++ 10 files changed, 154 insertions(+), 23 deletions(-) diff --git a/src/main/services/text-to-speech-settings-service.ts b/src/main/services/text-to-speech-settings-service.ts index 2690008..01f62ad 100644 --- a/src/main/services/text-to-speech-settings-service.ts +++ b/src/main/services/text-to-speech-settings-service.ts @@ -1,4 +1,4 @@ -import { app } from 'electron' +import { app, net } from 'electron' import fs from 'fs-extra' import path from 'path' import { randomUUID } from 'crypto' @@ -119,7 +119,7 @@ export class TextToSpeechSettingsService { if (tag.trim()) url.searchParams.append('tag', tag.trim()) } - const response = await fetch(url, { + const response = await fishAudioFetch(url.toString(), { headers: { Authorization: `Bearer ${resolved.key}` }, signal: AbortSignal.timeout(30_000) }) @@ -179,7 +179,7 @@ export class TextToSpeechSettingsService { } try { - const response = await fetch(`${FISH_AUDIO_BASE_URL}/v1/tts`, { + const response = await fishAudioFetch(`${FISH_AUDIO_BASE_URL}/v1/tts`, { method: 'POST', headers: { Authorization: `Bearer ${resolved.key}`, @@ -255,10 +255,13 @@ export class TextToSpeechSettingsService { private async getVoice(id: string, key: string): Promise { try { - const response = await fetch(`${FISH_AUDIO_BASE_URL}/model/${encodeURIComponent(id)}`, { - headers: { Authorization: `Bearer ${key}` }, - signal: AbortSignal.timeout(15_000) - }) + const response = await fishAudioFetch( + `${FISH_AUDIO_BASE_URL}/model/${encodeURIComponent(id)}`, + { + headers: { Authorization: `Bearer ${key}` }, + signal: AbortSignal.timeout(15_000) + } + ) if (!response.ok) return null const model = (await response.json()) as FishAudioModelEntity return model.type === 'tts' && model.state === 'trained' ? toVoice(model) : null @@ -351,6 +354,25 @@ async function fishAudioError(response: Response): Promise { return new Error(detail || `语音服务请求失败(HTTP ${response.status})`) } +async function fishAudioFetch(input: string, init: RequestInit): Promise { + try { + return await net.fetch(input, init) + } catch (electronError) { + try { + return await fetch(input, init) + } catch (nodeError) { + throw new Error( + `Fish Audio 网络请求失败(Electron: ${networkErrorMessage(electronError)};Node: ${networkErrorMessage(nodeError)})` + ) + } + } +} + +function networkErrorMessage(error: unknown): string { + if (error instanceof Error && error.message.trim()) return error.message.trim() + return String(error || '未知错误') +} + function safeFishAudioError(error: unknown): string { if (error instanceof DOMException && error.name === 'TimeoutError') return '语音服务请求超时' if (error instanceof Error) return error.message diff --git a/src/renderer/src/components/FirstUseWelcome.tsx b/src/renderer/src/components/FirstUseWelcome.tsx index 51ab59a..266bd2f 100644 --- a/src/renderer/src/components/FirstUseWelcome.tsx +++ b/src/renderer/src/components/FirstUseWelcome.tsx @@ -48,7 +48,7 @@ export function FirstUseWelcome({