@juspay/neurolink 8.15.0 → 8.16.0

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [8.16.0](https://github.com/juspay/neurolink/compare/v8.15.0...v8.16.0) (2025-12-16)
2
+
3
+ ### Features
4
+
5
+ - **(tts):** Implement GoogleTTSHandler.getVoices() API ([15d39f7](https://github.com/juspay/neurolink/commit/15d39f7e6bfe093971bc822e8f4251b7e8711bb9))
6
+
1
7
  ## [8.15.0](https://github.com/juspay/neurolink/compare/v8.14.0...v8.15.0) (2025-12-14)
2
8
 
3
9
  ### Features
@@ -2,6 +2,8 @@ import type { TTSHandler } from "../../utils/ttsProcessor.js";
2
2
  import type { TTSOptions, TTSResult, TTSVoice } from "../../types/ttsTypes.js";
3
3
  export declare class GoogleTTSHandler implements TTSHandler {
4
4
  private client;
5
+ private voicesCache;
6
+ private static readonly CACHE_TTL_MS;
5
7
  /**
6
8
  * Google Cloud TTS maximum input size.
7
9
  * ~5000 bytes INCLUDING SSML tags.
@@ -35,12 +37,11 @@ export declare class GoogleTTSHandler implements TTSHandler {
35
37
  *
36
38
  * Note: This method is optional in the TTSHandler interface, but Google Cloud TTS
37
39
  * fully implements it to provide comprehensive voice discovery capabilities.
38
- * Will be Implemented in ISSUE - TTS-014
39
40
  *
40
41
  * @param languageCode - Optional language filter (e.g., "en-US")
41
42
  * @returns List of available voices
42
43
  */
43
- getVoices(_languageCode?: string): Promise<TTSVoice[]>;
44
+ getVoices(languageCode?: string): Promise<TTSVoice[]>;
44
45
  /**
45
46
  * Generate audio from text using provider-specific TTS API
46
47
  *
@@ -67,4 +68,21 @@ export declare class GoogleTTSHandler implements TTSHandler {
67
68
  * @throws Error if format is unsupported
68
69
  */
69
70
  private mapFormat;
71
+ /**
72
+ * Detect the voice type from a Google Cloud TTS voice name
73
+ *
74
+ * Parses the voice name to identify the underlying voice technology/model type.
75
+ * Google Cloud TTS offers different voice types with varying quality and pricing.
76
+ *
77
+ * @param name - The full Google Cloud voice name (e.g., "en-US-Neural2-C")
78
+ * @returns The detected voice type
79
+ *
80
+ * @example
81
+ * detectVoiceType("en-US-Neural2-C") // returns "neural"
82
+ * detectVoiceType("en-US-Wavenet-A") // returns "wavenet"
83
+ * detectVoiceType("en-US-Standard-B") // returns "standard"
84
+ * detectVoiceType("en-US-Chirp-A") // returns "chirp"
85
+ * detectVoiceType("en-US-Journey-D") // returns "unknown" (unrecognized type)
86
+ */
87
+ private detectVoiceType;
70
88
  }
@@ -9,8 +9,11 @@
9
9
  import { TextToSpeechClient } from "@google-cloud/text-to-speech";
10
10
  import { TTSError, TTS_ERROR_CODES } from "../../utils/ttsProcessor.js";
11
11
  import { ErrorCategory, ErrorSeverity } from "../../constants/enums.js";
12
+ import { logger } from "../../utils/logger.js";
12
13
  export class GoogleTTSHandler {
13
14
  client = null;
15
+ voicesCache = null;
16
+ static CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
14
17
  /**
15
18
  * Google Cloud TTS maximum input size.
16
19
  * ~5000 bytes INCLUDING SSML tags.
@@ -51,13 +54,78 @@ export class GoogleTTSHandler {
51
54
  *
52
55
  * Note: This method is optional in the TTSHandler interface, but Google Cloud TTS
53
56
  * fully implements it to provide comprehensive voice discovery capabilities.
54
- * Will be Implemented in ISSUE - TTS-014
55
57
  *
56
58
  * @param languageCode - Optional language filter (e.g., "en-US")
57
59
  * @returns List of available voices
58
60
  */
59
- async getVoices(_languageCode) {
60
- throw new Error("Not implemented yet");
61
+ async getVoices(languageCode) {
62
+ if (!this.client) {
63
+ throw new TTSError({
64
+ code: TTS_ERROR_CODES.PROVIDER_NOT_CONFIGURED,
65
+ message: "Google Cloud TTS client not initialized. Set GOOGLE_APPLICATION_CREDENTIALS or pass credentials path.",
66
+ category: ErrorCategory.CONFIGURATION,
67
+ severity: ErrorSeverity.HIGH,
68
+ retriable: false,
69
+ });
70
+ }
71
+ try {
72
+ // Return cached voices if available, valid, and no language filter is specified
73
+ if (this.voicesCache &&
74
+ Date.now() - this.voicesCache.timestamp <
75
+ GoogleTTSHandler.CACHE_TTL_MS &&
76
+ !languageCode) {
77
+ return this.voicesCache.voices;
78
+ }
79
+ // Call Google Cloud listVoices API
80
+ const [response] = await this.client.listVoices(languageCode ? { languageCode } : {});
81
+ if (!response.voices || response.voices.length === 0) {
82
+ logger.warn("Google Cloud TTS returned no voices");
83
+ return [];
84
+ }
85
+ const voices = [];
86
+ for (const voice of response.voices ?? []) {
87
+ // Validate required fields
88
+ if (!voice.name ||
89
+ !Array.isArray(voice.languageCodes) ||
90
+ voice.languageCodes.length === 0) {
91
+ logger.warn("Skipping voice with missing required fields", {
92
+ name: voice.name,
93
+ languageCodesCount: voice.languageCodes?.length,
94
+ });
95
+ continue;
96
+ }
97
+ const voiceName = voice.name;
98
+ const languageCodes = voice.languageCodes;
99
+ const primaryLanguageCode = languageCodes[0];
100
+ const voiceType = this.detectVoiceType(voiceName);
101
+ // Map Google's ssmlGender → internal Gender
102
+ const gender = voice.ssmlGender === "MALE"
103
+ ? "male"
104
+ : voice.ssmlGender === "FEMALE"
105
+ ? "female"
106
+ : "neutral";
107
+ voices.push({
108
+ id: voiceName,
109
+ name: voiceName,
110
+ languageCode: primaryLanguageCode,
111
+ languageCodes,
112
+ gender,
113
+ type: voiceType,
114
+ naturalSampleRateHertz: voice.naturalSampleRateHertz ?? undefined,
115
+ });
116
+ }
117
+ // Cache the result with timestamp if no language filter
118
+ if (!languageCode) {
119
+ this.voicesCache = { voices, timestamp: Date.now() };
120
+ }
121
+ return voices;
122
+ }
123
+ catch (err) {
124
+ // Log error but return empty array for graceful degradation
125
+ const message = err instanceof Error ? err.message : "Unknown error";
126
+ logger.error(`Failed to fetch Google TTS voices: ${message}`);
127
+ return [];
128
+ }
61
129
  }
62
130
  /**
63
131
  * Generate audio from text using provider-specific TTS API
@@ -216,4 +284,36 @@ export class GoogleTTSHandler {
216
284
  });
217
285
  }
218
286
  }
287
+ /**
288
+ * Detect the voice type from a Google Cloud TTS voice name
289
+ *
290
+ * Parses the voice name to identify the underlying voice technology/model type.
291
+ * Google Cloud TTS offers different voice types with varying quality and pricing.
292
+ *
293
+ * @param name - The full Google Cloud voice name (e.g., "en-US-Neural2-C")
294
+ * @returns The detected voice type
295
+ *
296
+ * @example
297
+ * detectVoiceType("en-US-Neural2-C") // returns "neural"
298
+ * detectVoiceType("en-US-Wavenet-A") // returns "wavenet"
299
+ * detectVoiceType("en-US-Standard-B") // returns "standard"
300
+ * detectVoiceType("en-US-Chirp-A") // returns "chirp"
301
+ * detectVoiceType("en-US-Journey-D") // returns "unknown" (unrecognized type)
302
+ */
303
+ detectVoiceType(name) {
304
+ const tokens = name.toLowerCase().split("-");
305
+ if (tokens.some((t) => t.startsWith("chirp"))) {
306
+ return "chirp";
307
+ }
308
+ if (tokens.includes("neural2")) {
309
+ return "neural";
310
+ }
311
+ if (tokens.includes("wavenet")) {
312
+ return "wavenet";
313
+ }
314
+ if (tokens.includes("standard")) {
315
+ return "standard";
316
+ }
317
+ return "unknown";
318
+ }
219
319
  }
@@ -2,6 +2,8 @@ import type { TTSHandler } from "../../utils/ttsProcessor.js";
2
2
  import type { TTSOptions, TTSResult, TTSVoice } from "../../types/ttsTypes.js";
3
3
  export declare class GoogleTTSHandler implements TTSHandler {
4
4
  private client;
5
+ private voicesCache;
6
+ private static readonly CACHE_TTL_MS;
5
7
  /**
6
8
  * Google Cloud TTS maximum input size.
7
9
  * ~5000 bytes INCLUDING SSML tags.
@@ -35,12 +37,11 @@ export declare class GoogleTTSHandler implements TTSHandler {
35
37
  *
36
38
  * Note: This method is optional in the TTSHandler interface, but Google Cloud TTS
37
39
  * fully implements it to provide comprehensive voice discovery capabilities.
38
- * Will be Implemented in ISSUE - TTS-014
39
40
  *
40
41
  * @param languageCode - Optional language filter (e.g., "en-US")
41
42
  * @returns List of available voices
42
43
  */
43
- getVoices(_languageCode?: string): Promise<TTSVoice[]>;
44
+ getVoices(languageCode?: string): Promise<TTSVoice[]>;
44
45
  /**
45
46
  * Generate audio from text using provider-specific TTS API
46
47
  *
@@ -67,4 +68,21 @@ export declare class GoogleTTSHandler implements TTSHandler {
67
68
  * @throws Error if format is unsupported
68
69
  */
69
70
  private mapFormat;
71
+ /**
72
+ * Detect the voice type from a Google Cloud TTS voice name
73
+ *
74
+ * Parses the voice name to identify the underlying voice technology/model type.
75
+ * Google Cloud TTS offers different voice types with varying quality and pricing.
76
+ *
77
+ * @param name - The full Google Cloud voice name (e.g., "en-US-Neural2-C")
78
+ * @returns The detected voice type
79
+ *
80
+ * @example
81
+ * detectVoiceType("en-US-Neural2-C") // returns "neural"
82
+ * detectVoiceType("en-US-Wavenet-A") // returns "wavenet"
83
+ * detectVoiceType("en-US-Standard-B") // returns "standard"
84
+ * detectVoiceType("en-US-Chirp-A") // returns "chirp"
85
+ * detectVoiceType("en-US-Journey-D") // returns "unknown" (unrecognized type)
86
+ */
87
+ private detectVoiceType;
70
88
  }
@@ -9,8 +9,11 @@
9
9
  import { TextToSpeechClient } from "@google-cloud/text-to-speech";
10
10
  import { TTSError, TTS_ERROR_CODES } from "../../utils/ttsProcessor.js";
11
11
  import { ErrorCategory, ErrorSeverity } from "../../constants/enums.js";
12
+ import { logger } from "../../utils/logger.js";
12
13
  export class GoogleTTSHandler {
13
14
  client = null;
15
+ voicesCache = null;
16
+ static CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
14
17
  /**
15
18
  * Google Cloud TTS maximum input size.
16
19
  * ~5000 bytes INCLUDING SSML tags.
@@ -51,13 +54,78 @@ export class GoogleTTSHandler {
51
54
  *
52
55
  * Note: This method is optional in the TTSHandler interface, but Google Cloud TTS
53
56
  * fully implements it to provide comprehensive voice discovery capabilities.
54
- * Will be Implemented in ISSUE - TTS-014
55
57
  *
56
58
  * @param languageCode - Optional language filter (e.g., "en-US")
57
59
  * @returns List of available voices
58
60
  */
59
- async getVoices(_languageCode) {
60
- throw new Error("Not implemented yet");
61
+ async getVoices(languageCode) {
62
+ if (!this.client) {
63
+ throw new TTSError({
64
+ code: TTS_ERROR_CODES.PROVIDER_NOT_CONFIGURED,
65
+ message: "Google Cloud TTS client not initialized. Set GOOGLE_APPLICATION_CREDENTIALS or pass credentials path.",
66
+ category: ErrorCategory.CONFIGURATION,
67
+ severity: ErrorSeverity.HIGH,
68
+ retriable: false,
69
+ });
70
+ }
71
+ try {
72
+ // Return cached voices if available, valid, and no language filter is specified
73
+ if (this.voicesCache &&
74
+ Date.now() - this.voicesCache.timestamp <
75
+ GoogleTTSHandler.CACHE_TTL_MS &&
76
+ !languageCode) {
77
+ return this.voicesCache.voices;
78
+ }
79
+ // Call Google Cloud listVoices API
80
+ const [response] = await this.client.listVoices(languageCode ? { languageCode } : {});
81
+ if (!response.voices || response.voices.length === 0) {
82
+ logger.warn("Google Cloud TTS returned no voices");
83
+ return [];
84
+ }
85
+ const voices = [];
86
+ for (const voice of response.voices ?? []) {
87
+ // Validate required fields
88
+ if (!voice.name ||
89
+ !Array.isArray(voice.languageCodes) ||
90
+ voice.languageCodes.length === 0) {
91
+ logger.warn("Skipping voice with missing required fields", {
92
+ name: voice.name,
93
+ languageCodesCount: voice.languageCodes?.length,
94
+ });
95
+ continue;
96
+ }
97
+ const voiceName = voice.name;
98
+ const languageCodes = voice.languageCodes;
99
+ const primaryLanguageCode = languageCodes[0];
100
+ const voiceType = this.detectVoiceType(voiceName);
101
+ // Map Google's ssmlGender → internal Gender
102
+ const gender = voice.ssmlGender === "MALE"
103
+ ? "male"
104
+ : voice.ssmlGender === "FEMALE"
105
+ ? "female"
106
+ : "neutral";
107
+ voices.push({
108
+ id: voiceName,
109
+ name: voiceName,
110
+ languageCode: primaryLanguageCode,
111
+ languageCodes,
112
+ gender,
113
+ type: voiceType,
114
+ naturalSampleRateHertz: voice.naturalSampleRateHertz ?? undefined,
115
+ });
116
+ }
117
+ // Cache the result with timestamp if no language filter
118
+ if (!languageCode) {
119
+ this.voicesCache = { voices, timestamp: Date.now() };
120
+ }
121
+ return voices;
122
+ }
123
+ catch (err) {
124
+ // Log error but return empty array for graceful degradation
125
+ const message = err instanceof Error ? err.message : "Unknown error";
126
+ logger.error(`Failed to fetch Google TTS voices: ${message}`);
127
+ return [];
128
+ }
61
129
  }
62
130
  /**
63
131
  * Generate audio from text using provider-specific TTS API
@@ -216,5 +284,37 @@ export class GoogleTTSHandler {
216
284
  });
217
285
  }
218
286
  }
287
+ /**
288
+ * Detect the voice type from a Google Cloud TTS voice name
289
+ *
290
+ * Parses the voice name to identify the underlying voice technology/model type.
291
+ * Google Cloud TTS offers different voice types with varying quality and pricing.
292
+ *
293
+ * @param name - The full Google Cloud voice name (e.g., "en-US-Neural2-C")
294
+ * @returns The detected voice type
295
+ *
296
+ * @example
297
+ * detectVoiceType("en-US-Neural2-C") // returns "neural"
298
+ * detectVoiceType("en-US-Wavenet-A") // returns "wavenet"
299
+ * detectVoiceType("en-US-Standard-B") // returns "standard"
300
+ * detectVoiceType("en-US-Chirp-A") // returns "chirp"
301
+ * detectVoiceType("en-US-Journey-D") // returns "unknown" (unrecognized type)
302
+ */
303
+ detectVoiceType(name) {
304
+ const tokens = name.toLowerCase().split("-");
305
+ if (tokens.some((t) => t.startsWith("chirp"))) {
306
+ return "chirp";
307
+ }
308
+ if (tokens.includes("neural2")) {
309
+ return "neural";
310
+ }
311
+ if (tokens.includes("wavenet")) {
312
+ return "wavenet";
313
+ }
314
+ if (tokens.includes("standard")) {
315
+ return "standard";
316
+ }
317
+ return "unknown";
318
+ }
219
319
  }
220
320
  //# sourceMappingURL=googleTTSHandler.js.map
@@ -75,6 +75,10 @@ export type AudioSaveResult = {
75
75
  /** Error message if failed */
76
76
  error?: string;
77
77
  };
78
+ /** Allowed TTS voice types */
79
+ export type VoiceType = "standard" | "wavenet" | "neural" | "chirp" | "unknown";
80
+ /** Allowed genders for TTS voices */
81
+ export type Gender = "male" | "female" | "neutral";
78
82
  /**
79
83
  * TTS voice information
80
84
  */
@@ -83,12 +87,18 @@ export type TTSVoice = {
83
87
  id: string;
84
88
  /** Display name */
85
89
  name: string;
86
- /** Language code (e.g., "en-US") */
90
+ /** Primary language code (e.g., "en-US") */
87
91
  languageCode: string;
92
+ /** All supported language codes */
93
+ languageCodes: string[];
88
94
  /** Gender */
89
- gender: "male" | "female" | "neutral";
95
+ gender: Gender;
90
96
  /** Voice type */
91
- type: "neural" | "wavenet" | "standard";
97
+ type?: VoiceType;
98
+ /** Voice description (optional) */
99
+ description?: string;
100
+ /** Natural sample rate in Hz (optional) */
101
+ naturalSampleRateHertz?: number;
92
102
  };
93
103
  /** Valid audio formats as an array for runtime validation */
94
104
  export declare const VALID_AUDIO_FORMATS: readonly AudioFormat[];
@@ -75,6 +75,10 @@ export type AudioSaveResult = {
75
75
  /** Error message if failed */
76
76
  error?: string;
77
77
  };
78
+ /** Allowed TTS voice types */
79
+ export type VoiceType = "standard" | "wavenet" | "neural" | "chirp" | "unknown";
80
+ /** Allowed genders for TTS voices */
81
+ export type Gender = "male" | "female" | "neutral";
78
82
  /**
79
83
  * TTS voice information
80
84
  */
@@ -83,12 +87,18 @@ export type TTSVoice = {
83
87
  id: string;
84
88
  /** Display name */
85
89
  name: string;
86
- /** Language code (e.g., "en-US") */
90
+ /** Primary language code (e.g., "en-US") */
87
91
  languageCode: string;
92
+ /** All supported language codes */
93
+ languageCodes: string[];
88
94
  /** Gender */
89
- gender: "male" | "female" | "neutral";
95
+ gender: Gender;
90
96
  /** Voice type */
91
- type: "neural" | "wavenet" | "standard";
97
+ type?: VoiceType;
98
+ /** Voice description (optional) */
99
+ description?: string;
100
+ /** Natural sample rate in Hz (optional) */
101
+ naturalSampleRateHertz?: number;
92
102
  };
93
103
  /** Valid audio formats as an array for runtime validation */
94
104
  export declare const VALID_AUDIO_FORMATS: readonly AudioFormat[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "8.15.0",
3
+ "version": "8.16.0",
4
4
  "description": "Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and deploy AI applications with 9 major providers: OpenAI, Anthropic, Google AI, AWS Bedrock, Azure, Hugging Face, Ollama, and Mistral AI.",
5
5
  "author": {
6
6
  "name": "Juspay Technologies",