Skip to content

Commit 82fe289

Browse files
committed
fix(ui): use test-connection endpoint for TTS credential validation
Update CredentialsSection to call /v1/tts/test-connection instead of /v1/tts/synthesize - allows testing unsaved credentials before save.
1 parent 7c5630c commit 82fe289

3 files changed

Lines changed: 51 additions & 8 deletions

File tree

ui/web/src/pages/tts/hooks/use-tts-config.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ export interface SynthesizeParams {
5252
model_id?: string;
5353
}
5454

55+
export interface TestConnectionParams {
56+
provider: string;
57+
api_key?: string;
58+
api_base?: string;
59+
voice_id?: string;
60+
model_id?: string;
61+
group_id?: string;
62+
}
63+
64+
export interface TestConnectionResult {
65+
success: boolean;
66+
provider?: string;
67+
latency_ms?: number;
68+
error?: string;
69+
}
70+
5571
export function useTtsConfig() {
5672
const ws = useWs();
5773
const http = useHttp();
@@ -114,5 +130,22 @@ export function useTtsConfig() {
114130
[http],
115131
);
116132

117-
return { tts, loading, saving, error, refresh: invalidate, save, synthesize };
133+
// Test connection with unsaved credentials — uses ephemeral provider.
134+
const testConnection = useCallback(
135+
async (params: TestConnectionParams): Promise<TestConnectionResult> => {
136+
const res = await fetch("/v1/tts/test-connection", {
137+
method: "POST",
138+
headers: { "Content-Type": "application/json", ...http.getAuthHeaders() },
139+
body: JSON.stringify(params),
140+
});
141+
const data = (await res.json()) as TestConnectionResult;
142+
if (!res.ok || !data.success) {
143+
throw new Error(data.error || `Test failed (${res.status})`);
144+
}
145+
return data;
146+
},
147+
[http],
148+
);
149+
150+
return { tts, loading, saving, error, refresh: invalidate, save, synthesize, testConnection };
118151
}

ui/web/src/pages/tts/sections/credentials-section.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { Label } from "@/components/ui/label";
1313
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
1414
import { toast } from "@/stores/use-toast-store";
1515
import { getProviderDefinition } from "@/data/tts-providers";
16-
import type { TtsConfig, TtsProviderConfig, SynthesizeParams } from "../hooks/use-tts-config";
16+
import type { TtsConfig, TtsProviderConfig, TestConnectionParams, TestConnectionResult } from "../hooks/use-tts-config";
1717

1818
interface Props {
1919
provider: string;
@@ -22,10 +22,10 @@ interface Props {
2222
providerKey: keyof Pick<TtsConfig, "openai" | "elevenlabs" | "edge" | "minimax">,
2323
patch: Partial<TtsProviderConfig>,
2424
) => void;
25-
synthesize: (params: SynthesizeParams) => Promise<Blob>;
25+
testConnection: (params: TestConnectionParams) => Promise<TestConnectionResult>;
2626
}
2727

28-
export function CredentialsSection({ provider, draft, onUpdate, synthesize }: Props) {
28+
export function CredentialsSection({ provider, draft, onUpdate, testConnection }: Props) {
2929
const { t } = useTranslation("tts");
3030
const [testing, setTesting] = useState(false);
3131

@@ -36,8 +36,18 @@ export function CredentialsSection({ provider, draft, onUpdate, synthesize }: Pr
3636
const handleTestConnection = async () => {
3737
setTesting(true);
3838
try {
39-
await synthesize({ text: "Hello, this is a connection test.", provider });
40-
toast.success(t("testConnection.success", "Connection successful"));
39+
// Build params from draft credentials — test with unsaved config
40+
const cfg = draft[provider as keyof Pick<typeof draft, "openai" | "elevenlabs" | "minimax">];
41+
const params: TestConnectionParams = {
42+
provider,
43+
api_key: cfg?.api_key,
44+
api_base: cfg?.api_base || cfg?.base_url,
45+
voice_id: cfg?.voice_id || cfg?.voice,
46+
model_id: cfg?.model_id || cfg?.model,
47+
group_id: (cfg as { group_id?: string })?.group_id,
48+
};
49+
const result = await testConnection(params);
50+
toast.success(t("testConnection.success", "Connection successful"), `${result.latency_ms}ms`);
4151
} catch (err) {
4252
const msg = err instanceof Error ? err.message : String(err);
4353
toast.error(t("testConnection.failed", "Connection failed"), msg);

ui/web/src/pages/tts/tts-page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ function modelPatch(provider: string, value: string): [ProviderKey, Partial<TtsP
6868
export function TtsPage() {
6969
const { t } = useTranslation("tts");
7070
const { t: tc } = useTranslation("common");
71-
const { tts, loading, saving, error, refresh, save, synthesize } = useTtsConfig();
71+
const { tts, loading, saving, error, refresh, save, synthesize, testConnection } = useTtsConfig();
7272
const spinning = useMinLoading(loading);
7373

7474
const [draft, setDraft] = useState<TtsConfig>(tts);
@@ -138,7 +138,7 @@ export function TtsPage() {
138138
provider={draft.provider}
139139
draft={draft}
140140
onUpdate={updateProvider}
141-
synthesize={synthesize}
141+
testConnection={testConnection}
142142
/>
143143
)}
144144

0 commit comments

Comments
 (0)