@mastra/voice-sarvam 0.12.0-beta.0 → 0.12.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,95 @@
1
+ # Voice API Reference
2
+
3
+ > API reference for voice - 1 entries
4
+
5
+
6
+ ---
7
+
8
+ ## Reference: Sarvam
9
+
10
+ > Documentation for the Sarvam class, providing text-to-speech and speech-to-text capabilities.
11
+
12
+ The SarvamVoice class in Mastra provides text-to-speech and speech-to-text capabilities using Sarvam AI models.
13
+
14
+ ## Usage Example
15
+
16
+ ```typescript
17
+ import { SarvamVoice } from "@mastra/voice-sarvam";
18
+
19
+ // Initialize with default configuration using environment variables
20
+ const voice = new SarvamVoice();
21
+
22
+ // Or initialize with specific configuration
23
+ const voiceWithConfig = new SarvamVoice({
24
+ speechModel: {
25
+ model: "bulbul:v1",
26
+ apiKey: process.env.SARVAM_API_KEY!,
27
+ language: "en-IN",
28
+ properties: {
29
+ pitch: 0,
30
+ pace: 1.65,
31
+ loudness: 1.5,
32
+ speech_sample_rate: 8000,
33
+ enable_preprocessing: false,
34
+ eng_interpolation_wt: 123,
35
+ },
36
+ },
37
+ listeningModel: {
38
+ model: "saarika:v2",
39
+ apiKey: process.env.SARVAM_API_KEY!,
40
+ languageCode: "en-IN",
41
+ filetype?: 'wav';
42
+ },
43
+ speaker: "meera", // Default voice
44
+ });
45
+
46
+
47
+ // Convert text to speech
48
+ const audioStream = await voice.speak("Hello, how can I help you?");
49
+
50
+
51
+ // Convert speech to text
52
+ const text = await voice.listen(audioStream, {
53
+ filetype: "wav",
54
+ });
55
+ ```
56
+
57
+ ### Sarvam API Docs -
58
+
59
+ https://docs.sarvam.ai/api-reference-docs/endpoints/text-to-speech
60
+
61
+ ## Configuration
62
+
63
+ ### Constructor Options
64
+
65
+ ### SarvamVoiceConfig
66
+
67
+ ### SarvamListenOptions
68
+
69
+ ## Methods
70
+
71
+ ### speak()
72
+
73
+ Converts text to speech using Sarvam's text-to-speech models.
74
+
75
+ Returns: `Promise<NodeJS.ReadableStream>`
76
+
77
+ ### listen()
78
+
79
+ Transcribes audio using Sarvam's speech recognition models.
80
+
81
+ Returns: `Promise<string>`
82
+
83
+ ### getSpeakers()
84
+
85
+ Returns an array of available voice options.
86
+
87
+ Returns: `Promise<Array<{voiceId: SarvamVoiceId}>>`
88
+
89
+ ## Notes
90
+
91
+ - API key can be provided via constructor options or the `SARVAM_API_KEY` environment variable
92
+ - If no API key is provided, the constructor will throw an error
93
+ - The service communicates with the Sarvam AI API at `https://api.sarvam.ai`
94
+ - Audio is returned as a stream containing binary audio data
95
+ - Speech recognition supports mp3 and wav audio formats
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/voices.ts","../src/index.ts"],"names":["MastraVoice","stream","PassThrough"],"mappings":"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","file":"index.cjs","sourcesContent":["export const SARVAM_VOICES = [\n 'meera',\n 'pavithra',\n 'maitreyi',\n 'arvind',\n 'amol',\n 'amartya',\n 'diya',\n 'neel',\n 'misha',\n 'vian',\n 'arjun',\n 'maya',\n] as const;\n\nexport const SARVAM_TTS_LANGUAGES = [\n 'hi-IN',\n 'bn-IN',\n 'kn-IN',\n 'ml-IN',\n 'mr-IN',\n 'od-IN',\n 'pa-IN',\n 'ta-IN',\n 'te-IN',\n 'en-IN',\n 'gu-IN',\n] as const;\n\nexport const SARVAM_STT_LANGUAGES = [...SARVAM_TTS_LANGUAGES, 'unknown'] as const;\n\nexport const SARVAM_TTS_MODELS = ['bulbul:v1'] as const;\nexport const SARVAM_STT_MODELS = ['saarika:v1', 'saarika:v2', 'saarika:flash'] as const;\n\nexport type SarvamVoiceId = (typeof SARVAM_VOICES)[number];\n\nexport type SarvamTTSLanguage = (typeof SARVAM_TTS_LANGUAGES)[number];\nexport type SarvamSTTLanguage = (typeof SARVAM_STT_LANGUAGES)[number];\n\nexport type SarvamTTSModel = (typeof SARVAM_TTS_MODELS)[number];\nexport type SarvamSTTModel = (typeof SARVAM_STT_MODELS)[number];\n","import { PassThrough } from 'stream';\n\nimport { MastraVoice } from '@mastra/core/voice';\nimport { SARVAM_VOICES } from './voices';\nimport type { SarvamTTSLanguage, SarvamSTTLanguage, SarvamSTTModel, SarvamTTSModel, SarvamVoiceId } from './voices';\n\ninterface SarvamVoiceConfig {\n apiKey?: string;\n model?: SarvamTTSModel;\n language?: SarvamTTSLanguage;\n properties?: {\n pitch?: number;\n pace?: number;\n loudness?: number;\n speech_sample_rate?: 8000 | 16000 | 22050;\n enable_preprocessing?: boolean;\n eng_interpolation_wt?: number;\n };\n}\n\ninterface SarvamListenOptions {\n apiKey?: string;\n model?: SarvamSTTModel;\n languageCode?: SarvamSTTLanguage;\n filetype?: 'mp3' | 'wav';\n}\n\nconst defaultSpeechModel = {\n model: 'bulbul:v1' as const,\n apiKey: process.env.SARVAM_API_KEY,\n language: 'en-IN' as const,\n};\n\nconst defaultListeningModel = {\n model: 'saarika:v2' as const,\n apiKey: process.env.SARVAM_API_KEY,\n language_code: 'unknown' as const,\n};\n\nexport class SarvamVoice extends MastraVoice {\n private apiKey?: string;\n private model: SarvamTTSModel = 'bulbul:v1';\n private language: SarvamTTSLanguage = 'en-IN';\n private properties: Record<string, any> = {};\n speaker: SarvamVoiceId = 'meera';\n private baseUrl = 'https://api.sarvam.ai';\n\n constructor({\n speechModel,\n speaker,\n listeningModel,\n }: {\n speechModel?: SarvamVoiceConfig;\n speaker?: SarvamVoiceId;\n listeningModel?: SarvamListenOptions;\n } = {}) {\n super({\n speechModel: {\n name: speechModel?.model ?? defaultSpeechModel.model,\n apiKey: speechModel?.apiKey ?? defaultSpeechModel.apiKey,\n },\n listeningModel: {\n name: listeningModel?.model ?? defaultListeningModel.model,\n apiKey: listeningModel?.model ?? defaultListeningModel.apiKey,\n },\n speaker,\n });\n\n this.apiKey = speechModel?.apiKey || defaultSpeechModel.apiKey;\n if (!this.apiKey) {\n throw new Error('SARVAM_API_KEY must be set');\n }\n this.model = speechModel?.model || defaultSpeechModel.model;\n this.language = speechModel?.language || defaultSpeechModel.language;\n this.properties = speechModel?.properties || {};\n this.speaker = speaker || 'meera';\n }\n\n private async makeRequest(endpoint: string, payload: any) {\n const headers = new Headers({\n 'api-subscription-key': this.apiKey!,\n 'Content-Type': 'application/json',\n });\n const response = await fetch(`${this.baseUrl}${endpoint}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(payload),\n });\n if (!response.ok) {\n let errorMessage;\n try {\n const error = (await response.json()) as { message?: string };\n errorMessage = error.message || response.statusText;\n } catch {\n errorMessage = response.statusText;\n }\n throw new Error(`Sarvam AI API Error: ${errorMessage}`);\n }\n\n return response;\n }\n private async streamToString(stream: NodeJS.ReadableStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n if (typeof chunk === 'string') {\n chunks.push(Buffer.from(chunk));\n } else {\n chunks.push(chunk);\n }\n }\n return Buffer.concat(chunks).toString('utf-8');\n }\n async speak(\n input: string | NodeJS.ReadableStream,\n options?: { speaker?: SarvamVoiceId },\n ): Promise<NodeJS.ReadableStream> {\n const text = typeof input === 'string' ? input : await this.streamToString(input);\n\n const payload = {\n inputs: [text],\n target_language_code: this.language,\n speaker: options?.speaker || this.speaker,\n model: this.model,\n ...this.properties,\n };\n\n const response = await this.makeRequest('/text-to-speech', payload);\n\n const { audios } = (await response.json()) as { audios: any };\n\n if (!audios || !audios.length) {\n throw new Error('No audio received from Sarvam AI');\n }\n\n // Convert base64 to buffer\n const audioBuffer = Buffer.from(audios[0], 'base64');\n\n // Create a PassThrough stream for the audio\n const stream = new PassThrough();\n stream.write(audioBuffer);\n stream.end();\n\n return stream;\n }\n\n async getSpeakers() {\n return SARVAM_VOICES.map(voice => ({\n voiceId: voice,\n }));\n }\n\n /**\n * Checks if listening capabilities are enabled.\n *\n * @returns {Promise<{ enabled: boolean }>}\n */\n async getListener() {\n return { enabled: true };\n }\n\n async listen(input: NodeJS.ReadableStream, options?: SarvamListenOptions): Promise<string> {\n // Collect audio data into buffer\n const chunks: Buffer[] = [];\n for await (const chunk of input) {\n if (typeof chunk === 'string') {\n chunks.push(Buffer.from(chunk));\n } else {\n chunks.push(chunk);\n }\n }\n const audioBuffer = Buffer.concat(chunks);\n\n const form = new FormData();\n const mimeType = options?.filetype === 'mp3' ? 'audio/mpeg' : 'audio/wav';\n const blob = new Blob([audioBuffer], { type: mimeType });\n\n form.append('file', blob);\n form.append('model', options?.model || 'saarika:v2');\n form.append('language_code', options?.languageCode || 'unknown');\n const requestOptions = {\n method: 'POST',\n headers: {\n 'api-subscription-key': this.apiKey!,\n },\n body: form,\n };\n\n try {\n const response = await fetch(`${this.baseUrl}/speech-to-text`, requestOptions);\n const result = (await response.json()) as any;\n //console.log(result);\n return result.transcript;\n } catch (error) {\n console.error('Error during speech-to-text request:', error);\n throw error;\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/voices.ts","../src/index.ts"],"names":["MastraVoice","stream","PassThrough"],"mappings":"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","file":"index.cjs","sourcesContent":["export const SARVAM_VOICES = [\n 'meera',\n 'pavithra',\n 'maitreyi',\n 'arvind',\n 'amol',\n 'amartya',\n 'diya',\n 'neel',\n 'misha',\n 'vian',\n 'arjun',\n 'maya',\n] as const;\n\nexport const SARVAM_TTS_LANGUAGES = [\n 'hi-IN',\n 'bn-IN',\n 'kn-IN',\n 'ml-IN',\n 'mr-IN',\n 'od-IN',\n 'pa-IN',\n 'ta-IN',\n 'te-IN',\n 'en-IN',\n 'gu-IN',\n] as const;\n\nexport const SARVAM_STT_LANGUAGES = [...SARVAM_TTS_LANGUAGES, 'unknown'] as const;\n\nexport const SARVAM_TTS_MODELS = ['bulbul:v1'] as const;\nexport const SARVAM_STT_MODELS = ['saarika:v1', 'saarika:v2', 'saarika:flash'] as const;\n\nexport type SarvamVoiceId = (typeof SARVAM_VOICES)[number];\n\nexport type SarvamTTSLanguage = (typeof SARVAM_TTS_LANGUAGES)[number];\nexport type SarvamSTTLanguage = (typeof SARVAM_STT_LANGUAGES)[number];\n\nexport type SarvamTTSModel = (typeof SARVAM_TTS_MODELS)[number];\nexport type SarvamSTTModel = (typeof SARVAM_STT_MODELS)[number];\n","import { PassThrough } from 'node:stream';\n\nimport { MastraVoice } from '@mastra/core/voice';\nimport { SARVAM_VOICES } from './voices';\nimport type { SarvamTTSLanguage, SarvamSTTLanguage, SarvamSTTModel, SarvamTTSModel, SarvamVoiceId } from './voices';\n\ninterface SarvamVoiceConfig {\n apiKey?: string;\n model?: SarvamTTSModel;\n language?: SarvamTTSLanguage;\n properties?: {\n pitch?: number;\n pace?: number;\n loudness?: number;\n speech_sample_rate?: 8000 | 16000 | 22050;\n enable_preprocessing?: boolean;\n eng_interpolation_wt?: number;\n };\n}\n\ninterface SarvamListenOptions {\n apiKey?: string;\n model?: SarvamSTTModel;\n languageCode?: SarvamSTTLanguage;\n filetype?: 'mp3' | 'wav';\n}\n\nconst defaultSpeechModel = {\n model: 'bulbul:v1' as const,\n apiKey: process.env.SARVAM_API_KEY,\n language: 'en-IN' as const,\n};\n\nconst defaultListeningModel = {\n model: 'saarika:v2' as const,\n apiKey: process.env.SARVAM_API_KEY,\n language_code: 'unknown' as const,\n};\n\nexport class SarvamVoice extends MastraVoice {\n private apiKey?: string;\n private model: SarvamTTSModel = 'bulbul:v1';\n private language: SarvamTTSLanguage = 'en-IN';\n private properties: Record<string, any> = {};\n speaker: SarvamVoiceId = 'meera';\n private baseUrl = 'https://api.sarvam.ai';\n\n constructor({\n speechModel,\n speaker,\n listeningModel,\n }: {\n speechModel?: SarvamVoiceConfig;\n speaker?: SarvamVoiceId;\n listeningModel?: SarvamListenOptions;\n } = {}) {\n super({\n speechModel: {\n name: speechModel?.model ?? defaultSpeechModel.model,\n apiKey: speechModel?.apiKey ?? defaultSpeechModel.apiKey,\n },\n listeningModel: {\n name: listeningModel?.model ?? defaultListeningModel.model,\n apiKey: listeningModel?.model ?? defaultListeningModel.apiKey,\n },\n speaker,\n });\n\n this.apiKey = speechModel?.apiKey || defaultSpeechModel.apiKey;\n if (!this.apiKey) {\n throw new Error('SARVAM_API_KEY must be set');\n }\n this.model = speechModel?.model || defaultSpeechModel.model;\n this.language = speechModel?.language || defaultSpeechModel.language;\n this.properties = speechModel?.properties || {};\n this.speaker = speaker || 'meera';\n }\n\n private async makeRequest(endpoint: string, payload: any) {\n const headers = new Headers({\n 'api-subscription-key': this.apiKey!,\n 'Content-Type': 'application/json',\n });\n const response = await fetch(`${this.baseUrl}${endpoint}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(payload),\n });\n if (!response.ok) {\n let errorMessage;\n try {\n const error = (await response.json()) as { message?: string };\n errorMessage = error.message || response.statusText;\n } catch {\n errorMessage = response.statusText;\n }\n throw new Error(`Sarvam AI API Error: ${errorMessage}`);\n }\n\n return response;\n }\n private async streamToString(stream: NodeJS.ReadableStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n if (typeof chunk === 'string') {\n chunks.push(Buffer.from(chunk));\n } else {\n chunks.push(chunk);\n }\n }\n return Buffer.concat(chunks).toString('utf-8');\n }\n async speak(\n input: string | NodeJS.ReadableStream,\n options?: { speaker?: SarvamVoiceId },\n ): Promise<NodeJS.ReadableStream> {\n const text = typeof input === 'string' ? input : await this.streamToString(input);\n\n const payload = {\n inputs: [text],\n target_language_code: this.language,\n speaker: options?.speaker || this.speaker,\n model: this.model,\n ...this.properties,\n };\n\n const response = await this.makeRequest('/text-to-speech', payload);\n\n const { audios } = (await response.json()) as { audios: any };\n\n if (!audios || !audios.length) {\n throw new Error('No audio received from Sarvam AI');\n }\n\n // Convert base64 to buffer\n const audioBuffer = Buffer.from(audios[0], 'base64');\n\n // Create a PassThrough stream for the audio\n const stream = new PassThrough();\n stream.write(audioBuffer);\n stream.end();\n\n return stream;\n }\n\n async getSpeakers() {\n return SARVAM_VOICES.map(voice => ({\n voiceId: voice,\n }));\n }\n\n /**\n * Checks if listening capabilities are enabled.\n *\n * @returns {Promise<{ enabled: boolean }>}\n */\n async getListener() {\n return { enabled: true };\n }\n\n async listen(input: NodeJS.ReadableStream, options?: SarvamListenOptions): Promise<string> {\n // Collect audio data into buffer\n const chunks: Buffer[] = [];\n for await (const chunk of input) {\n if (typeof chunk === 'string') {\n chunks.push(Buffer.from(chunk));\n } else {\n chunks.push(chunk);\n }\n }\n const audioBuffer = Buffer.concat(chunks);\n\n const form = new FormData();\n const mimeType = options?.filetype === 'mp3' ? 'audio/mpeg' : 'audio/wav';\n const blob = new Blob([audioBuffer], { type: mimeType });\n\n form.append('file', blob);\n form.append('model', options?.model || 'saarika:v2');\n form.append('language_code', options?.languageCode || 'unknown');\n const requestOptions = {\n method: 'POST',\n headers: {\n 'api-subscription-key': this.apiKey!,\n },\n body: form,\n };\n\n try {\n const response = await fetch(`${this.baseUrl}/speech-to-text`, requestOptions);\n const result = (await response.json()) as any;\n //console.log(result);\n return result.transcript;\n } catch (error) {\n console.error('Error during speech-to-text request:', error);\n throw error;\n }\n }\n}\n"]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/voices.ts","../src/index.ts"],"names":[],"mappings":";;;;;;AAAO,IAAM,aAAA,GAAgB;AAAA,EAC3B,OAAA;AAAA,EACA,UAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA;;;ACcA,IAAM,kBAAA,GAAqB;AAAA,EACzB,KAAA,EAAO,WAAA;AAAA,EACP,MAAA,EAAQ,QAAQ,GAAA,CAAI,cAAA;AAAA,EACpB,QAAA,EAAU;AACZ,CAAA;AAEA,IAAM,qBAAA,GAAwB;AAAA,EAC5B,KAAA,EAAO,YAAA;AAAA,EACP,MAAA,EAAQ,QAAQ,GAAA,CAAI,cAEtB,CAAA;AAEO,IAAM,WAAA,GAAN,cAA0B,WAAA,CAAY;AAAA,EACnC,MAAA;AAAA,EACA,KAAA,GAAwB,WAAA;AAAA,EACxB,QAAA,GAA8B,OAAA;AAAA,EAC9B,aAAkC,EAAC;AAAA,EAC3C,OAAA,GAAyB,OAAA;AAAA,EACjB,OAAA,GAAU,uBAAA;AAAA,EAElB,WAAA,CAAY;AAAA,IACV,WAAA;AAAA,IACA,OAAA;AAAA,IACA;AAAA,GACF,GAII,EAAC,EAAG;AACN,IAAA,KAAA,CAAM;AAAA,MACJ,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,WAAA,EAAa,KAAA,IAAS,kBAAA,CAAmB,KAAA;AAAA,QAC/C,MAAA,EAAQ,WAAA,EAAa,MAAA,IAAU,kBAAA,CAAmB;AAAA,OACpD;AAAA,MACA,cAAA,EAAgB;AAAA,QACd,IAAA,EAAM,cAAA,EAAgB,KAAA,IAAS,qBAAA,CAAsB,KAAA;AAAA,QACrD,MAAA,EAAQ,cAAA,EAAgB,KAAA,IAAS,qBAAA,CAAsB;AAAA,OACzD;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,IAAA,CAAK,MAAA,GAAS,WAAA,EAAa,MAAA,IAAU,kBAAA,CAAmB,MAAA;AACxD,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,MAAA,MAAM,IAAI,MAAM,4BAA4B,CAAA;AAAA,IAC9C;AACA,IAAA,IAAA,CAAK,KAAA,GAAQ,WAAA,EAAa,KAAA,IAAS,kBAAA,CAAmB,KAAA;AACtD,IAAA,IAAA,CAAK,QAAA,GAAW,WAAA,EAAa,QAAA,IAAY,kBAAA,CAAmB,QAAA;AAC5D,IAAA,IAAA,CAAK,UAAA,GAAa,WAAA,EAAa,UAAA,IAAc,EAAC;AAC9C,IAAA,IAAA,CAAK,UAAU,OAAA,IAAW,OAAA;AAAA,EAC5B;AAAA,EAEA,MAAc,WAAA,CAAY,QAAA,EAAkB,OAAA,EAAc;AACxD,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ;AAAA,MAC1B,wBAAwB,IAAA,CAAK,MAAA;AAAA,MAC7B,cAAA,EAAgB;AAAA,KACjB,CAAA;AACD,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,EAAG,KAAK,OAAO,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI;AAAA,MACzD,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAC7B,CAAA;AACD,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,IAAI,YAAA;AACJ,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,GAAS,MAAM,QAAA,CAAS,IAAA,EAAK;AACnC,QAAA,YAAA,GAAe,KAAA,CAAM,WAAW,QAAA,CAAS,UAAA;AAAA,MAC3C,CAAA,CAAA,MAAQ;AACN,QAAA,YAAA,GAAe,QAAA,CAAS,UAAA;AAAA,MAC1B;AACA,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qBAAA,EAAwB,YAAY,CAAA,CAAE,CAAA;AAAA,IACxD;AAEA,IAAA,OAAO,QAAA;AAAA,EACT;AAAA,EACA,MAAc,eAAe,MAAA,EAAgD;AAC3E,IAAA,MAAM,SAAmB,EAAC;AAC1B,IAAA,WAAA,MAAiB,SAAS,MAAA,EAAQ;AAChC,MAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,QAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,MAChC,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,MACnB;AAAA,IACF;AACA,IAAA,OAAO,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA,CAAE,SAAS,OAAO,CAAA;AAAA,EAC/C;AAAA,EACA,MAAM,KAAA,CACJ,KAAA,EACA,OAAA,EACgC;AAChC,IAAA,MAAM,IAAA,GAAO,OAAO,KAAA,KAAU,QAAA,GAAW,QAAQ,MAAM,IAAA,CAAK,eAAe,KAAK,CAAA;AAEhF,IAAA,MAAM,OAAA,GAAU;AAAA,MACd,MAAA,EAAQ,CAAC,IAAI,CAAA;AAAA,MACb,sBAAsB,IAAA,CAAK,QAAA;AAAA,MAC3B,OAAA,EAAS,OAAA,EAAS,OAAA,IAAW,IAAA,CAAK,OAAA;AAAA,MAClC,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,GAAG,IAAA,CAAK;AAAA,KACV;AAEA,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,WAAA,CAAY,mBAAmB,OAAO,CAAA;AAElE,IAAA,MAAM,EAAE,MAAA,EAAO,GAAK,MAAM,SAAS,IAAA,EAAK;AAExC,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,MAAA,CAAO,MAAA,EAAQ;AAC7B,MAAA,MAAM,IAAI,MAAM,kCAAkC,CAAA;AAAA,IACpD;AAGA,IAAA,MAAM,cAAc,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,CAAC,GAAG,QAAQ,CAAA;AAGnD,IAAA,MAAM,MAAA,GAAS,IAAI,WAAA,EAAY;AAC/B,IAAA,MAAA,CAAO,MAAM,WAAW,CAAA;AACxB,IAAA,MAAA,CAAO,GAAA,EAAI;AAEX,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEA,MAAM,WAAA,GAAc;AAClB,IAAA,OAAO,aAAA,CAAc,IAAI,CAAA,KAAA,MAAU;AAAA,MACjC,OAAA,EAAS;AAAA,KACX,CAAE,CAAA;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WAAA,GAAc;AAClB,IAAA,OAAO,EAAE,SAAS,IAAA,EAAK;AAAA,EACzB;AAAA,EAEA,MAAM,MAAA,CAAO,KAAA,EAA8B,OAAA,EAAgD;AAEzF,IAAA,MAAM,SAAmB,EAAC;AAC1B,IAAA,WAAA,MAAiB,SAAS,KAAA,EAAO;AAC/B,MAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,QAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,MAChC,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,MACnB;AAAA,IACF;AACA,IAAA,MAAM,WAAA,GAAc,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA;AAExC,IAAA,MAAM,IAAA,GAAO,IAAI,QAAA,EAAS;AAC1B,IAAA,MAAM,QAAA,GAAW,OAAA,EAAS,QAAA,KAAa,KAAA,GAAQ,YAAA,GAAe,WAAA;AAC9D,IAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,CAAC,WAAW,CAAA,EAAG,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA;AAEvD,IAAA,IAAA,CAAK,MAAA,CAAO,QAAQ,IAAI,CAAA;AACxB,IAAA,IAAA,CAAK,MAAA,CAAO,OAAA,EAAS,OAAA,EAAS,KAAA,IAAS,YAAY,CAAA;AACnD,IAAA,IAAA,CAAK,MAAA,CAAO,eAAA,EAAiB,OAAA,EAAS,YAAA,IAAgB,SAAS,CAAA;AAC/D,IAAA,MAAM,cAAA,GAAiB;AAAA,MACrB,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,wBAAwB,IAAA,CAAK;AAAA,OAC/B;AAAA,MACA,IAAA,EAAM;AAAA,KACR;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,IAAA,CAAK,OAAO,mBAAmB,cAAc,CAAA;AAC7E,MAAA,MAAM,MAAA,GAAU,MAAM,QAAA,CAAS,IAAA,EAAK;AAEpC,MAAA,OAAO,MAAA,CAAO,UAAA;AAAA,IAChB,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAA,CAAM,wCAAwC,KAAK,CAAA;AAC3D,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AACF","file":"index.js","sourcesContent":["export const SARVAM_VOICES = [\n 'meera',\n 'pavithra',\n 'maitreyi',\n 'arvind',\n 'amol',\n 'amartya',\n 'diya',\n 'neel',\n 'misha',\n 'vian',\n 'arjun',\n 'maya',\n] as const;\n\nexport const SARVAM_TTS_LANGUAGES = [\n 'hi-IN',\n 'bn-IN',\n 'kn-IN',\n 'ml-IN',\n 'mr-IN',\n 'od-IN',\n 'pa-IN',\n 'ta-IN',\n 'te-IN',\n 'en-IN',\n 'gu-IN',\n] as const;\n\nexport const SARVAM_STT_LANGUAGES = [...SARVAM_TTS_LANGUAGES, 'unknown'] as const;\n\nexport const SARVAM_TTS_MODELS = ['bulbul:v1'] as const;\nexport const SARVAM_STT_MODELS = ['saarika:v1', 'saarika:v2', 'saarika:flash'] as const;\n\nexport type SarvamVoiceId = (typeof SARVAM_VOICES)[number];\n\nexport type SarvamTTSLanguage = (typeof SARVAM_TTS_LANGUAGES)[number];\nexport type SarvamSTTLanguage = (typeof SARVAM_STT_LANGUAGES)[number];\n\nexport type SarvamTTSModel = (typeof SARVAM_TTS_MODELS)[number];\nexport type SarvamSTTModel = (typeof SARVAM_STT_MODELS)[number];\n","import { PassThrough } from 'stream';\n\nimport { MastraVoice } from '@mastra/core/voice';\nimport { SARVAM_VOICES } from './voices';\nimport type { SarvamTTSLanguage, SarvamSTTLanguage, SarvamSTTModel, SarvamTTSModel, SarvamVoiceId } from './voices';\n\ninterface SarvamVoiceConfig {\n apiKey?: string;\n model?: SarvamTTSModel;\n language?: SarvamTTSLanguage;\n properties?: {\n pitch?: number;\n pace?: number;\n loudness?: number;\n speech_sample_rate?: 8000 | 16000 | 22050;\n enable_preprocessing?: boolean;\n eng_interpolation_wt?: number;\n };\n}\n\ninterface SarvamListenOptions {\n apiKey?: string;\n model?: SarvamSTTModel;\n languageCode?: SarvamSTTLanguage;\n filetype?: 'mp3' | 'wav';\n}\n\nconst defaultSpeechModel = {\n model: 'bulbul:v1' as const,\n apiKey: process.env.SARVAM_API_KEY,\n language: 'en-IN' as const,\n};\n\nconst defaultListeningModel = {\n model: 'saarika:v2' as const,\n apiKey: process.env.SARVAM_API_KEY,\n language_code: 'unknown' as const,\n};\n\nexport class SarvamVoice extends MastraVoice {\n private apiKey?: string;\n private model: SarvamTTSModel = 'bulbul:v1';\n private language: SarvamTTSLanguage = 'en-IN';\n private properties: Record<string, any> = {};\n speaker: SarvamVoiceId = 'meera';\n private baseUrl = 'https://api.sarvam.ai';\n\n constructor({\n speechModel,\n speaker,\n listeningModel,\n }: {\n speechModel?: SarvamVoiceConfig;\n speaker?: SarvamVoiceId;\n listeningModel?: SarvamListenOptions;\n } = {}) {\n super({\n speechModel: {\n name: speechModel?.model ?? defaultSpeechModel.model,\n apiKey: speechModel?.apiKey ?? defaultSpeechModel.apiKey,\n },\n listeningModel: {\n name: listeningModel?.model ?? defaultListeningModel.model,\n apiKey: listeningModel?.model ?? defaultListeningModel.apiKey,\n },\n speaker,\n });\n\n this.apiKey = speechModel?.apiKey || defaultSpeechModel.apiKey;\n if (!this.apiKey) {\n throw new Error('SARVAM_API_KEY must be set');\n }\n this.model = speechModel?.model || defaultSpeechModel.model;\n this.language = speechModel?.language || defaultSpeechModel.language;\n this.properties = speechModel?.properties || {};\n this.speaker = speaker || 'meera';\n }\n\n private async makeRequest(endpoint: string, payload: any) {\n const headers = new Headers({\n 'api-subscription-key': this.apiKey!,\n 'Content-Type': 'application/json',\n });\n const response = await fetch(`${this.baseUrl}${endpoint}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(payload),\n });\n if (!response.ok) {\n let errorMessage;\n try {\n const error = (await response.json()) as { message?: string };\n errorMessage = error.message || response.statusText;\n } catch {\n errorMessage = response.statusText;\n }\n throw new Error(`Sarvam AI API Error: ${errorMessage}`);\n }\n\n return response;\n }\n private async streamToString(stream: NodeJS.ReadableStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n if (typeof chunk === 'string') {\n chunks.push(Buffer.from(chunk));\n } else {\n chunks.push(chunk);\n }\n }\n return Buffer.concat(chunks).toString('utf-8');\n }\n async speak(\n input: string | NodeJS.ReadableStream,\n options?: { speaker?: SarvamVoiceId },\n ): Promise<NodeJS.ReadableStream> {\n const text = typeof input === 'string' ? input : await this.streamToString(input);\n\n const payload = {\n inputs: [text],\n target_language_code: this.language,\n speaker: options?.speaker || this.speaker,\n model: this.model,\n ...this.properties,\n };\n\n const response = await this.makeRequest('/text-to-speech', payload);\n\n const { audios } = (await response.json()) as { audios: any };\n\n if (!audios || !audios.length) {\n throw new Error('No audio received from Sarvam AI');\n }\n\n // Convert base64 to buffer\n const audioBuffer = Buffer.from(audios[0], 'base64');\n\n // Create a PassThrough stream for the audio\n const stream = new PassThrough();\n stream.write(audioBuffer);\n stream.end();\n\n return stream;\n }\n\n async getSpeakers() {\n return SARVAM_VOICES.map(voice => ({\n voiceId: voice,\n }));\n }\n\n /**\n * Checks if listening capabilities are enabled.\n *\n * @returns {Promise<{ enabled: boolean }>}\n */\n async getListener() {\n return { enabled: true };\n }\n\n async listen(input: NodeJS.ReadableStream, options?: SarvamListenOptions): Promise<string> {\n // Collect audio data into buffer\n const chunks: Buffer[] = [];\n for await (const chunk of input) {\n if (typeof chunk === 'string') {\n chunks.push(Buffer.from(chunk));\n } else {\n chunks.push(chunk);\n }\n }\n const audioBuffer = Buffer.concat(chunks);\n\n const form = new FormData();\n const mimeType = options?.filetype === 'mp3' ? 'audio/mpeg' : 'audio/wav';\n const blob = new Blob([audioBuffer], { type: mimeType });\n\n form.append('file', blob);\n form.append('model', options?.model || 'saarika:v2');\n form.append('language_code', options?.languageCode || 'unknown');\n const requestOptions = {\n method: 'POST',\n headers: {\n 'api-subscription-key': this.apiKey!,\n },\n body: form,\n };\n\n try {\n const response = await fetch(`${this.baseUrl}/speech-to-text`, requestOptions);\n const result = (await response.json()) as any;\n //console.log(result);\n return result.transcript;\n } catch (error) {\n console.error('Error during speech-to-text request:', error);\n throw error;\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/voices.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export const SARVAM_VOICES = [\n 'meera',\n 'pavithra',\n 'maitreyi',\n 'arvind',\n 'amol',\n 'amartya',\n 'diya',\n 'neel',\n 'misha',\n 'vian',\n 'arjun',\n 'maya',\n] as const;\n\nexport const SARVAM_TTS_LANGUAGES = [\n 'hi-IN',\n 'bn-IN',\n 'kn-IN',\n 'ml-IN',\n 'mr-IN',\n 'od-IN',\n 'pa-IN',\n 'ta-IN',\n 'te-IN',\n 'en-IN',\n 'gu-IN',\n] as const;\n\nexport const SARVAM_STT_LANGUAGES = [...SARVAM_TTS_LANGUAGES, 'unknown'] as const;\n\nexport const SARVAM_TTS_MODELS = ['bulbul:v1'] as const;\nexport const SARVAM_STT_MODELS = ['saarika:v1', 'saarika:v2', 'saarika:flash'] as const;\n\nexport type SarvamVoiceId = (typeof SARVAM_VOICES)[number];\n\nexport type SarvamTTSLanguage = (typeof SARVAM_TTS_LANGUAGES)[number];\nexport type SarvamSTTLanguage = (typeof SARVAM_STT_LANGUAGES)[number];\n\nexport type SarvamTTSModel = (typeof SARVAM_TTS_MODELS)[number];\nexport type SarvamSTTModel = (typeof SARVAM_STT_MODELS)[number];\n","import { PassThrough } from 'node:stream';\n\nimport { MastraVoice } from '@mastra/core/voice';\nimport { SARVAM_VOICES } from './voices';\nimport type { SarvamTTSLanguage, SarvamSTTLanguage, SarvamSTTModel, SarvamTTSModel, SarvamVoiceId } from './voices';\n\ninterface SarvamVoiceConfig {\n apiKey?: string;\n model?: SarvamTTSModel;\n language?: SarvamTTSLanguage;\n properties?: {\n pitch?: number;\n pace?: number;\n loudness?: number;\n speech_sample_rate?: 8000 | 16000 | 22050;\n enable_preprocessing?: boolean;\n eng_interpolation_wt?: number;\n };\n}\n\ninterface SarvamListenOptions {\n apiKey?: string;\n model?: SarvamSTTModel;\n languageCode?: SarvamSTTLanguage;\n filetype?: 'mp3' | 'wav';\n}\n\nconst defaultSpeechModel = {\n model: 'bulbul:v1' as const,\n apiKey: process.env.SARVAM_API_KEY,\n language: 'en-IN' as const,\n};\n\nconst defaultListeningModel = {\n model: 'saarika:v2' as const,\n apiKey: process.env.SARVAM_API_KEY,\n language_code: 'unknown' as const,\n};\n\nexport class SarvamVoice extends MastraVoice {\n private apiKey?: string;\n private model: SarvamTTSModel = 'bulbul:v1';\n private language: SarvamTTSLanguage = 'en-IN';\n private properties: Record<string, any> = {};\n speaker: SarvamVoiceId = 'meera';\n private baseUrl = 'https://api.sarvam.ai';\n\n constructor({\n speechModel,\n speaker,\n listeningModel,\n }: {\n speechModel?: SarvamVoiceConfig;\n speaker?: SarvamVoiceId;\n listeningModel?: SarvamListenOptions;\n } = {}) {\n super({\n speechModel: {\n name: speechModel?.model ?? defaultSpeechModel.model,\n apiKey: speechModel?.apiKey ?? defaultSpeechModel.apiKey,\n },\n listeningModel: {\n name: listeningModel?.model ?? defaultListeningModel.model,\n apiKey: listeningModel?.model ?? defaultListeningModel.apiKey,\n },\n speaker,\n });\n\n this.apiKey = speechModel?.apiKey || defaultSpeechModel.apiKey;\n if (!this.apiKey) {\n throw new Error('SARVAM_API_KEY must be set');\n }\n this.model = speechModel?.model || defaultSpeechModel.model;\n this.language = speechModel?.language || defaultSpeechModel.language;\n this.properties = speechModel?.properties || {};\n this.speaker = speaker || 'meera';\n }\n\n private async makeRequest(endpoint: string, payload: any) {\n const headers = new Headers({\n 'api-subscription-key': this.apiKey!,\n 'Content-Type': 'application/json',\n });\n const response = await fetch(`${this.baseUrl}${endpoint}`, {\n method: 'POST',\n headers,\n body: JSON.stringify(payload),\n });\n if (!response.ok) {\n let errorMessage;\n try {\n const error = (await response.json()) as { message?: string };\n errorMessage = error.message || response.statusText;\n } catch {\n errorMessage = response.statusText;\n }\n throw new Error(`Sarvam AI API Error: ${errorMessage}`);\n }\n\n return response;\n }\n private async streamToString(stream: NodeJS.ReadableStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n if (typeof chunk === 'string') {\n chunks.push(Buffer.from(chunk));\n } else {\n chunks.push(chunk);\n }\n }\n return Buffer.concat(chunks).toString('utf-8');\n }\n async speak(\n input: string | NodeJS.ReadableStream,\n options?: { speaker?: SarvamVoiceId },\n ): Promise<NodeJS.ReadableStream> {\n const text = typeof input === 'string' ? input : await this.streamToString(input);\n\n const payload = {\n inputs: [text],\n target_language_code: this.language,\n speaker: options?.speaker || this.speaker,\n model: this.model,\n ...this.properties,\n };\n\n const response = await this.makeRequest('/text-to-speech', payload);\n\n const { audios } = (await response.json()) as { audios: any };\n\n if (!audios || !audios.length) {\n throw new Error('No audio received from Sarvam AI');\n }\n\n // Convert base64 to buffer\n const audioBuffer = Buffer.from(audios[0], 'base64');\n\n // Create a PassThrough stream for the audio\n const stream = new PassThrough();\n stream.write(audioBuffer);\n stream.end();\n\n return stream;\n }\n\n async getSpeakers() {\n return SARVAM_VOICES.map(voice => ({\n voiceId: voice,\n }));\n }\n\n /**\n * Checks if listening capabilities are enabled.\n *\n * @returns {Promise<{ enabled: boolean }>}\n */\n async getListener() {\n return { enabled: true };\n }\n\n async listen(input: NodeJS.ReadableStream, options?: SarvamListenOptions): Promise<string> {\n // Collect audio data into buffer\n const chunks: Buffer[] = [];\n for await (const chunk of input) {\n if (typeof chunk === 'string') {\n chunks.push(Buffer.from(chunk));\n } else {\n chunks.push(chunk);\n }\n }\n const audioBuffer = Buffer.concat(chunks);\n\n const form = new FormData();\n const mimeType = options?.filetype === 'mp3' ? 'audio/mpeg' : 'audio/wav';\n const blob = new Blob([audioBuffer], { type: mimeType });\n\n form.append('file', blob);\n form.append('model', options?.model || 'saarika:v2');\n form.append('language_code', options?.languageCode || 'unknown');\n const requestOptions = {\n method: 'POST',\n headers: {\n 'api-subscription-key': this.apiKey!,\n },\n body: form,\n };\n\n try {\n const response = await fetch(`${this.baseUrl}/speech-to-text`, requestOptions);\n const result = (await response.json()) as any;\n //console.log(result);\n return result.transcript;\n } catch (error) {\n console.error('Error during speech-to-text request:', error);\n throw error;\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/voice-sarvam",
3
- "version": "0.12.0-beta.0",
3
+ "version": "0.12.0-beta.1",
4
4
  "description": "Mastra Sarvam AI voice integration",
5
5
  "type": "module",
6
6
  "files": [
@@ -23,18 +23,18 @@
23
23
  "./package.json": "./package.json"
24
24
  },
25
25
  "license": "Apache-2.0",
26
- "dependencies": {},
27
26
  "devDependencies": {
28
- "@microsoft/api-extractor": "^7.52.8",
29
- "@types/node": "^20.19.0",
27
+ "@types/node": "22.13.17",
28
+ "@vitest/coverage-v8": "4.0.12",
29
+ "@vitest/ui": "4.0.12",
30
30
  "eslint": "^9.37.0",
31
31
  "tsup": "^8.5.0",
32
- "typescript": "^5.8.3",
33
- "vitest": "^3.2.4",
32
+ "typescript": "^5.9.3",
33
+ "vitest": "4.0.16",
34
34
  "zod": "^3.25.76",
35
35
  "@internal/lint": "0.0.53",
36
- "@mastra/core": "1.0.0-beta.0",
37
- "@internal/types-builder": "0.0.28"
36
+ "@internal/types-builder": "0.0.28",
37
+ "@mastra/core": "1.0.0-beta.20"
38
38
  },
39
39
  "keywords": [
40
40
  "mastra",
@@ -64,6 +64,7 @@
64
64
  },
65
65
  "scripts": {
66
66
  "build": "tsup --silent --config tsup.config.ts",
67
+ "postbuild": "pnpx tsx ../../scripts/generate-package-docs.ts voice/sarvam",
67
68
  "build:watch": "tsup --watch --silent --config tsup.config.ts",
68
69
  "test": "vitest run",
69
70
  "test:watch": "vitest watch",