"use client"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { getDefaultConfigurationsApiV1UserConfigurationsDefaultsGet } from '@/client/sdk.gen'; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useUserConfig } from "@/context/UserConfigContext"; type ServiceSegment = "llm" | "tts" | "stt"; interface SchemaProperty { type?: string; default?: string | number | boolean; enum?: string[]; $ref?: string; description?: string; format?: string; } interface ProviderSchema { properties: Record; required?: string[]; $defs?: Record; [key: string]: unknown; } interface FormValues { [key: string]: string | number | boolean; } export default function ServiceConfiguration() { const [apiError, setApiError] = useState(null); const [isSaving, setIsSaving] = useState(false); const { userConfig, saveUserConfig } = useUserConfig(); const [schemas, setSchemas] = useState>>({ llm: {}, tts: {}, stt: {} }); const [serviceProviders, setServiceProviders] = useState>({ llm: "", tts: "", stt: "" }); const { register, handleSubmit, formState: { errors }, reset, getValues, setValue, watch } = useForm(); useEffect(() => { const fetchConfigurations = async () => { const response = await getDefaultConfigurationsApiV1UserConfigurationsDefaultsGet(); if (response.data) { setSchemas({ llm: response.data.llm as Record, tts: response.data.tts as Record, stt: response.data.stt as Record }); } else { console.error("Failed to fetch configurations"); return; } const defaultValues: Record = {}; const selectedProviders: Record = { llm: response.data.default_providers.llm, tts: response.data.default_providers.tts, stt: response.data.default_providers.stt }; const setServicePropertyValues = (service: ServiceSegment) => { /* sets service properties like api_key, model etc. from default configurations if not present in user configurations service - llm/ tts/ stt userConfig['llm'] = { provider: 'openai', api_key: 'sk-...' } response.data.llm = { openai: { properties: { provider: 'openai' api_key: 'sk-...' } } } */ if (userConfig?.[service]?.provider) { Object.entries(userConfig?.[service]).forEach(([field, value]) => { if (field !== "provider") { defaultValues[`${service}_${field}`] = value; } }); selectedProviders[service] = userConfig?.[service]?.provider as string; } else { // response.data['service'] will all providers for the given service // selectedProviders[service] will have the provider name const properties = response.data[service]?.[selectedProviders[service]]?.properties as Record; if (properties) { Object.entries(properties).forEach(([field, schema]) => { if (field !== "provider" && schema.default) { defaultValues[`${service}_${field}`] = schema.default; } }); } } } setServicePropertyValues("llm"); setServicePropertyValues("tts"); setServicePropertyValues("stt"); setServiceProviders(selectedProviders); reset(defaultValues); }; fetchConfigurations(); }, [reset, userConfig]); const handleProviderChange = (service: ServiceSegment, providerName: string) => { /* service can be llm/ tts/ stt providerName is openAI/ Deepgram etc. */ if (!providerName) { return; } const currentValues = getValues(); const preservedValues: Record = {}; // Preserve values from other services Object.keys(currentValues).forEach(key => { if (!key.startsWith(`${service}_`)) { preservedValues[key] = currentValues[key]; } }); // Set default values from schema if (schemas?.[service]?.[providerName]) { const providerSchema = schemas[service][providerName]; Object.entries(providerSchema.properties).forEach(([field, schema]: [string, SchemaProperty]) => { if (field !== "provider" && schema.default !== undefined) { preservedValues[`${service}_${field}`] = schema.default; } }); } preservedValues[`${service}_provider`] = providerName; reset(preservedValues); setServiceProviders(prev => ({ ...prev, [service]: providerName })); } const onSubmit = async (data: FormValues) => { /* data contains form values like llm_api_key: "sk...", llm_model: "gpt-4o" etc. extract the values in relevant form */ setApiError(null); setIsSaving(true); const userConfig = { llm: { provider: serviceProviders.llm, api_key: data.llm_api_key as string, model: data.llm_model as string }, tts: { provider: serviceProviders.tts, api_key: data.tts_api_key as string }, stt: { provider: serviceProviders.stt, api_key: data.stt_api_key as string } }; // Add any extra properties in the payload Object.entries(data).forEach(([property, value]) => { const parts = property.split('_'); const service = parts[0] as ServiceSegment; const field = parts.slice(1).join('_'); // Join all parts after the service name if (userConfig[service] && !(field in userConfig[service])) { (userConfig[service] as Record)[field] = value as string; } }); try { await saveUserConfig({ llm: userConfig.llm, tts: userConfig.tts, stt: userConfig.stt }); setApiError(null); } catch (error: unknown) { if (error instanceof Error) { setApiError(error.message); } else { setApiError('An unknown error occurred'); } } finally { setIsSaving(false); } }; const renderServiceSegmentFields = (service: ServiceSegment) => { // Segment is segments like llm, tts and stt const currentProvider = serviceProviders[service]; const providerSchema = schemas?.[service]?.[currentProvider]; const availableProviders = schemas?.[service] ? Object.keys(schemas[service]) : []; return ( {service.toUpperCase()} Configuration Configure your {service.toUpperCase()} service
{currentProvider && providerSchema && (
{Object.entries(providerSchema.properties).map(([field, schema]: [string, SchemaProperty]) => { // Handle $ref fields by getting the actual schema from $defs const actualSchema = schema.$ref && providerSchema.$defs ? providerSchema.$defs[schema.$ref.split('/').pop() || ''] : schema; // Skip provider field as it's handled separately return field !== "provider" && (
{actualSchema?.enum ? ( ) : ( )} {errors[`${service}_${field}`] && (

{typeof errors[`${service}_${field}`]?.message === 'string' ? String(errors[`${service}_${field}`]?.message) : "This field is required"}

)}
); })}
)}
); }; return (

Service Configuration

{renderServiceSegmentFields("llm")} {renderServiceSegmentFields("tts")} {renderServiceSegmentFields("stt")} {apiError &&

{apiError}

}
); }