@neosapience/typecast-js 0.1.3 → 0.1.5
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/README.md +219 -184
- package/lib/index.cjs +109 -41
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +142 -19
- package/lib/index.d.ts +142 -19
- package/lib/index.js +109 -37
- package/lib/index.js.map +1 -1
- package/package.json +3 -5
package/lib/index.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
|
|
3
|
-
// src/client.ts
|
|
4
|
-
|
|
5
1
|
// src/errors.ts
|
|
6
2
|
var TypecastAPIError = class _TypecastAPIError extends Error {
|
|
7
3
|
constructor(message, statusCode, response) {
|
|
@@ -48,58 +44,134 @@ var TypecastAPIError = class _TypecastAPIError extends Error {
|
|
|
48
44
|
// src/client.ts
|
|
49
45
|
var TypecastClient = class {
|
|
50
46
|
constructor(config = {}) {
|
|
51
|
-
|
|
47
|
+
const finalConfig = {
|
|
52
48
|
baseHost: process.env.TYPECAST_API_HOST || "https://api.typecast.ai",
|
|
53
49
|
apiKey: process.env.TYPECAST_API_KEY || "",
|
|
54
50
|
...config
|
|
55
51
|
};
|
|
56
|
-
this.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
this.baseHost = finalConfig.baseHost;
|
|
53
|
+
this.headers = {
|
|
54
|
+
"X-API-KEY": finalConfig.apiKey,
|
|
55
|
+
"Content-Type": "application/json"
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Handle HTTP error responses
|
|
60
|
+
*/
|
|
61
|
+
async handleResponse(response) {
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
let errorData;
|
|
64
|
+
try {
|
|
65
|
+
errorData = await response.json();
|
|
66
|
+
} catch {
|
|
61
67
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
throw TypecastAPIError.fromResponse(
|
|
69
|
+
response.status,
|
|
70
|
+
response.statusText,
|
|
71
|
+
errorData
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
return response.json();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Build URL with query parameters
|
|
78
|
+
*/
|
|
79
|
+
buildUrl(path, params) {
|
|
80
|
+
const url = new URL(path, this.baseHost);
|
|
81
|
+
if (params) {
|
|
82
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
83
|
+
if (value !== void 0 && value !== null) {
|
|
84
|
+
url.searchParams.append(key, String(value));
|
|
72
85
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return url.toString();
|
|
76
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Convert text to speech
|
|
92
|
+
* @param request - TTS request parameters including text, voice_id, model, and optional settings
|
|
93
|
+
* @returns TTSResponse containing audio data, duration, and format
|
|
94
|
+
*/
|
|
77
95
|
async textToSpeech(request) {
|
|
78
|
-
const response = await this.
|
|
79
|
-
|
|
96
|
+
const response = await fetch(this.buildUrl("/v1/text-to-speech"), {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: this.headers,
|
|
99
|
+
body: JSON.stringify(request)
|
|
80
100
|
});
|
|
81
|
-
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
let errorData;
|
|
103
|
+
try {
|
|
104
|
+
errorData = await response.json();
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
throw TypecastAPIError.fromResponse(
|
|
108
|
+
response.status,
|
|
109
|
+
response.statusText,
|
|
110
|
+
errorData
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
const contentType = response.headers.get("content-type") || "audio/wav";
|
|
82
114
|
const formatFromHeader = contentType.split("/")[1] || "wav";
|
|
83
115
|
const format = formatFromHeader === "mp3" ? "mp3" : "wav";
|
|
84
|
-
const durationHeader = response.headers
|
|
85
|
-
const duration =
|
|
116
|
+
const durationHeader = response.headers.get("x-audio-duration");
|
|
117
|
+
const duration = durationHeader ? Number(durationHeader) : 0;
|
|
118
|
+
const audioData = await response.arrayBuffer();
|
|
86
119
|
return {
|
|
87
|
-
audioData
|
|
120
|
+
audioData,
|
|
88
121
|
duration,
|
|
89
122
|
format
|
|
90
123
|
};
|
|
91
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Get available voices (V1 API)
|
|
127
|
+
* @param model - Optional model filter (e.g., 'ssfm-v21', 'ssfm-v30')
|
|
128
|
+
* @returns List of available voices with their emotions
|
|
129
|
+
* @deprecated Use getVoicesV2() for enhanced metadata and filtering options
|
|
130
|
+
*/
|
|
92
131
|
async getVoices(model) {
|
|
93
|
-
const response = await
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
132
|
+
const response = await fetch(
|
|
133
|
+
this.buildUrl("/v1/voices", model ? { model } : void 0),
|
|
134
|
+
{ headers: this.headers }
|
|
135
|
+
);
|
|
136
|
+
return this.handleResponse(response);
|
|
97
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Get voice by ID (V1 API)
|
|
140
|
+
* @param voiceId - The voice ID (e.g., 'tc_62a8975e695ad26f7fb514d1')
|
|
141
|
+
* @param model - Optional model filter
|
|
142
|
+
* @returns Voice information including available emotions
|
|
143
|
+
* @deprecated Use getVoicesV2() for enhanced metadata
|
|
144
|
+
*/
|
|
98
145
|
async getVoiceById(voiceId, model) {
|
|
99
|
-
const response = await
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
146
|
+
const response = await fetch(
|
|
147
|
+
this.buildUrl(`/v1/voices/${voiceId}`, model ? { model } : void 0),
|
|
148
|
+
{ headers: this.headers }
|
|
149
|
+
);
|
|
150
|
+
return this.handleResponse(response);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Get voices with enhanced metadata (V2 API)
|
|
154
|
+
* Returns voices with model-grouped emotions and additional metadata
|
|
155
|
+
* @param filter - Optional filter options (model, gender, age, use_cases)
|
|
156
|
+
*/
|
|
157
|
+
async getVoicesV2(filter) {
|
|
158
|
+
const response = await fetch(
|
|
159
|
+
this.buildUrl("/v2/voices", filter),
|
|
160
|
+
{ headers: this.headers }
|
|
161
|
+
);
|
|
162
|
+
return this.handleResponse(response);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get a specific voice by ID with enhanced metadata (V2 API)
|
|
166
|
+
* @param voiceId - The voice ID (e.g., 'tc_62a8975e695ad26f7fb514d1')
|
|
167
|
+
* @returns Voice information with model-grouped emotions and metadata
|
|
168
|
+
*/
|
|
169
|
+
async getVoiceV2(voiceId) {
|
|
170
|
+
const response = await fetch(
|
|
171
|
+
this.buildUrl(`/v2/voices/${voiceId}`),
|
|
172
|
+
{ headers: this.headers }
|
|
173
|
+
);
|
|
174
|
+
return this.handleResponse(response);
|
|
103
175
|
}
|
|
104
176
|
};
|
|
105
177
|
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { ApiErrorResponse } from './types';\n\nexport class TypecastAPIError extends Error {\n public readonly statusCode: number;\n public readonly response?: ApiErrorResponse;\n\n constructor(message: string, statusCode: number, response?: ApiErrorResponse) {\n super(message);\n this.name = 'TypecastAPIError';\n this.statusCode = statusCode;\n this.response = response;\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TypecastAPIError);\n }\n }\n\n static fromResponse(statusCode: number, statusText: string, data?: ApiErrorResponse): TypecastAPIError {\n let message: string;\n\n switch (statusCode) {\n case 400:\n message = 'Bad Request - The request was invalid or cannot be served';\n break;\n case 401:\n message = 'Unauthorized - Invalid or missing API key';\n break;\n case 402:\n message = 'Payment Required - Insufficient credits to complete the request';\n break;\n case 404:\n message = 'Not Found - The requested resource does not exist';\n break;\n case 422:\n message = 'Validation Error - The request data failed validation';\n break;\n case 500:\n message = 'Internal Server Error - Something went wrong on the server';\n break;\n default:\n message = `API request failed with status ${statusCode}: ${statusText}`;\n }\n\n if (data?.detail) {\n const detailStr = typeof data.detail === 'string' \n ? data.detail \n : JSON.stringify(data.detail);\n message += ` - ${detailStr}`;\n }\n\n return new TypecastAPIError(message, statusCode, data);\n }\n}\n\n","import axios, { AxiosInstance, AxiosError } from 'axios';\nimport { ClientConfig, TTSRequest, TTSResponse, ApiErrorResponse } from './types';\nimport { VoicesResponse } from './types/Voices';\nimport { TypecastAPIError } from './errors';\n\nexport class TypecastClient {\n private client: AxiosInstance;\n private config: ClientConfig;\n\n constructor(config: Partial<ClientConfig> = {}) {\n this.config = {\n baseHost: process.env.TYPECAST_API_HOST || 'https://api.typecast.ai',\n apiKey: process.env.TYPECAST_API_KEY || '',\n ...config,\n };\n this.client = axios.create({\n baseURL: this.config.baseHost,\n headers: {\n 'X-API-KEY': this.config.apiKey,\n 'Content-Type': 'application/json',\n },\n });\n\n // Add response interceptor for error handling\n this.client.interceptors.response.use(\n (response) => response,\n (error: AxiosError<ApiErrorResponse>) => {\n if (error.response) {\n throw TypecastAPIError.fromResponse(\n error.response.status,\n error.response.statusText,\n error.response.data\n );\n }\n throw error;\n }\n );\n }\n\n async textToSpeech(request: TTSRequest): Promise<TTSResponse> {\n const response = await this.client.post<ArrayBuffer>('/v1/text-to-speech', request, {\n responseType: 'arraybuffer',\n });\n\n const contentType = String(response.headers['content-type'] || 'audio/wav');\n const formatFromHeader = contentType.split('/')[1] || 'wav';\n const format: 'wav' | 'mp3' = formatFromHeader === 'mp3' ? 'mp3' : 'wav';\n\n const durationHeader: unknown = response.headers['x-audio-duration'];\n const duration = typeof durationHeader === 'string' ? Number(durationHeader) : 0;\n\n return {\n audioData: response.data,\n duration,\n format,\n };\n }\n\n async getVoices(model?: string): Promise<VoicesResponse[]> {\n const response = await this.client.get<VoicesResponse[]>('/v1/voices', {\n params: model ? { model } : undefined,\n });\n return response.data;\n }\n\n async getVoiceById(voiceId: string, model?: string): Promise<VoicesResponse[]> {\n const response = await this.client.get<VoicesResponse[]>(`/v1/voices/${voiceId}`, {\n params: model ? { model } : undefined,\n });\n return response.data;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { ApiErrorResponse } from './types';\n\nexport class TypecastAPIError extends Error {\n public readonly statusCode: number;\n public readonly response?: ApiErrorResponse;\n\n constructor(message: string, statusCode: number, response?: ApiErrorResponse) {\n super(message);\n this.name = 'TypecastAPIError';\n this.statusCode = statusCode;\n this.response = response;\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TypecastAPIError);\n }\n }\n\n static fromResponse(statusCode: number, statusText: string, data?: ApiErrorResponse): TypecastAPIError {\n let message: string;\n\n switch (statusCode) {\n case 400:\n message = 'Bad Request - The request was invalid or cannot be served';\n break;\n case 401:\n message = 'Unauthorized - Invalid or missing API key';\n break;\n case 402:\n message = 'Payment Required - Insufficient credits to complete the request';\n break;\n case 404:\n message = 'Not Found - The requested resource does not exist';\n break;\n case 422:\n message = 'Validation Error - The request data failed validation';\n break;\n case 500:\n message = 'Internal Server Error - Something went wrong on the server';\n break;\n default:\n message = `API request failed with status ${statusCode}: ${statusText}`;\n }\n\n if (data?.detail) {\n const detailStr = typeof data.detail === 'string' \n ? data.detail \n : JSON.stringify(data.detail);\n message += ` - ${detailStr}`;\n }\n\n return new TypecastAPIError(message, statusCode, data);\n }\n}\n\n","import { ClientConfig, TTSRequest, TTSResponse, ApiErrorResponse } from './types';\nimport { VoicesResponse, VoiceV2Response, VoicesV2Filter } from './types/Voices';\nimport { TypecastAPIError } from './errors';\n\nexport class TypecastClient {\n private baseHost: string;\n private headers: Record<string, string>;\n\n constructor(config: Partial<ClientConfig> = {}) {\n const finalConfig: ClientConfig = {\n baseHost: process.env.TYPECAST_API_HOST || 'https://api.typecast.ai',\n apiKey: process.env.TYPECAST_API_KEY || '',\n ...config,\n };\n this.baseHost = finalConfig.baseHost;\n this.headers = {\n 'X-API-KEY': finalConfig.apiKey,\n 'Content-Type': 'application/json',\n };\n }\n\n /**\n * Handle HTTP error responses\n */\n private async handleResponse<T>(response: Response): Promise<T> {\n if (!response.ok) {\n let errorData: ApiErrorResponse | undefined;\n try {\n errorData = (await response.json()) as ApiErrorResponse;\n } catch {\n // Response body is not JSON\n }\n throw TypecastAPIError.fromResponse(\n response.status,\n response.statusText,\n errorData\n );\n }\n return response.json() as Promise<T>;\n }\n\n /**\n * Build URL with query parameters\n */\n private buildUrl(path: string, params?: Record<string, unknown>): string {\n const url = new URL(path, this.baseHost);\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.append(key, String(value));\n }\n });\n }\n return url.toString();\n }\n\n /**\n * Convert text to speech\n * @param request - TTS request parameters including text, voice_id, model, and optional settings\n * @returns TTSResponse containing audio data, duration, and format\n */\n async textToSpeech(request: TTSRequest): Promise<TTSResponse> {\n const response = await fetch(this.buildUrl('/v1/text-to-speech'), {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n let errorData: ApiErrorResponse | undefined;\n try {\n errorData = (await response.json()) as ApiErrorResponse;\n } catch {\n // Response body is not JSON\n }\n throw TypecastAPIError.fromResponse(\n response.status,\n response.statusText,\n errorData\n );\n }\n\n const contentType = response.headers.get('content-type') || 'audio/wav';\n const formatFromHeader = contentType.split('/')[1] || 'wav';\n const format: 'wav' | 'mp3' = formatFromHeader === 'mp3' ? 'mp3' : 'wav';\n\n const durationHeader = response.headers.get('x-audio-duration');\n const duration = durationHeader ? Number(durationHeader) : 0;\n\n const audioData = await response.arrayBuffer();\n\n return {\n audioData,\n duration,\n format,\n };\n }\n\n /**\n * Get available voices (V1 API)\n * @param model - Optional model filter (e.g., 'ssfm-v21', 'ssfm-v30')\n * @returns List of available voices with their emotions\n * @deprecated Use getVoicesV2() for enhanced metadata and filtering options\n */\n async getVoices(model?: string): Promise<VoicesResponse[]> {\n const response = await fetch(\n this.buildUrl('/v1/voices', model ? { model } : undefined),\n { headers: this.headers }\n );\n return this.handleResponse<VoicesResponse[]>(response);\n }\n\n /**\n * Get voice by ID (V1 API)\n * @param voiceId - The voice ID (e.g., 'tc_62a8975e695ad26f7fb514d1')\n * @param model - Optional model filter\n * @returns Voice information including available emotions\n * @deprecated Use getVoicesV2() for enhanced metadata\n */\n async getVoiceById(voiceId: string, model?: string): Promise<VoicesResponse[]> {\n const response = await fetch(\n this.buildUrl(`/v1/voices/${voiceId}`, model ? { model } : undefined),\n { headers: this.headers }\n );\n return this.handleResponse<VoicesResponse[]>(response);\n }\n\n /**\n * Get voices with enhanced metadata (V2 API)\n * Returns voices with model-grouped emotions and additional metadata\n * @param filter - Optional filter options (model, gender, age, use_cases)\n */\n async getVoicesV2(filter?: VoicesV2Filter): Promise<VoiceV2Response[]> {\n const response = await fetch(\n this.buildUrl('/v2/voices', filter as Record<string, unknown>),\n { headers: this.headers }\n );\n return this.handleResponse<VoiceV2Response[]>(response);\n }\n\n /**\n * Get a specific voice by ID with enhanced metadata (V2 API)\n * @param voiceId - The voice ID (e.g., 'tc_62a8975e695ad26f7fb514d1')\n * @returns Voice information with model-grouped emotions and metadata\n */\n async getVoiceV2(voiceId: string): Promise<VoiceV2Response> {\n const response = await fetch(\n this.buildUrl(`/v2/voices/${voiceId}`),\n { headers: this.headers }\n );\n return this.handleResponse<VoiceV2Response>(response);\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neosapience/typecast-js",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/index.cjs",
|
|
6
6
|
"module": "./lib/index.js",
|
|
@@ -72,7 +72,5 @@
|
|
|
72
72
|
"typescript": "^5.7.3",
|
|
73
73
|
"vitest": "^3.0.9"
|
|
74
74
|
},
|
|
75
|
-
"dependencies": {
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
}
|
|
75
|
+
"dependencies": {}
|
|
76
|
+
}
|