api2key-base-sdk 0.1.5 → 0.1.6
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 +192 -4
- package/dist/core/client.d.ts +2 -0
- package/dist/core/client.js +27 -3
- package/dist/core/types.d.ts +176 -4
- package/dist/credits/client.d.ts +6 -1
- package/dist/credits/client.js +11 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/speech/client.d.ts +32 -0
- package/dist/speech/client.js +169 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
6. `orders`
|
|
17
17
|
7. `payment`
|
|
18
18
|
8. `ai`
|
|
19
|
-
9. `
|
|
19
|
+
9. `speech`
|
|
20
|
+
10. `admin`
|
|
20
21
|
|
|
21
22
|
安装原则:
|
|
22
23
|
|
|
@@ -36,7 +37,8 @@
|
|
|
36
37
|
6. `orders`
|
|
37
38
|
7. `payment`
|
|
38
39
|
8. `ai`
|
|
39
|
-
9. `
|
|
40
|
+
9. `speech`
|
|
41
|
+
10. `admin`
|
|
40
42
|
|
|
41
43
|
### 1. `auth`
|
|
42
44
|
|
|
@@ -76,9 +78,18 @@
|
|
|
76
78
|
|
|
77
79
|
负责用户级设置的读取与更新。
|
|
78
80
|
|
|
79
|
-
### 5. `projects / orders / payment / ai`
|
|
81
|
+
### 5. `projects / orders / payment / ai / speech`
|
|
80
82
|
|
|
81
|
-
负责项目商品、会员、订单、支付、AI
|
|
83
|
+
负责项目商品、会员、订单、支付、AI 以及语音运行时能力。
|
|
84
|
+
|
|
85
|
+
其中 `speech` 对齐当前 `api2key-base-api` 的内置语音接口:
|
|
86
|
+
|
|
87
|
+
1. `listVoices(...)`
|
|
88
|
+
2. `synthesize(...)`
|
|
89
|
+
3. `transcribe(...)`
|
|
90
|
+
4. `transcribeSrt(...)`
|
|
91
|
+
5. `getAsrTask(...)`
|
|
92
|
+
6. `downloadAudio(...)`
|
|
82
93
|
|
|
83
94
|
### 6. `admin`
|
|
84
95
|
|
|
@@ -132,6 +143,7 @@ await baseClient.auth.resetPassword({
|
|
|
132
143
|
const projectClient = createProjectPlatformClient({
|
|
133
144
|
baseUrl: process.env.API2KEY_BASE_URL!,
|
|
134
145
|
getAccessToken: () => process.env.ACCESS_TOKEN,
|
|
146
|
+
getApiKey: () => process.env.API_KEY,
|
|
135
147
|
getProjectId: () => process.env.PROJECT_ID,
|
|
136
148
|
});
|
|
137
149
|
|
|
@@ -141,9 +153,185 @@ const adminClient = createAdminPlatformClient({
|
|
|
141
153
|
});
|
|
142
154
|
|
|
143
155
|
const products = await projectClient.projects.getCatalogProducts(process.env.PROJECT_ID!);
|
|
156
|
+
const voices = await projectClient.speech.listVoices({
|
|
157
|
+
provider: 'azure',
|
|
158
|
+
locale: 'zh-CN',
|
|
159
|
+
});
|
|
144
160
|
const projects = await adminClient.admin.listProjects();
|
|
145
161
|
```
|
|
146
162
|
|
|
163
|
+
说明:
|
|
164
|
+
|
|
165
|
+
1. SDK 仍然接收单一 `baseUrl`
|
|
166
|
+
2. `/api/v1/*` 接口继续基于 `baseUrl` 访问
|
|
167
|
+
3. `speech` 客户端会自动基于同一域名访问根路径下的 `/api/*` 语音接口,无需额外配置第二个 URL
|
|
168
|
+
|
|
169
|
+
## Speech 示例
|
|
170
|
+
|
|
171
|
+
推荐在项目级客户端上使用:
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { createProjectPlatformClient } from 'api2key-base-sdk';
|
|
175
|
+
|
|
176
|
+
const client = createProjectPlatformClient({
|
|
177
|
+
baseUrl: process.env.API2KEY_BASE_URL!,
|
|
178
|
+
getAccessToken: () => process.env.ACCESS_TOKEN,
|
|
179
|
+
getApiKey: () => process.env.API_KEY,
|
|
180
|
+
getProjectId: () => process.env.PROJECT_ID,
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 1. 获取声音列表
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
const voices = await client.speech.listVoices({
|
|
188
|
+
provider: 'azure',
|
|
189
|
+
locale: 'zh-CN',
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
console.log(voices.provider);
|
|
193
|
+
console.log(voices.total);
|
|
194
|
+
console.log(voices.voices[0]?.shortName);
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### 2. 文本转音频
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
const synthesized = await client.speech.synthesize({
|
|
201
|
+
provider: 'azure',
|
|
202
|
+
text: '你好,欢迎使用 api2key speech client。',
|
|
203
|
+
locale: 'zh-CN',
|
|
204
|
+
voice: 'zh-CN-XiaoxiaoNeural',
|
|
205
|
+
format: 'audio-24khz-96kbitrate-mono-mp3',
|
|
206
|
+
rate: 1,
|
|
207
|
+
volume: 100,
|
|
208
|
+
pitch: 0,
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
console.log(synthesized.contentType);
|
|
212
|
+
console.log(synthesized.creditsCharged);
|
|
213
|
+
console.log(synthesized.storageKey);
|
|
214
|
+
console.log(synthesized.downloadUrl);
|
|
215
|
+
console.log(synthesized.audio.byteLength);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
如果你要把返回音频写入文件,在 Node.js 中可以这样处理:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
import { writeFile } from 'node:fs/promises';
|
|
222
|
+
|
|
223
|
+
await writeFile('speech.mp3', Buffer.from(synthesized.audio));
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### 3. 简洁音频转文本
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
import { readFile } from 'node:fs/promises';
|
|
230
|
+
|
|
231
|
+
const audioBytes = await readFile('./sample.mp3');
|
|
232
|
+
const audioBlob = new Blob([audioBytes], { type: 'audio/mpeg' });
|
|
233
|
+
|
|
234
|
+
const transcript = await client.speech.transcribe({
|
|
235
|
+
provider: 'groq',
|
|
236
|
+
file: audioBlob,
|
|
237
|
+
fileName: 'sample.mp3',
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
console.log(transcript.language);
|
|
241
|
+
console.log(transcript.full_text);
|
|
242
|
+
console.log(transcript.segments.length);
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
也可以直接传远程地址:
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
const transcript = await client.speech.transcribe({
|
|
249
|
+
provider: 'groq',
|
|
250
|
+
audioUrl: 'https://example.com/sample.mp3',
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### 4. 音频转 SRT
|
|
255
|
+
|
|
256
|
+
同步模式:
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
const srtResult = await client.speech.transcribeSrt({
|
|
260
|
+
provider: 'tencent',
|
|
261
|
+
file: audioBlob,
|
|
262
|
+
fileName: 'sample.mp3',
|
|
263
|
+
async: false,
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
if ('srt' in srtResult) {
|
|
267
|
+
console.log(srtResult.text);
|
|
268
|
+
console.log(srtResult.srt);
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
异步模式:
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
const submitted = await client.speech.transcribeSrt({
|
|
276
|
+
provider: 'tencent',
|
|
277
|
+
file: audioBlob,
|
|
278
|
+
fileName: 'sample.mp3',
|
|
279
|
+
async: true,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
if ('taskId' in submitted && !('srt' in submitted)) {
|
|
283
|
+
console.log(submitted.taskId);
|
|
284
|
+
console.log(submitted.statusStr);
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### 5. 查询异步字幕任务
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
const task = await client.speech.getAsrTask({
|
|
292
|
+
provider: 'tencent',
|
|
293
|
+
taskId: 123456,
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
console.log(task.status);
|
|
297
|
+
console.log(task.statusStr);
|
|
298
|
+
console.log(task.retryAfterSeconds);
|
|
299
|
+
console.log(task.srt);
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### 6. 通过存储 key 下载合成音频
|
|
303
|
+
|
|
304
|
+
```ts
|
|
305
|
+
const downloaded = await client.speech.downloadAudio({
|
|
306
|
+
key: synthesized.storageKey!,
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
console.log(downloaded.contentType);
|
|
310
|
+
console.log(downloaded.fileName);
|
|
311
|
+
console.log(downloaded.audio.byteLength);
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### 7. 鉴权建议
|
|
315
|
+
|
|
316
|
+
推荐方式:
|
|
317
|
+
|
|
318
|
+
1. 服务端项目调用时,通过 `getApiKey()` 提供 `sk-...`
|
|
319
|
+
2. 用户登录态场景,通过 `getAccessToken()` 提供 JWT
|
|
320
|
+
3. 大多数项目建议同时提供 `getProjectId()`,保持语音接口和项目上下文一致
|
|
321
|
+
|
|
322
|
+
### 8. 路径说明
|
|
323
|
+
|
|
324
|
+
你只需要传一个 `baseUrl`,例如:
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
baseUrl: 'https://open.api2key.com/api/v1'
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
SDK 会自动处理:
|
|
331
|
+
|
|
332
|
+
1. 普通平台接口继续访问 `/api/v1/*`
|
|
333
|
+
2. speech client 自动访问同域名下的 `/api/*`
|
|
334
|
+
|
|
147
335
|
## 设计原则
|
|
148
336
|
|
|
149
337
|
1. 新项目默认只依赖这个包
|
package/dist/core/client.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export declare class PlatformHttpClient {
|
|
|
4
4
|
private readonly fetchImpl;
|
|
5
5
|
private readonly options;
|
|
6
6
|
constructor(options: PlatformClientOptions);
|
|
7
|
+
private resolveBaseUrl;
|
|
8
|
+
private buildUrl;
|
|
7
9
|
private send;
|
|
8
10
|
request<T>(path: string, requestOptions?: PlatformRequestOptions): Promise<T>;
|
|
9
11
|
requestRaw(path: string, requestOptions?: PlatformRequestOptions): Promise<Response>;
|
package/dist/core/client.js
CHANGED
|
@@ -18,9 +18,29 @@ export class PlatformHttpClient {
|
|
|
18
18
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
19
19
|
this.fetchImpl = fetchImpl.bind(globalThis);
|
|
20
20
|
}
|
|
21
|
+
resolveBaseUrl(mode = 'default') {
|
|
22
|
+
if (mode === 'origin') {
|
|
23
|
+
return new URL(this.baseUrl).origin;
|
|
24
|
+
}
|
|
25
|
+
return this.baseUrl;
|
|
26
|
+
}
|
|
27
|
+
buildUrl(path, requestOptions) {
|
|
28
|
+
if (/^https?:\/\//.test(path)) {
|
|
29
|
+
return `${path}${buildQueryString(requestOptions.query)}`;
|
|
30
|
+
}
|
|
31
|
+
return `${this.resolveBaseUrl(requestOptions.baseUrlMode)}${path}${buildQueryString(requestOptions.query)}`;
|
|
32
|
+
}
|
|
21
33
|
async send(path, requestOptions = {}) {
|
|
22
34
|
const headers = new Headers(this.options.defaultHeaders);
|
|
23
|
-
|
|
35
|
+
if (requestOptions.contentType === null) {
|
|
36
|
+
headers.delete('Content-Type');
|
|
37
|
+
}
|
|
38
|
+
else if (requestOptions.contentType) {
|
|
39
|
+
headers.set('Content-Type', requestOptions.contentType);
|
|
40
|
+
}
|
|
41
|
+
else if (requestOptions.rawBody === undefined) {
|
|
42
|
+
headers.set('Content-Type', 'application/json');
|
|
43
|
+
}
|
|
24
44
|
if (requestOptions.headers) {
|
|
25
45
|
for (const [key, value] of Object.entries(requestOptions.headers)) {
|
|
26
46
|
headers.set(key, value);
|
|
@@ -30,6 +50,10 @@ export class PlatformHttpClient {
|
|
|
30
50
|
if (accessToken) {
|
|
31
51
|
headers.set('Authorization', `Bearer ${accessToken}`);
|
|
32
52
|
}
|
|
53
|
+
const apiKey = requestOptions.apiKey ?? (await this.options.getApiKey?.());
|
|
54
|
+
if (apiKey) {
|
|
55
|
+
headers.set('x-api-key', apiKey);
|
|
56
|
+
}
|
|
33
57
|
const projectId = requestOptions.projectId ?? (await this.options.getProjectId?.());
|
|
34
58
|
if (projectId) {
|
|
35
59
|
headers.set('X-Project-Id', projectId);
|
|
@@ -41,13 +65,13 @@ export class PlatformHttpClient {
|
|
|
41
65
|
}
|
|
42
66
|
headers.set('X-Service-Secret', serviceSecret);
|
|
43
67
|
}
|
|
44
|
-
const url =
|
|
68
|
+
const url = this.buildUrl(path, requestOptions);
|
|
45
69
|
let response;
|
|
46
70
|
try {
|
|
47
71
|
response = await this.fetchImpl(url, {
|
|
48
72
|
method: requestOptions.method ?? 'GET',
|
|
49
73
|
headers,
|
|
50
|
-
body: requestOptions.body == null ? undefined : JSON.stringify(requestOptions.body),
|
|
74
|
+
body: requestOptions.rawBody ?? (requestOptions.body == null ? undefined : JSON.stringify(requestOptions.body)),
|
|
51
75
|
});
|
|
52
76
|
}
|
|
53
77
|
catch (error) {
|
package/dist/core/types.d.ts
CHANGED
|
@@ -9,17 +9,22 @@ export interface PlatformClientOptions {
|
|
|
9
9
|
fetchImpl?: typeof fetch;
|
|
10
10
|
defaultHeaders?: Record<string, string>;
|
|
11
11
|
getAccessToken?: () => MaybePromise<string | undefined>;
|
|
12
|
+
getApiKey?: () => MaybePromise<string | undefined>;
|
|
12
13
|
getServiceSecret?: () => MaybePromise<string | undefined>;
|
|
13
14
|
getProjectId?: () => MaybePromise<string | undefined>;
|
|
14
15
|
}
|
|
15
16
|
export interface PlatformRequestOptions {
|
|
16
17
|
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
17
18
|
body?: unknown;
|
|
19
|
+
rawBody?: BodyInit;
|
|
18
20
|
query?: Record<string, string | number | boolean | undefined | null>;
|
|
19
21
|
headers?: Record<string, string>;
|
|
22
|
+
contentType?: string | null;
|
|
20
23
|
accessToken?: string;
|
|
24
|
+
apiKey?: string;
|
|
21
25
|
projectId?: string;
|
|
22
26
|
useServiceSecret?: boolean;
|
|
27
|
+
baseUrlMode?: 'default' | 'origin';
|
|
23
28
|
}
|
|
24
29
|
export interface AuthUser {
|
|
25
30
|
id: string;
|
|
@@ -29,12 +34,14 @@ export interface AuthUser {
|
|
|
29
34
|
role: 'user' | 'admin' | 'super_admin';
|
|
30
35
|
emailVerified?: boolean;
|
|
31
36
|
emailVerifiedAt?: number | null;
|
|
37
|
+
credits?: number;
|
|
32
38
|
creditsBalance?: number;
|
|
33
39
|
projectId?: string | null;
|
|
34
40
|
projectName?: string | null;
|
|
35
41
|
projectSlug?: string | null;
|
|
36
42
|
membership?: {
|
|
37
43
|
tier: string;
|
|
44
|
+
status?: string;
|
|
38
45
|
power?: number;
|
|
39
46
|
endDate?: number | null;
|
|
40
47
|
} | null;
|
|
@@ -125,10 +132,7 @@ export interface MembershipView {
|
|
|
125
132
|
days_remaining?: number;
|
|
126
133
|
}
|
|
127
134
|
export interface CreditsBalance {
|
|
128
|
-
|
|
129
|
-
reserved?: number;
|
|
130
|
-
total_earned?: number;
|
|
131
|
-
total_spent?: number;
|
|
135
|
+
user: AuthUser;
|
|
132
136
|
}
|
|
133
137
|
export interface CreditsLedgerItem {
|
|
134
138
|
id: string;
|
|
@@ -219,6 +223,174 @@ export interface AiModelSummary {
|
|
|
219
223
|
outputPricing?: number;
|
|
220
224
|
locked?: boolean;
|
|
221
225
|
}
|
|
226
|
+
export type SpeechTtsProvider = 'azure' | 'tencent';
|
|
227
|
+
export type SpeechAsrProvider = 'tencent' | 'groq' | 'bcut';
|
|
228
|
+
export interface SpeechVoice {
|
|
229
|
+
provider: SpeechTtsProvider;
|
|
230
|
+
shortName: string;
|
|
231
|
+
displayName: string;
|
|
232
|
+
localName: string;
|
|
233
|
+
locale: string;
|
|
234
|
+
localeName: string;
|
|
235
|
+
gender: string;
|
|
236
|
+
voiceType?: string;
|
|
237
|
+
styles: string[];
|
|
238
|
+
roles: string[];
|
|
239
|
+
sampleRateHertz?: string;
|
|
240
|
+
sampleRates?: string[];
|
|
241
|
+
status?: string;
|
|
242
|
+
wordsPerMinute?: string;
|
|
243
|
+
secondaryLocales: string[];
|
|
244
|
+
recommendedScene?: string;
|
|
245
|
+
supportedLanguages?: string[];
|
|
246
|
+
emotions?: string[];
|
|
247
|
+
}
|
|
248
|
+
export interface SpeechAccessUser {
|
|
249
|
+
id: string;
|
|
250
|
+
email: string;
|
|
251
|
+
role: string;
|
|
252
|
+
}
|
|
253
|
+
export interface SpeechAccessProject {
|
|
254
|
+
id: string;
|
|
255
|
+
name: string;
|
|
256
|
+
slug: string;
|
|
257
|
+
}
|
|
258
|
+
export interface SpeechAccessMembership {
|
|
259
|
+
tier: string;
|
|
260
|
+
status: string;
|
|
261
|
+
end_date: number | null;
|
|
262
|
+
is_active: boolean;
|
|
263
|
+
}
|
|
264
|
+
export interface SpeechVoiceListResult {
|
|
265
|
+
provider: SpeechTtsProvider;
|
|
266
|
+
user: SpeechAccessUser;
|
|
267
|
+
project: SpeechAccessProject;
|
|
268
|
+
membership: SpeechAccessMembership;
|
|
269
|
+
total: number;
|
|
270
|
+
voices: SpeechVoice[];
|
|
271
|
+
}
|
|
272
|
+
export interface SpeechSynthesisRequest {
|
|
273
|
+
provider?: SpeechTtsProvider;
|
|
274
|
+
text: string;
|
|
275
|
+
voice?: string;
|
|
276
|
+
locale?: string;
|
|
277
|
+
rate?: number;
|
|
278
|
+
volume?: number;
|
|
279
|
+
pitch?: number;
|
|
280
|
+
style?: string;
|
|
281
|
+
styleDegree?: number;
|
|
282
|
+
role?: string;
|
|
283
|
+
emotionCategory?: string;
|
|
284
|
+
emotionIntensity?: number;
|
|
285
|
+
format?: string;
|
|
286
|
+
}
|
|
287
|
+
export interface SpeechSynthesisResult {
|
|
288
|
+
audio: ArrayBuffer;
|
|
289
|
+
contentType: string;
|
|
290
|
+
fileName: string | null;
|
|
291
|
+
provider: string | null;
|
|
292
|
+
voice: string | null;
|
|
293
|
+
locale: string | null;
|
|
294
|
+
format: string | null;
|
|
295
|
+
creditsCharged: number | null;
|
|
296
|
+
storageKey: string | null;
|
|
297
|
+
downloadUrl: string | null;
|
|
298
|
+
projectId: string | null;
|
|
299
|
+
providerRequestId: string | null;
|
|
300
|
+
headers: Headers;
|
|
301
|
+
}
|
|
302
|
+
export interface SpeechSimpleTranscriptSegment {
|
|
303
|
+
start: number;
|
|
304
|
+
end: number;
|
|
305
|
+
text: string;
|
|
306
|
+
}
|
|
307
|
+
export interface SpeechTranscribeResult {
|
|
308
|
+
language: string;
|
|
309
|
+
full_text: string;
|
|
310
|
+
segments: SpeechSimpleTranscriptSegment[];
|
|
311
|
+
srt: string;
|
|
312
|
+
}
|
|
313
|
+
export interface SpeechAsrSegment {
|
|
314
|
+
id: number;
|
|
315
|
+
startMs: number;
|
|
316
|
+
endMs: number;
|
|
317
|
+
startTimecode: string;
|
|
318
|
+
endTimecode: string;
|
|
319
|
+
text: string;
|
|
320
|
+
speakerId?: number;
|
|
321
|
+
emotionTypes?: string[];
|
|
322
|
+
}
|
|
323
|
+
export interface SpeechAsrSrtResult {
|
|
324
|
+
user: SpeechAccessUser;
|
|
325
|
+
project: SpeechAccessProject;
|
|
326
|
+
membership: SpeechAccessMembership;
|
|
327
|
+
provider: SpeechAsrProvider;
|
|
328
|
+
format: 'srt';
|
|
329
|
+
engineModelType: string;
|
|
330
|
+
taskId: number | null;
|
|
331
|
+
requestId?: string | null;
|
|
332
|
+
language: string;
|
|
333
|
+
durationMs: number;
|
|
334
|
+
sourceType: 'file' | 'url';
|
|
335
|
+
sourceName?: string | null;
|
|
336
|
+
sourceSize?: number | null;
|
|
337
|
+
text: string;
|
|
338
|
+
srt: string;
|
|
339
|
+
segments: SpeechAsrSegment[];
|
|
340
|
+
}
|
|
341
|
+
export interface SpeechAsrTaskSubmission {
|
|
342
|
+
user: SpeechAccessUser;
|
|
343
|
+
project: SpeechAccessProject;
|
|
344
|
+
membership: SpeechAccessMembership;
|
|
345
|
+
provider: SpeechAsrProvider;
|
|
346
|
+
taskId: number;
|
|
347
|
+
requestId?: string | null;
|
|
348
|
+
engineModelType: string;
|
|
349
|
+
status: number;
|
|
350
|
+
statusStr: string;
|
|
351
|
+
sourceType: 'file' | 'url';
|
|
352
|
+
sourceName?: string | null;
|
|
353
|
+
sourceSize?: number | null;
|
|
354
|
+
}
|
|
355
|
+
export interface SpeechAsrTaskResult {
|
|
356
|
+
user: SpeechAccessUser;
|
|
357
|
+
project: SpeechAccessProject;
|
|
358
|
+
membership: SpeechAccessMembership;
|
|
359
|
+
provider: SpeechAsrProvider;
|
|
360
|
+
format: 'srt';
|
|
361
|
+
taskId: number;
|
|
362
|
+
requestId?: string | null;
|
|
363
|
+
status: number;
|
|
364
|
+
statusStr: string;
|
|
365
|
+
retryAfterSeconds?: number | null;
|
|
366
|
+
durationMs: number;
|
|
367
|
+
language: string;
|
|
368
|
+
audioDurationSeconds?: number | null;
|
|
369
|
+
errorMessage?: string | null;
|
|
370
|
+
text: string;
|
|
371
|
+
srt: string;
|
|
372
|
+
segments: SpeechAsrSegment[];
|
|
373
|
+
}
|
|
374
|
+
export interface SpeechAsrRequestInput {
|
|
375
|
+
provider?: SpeechAsrProvider;
|
|
376
|
+
audioUrl?: string;
|
|
377
|
+
file?: Blob;
|
|
378
|
+
fileName?: string;
|
|
379
|
+
async?: boolean;
|
|
380
|
+
language?: string;
|
|
381
|
+
prompt?: string;
|
|
382
|
+
temperature?: number;
|
|
383
|
+
engineModelType?: string;
|
|
384
|
+
channelNum?: number;
|
|
385
|
+
speakerDiarization?: number;
|
|
386
|
+
speakerNumber?: number;
|
|
387
|
+
sentenceMaxLength?: number;
|
|
388
|
+
emotionRecognition?: number;
|
|
389
|
+
filterDirty?: number;
|
|
390
|
+
filterModal?: number;
|
|
391
|
+
filterPunc?: number;
|
|
392
|
+
convertNumMode?: number;
|
|
393
|
+
}
|
|
222
394
|
export interface AdminProject {
|
|
223
395
|
id: string;
|
|
224
396
|
name: string;
|
package/dist/credits/client.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { PlatformHttpClient } from '../core/client';
|
|
2
2
|
import type { CreditsBalance, CreditsLedgerItem } from '../core/types';
|
|
3
|
+
type GetBalanceOptions = {
|
|
4
|
+
accessToken?: string;
|
|
5
|
+
projectId?: string;
|
|
6
|
+
};
|
|
3
7
|
export declare class CreditsClient {
|
|
4
8
|
private readonly http;
|
|
5
9
|
constructor(http: PlatformHttpClient);
|
|
6
|
-
getBalance(
|
|
10
|
+
getBalance(options?: string | GetBalanceOptions): Promise<CreditsBalance>;
|
|
7
11
|
getLedger(input: {
|
|
8
12
|
accessToken?: string;
|
|
9
13
|
page?: number;
|
|
@@ -38,3 +42,4 @@ export declare class CreditsClient {
|
|
|
38
42
|
ok: boolean;
|
|
39
43
|
}>;
|
|
40
44
|
}
|
|
45
|
+
export {};
|
package/dist/credits/client.js
CHANGED
|
@@ -2,8 +2,17 @@ export class CreditsClient {
|
|
|
2
2
|
constructor(http) {
|
|
3
3
|
this.http = http;
|
|
4
4
|
}
|
|
5
|
-
getBalance(
|
|
6
|
-
|
|
5
|
+
getBalance(options) {
|
|
6
|
+
const normalizedOptions = typeof options === 'string'
|
|
7
|
+
? { accessToken: options }
|
|
8
|
+
: (options ?? {});
|
|
9
|
+
return this.http.request('/api/v1/credits/balance', {
|
|
10
|
+
accessToken: normalizedOptions.accessToken,
|
|
11
|
+
projectId: normalizedOptions.projectId,
|
|
12
|
+
query: {
|
|
13
|
+
projectId: normalizedOptions.projectId,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
7
16
|
}
|
|
8
17
|
getLedger(input) {
|
|
9
18
|
return this.http.request('/api/v1/credits/ledger', {
|
package/dist/index.d.ts
CHANGED
|
@@ -7,10 +7,11 @@ import { CreditsClient } from './credits/client';
|
|
|
7
7
|
import { OrdersClient } from './orders/client';
|
|
8
8
|
import { PaymentClient } from './payment/client';
|
|
9
9
|
import { ProjectsClient } from './projects/client';
|
|
10
|
+
import { SpeechClient } from './speech/client';
|
|
10
11
|
import { UserApiKeysClient } from './user/api-keys-client';
|
|
11
12
|
import { UserSettingsClient } from './user/settings-client';
|
|
12
13
|
export * from './core/errors';
|
|
13
|
-
export type { AdminConfigItem, AdminMembershipFilters, AdminMembershipRecord, AdminModelInput, AdminModelRecord, AdminOrderFilters, AdminOrderRecord, AdminProduct, AdminProductBackfillResult, AdminProductListResult, AdminProject, AdminProjectExportFormat, AdminUserCreditsSummary, AdminUserRecord, AiModelSummary, AuthChangePasswordInput, AuthPasswordResetDispatchResult, AuthRegisterResult, AuthRegistrationPending, AuthSession, AuthUser, AuthVerificationDispatchResult, AuthVerifyEmailInput, AuthResetPasswordInput, CreditsBalance, CreditsLedgerItem, MembershipView, OrderDetail, OrderSummary, PaymentCreateResponse, PaymentQueryResponse, PlatformClientOptions, PlatformEnvelope, PlatformRequestOptions, ProductSummary, ProjectSummary, UpdateAdminUserInput, UserApiKeyRecord, UserApiKeySecret, UserSettingDefinition, UserSettingsPayload, } from './core/types';
|
|
14
|
+
export type { AdminConfigItem, AdminMembershipFilters, AdminMembershipRecord, AdminModelInput, AdminModelRecord, AdminOrderFilters, AdminOrderRecord, AdminProduct, AdminProductBackfillResult, AdminProductListResult, AdminProject, AdminProjectExportFormat, AdminUserCreditsSummary, AdminUserRecord, AiModelSummary, AuthChangePasswordInput, AuthPasswordResetDispatchResult, AuthRegisterResult, AuthRegistrationPending, AuthSession, AuthUser, AuthVerificationDispatchResult, AuthVerifyEmailInput, AuthResetPasswordInput, CreditsBalance, CreditsLedgerItem, MembershipView, OrderDetail, OrderSummary, PaymentCreateResponse, PaymentQueryResponse, PlatformClientOptions, PlatformEnvelope, PlatformRequestOptions, ProductSummary, ProjectSummary, SpeechAccessMembership, SpeechAccessProject, SpeechAccessUser, SpeechAsrProvider, SpeechAsrRequestInput, SpeechAsrSegment, SpeechAsrSrtResult, SpeechAsrTaskResult, SpeechAsrTaskSubmission, SpeechSimpleTranscriptSegment, SpeechSynthesisRequest, SpeechSynthesisResult, SpeechTranscribeResult, SpeechTtsProvider, SpeechVoice, SpeechVoiceListResult, UpdateAdminUserInput, UserApiKeyRecord, UserApiKeySecret, UserSettingDefinition, UserSettingsPayload, } from './core/types';
|
|
14
15
|
export declare class BasePlatformClient {
|
|
15
16
|
readonly http: PlatformHttpClient;
|
|
16
17
|
readonly auth: AuthClient;
|
|
@@ -26,6 +27,7 @@ export declare class ProjectPlatformClient {
|
|
|
26
27
|
readonly orders: OrdersClient;
|
|
27
28
|
readonly payment: PaymentClient;
|
|
28
29
|
readonly ai: AiClient;
|
|
30
|
+
readonly speech: SpeechClient;
|
|
29
31
|
constructor(options: PlatformClientOptions);
|
|
30
32
|
}
|
|
31
33
|
export declare function createProjectPlatformClient(options: PlatformClientOptions): ProjectPlatformClient;
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { CreditsClient } from './credits/client.js';
|
|
|
6
6
|
import { OrdersClient } from './orders/client.js';
|
|
7
7
|
import { PaymentClient } from './payment/client.js';
|
|
8
8
|
import { ProjectsClient } from './projects/client.js';
|
|
9
|
+
import { SpeechClient } from './speech/client.js';
|
|
9
10
|
import { UserApiKeysClient } from './user/api-keys-client.js';
|
|
10
11
|
import { UserSettingsClient } from './user/settings-client.js';
|
|
11
12
|
export * from './core/errors.js';
|
|
@@ -28,6 +29,7 @@ export class ProjectPlatformClient {
|
|
|
28
29
|
this.orders = new OrdersClient(this.http);
|
|
29
30
|
this.payment = new PaymentClient(this.http);
|
|
30
31
|
this.ai = new AiClient(this.http);
|
|
32
|
+
this.speech = new SpeechClient(this.http);
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
export function createProjectPlatformClient(options) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { PlatformHttpClient } from '../core/client';
|
|
2
|
+
import type { SpeechAsrRequestInput, SpeechAsrSrtResult, SpeechAsrTaskResult, SpeechAsrTaskSubmission, SpeechSynthesisRequest, SpeechSynthesisResult, SpeechTranscribeResult, SpeechVoiceListResult } from '../core/types';
|
|
3
|
+
type SpeechRequestAuth = {
|
|
4
|
+
accessToken?: string;
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
projectId?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare class SpeechClient {
|
|
9
|
+
private readonly http;
|
|
10
|
+
constructor(http: PlatformHttpClient);
|
|
11
|
+
listVoices(input?: SpeechRequestAuth & {
|
|
12
|
+
provider?: 'azure' | 'tencent';
|
|
13
|
+
locale?: string;
|
|
14
|
+
search?: string;
|
|
15
|
+
}): Promise<SpeechVoiceListResult>;
|
|
16
|
+
synthesize(input: SpeechRequestAuth & SpeechSynthesisRequest): Promise<SpeechSynthesisResult>;
|
|
17
|
+
transcribe(input: SpeechRequestAuth & SpeechAsrRequestInput): Promise<SpeechTranscribeResult>;
|
|
18
|
+
transcribeSrt(input: SpeechRequestAuth & SpeechAsrRequestInput): Promise<SpeechAsrSrtResult | SpeechAsrTaskSubmission>;
|
|
19
|
+
getAsrTask(input: SpeechRequestAuth & {
|
|
20
|
+
taskId: number | string;
|
|
21
|
+
provider?: 'tencent' | 'groq' | 'bcut';
|
|
22
|
+
}): Promise<SpeechAsrTaskResult>;
|
|
23
|
+
downloadAudio(input: {
|
|
24
|
+
key: string;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
audio: ArrayBuffer;
|
|
27
|
+
contentType: string;
|
|
28
|
+
fileName: string | null;
|
|
29
|
+
headers: Headers;
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { PlatformApiError, PlatformTransportError } from '../core/errors.js';
|
|
2
|
+
function parseContentDispositionFileName(value) {
|
|
3
|
+
if (!value) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
const utf8Match = value.match(/filename\*=UTF-8''([^;]+)/i);
|
|
7
|
+
if (utf8Match) {
|
|
8
|
+
try {
|
|
9
|
+
return decodeURIComponent(utf8Match[1]);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return utf8Match[1];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const plainMatch = value.match(/filename="?([^";]+)"?/i);
|
|
16
|
+
return plainMatch?.[1] ?? null;
|
|
17
|
+
}
|
|
18
|
+
async function throwPlatformError(response) {
|
|
19
|
+
let payload = null;
|
|
20
|
+
try {
|
|
21
|
+
payload = (await response.json());
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
const detail = await response.text().catch(() => '');
|
|
25
|
+
throw new PlatformTransportError(`Platform API returned a non-JSON error response for ${response.url}: ${detail}`);
|
|
26
|
+
}
|
|
27
|
+
throw new PlatformApiError(payload.message, response.status, payload.code, payload.data);
|
|
28
|
+
}
|
|
29
|
+
function buildAsrFormData(input) {
|
|
30
|
+
const formData = new FormData();
|
|
31
|
+
const scalarEntries = [
|
|
32
|
+
['provider', input.provider],
|
|
33
|
+
['audioUrl', input.audioUrl],
|
|
34
|
+
['async', input.async],
|
|
35
|
+
['language', input.language],
|
|
36
|
+
['prompt', input.prompt],
|
|
37
|
+
['temperature', input.temperature],
|
|
38
|
+
['engineModelType', input.engineModelType],
|
|
39
|
+
['channelNum', input.channelNum],
|
|
40
|
+
['speakerDiarization', input.speakerDiarization],
|
|
41
|
+
['speakerNumber', input.speakerNumber],
|
|
42
|
+
['sentenceMaxLength', input.sentenceMaxLength],
|
|
43
|
+
['emotionRecognition', input.emotionRecognition],
|
|
44
|
+
['filterDirty', input.filterDirty],
|
|
45
|
+
['filterModal', input.filterModal],
|
|
46
|
+
['filterPunc', input.filterPunc],
|
|
47
|
+
['convertNumMode', input.convertNumMode],
|
|
48
|
+
];
|
|
49
|
+
for (const [key, value] of scalarEntries) {
|
|
50
|
+
if (value == null) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
formData.append(key, String(value));
|
|
54
|
+
}
|
|
55
|
+
if (input.file) {
|
|
56
|
+
formData.append('file', input.file, input.fileName ?? 'audio');
|
|
57
|
+
}
|
|
58
|
+
return formData;
|
|
59
|
+
}
|
|
60
|
+
export class SpeechClient {
|
|
61
|
+
constructor(http) {
|
|
62
|
+
this.http = http;
|
|
63
|
+
}
|
|
64
|
+
listVoices(input = {}) {
|
|
65
|
+
return this.http.request('/api/voices', {
|
|
66
|
+
accessToken: input.accessToken,
|
|
67
|
+
apiKey: input.apiKey,
|
|
68
|
+
baseUrlMode: 'origin',
|
|
69
|
+
query: {
|
|
70
|
+
projectId: input.projectId,
|
|
71
|
+
provider: input.provider,
|
|
72
|
+
locale: input.locale,
|
|
73
|
+
search: input.search,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
async synthesize(input) {
|
|
78
|
+
const response = await this.http.requestRaw('/api/speech', {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
accessToken: input.accessToken,
|
|
81
|
+
apiKey: input.apiKey,
|
|
82
|
+
baseUrlMode: 'origin',
|
|
83
|
+
query: { projectId: input.projectId },
|
|
84
|
+
body: {
|
|
85
|
+
provider: input.provider,
|
|
86
|
+
text: input.text,
|
|
87
|
+
voice: input.voice,
|
|
88
|
+
locale: input.locale,
|
|
89
|
+
rate: input.rate,
|
|
90
|
+
volume: input.volume,
|
|
91
|
+
pitch: input.pitch,
|
|
92
|
+
style: input.style,
|
|
93
|
+
styleDegree: input.styleDegree,
|
|
94
|
+
role: input.role,
|
|
95
|
+
emotionCategory: input.emotionCategory,
|
|
96
|
+
emotionIntensity: input.emotionIntensity,
|
|
97
|
+
format: input.format,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
if (!response.ok) {
|
|
101
|
+
return throwPlatformError(response);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
audio: await response.arrayBuffer(),
|
|
105
|
+
contentType: response.headers.get('Content-Type') ?? 'application/octet-stream',
|
|
106
|
+
fileName: parseContentDispositionFileName(response.headers.get('Content-Disposition')),
|
|
107
|
+
provider: response.headers.get('X-TTS-Provider'),
|
|
108
|
+
voice: response.headers.get('X-TTS-Voice'),
|
|
109
|
+
locale: response.headers.get('X-TTS-Locale'),
|
|
110
|
+
format: response.headers.get('X-TTS-Format'),
|
|
111
|
+
creditsCharged: response.headers.get('X-TTS-Credits-Charged') == null
|
|
112
|
+
? null
|
|
113
|
+
: Number(response.headers.get('X-TTS-Credits-Charged')),
|
|
114
|
+
storageKey: response.headers.get('X-TTS-Storage-Key'),
|
|
115
|
+
downloadUrl: response.headers.get('X-TTS-Download-Url'),
|
|
116
|
+
projectId: response.headers.get('X-TTS-Project-Id'),
|
|
117
|
+
providerRequestId: response.headers.get('X-TTS-Provider-Request-Id'),
|
|
118
|
+
headers: response.headers,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
transcribe(input) {
|
|
122
|
+
return this.http.request('/api/asr/transcribe', {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
accessToken: input.accessToken,
|
|
125
|
+
apiKey: input.apiKey,
|
|
126
|
+
baseUrlMode: 'origin',
|
|
127
|
+
query: { projectId: input.projectId },
|
|
128
|
+
rawBody: buildAsrFormData(input),
|
|
129
|
+
contentType: null,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
transcribeSrt(input) {
|
|
133
|
+
return this.http.request('/api/asr/srt', {
|
|
134
|
+
method: 'POST',
|
|
135
|
+
accessToken: input.accessToken,
|
|
136
|
+
apiKey: input.apiKey,
|
|
137
|
+
baseUrlMode: 'origin',
|
|
138
|
+
query: { projectId: input.projectId },
|
|
139
|
+
rawBody: buildAsrFormData(input),
|
|
140
|
+
contentType: null,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
getAsrTask(input) {
|
|
144
|
+
return this.http.request(`/api/asr/tasks/${input.taskId}`, {
|
|
145
|
+
accessToken: input.accessToken,
|
|
146
|
+
apiKey: input.apiKey,
|
|
147
|
+
baseUrlMode: 'origin',
|
|
148
|
+
query: {
|
|
149
|
+
projectId: input.projectId,
|
|
150
|
+
provider: input.provider,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
async downloadAudio(input) {
|
|
155
|
+
const response = await this.http.requestRaw('/api/files/download', {
|
|
156
|
+
baseUrlMode: 'origin',
|
|
157
|
+
query: { key: input.key },
|
|
158
|
+
});
|
|
159
|
+
if (!response.ok) {
|
|
160
|
+
return throwPlatformError(response);
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
audio: await response.arrayBuffer(),
|
|
164
|
+
contentType: response.headers.get('Content-Type') ?? 'application/octet-stream',
|
|
165
|
+
fileName: parseContentDispositionFileName(response.headers.get('Content-Disposition')),
|
|
166
|
+
headers: response.headers,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|