playkit-sdk 1.3.0 → 1.4.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.
- package/README.md +20 -0
- package/dist/playkit-sdk.cjs.js +207 -12
- package/dist/playkit-sdk.cjs.js.map +1 -1
- package/dist/playkit-sdk.d.ts +142 -2
- package/dist/playkit-sdk.esm.js +207 -13
- package/dist/playkit-sdk.esm.js.map +1 -1
- package/dist/playkit-sdk.umd.js +207 -12
- package/dist/playkit-sdk.umd.js.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -83,6 +83,26 @@ const imgElement = await image.toHTMLImage();
|
|
|
83
83
|
document.body.appendChild(imgElement);
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
### Text-to-Speech (TTS)
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const tts = sdk.createTTSClient(); // defaults to 'default-tts-model'
|
|
90
|
+
|
|
91
|
+
// Get raw audio bytes plus usage metadata
|
|
92
|
+
const result = await tts.synthesize({
|
|
93
|
+
text: 'Welcome to the game, brave adventurer!',
|
|
94
|
+
voice: 'male-qn-qingse',
|
|
95
|
+
format: 'mp3',
|
|
96
|
+
});
|
|
97
|
+
console.log('Characters billed:', result.usageCharacters);
|
|
98
|
+
console.log('Audio length (ms):', result.audioLengthMs);
|
|
99
|
+
|
|
100
|
+
// Or get a playable object URL directly (browser)
|
|
101
|
+
const url = await tts.synthesizeToObjectURL({ text: 'Hello there!' });
|
|
102
|
+
const audio = new Audio(url);
|
|
103
|
+
audio.play();
|
|
104
|
+
```
|
|
105
|
+
|
|
86
106
|
### NPC Conversations
|
|
87
107
|
|
|
88
108
|
```typescript
|
package/dist/playkit-sdk.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* playkit-sdk v1.
|
|
2
|
+
* playkit-sdk v1.4.0-beta.1
|
|
3
3
|
* PlayKit SDK for JavaScript
|
|
4
4
|
* @license SEE LICENSE IN LICENSE
|
|
5
5
|
*/
|
|
@@ -830,7 +830,7 @@ class TokenStorage {
|
|
|
830
830
|
}
|
|
831
831
|
|
|
832
832
|
const SDK_TYPE = 'Javascript';
|
|
833
|
-
const SDK_VERSION = '"1.
|
|
833
|
+
const SDK_VERSION = '"1.4.0-beta.1"';
|
|
834
834
|
function getSDKHeaders() {
|
|
835
835
|
return {
|
|
836
836
|
'X-SDK-Type': SDK_TYPE,
|
|
@@ -2426,7 +2426,7 @@ DeviceAuthFlowManager.activeInstance = null;
|
|
|
2426
2426
|
* Handles JWT exchange and token management
|
|
2427
2427
|
*/
|
|
2428
2428
|
// @ts-ignore - replaced at build time
|
|
2429
|
-
const DEFAULT_BASE_URL$
|
|
2429
|
+
const DEFAULT_BASE_URL$6 = "https://api.playkit.ai";
|
|
2430
2430
|
const JWT_EXCHANGE_ENDPOINT = '/api/external/exchange-jwt';
|
|
2431
2431
|
const TOKEN_REFRESH_ENDPOINT = '/api/auth/refresh';
|
|
2432
2432
|
class AuthManager extends EventEmitter {
|
|
@@ -2444,7 +2444,7 @@ class AuthManager extends EventEmitter {
|
|
|
2444
2444
|
this.storage = new TokenStorage({
|
|
2445
2445
|
mode: config.mode === 'server' ? 'server' : 'browser',
|
|
2446
2446
|
});
|
|
2447
|
-
this.baseURL = config.baseURL || DEFAULT_BASE_URL$
|
|
2447
|
+
this.baseURL = config.baseURL || DEFAULT_BASE_URL$6;
|
|
2448
2448
|
this.authState = {
|
|
2449
2449
|
isAuthenticated: false,
|
|
2450
2450
|
};
|
|
@@ -3533,7 +3533,7 @@ class RechargeManager extends EventEmitter {
|
|
|
3533
3533
|
* Player client for managing player information and credits
|
|
3534
3534
|
*/
|
|
3535
3535
|
// @ts-ignore - replaced at build time
|
|
3536
|
-
const DEFAULT_BASE_URL$
|
|
3536
|
+
const DEFAULT_BASE_URL$5 = "https://api.playkit.ai";
|
|
3537
3537
|
const PLAYER_INFO_ENDPOINT = '/api/external/player-info';
|
|
3538
3538
|
const SET_NICKNAME_ENDPOINT = '/api/external/set-game-player-nickname';
|
|
3539
3539
|
class PlayerClient extends EventEmitter {
|
|
@@ -3545,7 +3545,7 @@ class PlayerClient extends EventEmitter {
|
|
|
3545
3545
|
this.balanceCheckInterval = null;
|
|
3546
3546
|
this.logger = Logger.getLogger('PlayerClient');
|
|
3547
3547
|
this.authManager = authManager;
|
|
3548
|
-
this.baseURL = config.baseURL || DEFAULT_BASE_URL$
|
|
3548
|
+
this.baseURL = config.baseURL || DEFAULT_BASE_URL$5;
|
|
3549
3549
|
this.gameId = config.gameId;
|
|
3550
3550
|
this.rechargeConfig = {
|
|
3551
3551
|
autoShowBalanceModal: (_a = rechargeConfig.autoShowBalanceModal) !== null && _a !== void 0 ? _a : true,
|
|
@@ -3893,12 +3893,12 @@ function contentToString$1(content) {
|
|
|
3893
3893
|
return textParts.map(part => part.text).join('');
|
|
3894
3894
|
}
|
|
3895
3895
|
// @ts-ignore - replaced at build time
|
|
3896
|
-
const DEFAULT_BASE_URL$
|
|
3896
|
+
const DEFAULT_BASE_URL$4 = "https://api.playkit.ai";
|
|
3897
3897
|
class ChatProvider {
|
|
3898
3898
|
constructor(authManager, config) {
|
|
3899
3899
|
this.authManager = authManager;
|
|
3900
3900
|
this.config = config;
|
|
3901
|
-
this.baseURL = config.baseURL || DEFAULT_BASE_URL$
|
|
3901
|
+
this.baseURL = config.baseURL || DEFAULT_BASE_URL$4;
|
|
3902
3902
|
}
|
|
3903
3903
|
/**
|
|
3904
3904
|
* Set player client for balance checking
|
|
@@ -4225,12 +4225,12 @@ class ChatProvider {
|
|
|
4225
4225
|
* Image generation provider for HTTP communication with image API
|
|
4226
4226
|
*/
|
|
4227
4227
|
// @ts-ignore - replaced at build time
|
|
4228
|
-
const DEFAULT_BASE_URL$
|
|
4228
|
+
const DEFAULT_BASE_URL$3 = "https://api.playkit.ai";
|
|
4229
4229
|
class ImageProvider {
|
|
4230
4230
|
constructor(authManager, config) {
|
|
4231
4231
|
this.authManager = authManager;
|
|
4232
4232
|
this.config = config;
|
|
4233
|
-
this.baseURL = config.baseURL || DEFAULT_BASE_URL$
|
|
4233
|
+
this.baseURL = config.baseURL || DEFAULT_BASE_URL$3;
|
|
4234
4234
|
}
|
|
4235
4235
|
/**
|
|
4236
4236
|
* Set player client for balance checking
|
|
@@ -4314,12 +4314,12 @@ class ImageProvider {
|
|
|
4314
4314
|
* Transcription provider for HTTP communication with audio transcription API
|
|
4315
4315
|
*/
|
|
4316
4316
|
// @ts-ignore - replaced at build time
|
|
4317
|
-
const DEFAULT_BASE_URL$
|
|
4317
|
+
const DEFAULT_BASE_URL$2 = "https://api.playkit.ai";
|
|
4318
4318
|
class TranscriptionProvider {
|
|
4319
4319
|
constructor(authManager, config) {
|
|
4320
4320
|
this.authManager = authManager;
|
|
4321
4321
|
this.config = config;
|
|
4322
|
-
this.baseURL = config.baseURL || DEFAULT_BASE_URL$
|
|
4322
|
+
this.baseURL = config.baseURL || DEFAULT_BASE_URL$2;
|
|
4323
4323
|
}
|
|
4324
4324
|
/**
|
|
4325
4325
|
* Set player client for balance checking
|
|
@@ -4413,6 +4413,116 @@ class TranscriptionProvider {
|
|
|
4413
4413
|
}
|
|
4414
4414
|
}
|
|
4415
4415
|
|
|
4416
|
+
/**
|
|
4417
|
+
* TTS provider for HTTP communication with the text-to-speech API
|
|
4418
|
+
*/
|
|
4419
|
+
// @ts-ignore - replaced at build time
|
|
4420
|
+
const DEFAULT_BASE_URL$1 = "https://api.playkit.ai";
|
|
4421
|
+
class TTSProvider {
|
|
4422
|
+
constructor(authManager, config) {
|
|
4423
|
+
this.authManager = authManager;
|
|
4424
|
+
this.config = config;
|
|
4425
|
+
this.baseURL = config.baseURL || DEFAULT_BASE_URL$1;
|
|
4426
|
+
}
|
|
4427
|
+
/**
|
|
4428
|
+
* Set player client for balance checking
|
|
4429
|
+
*/
|
|
4430
|
+
setPlayerClient(playerClient) {
|
|
4431
|
+
this.playerClient = playerClient;
|
|
4432
|
+
}
|
|
4433
|
+
/**
|
|
4434
|
+
* Synthesize text into speech audio
|
|
4435
|
+
*/
|
|
4436
|
+
async synthesize(ttsConfig) {
|
|
4437
|
+
// Ensure token is valid, auto-refresh if needed (browser mode only)
|
|
4438
|
+
await this.authManager.ensureValidToken();
|
|
4439
|
+
const token = this.authManager.getToken();
|
|
4440
|
+
if (!token) {
|
|
4441
|
+
throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
|
|
4442
|
+
}
|
|
4443
|
+
const model = ttsConfig.model || this.config.defaultTTSModel || 'default-tts-model';
|
|
4444
|
+
const endpoint = `/ai/${this.config.gameId}/v2/audio/speech`;
|
|
4445
|
+
const requestBody = {
|
|
4446
|
+
model,
|
|
4447
|
+
text: ttsConfig.text,
|
|
4448
|
+
};
|
|
4449
|
+
// Add optional parameters (only when defined)
|
|
4450
|
+
if (ttsConfig.voice !== undefined) {
|
|
4451
|
+
requestBody.voice = ttsConfig.voice;
|
|
4452
|
+
}
|
|
4453
|
+
if (ttsConfig.speed !== undefined) {
|
|
4454
|
+
requestBody.speed = ttsConfig.speed;
|
|
4455
|
+
}
|
|
4456
|
+
if (ttsConfig.vol !== undefined) {
|
|
4457
|
+
requestBody.vol = ttsConfig.vol;
|
|
4458
|
+
}
|
|
4459
|
+
if (ttsConfig.pitch !== undefined) {
|
|
4460
|
+
requestBody.pitch = ttsConfig.pitch;
|
|
4461
|
+
}
|
|
4462
|
+
if (ttsConfig.emotion !== undefined) {
|
|
4463
|
+
requestBody.emotion = ttsConfig.emotion;
|
|
4464
|
+
}
|
|
4465
|
+
if (ttsConfig.languageBoost !== undefined) {
|
|
4466
|
+
requestBody.language_boost = ttsConfig.languageBoost;
|
|
4467
|
+
}
|
|
4468
|
+
if (ttsConfig.format !== undefined) {
|
|
4469
|
+
requestBody.response_format = ttsConfig.format;
|
|
4470
|
+
}
|
|
4471
|
+
if (ttsConfig.voiceSetting !== undefined) {
|
|
4472
|
+
requestBody.voice_setting = ttsConfig.voiceSetting;
|
|
4473
|
+
}
|
|
4474
|
+
if (ttsConfig.audioSetting !== undefined) {
|
|
4475
|
+
requestBody.audio_setting = ttsConfig.audioSetting;
|
|
4476
|
+
}
|
|
4477
|
+
try {
|
|
4478
|
+
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
4479
|
+
method: 'POST',
|
|
4480
|
+
headers: Object.assign({ Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, getSDKHeaders()),
|
|
4481
|
+
body: JSON.stringify(requestBody),
|
|
4482
|
+
});
|
|
4483
|
+
if (!response.ok) {
|
|
4484
|
+
const error = await response.json().catch(() => ({ message: 'Speech synthesis failed' }));
|
|
4485
|
+
const playKitError = new PlayKitError(error.message || 'Speech synthesis failed', error.code, response.status);
|
|
4486
|
+
// Check for insufficient credits error
|
|
4487
|
+
if (error.code === 'INSUFFICIENT_CREDITS' ||
|
|
4488
|
+
error.code === 'PLAYER_INSUFFICIENT_CREDIT' ||
|
|
4489
|
+
response.status === 402) {
|
|
4490
|
+
if (this.playerClient) {
|
|
4491
|
+
await this.playerClient.handleInsufficientCredits(playKitError);
|
|
4492
|
+
}
|
|
4493
|
+
}
|
|
4494
|
+
throw playKitError;
|
|
4495
|
+
}
|
|
4496
|
+
// SUCCESS: response is raw audio bytes, NOT JSON.
|
|
4497
|
+
const audio = await response.arrayBuffer();
|
|
4498
|
+
const contentType = response.headers.get('Content-Type');
|
|
4499
|
+
const usageHeader = response.headers.get('X-Usage-Characters');
|
|
4500
|
+
const audioLengthHeader = response.headers.get('X-Audio-Length-Ms');
|
|
4501
|
+
const result = {
|
|
4502
|
+
audio,
|
|
4503
|
+
format: contentType || ttsConfig.format || 'mp3',
|
|
4504
|
+
usageCharacters: Number(usageHeader) || 0,
|
|
4505
|
+
};
|
|
4506
|
+
if (audioLengthHeader !== null) {
|
|
4507
|
+
result.audioLengthMs = Number(audioLengthHeader) || 0;
|
|
4508
|
+
}
|
|
4509
|
+
// Check balance after successful API call
|
|
4510
|
+
if (this.playerClient) {
|
|
4511
|
+
this.playerClient.checkBalanceAfterApiCall().catch(() => {
|
|
4512
|
+
// Silently fail
|
|
4513
|
+
});
|
|
4514
|
+
}
|
|
4515
|
+
return result;
|
|
4516
|
+
}
|
|
4517
|
+
catch (error) {
|
|
4518
|
+
if (error instanceof PlayKitError) {
|
|
4519
|
+
throw error;
|
|
4520
|
+
}
|
|
4521
|
+
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'TTS_ERROR');
|
|
4522
|
+
}
|
|
4523
|
+
}
|
|
4524
|
+
}
|
|
4525
|
+
|
|
4416
4526
|
/******************************************************************************
|
|
4417
4527
|
Copyright (c) Microsoft Corporation.
|
|
4418
4528
|
|
|
@@ -5077,6 +5187,80 @@ class TranscriptionClient {
|
|
|
5077
5187
|
}
|
|
5078
5188
|
}
|
|
5079
5189
|
|
|
5190
|
+
/**
|
|
5191
|
+
* High-level client for text-to-speech synthesis
|
|
5192
|
+
*/
|
|
5193
|
+
/**
|
|
5194
|
+
* Resolve an audio format/content-type string into a valid MIME type.
|
|
5195
|
+
* The provider's `result.format` may be a full MIME (e.g. 'audio/mpeg' from
|
|
5196
|
+
* the Content-Type header) or a bare token (e.g. 'mp3' from the fallback).
|
|
5197
|
+
* Full MIME strings pass through; bare tokens are mapped.
|
|
5198
|
+
*/
|
|
5199
|
+
function contentTypeFor(format) {
|
|
5200
|
+
if (format.includes('/')) {
|
|
5201
|
+
return format;
|
|
5202
|
+
}
|
|
5203
|
+
switch (format.toLowerCase()) {
|
|
5204
|
+
case 'mp3':
|
|
5205
|
+
return 'audio/mpeg';
|
|
5206
|
+
case 'wav':
|
|
5207
|
+
return 'audio/wav';
|
|
5208
|
+
case 'ogg':
|
|
5209
|
+
return 'audio/ogg';
|
|
5210
|
+
case 'flac':
|
|
5211
|
+
return 'audio/flac';
|
|
5212
|
+
case 'aac':
|
|
5213
|
+
return 'audio/aac';
|
|
5214
|
+
case 'pcm':
|
|
5215
|
+
return 'audio/pcm';
|
|
5216
|
+
default:
|
|
5217
|
+
return 'audio/mpeg';
|
|
5218
|
+
}
|
|
5219
|
+
}
|
|
5220
|
+
class TTSClient {
|
|
5221
|
+
constructor(provider, model) {
|
|
5222
|
+
this.provider = provider;
|
|
5223
|
+
this.model = model || 'default-tts-model';
|
|
5224
|
+
}
|
|
5225
|
+
/**
|
|
5226
|
+
* Get the current model name
|
|
5227
|
+
*/
|
|
5228
|
+
get modelName() {
|
|
5229
|
+
return this.model;
|
|
5230
|
+
}
|
|
5231
|
+
/**
|
|
5232
|
+
* Synthesize text into speech audio
|
|
5233
|
+
* @param config - Full TTS configuration
|
|
5234
|
+
* @returns TTS result containing raw audio bytes and usage metadata
|
|
5235
|
+
*/
|
|
5236
|
+
async synthesize(config) {
|
|
5237
|
+
return this.provider.synthesize(Object.assign(Object.assign({}, config), { model: config.model || this.model }));
|
|
5238
|
+
}
|
|
5239
|
+
/**
|
|
5240
|
+
* Synthesize text into speech and return it as a Blob (browser-friendly)
|
|
5241
|
+
* @param config - Full TTS configuration
|
|
5242
|
+
* @returns Audio Blob with the appropriate MIME type
|
|
5243
|
+
*/
|
|
5244
|
+
async synthesizeToBlob(config) {
|
|
5245
|
+
const result = await this.synthesize(config);
|
|
5246
|
+
return new Blob([result.audio], { type: contentTypeFor(result.format) });
|
|
5247
|
+
}
|
|
5248
|
+
/**
|
|
5249
|
+
* Synthesize text into speech and return an object URL (browser only)
|
|
5250
|
+
* @param config - Full TTS configuration
|
|
5251
|
+
* @returns An object URL that can be assigned to an <audio> element
|
|
5252
|
+
* @throws PlayKitError if URL.createObjectURL is unavailable (e.g. Node.js)
|
|
5253
|
+
*/
|
|
5254
|
+
async synthesizeToObjectURL(config) {
|
|
5255
|
+
if (typeof URL === 'undefined' || typeof URL.createObjectURL !== 'function') {
|
|
5256
|
+
throw new PlayKitError('URL.createObjectURL is not available in this environment. ' +
|
|
5257
|
+
'Use synthesize() to access the raw audio bytes instead.', 'TTS_OBJECT_URL_UNAVAILABLE');
|
|
5258
|
+
}
|
|
5259
|
+
const blob = await this.synthesizeToBlob(config);
|
|
5260
|
+
return URL.createObjectURL(blob);
|
|
5261
|
+
}
|
|
5262
|
+
}
|
|
5263
|
+
|
|
5080
5264
|
/**
|
|
5081
5265
|
* Global AI Context Manager for managing NPC conversations and player context.
|
|
5082
5266
|
*
|
|
@@ -6400,10 +6584,12 @@ class PlayKitSDK extends EventEmitter {
|
|
|
6400
6584
|
this.chatProvider = new ChatProvider(this.authManager, this.config);
|
|
6401
6585
|
this.imageProvider = new ImageProvider(this.authManager, this.config);
|
|
6402
6586
|
this.transcriptionProvider = new TranscriptionProvider(this.authManager, this.config);
|
|
6587
|
+
this.ttsProvider = new TTSProvider(this.authManager, this.config);
|
|
6403
6588
|
// Connect providers to player client for balance checking
|
|
6404
6589
|
this.chatProvider.setPlayerClient(this.playerClient);
|
|
6405
6590
|
this.imageProvider.setPlayerClient(this.playerClient);
|
|
6406
6591
|
this.transcriptionProvider.setPlayerClient(this.playerClient);
|
|
6592
|
+
this.ttsProvider.setPlayerClient(this.playerClient);
|
|
6407
6593
|
// Initialize AI context manager
|
|
6408
6594
|
this.contextManager = new AIContextManager(this.config.aiContext);
|
|
6409
6595
|
// Set chat client factory for compaction
|
|
@@ -6652,6 +6838,14 @@ class PlayKitSDK extends EventEmitter {
|
|
|
6652
6838
|
this.ensureInitialized();
|
|
6653
6839
|
return new TranscriptionClient(this.transcriptionProvider, model || this.config.defaultTranscriptionModel);
|
|
6654
6840
|
}
|
|
6841
|
+
/**
|
|
6842
|
+
* Create a TTS client for text-to-speech
|
|
6843
|
+
* @param model - TTS model to use (default: 'default-tts-model')
|
|
6844
|
+
*/
|
|
6845
|
+
createTTSClient(model) {
|
|
6846
|
+
this.ensureInitialized();
|
|
6847
|
+
return new TTSClient(this.ttsProvider, model || this.config.defaultTTSModel);
|
|
6848
|
+
}
|
|
6655
6849
|
/**
|
|
6656
6850
|
* Create an NPC client
|
|
6657
6851
|
* Automatically registers with AIContextManager
|
|
@@ -7059,6 +7253,7 @@ exports.PlayerClient = PlayerClient;
|
|
|
7059
7253
|
exports.RechargeManager = RechargeManager;
|
|
7060
7254
|
exports.SchemaLibrary = SchemaLibrary;
|
|
7061
7255
|
exports.StreamParser = StreamParser;
|
|
7256
|
+
exports.TTSClient = TTSClient;
|
|
7062
7257
|
exports.TokenStorage = TokenStorage;
|
|
7063
7258
|
exports.TokenValidator = TokenValidator;
|
|
7064
7259
|
exports.TranscriptionClient = TranscriptionClient;
|