@unboundcx/sdk 2.8.5 → 2.8.7
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 +48 -1
- package/base.js +43 -12
- package/index.js +75 -0
- package/package.json +5 -2
- package/proto/transcription.proto +207 -0
- package/services/ai/SttStream.js +311 -0
- package/services/ai/playbooks.js +958 -0
- package/services/ai.js +773 -52
- package/services/engagementMetrics.js +6 -2
- package/services/objects.js +12 -3
- package/services/phoneNumbers.js +88 -3
- package/services/sipEndpoints.js +105 -33
- package/services/storage.js +176 -6
- package/services/taskRouter/MetricsService.js +111 -0
- package/services/taskRouter/TaskRouterService.js +12 -0
- package/services/taskRouter/TaskService.js +838 -0
- package/services/taskRouter/WorkerService.js +394 -0
- package/services/taskRouter.js +6 -0
- package/services/video.js +145 -5
- package/services/voice.js +124 -67
- package/services/workflows.js +34 -7
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ The official JavaScript SDK for Unbound's comprehensive communication and AI pla
|
|
|
11
11
|
- 📱 **Messaging**: SMS/MMS and Email with templates and campaigns
|
|
12
12
|
- 📞 **Voice**: Call management, conferencing, recording, transcription
|
|
13
13
|
- 📹 **Video**: Video conferencing with advanced controls
|
|
14
|
-
- 🤖 **AI**: Generative AI chat and
|
|
14
|
+
- 🤖 **AI**: Generative AI chat, text-to-speech, and speech-to-text
|
|
15
15
|
- 💾 **Data**: Object management with queries and relationships
|
|
16
16
|
- 🔄 **Workflows**: Programmable workflow execution
|
|
17
17
|
- 🔌 **Extensible**: Plugin system for transports and extensions
|
|
@@ -276,6 +276,53 @@ const audio = await api.ai.tts.create({
|
|
|
276
276
|
voice: 'en-US-Standard-A',
|
|
277
277
|
audioEncoding: 'MP3',
|
|
278
278
|
});
|
|
279
|
+
|
|
280
|
+
// Speech-to-Text - File/Storage Transcription
|
|
281
|
+
const transcription = await api.ai.stt.create({
|
|
282
|
+
sourceType: 'storage',
|
|
283
|
+
storageId: 'audio-file-id',
|
|
284
|
+
engine: 'google',
|
|
285
|
+
languageCode: 'en-US',
|
|
286
|
+
metadata: {
|
|
287
|
+
diarization: true,
|
|
288
|
+
speakerCount: 2,
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Speech-to-Text - Real-Time Streaming (NEW Simplified API)
|
|
293
|
+
const stream = await api.ai.stt.stream({
|
|
294
|
+
engine: 'google',
|
|
295
|
+
model: 'phone_call',
|
|
296
|
+
languageCode: 'en-US',
|
|
297
|
+
encoding: 'LINEAR16',
|
|
298
|
+
sampleRateHertz: 16000,
|
|
299
|
+
engagementSessionId: 'eng-123',
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Handle transcription events
|
|
303
|
+
stream.on('transcript', (result) => {
|
|
304
|
+
console.log(`${result.isFinal ? '[FINAL]' : '[interim]'} ${result.text}`);
|
|
305
|
+
// Transcripts are automatically saved to database!
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
stream.on('error', (error) => console.error('Stream error:', error));
|
|
309
|
+
stream.on('close', () => console.log('Stream closed'));
|
|
310
|
+
|
|
311
|
+
// Write audio chunks
|
|
312
|
+
stream.write(audioChunk); // Buffer or Uint8Array
|
|
313
|
+
stream.end(); // Close when done
|
|
314
|
+
|
|
315
|
+
// Later: Retrieve full transcript from database (automatic storage)
|
|
316
|
+
const savedTranscript = await api.ai.stt.get(stream.sessionId, {
|
|
317
|
+
includeMessages: true,
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// List all transcriptions
|
|
321
|
+
const transcriptions = await api.ai.stt.list({
|
|
322
|
+
engagementSessionId: 'eng-123',
|
|
323
|
+
status: 'completed',
|
|
324
|
+
limit: 50,
|
|
325
|
+
});
|
|
279
326
|
```
|
|
280
327
|
|
|
281
328
|
### Utility Services
|
package/base.js
CHANGED
|
@@ -167,6 +167,7 @@ export class BaseSDK {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
async _fetch(endpoint, method, params = {}, forceFetch = false) {
|
|
170
|
+
const startTime = Date.now();
|
|
170
171
|
const { body, query, headers = {}, returnRawResponse = false } = params;
|
|
171
172
|
|
|
172
173
|
this.validateParams(
|
|
@@ -195,7 +196,6 @@ export class BaseSDK {
|
|
|
195
196
|
params.headers = headers;
|
|
196
197
|
|
|
197
198
|
// Try transport plugins first
|
|
198
|
-
console.log(`sdk :: request :: forceFetch:${forceFetch} :: endpoint:${endpoint}`);
|
|
199
199
|
const transport = await this._getAvailableTransport(forceFetch);
|
|
200
200
|
let response;
|
|
201
201
|
if (transport) {
|
|
@@ -221,14 +221,27 @@ export class BaseSDK {
|
|
|
221
221
|
);
|
|
222
222
|
|
|
223
223
|
// Built-in HTTP transport (fallback)
|
|
224
|
-
return this._httpRequest(
|
|
224
|
+
return this._httpRequest(
|
|
225
|
+
endpoint,
|
|
226
|
+
method,
|
|
227
|
+
params,
|
|
228
|
+
returnRawResponse,
|
|
229
|
+
startTime,
|
|
230
|
+
);
|
|
225
231
|
}
|
|
226
232
|
} else {
|
|
227
233
|
// No transport available, fallback to HTTP
|
|
228
234
|
if (forceFetch && process.env.AUTH_V3_TOKEN_TYPE_OVERRIDE) {
|
|
229
|
-
params.headers['x-token-type-override'] =
|
|
235
|
+
params.headers['x-token-type-override'] =
|
|
236
|
+
process.env.AUTH_V3_TOKEN_TYPE_OVERRIDE;
|
|
230
237
|
}
|
|
231
|
-
return this._httpRequest(
|
|
238
|
+
return this._httpRequest(
|
|
239
|
+
endpoint,
|
|
240
|
+
method,
|
|
241
|
+
params,
|
|
242
|
+
returnRawResponse,
|
|
243
|
+
startTime,
|
|
244
|
+
);
|
|
232
245
|
}
|
|
233
246
|
|
|
234
247
|
// For streaming requests, return the raw response from transports
|
|
@@ -236,7 +249,14 @@ export class BaseSDK {
|
|
|
236
249
|
return response;
|
|
237
250
|
}
|
|
238
251
|
|
|
239
|
-
|
|
252
|
+
const duration = Date.now() - startTime;
|
|
253
|
+
return this._processResponse(
|
|
254
|
+
response,
|
|
255
|
+
transport.name,
|
|
256
|
+
method,
|
|
257
|
+
endpoint,
|
|
258
|
+
duration,
|
|
259
|
+
);
|
|
240
260
|
}
|
|
241
261
|
|
|
242
262
|
_isMultipartBody(body) {
|
|
@@ -269,7 +289,13 @@ export class BaseSDK {
|
|
|
269
289
|
return false;
|
|
270
290
|
}
|
|
271
291
|
|
|
272
|
-
async _httpRequest(
|
|
292
|
+
async _httpRequest(
|
|
293
|
+
endpoint,
|
|
294
|
+
method,
|
|
295
|
+
params = {},
|
|
296
|
+
returnRawResponse = false,
|
|
297
|
+
startTime = Date.now(),
|
|
298
|
+
) {
|
|
273
299
|
const { body, query, headers = {} } = params;
|
|
274
300
|
|
|
275
301
|
const options = {
|
|
@@ -325,16 +351,17 @@ export class BaseSDK {
|
|
|
325
351
|
}
|
|
326
352
|
|
|
327
353
|
const response = await fetch(url, options);
|
|
354
|
+
const duration = Date.now() - startTime;
|
|
328
355
|
|
|
329
356
|
// For streaming requests, return the raw fetch response
|
|
330
357
|
if (returnRawResponse) {
|
|
331
358
|
return response;
|
|
332
359
|
}
|
|
333
360
|
|
|
334
|
-
return this._processResponse(response, 'https', method, endpoint);
|
|
361
|
+
return this._processResponse(response, 'https', method, endpoint, duration);
|
|
335
362
|
}
|
|
336
363
|
|
|
337
|
-
async _processResponse(response, transport, method, endpoint) {
|
|
364
|
+
async _processResponse(response, transport, method, endpoint, duration = 0) {
|
|
338
365
|
// Check if the response indicates an HTTP error
|
|
339
366
|
// These are API/configuration errors, not transport failures
|
|
340
367
|
|
|
@@ -400,9 +427,11 @@ export class BaseSDK {
|
|
|
400
427
|
// Debug logging for successful HTTP requests
|
|
401
428
|
if (this.debugMode) {
|
|
402
429
|
console.log(
|
|
403
|
-
`API :: ERROR :: ${transport} :: ${method.toUpperCase()} :: ${
|
|
430
|
+
`API :: ERROR :: ${transport} :: ${method.toUpperCase()} :: ${
|
|
431
|
+
this.baseURL
|
|
432
|
+
}${endpoint} :: ${
|
|
404
433
|
response?.status
|
|
405
|
-
} :: ${responseRequestId}`,
|
|
434
|
+
} :: ${responseRequestId} :: ${duration}ms`,
|
|
406
435
|
httpError,
|
|
407
436
|
);
|
|
408
437
|
}
|
|
@@ -443,9 +472,11 @@ export class BaseSDK {
|
|
|
443
472
|
// Debug logging for successful HTTP requests
|
|
444
473
|
if (this.debugMode) {
|
|
445
474
|
console.log(
|
|
446
|
-
`API :: ${transport} :: ${method.toUpperCase()} :: ${
|
|
475
|
+
`API :: ${transport} :: ${method.toUpperCase()} :: ${
|
|
476
|
+
this.baseURL
|
|
477
|
+
}${endpoint} :: ${
|
|
447
478
|
response?.status
|
|
448
|
-
} :: ${responseRequestId}`,
|
|
479
|
+
} :: ${responseRequestId} :: ${duration}ms`,
|
|
449
480
|
);
|
|
450
481
|
}
|
|
451
482
|
|
package/index.js
CHANGED
|
@@ -24,6 +24,7 @@ import { PhoneNumbersService } from './services/phoneNumbers.js';
|
|
|
24
24
|
import { RecordTypesService } from './services/recordTypes.js';
|
|
25
25
|
import { GenerateIdService } from './services/generateId.js';
|
|
26
26
|
import { EngagementMetricsService } from './services/engagementMetrics.js';
|
|
27
|
+
import { TaskRouterService } from './services/taskRouter.js';
|
|
27
28
|
|
|
28
29
|
class UnboundSDK extends BaseSDK {
|
|
29
30
|
constructor(options = {}) {
|
|
@@ -89,6 +90,7 @@ class UnboundSDK extends BaseSDK {
|
|
|
89
90
|
this.recordTypes = new RecordTypesService(this);
|
|
90
91
|
this.generateId = new GenerateIdService(this);
|
|
91
92
|
this.engagementMetrics = new EngagementMetricsService(this);
|
|
93
|
+
this.taskRouter = new TaskRouterService(this);
|
|
92
94
|
|
|
93
95
|
// Add additional services that might be missing
|
|
94
96
|
this._initializeAdditionalServices();
|
|
@@ -153,6 +155,77 @@ class UnboundSDK extends BaseSDK {
|
|
|
153
155
|
'buildMasterAuth is only available with the internal SDK extension. Please use: sdk.use(InternalExtension)',
|
|
154
156
|
);
|
|
155
157
|
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Check SDK configuration and API connectivity
|
|
161
|
+
* Calls the /health endpoint to verify SDK setup
|
|
162
|
+
*
|
|
163
|
+
* @returns {Promise<Object>} Health check result with:
|
|
164
|
+
* - healthy: boolean - If API is reachable
|
|
165
|
+
* - hasAuthorization: boolean - If auth credentials were received by API
|
|
166
|
+
* - authType: string|null - Type of auth detected by API ('bearer', 'cookie', or 'bearer+cookie')
|
|
167
|
+
* - namespace: string - Current namespace
|
|
168
|
+
* - environment: string - 'node' or 'browser'
|
|
169
|
+
* - transport: string - Transport method used ('HTTP', 'WebSocket', etc.)
|
|
170
|
+
*/
|
|
171
|
+
async status() {
|
|
172
|
+
try {
|
|
173
|
+
const response = await this._fetch('/health', 'GET', {
|
|
174
|
+
returnRawResponse: true,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Parse response
|
|
178
|
+
let healthData;
|
|
179
|
+
try {
|
|
180
|
+
if (typeof response.json === 'function') {
|
|
181
|
+
healthData = await response.json();
|
|
182
|
+
} else if (response.body) {
|
|
183
|
+
healthData =
|
|
184
|
+
typeof response.body === 'string'
|
|
185
|
+
? JSON.parse(response.body)
|
|
186
|
+
: response.body;
|
|
187
|
+
} else {
|
|
188
|
+
healthData = {};
|
|
189
|
+
}
|
|
190
|
+
} catch (e) {
|
|
191
|
+
healthData = {};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
healthy: response.ok || response.status === 200,
|
|
196
|
+
hasAuthorization: healthData.hasAuthorization || false,
|
|
197
|
+
authType: healthData.authType || null,
|
|
198
|
+
namespace: this.namespace,
|
|
199
|
+
environment: this.environment,
|
|
200
|
+
transport: healthData.transport || 'unknown',
|
|
201
|
+
timestamp: healthData.timestamp,
|
|
202
|
+
url: healthData.url || null,
|
|
203
|
+
statusCode: response.status,
|
|
204
|
+
};
|
|
205
|
+
} catch (error) {
|
|
206
|
+
return {
|
|
207
|
+
healthy: false,
|
|
208
|
+
hasAuthorization: false,
|
|
209
|
+
authType: null,
|
|
210
|
+
namespace: this.namespace,
|
|
211
|
+
environment: this.environment,
|
|
212
|
+
error: error.message,
|
|
213
|
+
statusCode: error.status || null,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Get the client's IP address
|
|
220
|
+
* Always uses fetch transport (never WebSocket or other transports)
|
|
221
|
+
*
|
|
222
|
+
* @returns {Promise<Object>} Response with:
|
|
223
|
+
* - ip: string - The client's IP address
|
|
224
|
+
*/
|
|
225
|
+
async getIp() {
|
|
226
|
+
// Force fetch transport (pass true as forceFetch parameter)
|
|
227
|
+
return await this._fetch('/get-ip', 'GET', {}, true);
|
|
228
|
+
}
|
|
156
229
|
}
|
|
157
230
|
|
|
158
231
|
// Export both the class and a factory function for convenience
|
|
@@ -193,4 +266,6 @@ export {
|
|
|
193
266
|
} from './services/recordTypes.js';
|
|
194
267
|
export { GenerateIdService } from './services/generateId.js';
|
|
195
268
|
export { EngagementMetricsService } from './services/engagementMetrics.js';
|
|
269
|
+
export { TaskRouterService } from './services/taskRouter.js';
|
|
270
|
+
export { WorkerService } from './services/taskRouter/WorkerService.js';
|
|
196
271
|
export { BaseSDK } from './base.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unboundcx/sdk",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.7",
|
|
4
4
|
"description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"services/**/*.js",
|
|
42
42
|
"transports/**/*.js",
|
|
43
43
|
"types/**/*.d.ts",
|
|
44
|
+
"proto/**/*.proto",
|
|
44
45
|
"README.md",
|
|
45
46
|
"LICENSE"
|
|
46
47
|
],
|
|
@@ -64,7 +65,9 @@
|
|
|
64
65
|
},
|
|
65
66
|
"dependencies": {},
|
|
66
67
|
"optionalDependencies": {
|
|
67
|
-
"mime-types": "^2.1.35"
|
|
68
|
+
"mime-types": "^2.1.35",
|
|
69
|
+
"@grpc/grpc-js": "^1.14.1",
|
|
70
|
+
"@grpc/proto-loader": "^0.7.15"
|
|
68
71
|
},
|
|
69
72
|
"peerDependencies": {
|
|
70
73
|
"socket.io-client": "^4.0.0"
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package transcription;
|
|
4
|
+
|
|
5
|
+
// Transcription Service Definition
|
|
6
|
+
service TranscriptionService {
|
|
7
|
+
// Bidirectional streaming for real-time transcription
|
|
8
|
+
// Client streams audio chunks, server streams back transcription results
|
|
9
|
+
rpc StreamTranscribe(stream AudioRequest) returns (stream TranscriptResponse);
|
|
10
|
+
|
|
11
|
+
// Get transcription session status
|
|
12
|
+
rpc GetSessionStatus(SessionStatusRequest) returns (SessionStatusResponse);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Audio streaming request message
|
|
16
|
+
message AudioRequest {
|
|
17
|
+
// Audio data chunk (raw bytes)
|
|
18
|
+
bytes audio_chunk = 1;
|
|
19
|
+
|
|
20
|
+
// Session ID for this transcription session
|
|
21
|
+
string session_id = 2;
|
|
22
|
+
|
|
23
|
+
// Authentication token
|
|
24
|
+
string token = 3;
|
|
25
|
+
|
|
26
|
+
// Language code (optional, will auto-detect if not provided)
|
|
27
|
+
// Examples: "en", "es", "fr", "de", "ja", "zh"
|
|
28
|
+
string language = 4;
|
|
29
|
+
|
|
30
|
+
// Transcription engine to use
|
|
31
|
+
// Options: "whisper", "google"
|
|
32
|
+
string engine = 5;
|
|
33
|
+
|
|
34
|
+
// Audio configuration
|
|
35
|
+
AudioConfig config = 6;
|
|
36
|
+
|
|
37
|
+
// Flag to indicate this is the first chunk
|
|
38
|
+
bool is_first_chunk = 7;
|
|
39
|
+
|
|
40
|
+
// Flag to indicate this is the last chunk
|
|
41
|
+
bool is_last_chunk = 8;
|
|
42
|
+
|
|
43
|
+
// SIP call identifier (required for multi-stream support)
|
|
44
|
+
// Used to identify which call this audio belongs to
|
|
45
|
+
string sip_call_id = 9;
|
|
46
|
+
|
|
47
|
+
// Audio stream side (required for multi-stream support)
|
|
48
|
+
// Options: "send" (outgoing), "recv" (incoming)
|
|
49
|
+
string side = 10;
|
|
50
|
+
|
|
51
|
+
// Speaker role (optional)
|
|
52
|
+
// Examples: "customer", "agent", "system"
|
|
53
|
+
string role = 11;
|
|
54
|
+
|
|
55
|
+
// VAD event type (optional - sent by media manager for speech detection)
|
|
56
|
+
// Options: "speaking_started", "speaking_stopped"
|
|
57
|
+
// When provided, this is a VAD event (not audio data)
|
|
58
|
+
string vad_event = 12;
|
|
59
|
+
|
|
60
|
+
// VAD event energy level (for speaking_started events)
|
|
61
|
+
double vad_energy = 13;
|
|
62
|
+
|
|
63
|
+
// VAD event speech duration in ms (for speaking_stopped events)
|
|
64
|
+
int64 vad_duration = 14;
|
|
65
|
+
|
|
66
|
+
// VAD event timestamp
|
|
67
|
+
int64 vad_timestamp = 15;
|
|
68
|
+
|
|
69
|
+
// Playbook identifier (optional - links transcription to a playbook session)
|
|
70
|
+
string playbook_id = 16;
|
|
71
|
+
|
|
72
|
+
// Bridge identifier (optional - links related transcription streams)
|
|
73
|
+
// When multiple bridged call legs have transcription active,
|
|
74
|
+
// bridge_id lets the transcription service correlate them
|
|
75
|
+
string bridge_id = 17;
|
|
76
|
+
|
|
77
|
+
// Task identifier (optional - links transcription to a specific task)
|
|
78
|
+
string task_id = 18;
|
|
79
|
+
|
|
80
|
+
// Worker identifier (optional)
|
|
81
|
+
string worker_id = 19;
|
|
82
|
+
|
|
83
|
+
// Generate subject from transcription (optional)
|
|
84
|
+
bool generate_subject = 20;
|
|
85
|
+
|
|
86
|
+
// Generate transcript summary (optional)
|
|
87
|
+
bool generate_transcript_summary = 21;
|
|
88
|
+
|
|
89
|
+
// Generate sentiment analysis (optional)
|
|
90
|
+
bool generate_sentiment = 22;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Audio configuration
|
|
94
|
+
message AudioConfig {
|
|
95
|
+
// Audio encoding format
|
|
96
|
+
// Examples: "LINEAR16", "FLAC", "MP3", "OGG_OPUS", "WEBM_OPUS"
|
|
97
|
+
string encoding = 1;
|
|
98
|
+
|
|
99
|
+
// Sample rate in Hertz
|
|
100
|
+
// Recommended: 16000 for most cases
|
|
101
|
+
int32 sample_rate_hertz = 2;
|
|
102
|
+
|
|
103
|
+
// Number of audio channels
|
|
104
|
+
// Mono = 1, Stereo = 2
|
|
105
|
+
int32 audio_channel_count = 3;
|
|
106
|
+
|
|
107
|
+
// Language code (deprecated, use AudioRequest.language instead)
|
|
108
|
+
string language_code = 4;
|
|
109
|
+
|
|
110
|
+
// Voice Activity Detection (VAD) configuration
|
|
111
|
+
// Enable VAD to filter out silence and improve transcription quality
|
|
112
|
+
bool vad_enabled = 5;
|
|
113
|
+
|
|
114
|
+
// Minimum silence duration in milliseconds to split segments
|
|
115
|
+
// Typical values: 300ms (fast, live calls) to 700ms (accurate, voicemails)
|
|
116
|
+
// Default: 500ms
|
|
117
|
+
int32 min_silence_duration_ms = 6;
|
|
118
|
+
|
|
119
|
+
// Padding around speech segments in milliseconds
|
|
120
|
+
// Adds context before/after detected speech
|
|
121
|
+
// Default: 400ms
|
|
122
|
+
int32 speech_pad_ms = 7;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Transcription response message
|
|
126
|
+
message TranscriptResponse {
|
|
127
|
+
// Transcribed text
|
|
128
|
+
string transcript = 1;
|
|
129
|
+
|
|
130
|
+
// Confidence score (0.0 to 1.0)
|
|
131
|
+
float confidence = 2;
|
|
132
|
+
|
|
133
|
+
// Whether this is a final result or interim
|
|
134
|
+
bool is_final = 3;
|
|
135
|
+
|
|
136
|
+
// Detected or specified language
|
|
137
|
+
string language = 4;
|
|
138
|
+
|
|
139
|
+
// Timestamp of this result (milliseconds since epoch)
|
|
140
|
+
int64 timestamp = 5;
|
|
141
|
+
|
|
142
|
+
// Word-level details (optional)
|
|
143
|
+
repeated WordInfo words = 6;
|
|
144
|
+
|
|
145
|
+
// Start time of this segment (seconds)
|
|
146
|
+
float start_time = 7;
|
|
147
|
+
|
|
148
|
+
// End time of this segment (seconds)
|
|
149
|
+
float end_time = 8;
|
|
150
|
+
|
|
151
|
+
// SIP call identifier (echoed back from AudioRequest)
|
|
152
|
+
string sip_call_id = 9;
|
|
153
|
+
|
|
154
|
+
// Audio stream side (echoed back from AudioRequest)
|
|
155
|
+
string side = 10;
|
|
156
|
+
|
|
157
|
+
// Speaker role (echoed back from AudioRequest)
|
|
158
|
+
string role = 11;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Word-level information
|
|
162
|
+
message WordInfo {
|
|
163
|
+
// The word text
|
|
164
|
+
string word = 1;
|
|
165
|
+
|
|
166
|
+
// Start time of the word (seconds)
|
|
167
|
+
float start_time = 2;
|
|
168
|
+
|
|
169
|
+
// End time of the word (seconds)
|
|
170
|
+
float end_time = 3;
|
|
171
|
+
|
|
172
|
+
// Confidence score for this word (0.0 to 1.0)
|
|
173
|
+
float confidence = 4;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Session status request
|
|
177
|
+
message SessionStatusRequest {
|
|
178
|
+
// Session ID to query
|
|
179
|
+
string session_id = 1;
|
|
180
|
+
|
|
181
|
+
// Authentication token
|
|
182
|
+
string token = 2;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Session status response
|
|
186
|
+
message SessionStatusResponse {
|
|
187
|
+
// Session ID
|
|
188
|
+
string session_id = 1;
|
|
189
|
+
|
|
190
|
+
// Session status: "active", "completed", "failed", "not_found"
|
|
191
|
+
string status = 2;
|
|
192
|
+
|
|
193
|
+
// Detected or specified language
|
|
194
|
+
string language = 3;
|
|
195
|
+
|
|
196
|
+
// Engine being used
|
|
197
|
+
string engine = 4;
|
|
198
|
+
|
|
199
|
+
// Session start time (milliseconds since epoch)
|
|
200
|
+
int64 start_time = 5;
|
|
201
|
+
|
|
202
|
+
// Total chunks processed
|
|
203
|
+
int32 total_chunks = 6;
|
|
204
|
+
|
|
205
|
+
// Error message (if status is "failed")
|
|
206
|
+
string error = 7;
|
|
207
|
+
}
|