mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 22:15:47 +00:00
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.
This commit is contained in:
1 parent
7c5630c27b
commit
82fe289918
3 files changed
+51
-8
No files matched your search
@@ -52,6 +52,22 @@ export interface SynthesizeParams {
|
||||
model_id?: string;
|
||||
}
|
||||
|
||||
export interface TestConnectionParams {
|
||||
provider: string;
|
||||
api_key?: string;
|
||||
api_base?: string;
|
||||
voice_id?: string;
|
||||
model_id?: string;
|
||||
group_id?: string;
|
||||
}
|
||||
|
||||
export interface TestConnectionResult {
|
||||
success: boolean;
|
||||
provider?: string;
|
||||
latency_ms?: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export function useTtsConfig() {
|
||||
const ws = useWs();
|
||||
const http = useHttp();
|
||||
@@ -114,5 +130,22 @@ export function useTtsConfig() {
|
||||
[http],
|
||||
);
|
||||
|
||||
return { tts, loading, saving, error, refresh: invalidate, save, synthesize };
|
||||
// Test connection with unsaved credentials — uses ephemeral provider.
|
||||
const testConnection = useCallback(
|
||||
async (params: TestConnectionParams): Promise<TestConnectionResult> => {
|
||||
const res = await fetch("/v1/tts/test-connection", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", ...http.getAuthHeaders() },
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
const data = (await res.json()) as TestConnectionResult;
|
||||
if (!res.ok || !data.success) {
|
||||
throw new Error(data.error || `Test failed (${res.status})`);
|
||||
}
|
||||
return data;
|
||||
},
|
||||
[http],
|
||||
);
|
||||
|
||||
return { tts, loading, saving, error, refresh: invalidate, save, synthesize, testConnection };
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import { Label } from "@/components/ui/label";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { toast } from "@/stores/use-toast-store";
|
||||
import { getProviderDefinition } from "@/data/tts-providers";
|
||||
import type { TtsConfig, TtsProviderConfig, SynthesizeParams } from "../hooks/use-tts-config";
|
||||
import type { TtsConfig, TtsProviderConfig, TestConnectionParams, TestConnectionResult } from "../hooks/use-tts-config";
|
||||
|
||||
interface Props {
|
||||
provider: string;
|
||||
@@ -22,10 +22,10 @@ interface Props {
|
||||
providerKey: keyof Pick<TtsConfig, "openai" | "elevenlabs" | "edge" | "minimax">,
|
||||
patch: Partial<TtsProviderConfig>,
|
||||
) => void;
|
||||
synthesize: (params: SynthesizeParams) => Promise<Blob>;
|
||||
testConnection: (params: TestConnectionParams) => Promise<TestConnectionResult>;
|
||||
}
|
||||
|
||||
export function CredentialsSection({ provider, draft, onUpdate, synthesize }: Props) {
|
||||
export function CredentialsSection({ provider, draft, onUpdate, testConnection }: Props) {
|
||||
const { t } = useTranslation("tts");
|
||||
const [testing, setTesting] = useState(false);
|
||||
|
||||
@@ -36,8 +36,18 @@ export function CredentialsSection({ provider, draft, onUpdate, synthesize }: Pr
|
||||
const handleTestConnection = async () => {
|
||||
setTesting(true);
|
||||
try {
|
||||
await synthesize({ text: "Hello, this is a connection test.", provider });
|
||||
toast.success(t("testConnection.success", "Connection successful"));
|
||||
// Build params from draft credentials — test with unsaved config
|
||||
const cfg = draft[provider as keyof Pick<typeof draft, "openai" | "elevenlabs" | "minimax">];
|
||||
const params: TestConnectionParams = {
|
||||
provider,
|
||||
api_key: cfg?.api_key,
|
||||
api_base: cfg?.api_base || cfg?.base_url,
|
||||
voice_id: cfg?.voice_id || cfg?.voice,
|
||||
model_id: cfg?.model_id || cfg?.model,
|
||||
group_id: (cfg as { group_id?: string })?.group_id,
|
||||
};
|
||||
const result = await testConnection(params);
|
||||
toast.success(t("testConnection.success", "Connection successful"), `${result.latency_ms}ms`);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
toast.error(t("testConnection.failed", "Connection failed"), msg);
|
||||
|
||||
@@ -68,7 +68,7 @@ function modelPatch(provider: string, value: string): [ProviderKey, Partial<TtsP
|
||||
export function TtsPage() {
|
||||
const { t } = useTranslation("tts");
|
||||
const { t: tc } = useTranslation("common");
|
||||
const { tts, loading, saving, error, refresh, save, synthesize } = useTtsConfig();
|
||||
const { tts, loading, saving, error, refresh, save, synthesize, testConnection } = useTtsConfig();
|
||||
const spinning = useMinLoading(loading);
|
||||
|
||||
const [draft, setDraft] = useState<TtsConfig>(tts);
|
||||
@@ -138,7 +138,7 @@ export function TtsPage() {
|
||||
provider={draft.provider}
|
||||
draft={draft}
|
||||
onUpdate={updateProvider}
|
||||
synthesize={synthesize}
|
||||
testConnection={testConnection}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
Reference in new issue
Block a user