import {z} from 'zod' export type SarvamModelApiTextToSpeechRequestText = string; export type SarvamModelAPITextToSpeechLanguage = 'bn-IN' | 'en-IN' | 'gu-IN' | 'hi-IN' | 'kn-IN' | 'ml-IN' | 'mr-IN' | 'od-IN' | 'pa-IN' | 'ta-IN' | 'te-IN'; export type SarvamModelAPITextToSpeechSpeaker = 'anushka' | 'abhilash' | 'manisha' | 'vidya' | 'arya' | 'karun' | 'hitesh' | 'aditya' | 'ritu' | 'priya' | 'neha' | 'rahul' | 'pooja' | 'rohan' | 'simran' | 'kavya' | 'amit' | 'dev' | 'ishita' | 'shreya' | 'ratan' | 'varun' | 'manan' | 'sumit' | 'roopa' | 'kabir' | 'aayan' | 'shubh' | 'ashutosh' | 'advait' | 'anand' | 'tanya' | 'tarun' | 'sunny' | 'mani' | 'gokul' | 'vijay' | 'shruti' | 'suhani' | 'mohit' | 'kavitha' | 'rehan' | 'soham' | 'rupali'; export type SarvamModelAPISpeechSampleRate = '8000' | '16000' | '22050' | '24000' | '32000' | '44100' | '48000'; export type SarvamModelAPITextToSpeechModel = 'bulbul:v2' | 'bulbul:v3'; export type TextToSpeechOutputAudioCodec = 'mp3' | 'linear16' | 'mulaw' | 'alaw' | 'opus' | 'flac' | 'aac' | 'wav'; export type SarvamModelAPITextToSpeechRequest = {text: SarvamModelApiTextToSpeechRequestText, target_language_code: SarvamModelAPITextToSpeechLanguage, speaker?: (SarvamModelAPITextToSpeechSpeaker | null) | undefined, pitch?: (number | null) | undefined, pace?: (number | null) | undefined, loudness?: (number | null) | undefined, speech_sample_rate?: (SarvamModelAPISpeechSampleRate | null) | undefined, enable_preprocessing?: boolean | undefined, model?: SarvamModelAPITextToSpeechModel | undefined, output_audio_codec?: (TextToSpeechOutputAudioCodec | null) | undefined, temperature?: (number | null) | undefined, dict_id?: (string | null) | undefined, enable_cached_responses?: boolean | undefined}; export type CreateApiTextToSpeechArgs = {'api-subscription-key': string, body: SarvamModelAPITextToSpeechRequest}; export type CreateApiTextToSpeechOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const sarvamModelAPITextToSpeechResponse = z.object({request_id: z.string().nullable(), audios: z.array(z.string())}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Text to Speech * * POST /text-to-speech */ export const createApiTextToSpeech = async (args: CreateApiTextToSpeechArgs, options?: CreateApiTextToSpeechOptions) => { const {baseUrl = "https://api.sarvam.ai", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (args['api-subscription-key'] != null) headers.set("api-subscription-key", String(args['api-subscription-key'])) const url = `${baseUrl.replace(/\/+$/, '')}/text-to-speech${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(sarvamModelAPITextToSpeechResponse, await res.json()) };