@ctchealth/plato-sdk 0.0.13 → 0.0.15
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/package.json +1 -1
- package/src/lib/plato-intefaces.d.ts +52 -0
- package/src/lib/plato-intefaces.js +20 -1
- package/src/lib/plato-intefaces.js.map +1 -1
- package/src/lib/plato-sdk.d.ts +79 -1
- package/src/lib/plato-sdk.js +218 -8
- package/src/lib/plato-sdk.js.map +1 -1
- package/README.md +0 -900
package/README.md
DELETED
|
@@ -1,900 +0,0 @@
|
|
|
1
|
-
# Plato SDK
|
|
2
|
-
|
|
3
|
-
A TypeScript SDK for interacting with the Plato API to create and manage AI-powered medical training simulations.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The Plato SDK provides a simple and type-safe way to integrate with the Plato platform, allowing you to create medical training simulations with AI personas and manage voice-based interactions.
|
|
8
|
-
|
|
9
|
-
## Authentication
|
|
10
|
-
|
|
11
|
-
All API requests require authentication using a Bearer token. Include your JWT token in the `API-AUTH` header:
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
API-AUTH: Bearer <your-jwt-token>
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Requests without a valid JWT token will be rejected with a `401 Unauthorized` response.
|
|
18
|
-
|
|
19
|
-
## Features
|
|
20
|
-
|
|
21
|
-
- Create AI personas with customizable professional profiles and personalities
|
|
22
|
-
- Real-time voice interactions with AI assistants
|
|
23
|
-
- Comprehensive event system for call management
|
|
24
|
-
- Type-safe API with full TypeScript support
|
|
25
|
-
- Medical training simulation configuration
|
|
26
|
-
- Simulation persistence and recovery across page reloads
|
|
27
|
-
|
|
28
|
-
## Installation
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npm install plato-sdk
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Quick Start
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
import { PlatoApiClient, AvatarLanguage } from 'plato-sdk';
|
|
38
|
-
|
|
39
|
-
// Initialize the client
|
|
40
|
-
const client = new PlatoApiClient({
|
|
41
|
-
baseUrl: 'https://your-plato-api.com',
|
|
42
|
-
token: 'your-api-token',
|
|
43
|
-
user: 'test@test.test',
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// Get available assistant images
|
|
47
|
-
const images = await client.getAssistantImages();
|
|
48
|
-
|
|
49
|
-
// Create a simulation
|
|
50
|
-
const simulation = await client.createSimulation({
|
|
51
|
-
persona: {
|
|
52
|
-
professionalProfile: {
|
|
53
|
-
location: 'City Hospital, New York',
|
|
54
|
-
practiceSettings: 'Outpatient Clinic',
|
|
55
|
-
yearOfExperience: 12,
|
|
56
|
-
specialityAndDepartment: 'Cardiology',
|
|
57
|
-
},
|
|
58
|
-
segment: SegmentType.CostConsciousPrescriber,
|
|
59
|
-
assistantGender: AssistantVoiceGender.Male,
|
|
60
|
-
name: 'Dr Vegapunk',
|
|
61
|
-
personalityAndBehaviour: {
|
|
62
|
-
riskTolerance: 40,
|
|
63
|
-
researchOrientation: 70,
|
|
64
|
-
recognitionNeed: 60,
|
|
65
|
-
brandLoyalty: 55,
|
|
66
|
-
patientEmpathy: 80,
|
|
67
|
-
},
|
|
68
|
-
context: {
|
|
69
|
-
subSpecialityOrTherapyFocus: 'Hypertension management',
|
|
70
|
-
typicalPatientMix: 'Elderly with comorbidities',
|
|
71
|
-
keyClinicalDrivers: 'Reducing cardiovascular risk',
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
product: {
|
|
75
|
-
name: 'Ibuprofen 1000mg',
|
|
76
|
-
description:
|
|
77
|
-
'A nonsteroidal anti-inflammatory drug used to reduce pain, inflammation, and fever',
|
|
78
|
-
},
|
|
79
|
-
presentation: 'Oral tablets, 10 tablets per pack',
|
|
80
|
-
scenario: 'Discussing treatment options for an elderly patient with chronic arthritis',
|
|
81
|
-
objectives:
|
|
82
|
-
'Demonstrate efficacy of Ibuprofen in pain management Highlight safety profile and contraindications Encourage patient adherence',
|
|
83
|
-
anticipatedObjections:
|
|
84
|
-
'Concerns about gastrointestinal side effects Preference for lower-cost generic alternatives Potential interactions with other medications',
|
|
85
|
-
imageId: images[0]._id,
|
|
86
|
-
avatarLanguage: AvatarLanguage.English,
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// Check the simulation status - If simulation creation phase is equals to FINISHED, the simulation is ready to use
|
|
90
|
-
// If the simulation creation phase is ERROR the simulation creation failed and you need to retry creating a new one
|
|
91
|
-
// tip: you can also check the simulation status periodically using a polling mechanism
|
|
92
|
-
const status = await client.getSimulationStatus(simulation.simulationId);
|
|
93
|
-
|
|
94
|
-
// Start a voice call
|
|
95
|
-
const call = await client.startCall(simulation.simulationId);
|
|
96
|
-
|
|
97
|
-
// Listen to call events
|
|
98
|
-
call.on('call-start', () => {
|
|
99
|
-
console.log('Call started');
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
call.on('message', message => {
|
|
103
|
-
console.log('Message received:', message.transcript);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
call.on('call-end', () => {
|
|
107
|
-
console.log('Call ended - processing feedback...');
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// Automatically receive post-call feedback when ready
|
|
111
|
-
call.on('call-details-ready', callDetails => {
|
|
112
|
-
console.log('Call Summary:', callDetails.summary);
|
|
113
|
-
console.log('Score:', callDetails.score);
|
|
114
|
-
console.log('Strengths:', callDetails.strengths);
|
|
115
|
-
console.log('Areas to improve:', callDetails.weaknesses);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// Stop the call when done
|
|
119
|
-
call.stopCall();
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
## API Reference
|
|
123
|
-
|
|
124
|
-
### PlatoApiClient
|
|
125
|
-
|
|
126
|
-
The main class for interacting with the Plato API.
|
|
127
|
-
|
|
128
|
-
#### Constructor
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
new PlatoApiClient(config: ApiClientConfig)
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
**Parameters:**
|
|
135
|
-
|
|
136
|
-
- `config.baseUrl` (string): The base URL of the Plato API
|
|
137
|
-
- `config.token` (string): Your API authentication token
|
|
138
|
-
- `config.user` (string): Your user identifier
|
|
139
|
-
|
|
140
|
-
#### Methods
|
|
141
|
-
|
|
142
|
-
##### createSimulation(params: CreateSimulationDto)
|
|
143
|
-
|
|
144
|
-
Creates a new medical training simulation. It may take a few minutes for the simulation to be ready for use.
|
|
145
|
-
|
|
146
|
-
**Returns:** `Promise<{ simulationId: string, phase: CreationPhase }>`
|
|
147
|
-
|
|
148
|
-
##### startCall(simulationId: string)
|
|
149
|
-
|
|
150
|
-
Starts a voice call with the AI persona for the specified simulation.
|
|
151
|
-
|
|
152
|
-
**Returns:** Object with:
|
|
153
|
-
|
|
154
|
-
- `stopCall()`: Function to end the call
|
|
155
|
-
- `callId`: Unique identifier for the call
|
|
156
|
-
- `on<K>(event: K, listener: CallEventListener<K>)`: Subscribe to call events
|
|
157
|
-
- `off<K>(event: K, listener: CallEventListener<K>)`: Unsubscribe from call events
|
|
158
|
-
|
|
159
|
-
##### getCallDetails(callId: string)
|
|
160
|
-
|
|
161
|
-
Retrieves detailed information about a completed call, including transcript, summary, recording URL, ratings, and evaluation metrics.
|
|
162
|
-
|
|
163
|
-
**Parameters:**
|
|
164
|
-
|
|
165
|
-
- `callId` (string): The MongoDB `_id` of the call
|
|
166
|
-
|
|
167
|
-
**Returns:** `Promise<CallDTO>` — An object containing:
|
|
168
|
-
|
|
169
|
-
- `_id`: MongoDB ID of the call
|
|
170
|
-
- `summary`: Summary of the conversation
|
|
171
|
-
- `transcript`: Full transcript of the call
|
|
172
|
-
- `recordingUrl`: URL to access the call recording
|
|
173
|
-
- `rating`: User-provided rating (0-5)
|
|
174
|
-
- `successEvaluation`: Boolean indicating if the call was successful
|
|
175
|
-
- `score`: Overall score for the call
|
|
176
|
-
- `strengths`: Array of identified strengths
|
|
177
|
-
- `weaknesses`: Array of identified weaknesses
|
|
178
|
-
- `metric1`, `metric2`, `metric3`: Evaluation metric names
|
|
179
|
-
- `metric1Value`, `metric2Value`, `metric3Value`: Values for each metric
|
|
180
|
-
- `createdAt`: Timestamp when the call was created
|
|
181
|
-
- `endedAt`: Timestamp when the call ended
|
|
182
|
-
- `callDurationMs`: Duration of the call in milliseconds
|
|
183
|
-
- And other call-related fields
|
|
184
|
-
|
|
185
|
-
**Example:**
|
|
186
|
-
|
|
187
|
-
```typescript
|
|
188
|
-
// After a call has ended, retrieve its details
|
|
189
|
-
const callDetails = await client.getCallDetails(call._id);
|
|
190
|
-
console.log('Call Summary:', callDetails.summary);
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
##### getCallRecordings(queryParams: SimulationRecordingsQueryDto)
|
|
194
|
-
|
|
195
|
-
Retrieves a paginated list of call recordings for the authenticated user.
|
|
196
|
-
|
|
197
|
-
**Parameters:**
|
|
198
|
-
|
|
199
|
-
- `queryParams` (SimulationRecordingsQueryDto): Query parameters for filtering and pagination
|
|
200
|
-
- `limit` (optional): Number of recordings per page (`5`, `10`, or `25`)
|
|
201
|
-
- `page` (optional): Page number for pagination
|
|
202
|
-
- `sort` (optional): Sort order (`'asc'` or `'desc'`)
|
|
203
|
-
|
|
204
|
-
**Returns:** `Promise<SimulationRecordingsDto[]>` — An array of recording objects, each containing:
|
|
205
|
-
|
|
206
|
-
- `_id`: MongoDB ID of the call
|
|
207
|
-
- `createdAt`: Timestamp when the call was created
|
|
208
|
-
- `recordingStatus`: Status of the recording (`'STARTED'`, `'PROCESSING'`, `'FINISHED'`, or `'FAILED'`)
|
|
209
|
-
|
|
210
|
-
**Example:**
|
|
211
|
-
|
|
212
|
-
```typescript
|
|
213
|
-
// Get the 10 most recent call recordings
|
|
214
|
-
const recordings = await client.getCallRecordings({
|
|
215
|
-
limit: 10,
|
|
216
|
-
page: 1,
|
|
217
|
-
sort: 'desc',
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
recordings.forEach(recording => {
|
|
221
|
-
console.log(`Call ${recording._id} - Status: ${recording.recordingStatus}`);
|
|
222
|
-
});
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
##### getCallRecording(callId: string)
|
|
226
|
-
|
|
227
|
-
Retrieves the recording URL for a specific call.
|
|
228
|
-
|
|
229
|
-
**Parameters:**
|
|
230
|
-
|
|
231
|
-
- `callId` (string): The MongoDB `_id` of the call
|
|
232
|
-
|
|
233
|
-
**Returns:** `Promise<string>` — The URL to access the call recording
|
|
234
|
-
|
|
235
|
-
**Example:**
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
238
|
-
// Get the recording URL for a specific call
|
|
239
|
-
const recordingUrl = await client.getCallRecording(call._id);
|
|
240
|
-
console.log('Recording URL:', recordingUrl);
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
##### uploadPdfSlides(file: File | Blob)
|
|
244
|
-
|
|
245
|
-
Uploads a PDF file for slide analysis. The file will be uploaded to S3 and analyzed asynchronously.
|
|
246
|
-
|
|
247
|
-
**Parameters:**
|
|
248
|
-
|
|
249
|
-
- `file` (File | Blob): The PDF file to upload
|
|
250
|
-
|
|
251
|
-
**Returns:** `Promise<string>` — A success message if the upload was successful.
|
|
252
|
-
|
|
253
|
-
**Example:**
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
// Upload a PDF file from an input element
|
|
257
|
-
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
|
|
258
|
-
const file = fileInput.files?.[0];
|
|
259
|
-
|
|
260
|
-
if (file) {
|
|
261
|
-
const result = await client.uploadPdfSlides(file);
|
|
262
|
-
console.log('PDF upload initiated');
|
|
263
|
-
}
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
##### getSlidesAnalysis(queryParams: PdfSlidesAnalysisQueryDto)
|
|
267
|
-
|
|
268
|
-
Retrieves a paginated and sorted list of PDF slide analysis records.
|
|
269
|
-
|
|
270
|
-
**Parameters:**
|
|
271
|
-
|
|
272
|
-
- `queryParams` (PdfSlidesAnalysisQueryDto):
|
|
273
|
-
- `limit` (optional): Number of records per page
|
|
274
|
-
- `page` (optional): Page number
|
|
275
|
-
- `sort` (optional): Sort order (`'asc'` or `'desc'`)
|
|
276
|
-
- `sortBy` (optional): Field to sort by (`'createdAt'`, `'originalFilename'`, or `'totalSlides'`)
|
|
277
|
-
|
|
278
|
-
**Returns:** `Promise<PdfSlidesDto[]>`
|
|
279
|
-
|
|
280
|
-
**Example:**
|
|
281
|
-
|
|
282
|
-
```typescript
|
|
283
|
-
const analysisList = await client.getSlidesAnalysis({
|
|
284
|
-
limit: 10,
|
|
285
|
-
page: 0,
|
|
286
|
-
sort: 'desc',
|
|
287
|
-
sortBy: 'createdAt',
|
|
288
|
-
});
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
##### getSlideAnalysis(id: string)
|
|
292
|
-
|
|
293
|
-
Retrieves the detailed analysis data for a specific PDF slide record, including the overview and individual slide analysis.
|
|
294
|
-
|
|
295
|
-
**Parameters:**
|
|
296
|
-
|
|
297
|
-
- `id` (string): The unique ID of the PDF slide record
|
|
298
|
-
|
|
299
|
-
**Returns:** `Promise<PdfSlideDto>`
|
|
300
|
-
|
|
301
|
-
**Example:**
|
|
302
|
-
|
|
303
|
-
```typescript
|
|
304
|
-
const details = await client.getSlideAnalysis('pdf-slide-id');
|
|
305
|
-
console.log('Lesson Overview:', details.lessonOverview);
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
##### deleteSlideAnalysis(id: string)
|
|
309
|
-
|
|
310
|
-
Deletes a PDF slide analysis record from the database and removes the corresponding file from S3 storage.
|
|
311
|
-
|
|
312
|
-
**Parameters:**
|
|
313
|
-
|
|
314
|
-
- `id` (string): The unique ID of the PDF slide record to delete
|
|
315
|
-
|
|
316
|
-
**Returns:** `Promise<void>`
|
|
317
|
-
|
|
318
|
-
**Example:**
|
|
319
|
-
|
|
320
|
-
```typescript
|
|
321
|
-
await client.deleteSlideAnalysis('pdf-slide-id');
|
|
322
|
-
console.log('Analysis deleted successfully');
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
##### getAssistantImages()
|
|
326
|
-
|
|
327
|
-
Retrieves all available assistant images that can be used when creating a simulation.
|
|
328
|
-
|
|
329
|
-
**Returns:** `Promise<AssistantImageDto[]>` — An array of assistant image objects, each containing:
|
|
330
|
-
|
|
331
|
-
- `_id`: Unique identifier for the image
|
|
332
|
-
- `imageUrl`: URL of the assistant image
|
|
333
|
-
|
|
334
|
-
**Example:**
|
|
335
|
-
|
|
336
|
-
```typescript
|
|
337
|
-
// Get all available assistant images
|
|
338
|
-
const images = await client.getAssistantImages();
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
##### getRecommendations()
|
|
342
|
-
|
|
343
|
-
Retrieves recommendations based on the user's recent call performance. Analyzes up to 10 of the most recent calls to identify patterns and provide actionable insights.
|
|
344
|
-
|
|
345
|
-
**Returns:** `Promise<RecommendationsResponseDto>` — An object containing:
|
|
346
|
-
|
|
347
|
-
- `recommendations`: Array of recommendation objects, each with:
|
|
348
|
-
- `title`: Brief title of the recommendation
|
|
349
|
-
- `description`: Detailed, actionable description
|
|
350
|
-
- `priority`: Priority level (`'high'`, `'medium'`, or `'low'`)
|
|
351
|
-
- `strengths`: Array of identified strengths, each with:
|
|
352
|
-
- `strength`: Description of the strength
|
|
353
|
-
- `frequency`: Number of calls where this strength appeared
|
|
354
|
-
- `improvementAreas`: Array of areas needing improvement, each with:
|
|
355
|
-
- `area`: Description of the improvement area
|
|
356
|
-
- `frequency`: Number of calls where this weakness appeared
|
|
357
|
-
- `summary`: A 2-3 sentence overall summary of performance trends
|
|
358
|
-
- `callsAnalyzed`: Number of calls that were analyzed
|
|
359
|
-
- `generatedAt`: Timestamp when the recommendations were generated
|
|
360
|
-
|
|
361
|
-
**Example:**
|
|
362
|
-
|
|
363
|
-
```typescript
|
|
364
|
-
// Get personalized recommendations based on call history
|
|
365
|
-
const recommendations = await client.getRecommendations();
|
|
366
|
-
|
|
367
|
-
console.log(`Analyzed ${recommendations.callsAnalyzed} calls`);
|
|
368
|
-
console.log('Summary:', recommendations.summary);
|
|
369
|
-
|
|
370
|
-
// Display high-priority recommendations
|
|
371
|
-
recommendations.recommendations
|
|
372
|
-
.filter(rec => rec.priority === 'high')
|
|
373
|
-
.forEach(rec => {
|
|
374
|
-
console.log(`[HIGH] ${rec.title}: ${rec.description}`);
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
// Show recurring strengths
|
|
378
|
-
recommendations.strengths.forEach(s => {
|
|
379
|
-
console.log(`Strength (${s.frequency} calls): ${s.strength}`);
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
// Show areas for improvement
|
|
383
|
-
recommendations.improvementAreas.forEach(area => {
|
|
384
|
-
console.log(`Needs work (${area.frequency} calls): ${area.area}`);
|
|
385
|
-
});
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
**Note:** This method requires the user to have at least one completed call. If no calls are found, a `BadRequestException` will be thrown.
|
|
389
|
-
|
|
390
|
-
## Checking Simulation Status
|
|
391
|
-
|
|
392
|
-
You can check the current phase/status of a simulation using the `checkSimulationStatus` method. This is useful for polling the simulation creation process until it is ready or has failed.
|
|
393
|
-
|
|
394
|
-
```typescript
|
|
395
|
-
const status = await client.checkSimulationStatus(simulation.simulationId);
|
|
396
|
-
console.log('Current phase:', status.phase); // e.g., 'FINISHED', 'ERROR', etc.
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
- **Returns:** `{ phase: CreationPhase }` — The current phase of the simulation creation process.
|
|
400
|
-
- **Typical usage:** Poll this method until the phase is `FINISHED` or `ERROR` before starting a call.
|
|
401
|
-
|
|
402
|
-
## Simulation Persistence
|
|
403
|
-
|
|
404
|
-
Simulations are persisted server-side and can be recovered after page reloads. Store the simulation ID client-side (e.g., localStorage) for quick recovery.
|
|
405
|
-
|
|
406
|
-
### getSimulationDetails(simulationId: string)
|
|
407
|
-
|
|
408
|
-
Retrieves detailed information about a simulation, including its original configuration.
|
|
409
|
-
|
|
410
|
-
**Returns:** `Promise<SimulationDetailsDto>` containing:
|
|
411
|
-
|
|
412
|
-
- `simulationId`: MongoDB ID
|
|
413
|
-
- `phase`: Current creation phase
|
|
414
|
-
- `assistantId`: The assistant ID (available after creation)
|
|
415
|
-
- `configuration`: Original `CreateSimulationDto`
|
|
416
|
-
- `createdAt`, `updatedAt`: Timestamps
|
|
417
|
-
|
|
418
|
-
**Example:**
|
|
419
|
-
|
|
420
|
-
```typescript
|
|
421
|
-
// Store simulation ID after creation
|
|
422
|
-
const simulation = await client.createSimulation(config);
|
|
423
|
-
localStorage.setItem('plato_simulation_id', simulation.simulationId);
|
|
424
|
-
|
|
425
|
-
// Recover simulation on page reload
|
|
426
|
-
const simulationId = localStorage.getItem('plato_simulation_id');
|
|
427
|
-
if (simulationId) {
|
|
428
|
-
const details = await client.getSimulationDetails(simulationId);
|
|
429
|
-
|
|
430
|
-
if (details.phase !== CreationPhase.ERROR) {
|
|
431
|
-
// Resume polling if still in progress
|
|
432
|
-
if (details.phase !== CreationPhase.FINISHED) {
|
|
433
|
-
startPolling(details.simulationId);
|
|
434
|
-
}
|
|
435
|
-
} else {
|
|
436
|
-
localStorage.removeItem('plato_simulation_id');
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
### getUserSimulations()
|
|
442
|
-
|
|
443
|
-
Retrieves all simulations for the authenticated user. Useful when the simulation ID is not stored locally.
|
|
444
|
-
|
|
445
|
-
**Returns:** `Promise<Array<{ simulationId: string; phase: CreationPhase }>>`
|
|
446
|
-
|
|
447
|
-
**Example:**
|
|
448
|
-
|
|
449
|
-
```typescript
|
|
450
|
-
const simulations = await client.getUserSimulations();
|
|
451
|
-
const inProgress = simulations.find(
|
|
452
|
-
sim => sim.phase !== CreationPhase.FINISHED && sim.phase !== CreationPhase.ERROR
|
|
453
|
-
);
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
## Event System
|
|
457
|
-
|
|
458
|
-
The SDK provides a comprehensive event system for managing voice calls:
|
|
459
|
-
|
|
460
|
-
### Available Events
|
|
461
|
-
|
|
462
|
-
- `call-start`: Triggered when a call begins
|
|
463
|
-
- `call-end`: Triggered when a call ends
|
|
464
|
-
- `speech-start`: Triggered when speech detection starts
|
|
465
|
-
- `speech-end`: Triggered when speech detection ends
|
|
466
|
-
- `message`: Triggered when a message is received (contains transcript and metadata)
|
|
467
|
-
- `volume-level`: Triggered with volume level updates (number)
|
|
468
|
-
- `error`: Triggered when an error occurs
|
|
469
|
-
- `call-details-ready`: Triggered when post-call processing completes and call details are available (includes full `CallDTO` with transcript, summary, ratings, and evaluation)
|
|
470
|
-
|
|
471
|
-
### Event Usage
|
|
472
|
-
|
|
473
|
-
```typescript
|
|
474
|
-
// Subscribe to events
|
|
475
|
-
call.on('message', message => {
|
|
476
|
-
console.log('Transcript:', message.transcript);
|
|
477
|
-
console.log('Type:', message.transcriptType); // 'final' or 'partial'
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
call.on('volume-level', level => {
|
|
481
|
-
console.log('Volume level:', level);
|
|
482
|
-
});
|
|
483
|
-
|
|
484
|
-
call.on('error', error => {
|
|
485
|
-
console.error('Call error:', error);
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
// Listen for call details after post-call processing
|
|
489
|
-
call.on('call-details-ready', callDetails => {
|
|
490
|
-
console.log('Post-call feedback ready:', callDetails);
|
|
491
|
-
});
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
## Automatic Post-Call Feedback
|
|
495
|
-
|
|
496
|
-
The SDK automatically fetches detailed call information after each call ends and completes post-call processing. This includes comprehensive feedback such as transcript, summary, evaluation metrics, strengths, weaknesses, and ratings.
|
|
497
|
-
|
|
498
|
-
### How It Works
|
|
499
|
-
|
|
500
|
-
When a call ends, the SDK automatically:
|
|
501
|
-
|
|
502
|
-
1. Triggers the `call-end` event
|
|
503
|
-
2. Processes the call on the backend (post-call analysis)
|
|
504
|
-
3. Fetches complete call details
|
|
505
|
-
4. Emits the `call-details-ready` event with full `CallDTO` data
|
|
506
|
-
|
|
507
|
-
This happens automatically—you don't need to manually call `getCallDetails()` after each call.
|
|
508
|
-
|
|
509
|
-
### Event Lifecycle
|
|
510
|
-
|
|
511
|
-
```typescript
|
|
512
|
-
const call = await client.startCall(simulationId);
|
|
513
|
-
|
|
514
|
-
// 1. Call begins
|
|
515
|
-
call.on('call-start', () => {
|
|
516
|
-
console.log('Call started');
|
|
517
|
-
});
|
|
518
|
-
|
|
519
|
-
// 2. Real-time transcript messages during the call
|
|
520
|
-
call.on('message', message => {
|
|
521
|
-
console.log('Real-time:', message.transcript);
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
// 3. Call ends
|
|
525
|
-
call.on('call-end', () => {
|
|
526
|
-
console.log('Call ended - processing feedback...');
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
// 4. Post-call details are automatically fetched and ready
|
|
530
|
-
call.on('call-details-ready', callDetails => {
|
|
531
|
-
console.log('Post-call feedback is ready!');
|
|
532
|
-
|
|
533
|
-
// Access all call details
|
|
534
|
-
console.log('Summary:', callDetails.summary);
|
|
535
|
-
console.log('Full Transcript:', callDetails.transcript);
|
|
536
|
-
console.log('Call Duration:', callDetails.callDurationMs, 'ms');
|
|
537
|
-
console.log('Success:', callDetails.successEvaluation);
|
|
538
|
-
console.log('Score:', callDetails.score);
|
|
539
|
-
|
|
540
|
-
// Display evaluation metrics
|
|
541
|
-
console.log(`${callDetails.metric1}: ${callDetails.metric1Value}`);
|
|
542
|
-
console.log(`${callDetails.metric2}: ${callDetails.metric2Value}`);
|
|
543
|
-
console.log(`${callDetails.metric3}: ${callDetails.metric3Value}`);
|
|
544
|
-
|
|
545
|
-
// Show strengths and areas for improvement
|
|
546
|
-
callDetails.strengths?.forEach(strength => {
|
|
547
|
-
console.log('✓ Strength:', strength);
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
callDetails.weaknesses?.forEach(weakness => {
|
|
551
|
-
console.log('⚠ Area to improve:', weakness);
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
// Access recording
|
|
555
|
-
if (callDetails.recordingUrl) {
|
|
556
|
-
console.log('Recording:', callDetails.recordingUrl);
|
|
557
|
-
}
|
|
558
|
-
});
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
### Practical Use Cases
|
|
562
|
-
|
|
563
|
-
#### 1. Display Post-Call Feedback in UI
|
|
564
|
-
|
|
565
|
-
```typescript
|
|
566
|
-
// Angular/React example
|
|
567
|
-
async startCall() {
|
|
568
|
-
const call = await this.client.startCall(this.simulationId);
|
|
569
|
-
|
|
570
|
-
// Automatically update UI when feedback is ready
|
|
571
|
-
call.on('call-details-ready', callDetails => {
|
|
572
|
-
this.callSummary = callDetails.summary;
|
|
573
|
-
this.callScore = callDetails.score;
|
|
574
|
-
this.strengths = callDetails.strengths;
|
|
575
|
-
this.weaknesses = callDetails.weaknesses;
|
|
576
|
-
this.showFeedbackModal = true; // Display feedback to user
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
```
|
|
580
|
-
|
|
581
|
-
#### 2. Track Performance Analytics
|
|
582
|
-
|
|
583
|
-
```typescript
|
|
584
|
-
call.on('call-details-ready', callDetails => {
|
|
585
|
-
// Send analytics to tracking service
|
|
586
|
-
analytics.track('call_completed', {
|
|
587
|
-
callId: callDetails._id,
|
|
588
|
-
duration: callDetails.callDurationMs,
|
|
589
|
-
score: callDetails.score,
|
|
590
|
-
success: callDetails.successEvaluation,
|
|
591
|
-
metrics: {
|
|
592
|
-
[callDetails.metric1]: callDetails.metric1Value,
|
|
593
|
-
[callDetails.metric2]: callDetails.metric2Value,
|
|
594
|
-
[callDetails.metric3]: callDetails.metric3Value,
|
|
595
|
-
},
|
|
596
|
-
});
|
|
597
|
-
});
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
#### 3. Store Call History
|
|
601
|
-
|
|
602
|
-
```typescript
|
|
603
|
-
call.on('call-details-ready', async callDetails => {
|
|
604
|
-
// Save to local storage or database
|
|
605
|
-
const callHistory = JSON.parse(localStorage.getItem('call_history') || '[]');
|
|
606
|
-
callHistory.push({
|
|
607
|
-
id: callDetails._id,
|
|
608
|
-
date: callDetails.createdAt,
|
|
609
|
-
summary: callDetails.summary,
|
|
610
|
-
score: callDetails.score,
|
|
611
|
-
});
|
|
612
|
-
localStorage.setItem('call_history', JSON.stringify(callHistory));
|
|
613
|
-
});
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
#### 4. Generate Learning Insights
|
|
617
|
-
|
|
618
|
-
```typescript
|
|
619
|
-
call.on('call-details-ready', callDetails => {
|
|
620
|
-
// Aggregate insights across multiple calls
|
|
621
|
-
if (callDetails.successEvaluation) {
|
|
622
|
-
this.successfulCalls++;
|
|
623
|
-
this.successStrategies.push(...(callDetails.strengths || []));
|
|
624
|
-
} else {
|
|
625
|
-
this.areasToImprove.push(...(callDetails.weaknesses || []));
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
this.updateLearningDashboard();
|
|
629
|
-
});
|
|
630
|
-
```
|
|
631
|
-
|
|
632
|
-
### Manual Fetching (Alternative Approach)
|
|
633
|
-
|
|
634
|
-
While the SDK automatically fetches call details after each call, you can also manually retrieve them later using the call ID:
|
|
635
|
-
|
|
636
|
-
```typescript
|
|
637
|
-
// Get call details at any time
|
|
638
|
-
const callDetails = await client.getCallDetails(callId);
|
|
639
|
-
```
|
|
640
|
-
|
|
641
|
-
This is useful when:
|
|
642
|
-
|
|
643
|
-
- Viewing historical calls
|
|
644
|
-
- Refreshing data after updates
|
|
645
|
-
- Building a call history view
|
|
646
|
-
|
|
647
|
-
### Error Handling
|
|
648
|
-
|
|
649
|
-
If fetching call details fails after a call ends, the error is logged but does not prevent the `call-end` event from completing. The call will still end gracefully.
|
|
650
|
-
|
|
651
|
-
```typescript
|
|
652
|
-
call.on('call-end', () => {
|
|
653
|
-
console.log('Call ended successfully');
|
|
654
|
-
// This will always fire, even if call-details-ready fails
|
|
655
|
-
});
|
|
656
|
-
|
|
657
|
-
call.on('call-details-ready', callDetails => {
|
|
658
|
-
// This may not fire if post-call processing fails
|
|
659
|
-
// In that case, you can manually fetch later using getCallDetails()
|
|
660
|
-
});
|
|
661
|
-
```
|
|
662
|
-
|
|
663
|
-
### Best Practices
|
|
664
|
-
|
|
665
|
-
1. **Always subscribe to `call-details-ready`** to capture post-call feedback automatically
|
|
666
|
-
2. **Show loading state** between `call-end` and `call-details-ready` events
|
|
667
|
-
3. **Handle missing data gracefully** - some fields may be `null` or `undefined` depending on call status
|
|
668
|
-
4. **Store call IDs** for later retrieval using `getCallDetails()` if needed
|
|
669
|
-
5. **Use the event data** to provide immediate feedback to users rather than making additional API calls
|
|
670
|
-
|
|
671
|
-
### Timing Considerations
|
|
672
|
-
|
|
673
|
-
- `call-end`: Fires immediately when the call stops
|
|
674
|
-
- `call-details-ready`: Fires after backend processing completes (typically 2-5 seconds after call ends)
|
|
675
|
-
|
|
676
|
-
Plan your UX accordingly—show a loading/processing state between these two events.
|
|
677
|
-
|
|
678
|
-
## Data Types
|
|
679
|
-
|
|
680
|
-
### CallDTO
|
|
681
|
-
|
|
682
|
-
Complete call details returned by `call-details-ready` event and `getCallDetails()` method:
|
|
683
|
-
|
|
684
|
-
```typescript
|
|
685
|
-
interface CallDTO {
|
|
686
|
-
_id: string; // MongoDB ID of the call
|
|
687
|
-
callId: string; // Vapi call ID
|
|
688
|
-
assistantId: string; // ID of the AI assistant used
|
|
689
|
-
summary?: string; // AI-generated summary of the conversation
|
|
690
|
-
transcript?: string; // Full transcript of the call
|
|
691
|
-
recordingUrl?: string; // URL to the call recording
|
|
692
|
-
rating?: number; // User-provided rating (0-5)
|
|
693
|
-
successEvaluation?: boolean; // Whether the call was successful
|
|
694
|
-
score?: number; // Overall score for the call
|
|
695
|
-
strengths?: string[]; // Array of identified strengths
|
|
696
|
-
weaknesses?: string[]; // Array of areas for improvement
|
|
697
|
-
metric1?: string; // Name of evaluation metric 1
|
|
698
|
-
metric1Value?: number; // Value for metric 1
|
|
699
|
-
metric2?: string; // Name of evaluation metric 2
|
|
700
|
-
metric2Value?: number; // Value for metric 2
|
|
701
|
-
metric3?: string; // Name of evaluation metric 3
|
|
702
|
-
metric3Value?: number; // Value for metric 3
|
|
703
|
-
createdAt: Date; // When the call was created
|
|
704
|
-
endedAt?: Date; // When the call ended
|
|
705
|
-
callDurationMs?: number; // Duration in milliseconds
|
|
706
|
-
// Additional fields may be present depending on call status
|
|
707
|
-
}
|
|
708
|
-
```
|
|
709
|
-
|
|
710
|
-
### CreateSimulationDto
|
|
711
|
-
|
|
712
|
-
Configuration for creating a simulation:
|
|
713
|
-
|
|
714
|
-
```typescript
|
|
715
|
-
interface CreateSimulationDto {
|
|
716
|
-
persona: CharacterCreateDto;
|
|
717
|
-
product: ProductConfig;
|
|
718
|
-
presentation?: string;
|
|
719
|
-
scenario: string;
|
|
720
|
-
objectives?: string;
|
|
721
|
-
anticipatedObjections?: string;
|
|
722
|
-
trainingConfiguration: TrainingConfigurationDto;
|
|
723
|
-
imageId: string;
|
|
724
|
-
avatarLanguage: AvatarLanguage;
|
|
725
|
-
}
|
|
726
|
-
```
|
|
727
|
-
|
|
728
|
-
### CharacterCreateDto
|
|
729
|
-
|
|
730
|
-
AI persona configuration:
|
|
731
|
-
|
|
732
|
-
```typescript
|
|
733
|
-
interface CharacterCreateDto {
|
|
734
|
-
name: string;
|
|
735
|
-
professionalProfile: ProfessionalProfileDto;
|
|
736
|
-
segment: SegmentType;
|
|
737
|
-
personalityAndBehaviour: PersonalityAndBehaviourDto;
|
|
738
|
-
context: ContextDto;
|
|
739
|
-
assistantGender?: AssistantVoiceGender;
|
|
740
|
-
}
|
|
741
|
-
```
|
|
742
|
-
|
|
743
|
-
### SimulationDetailsDto
|
|
744
|
-
|
|
745
|
-
Detailed simulation information returned by `getSimulationDetails()`:
|
|
746
|
-
|
|
747
|
-
```typescript
|
|
748
|
-
interface SimulationDetailsDto {
|
|
749
|
-
simulationId: string;
|
|
750
|
-
phase: CreationPhase;
|
|
751
|
-
assistantId: string;
|
|
752
|
-
configuration?: CreateSimulationDto;
|
|
753
|
-
createdAt: Date;
|
|
754
|
-
updatedAt: Date;
|
|
755
|
-
}
|
|
756
|
-
```
|
|
757
|
-
|
|
758
|
-
### CreationPhase
|
|
759
|
-
|
|
760
|
-
Enum representing the simulation creation phases:
|
|
761
|
-
|
|
762
|
-
```typescript
|
|
763
|
-
enum CreationPhase {
|
|
764
|
-
STARTING = 'STARTING',
|
|
765
|
-
CORE = 'CORE',
|
|
766
|
-
BOUNDARIES = 'BOUNDARIES',
|
|
767
|
-
SPEECH_AND_THOUGHT = 'SPEECH_AND_THOUGHT',
|
|
768
|
-
CONVERSATION_EVOLUTION = 'CONVERSATION_EVOLUTION',
|
|
769
|
-
MEMORY = 'MEMORY',
|
|
770
|
-
FINISHED = 'FINISHED',
|
|
771
|
-
ERROR = 'ERROR',
|
|
772
|
-
}
|
|
773
|
-
```
|
|
774
|
-
|
|
775
|
-
### RecommendationsResponseDto
|
|
776
|
-
|
|
777
|
-
Response object from `getRecommendations()`:
|
|
778
|
-
|
|
779
|
-
```typescript
|
|
780
|
-
interface RecommendationsResponseDto {
|
|
781
|
-
recommendations: RecommendationItemDto[];
|
|
782
|
-
strengths: PerformancePatternDto[];
|
|
783
|
-
improvementAreas: ImprovementAreaDto[];
|
|
784
|
-
summary: string;
|
|
785
|
-
callsAnalyzed: number;
|
|
786
|
-
generatedAt: Date;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
interface RecommendationItemDto {
|
|
790
|
-
title: string;
|
|
791
|
-
description: string;
|
|
792
|
-
priority: 'high' | 'medium' | 'low';
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
interface PerformancePatternDto {
|
|
796
|
-
strength: string;
|
|
797
|
-
frequency: number;
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
interface ImprovementAreaDto {
|
|
801
|
-
area: string;
|
|
802
|
-
frequency: number;
|
|
803
|
-
}
|
|
804
|
-
```
|
|
805
|
-
|
|
806
|
-
### PdfSlidesDto
|
|
807
|
-
|
|
808
|
-
Simplified data structure for PDF slide records (used in lists):
|
|
809
|
-
|
|
810
|
-
```typescript
|
|
811
|
-
interface PdfSlidesDto {
|
|
812
|
-
_id: string;
|
|
813
|
-
originalFilename: string;
|
|
814
|
-
totalSlides?: number;
|
|
815
|
-
lessonOverview?: string;
|
|
816
|
-
createdAt: Date;
|
|
817
|
-
updatedAt: Date;
|
|
818
|
-
}
|
|
819
|
-
```
|
|
820
|
-
|
|
821
|
-
### PdfSlideDto
|
|
822
|
-
|
|
823
|
-
Detailed data structure for a single PDF slide analysis:
|
|
824
|
-
|
|
825
|
-
```typescript
|
|
826
|
-
interface PdfSlideDto {
|
|
827
|
-
_id: string;
|
|
828
|
-
originalFilename: string;
|
|
829
|
-
totalSlides?: number;
|
|
830
|
-
lessonOverview?: string;
|
|
831
|
-
slideAnalysis?: Array<{
|
|
832
|
-
slideNumber: number;
|
|
833
|
-
title: string;
|
|
834
|
-
textExtraction: string;
|
|
835
|
-
}>;
|
|
836
|
-
createdAt: Date;
|
|
837
|
-
updatedAt: Date;
|
|
838
|
-
}
|
|
839
|
-
```
|
|
840
|
-
|
|
841
|
-
### PdfSlidesAnalysisQueryDto
|
|
842
|
-
|
|
843
|
-
Query parameters for retrieving slide analysis records:
|
|
844
|
-
|
|
845
|
-
```typescript
|
|
846
|
-
interface PdfSlidesAnalysisQueryDto {
|
|
847
|
-
limit?: 5 | 10 | 25;
|
|
848
|
-
page?: number;
|
|
849
|
-
sort?: 'asc' | 'desc';
|
|
850
|
-
sortBy?: 'createdAt' | 'originalFilename' | 'totalSlides';
|
|
851
|
-
}
|
|
852
|
-
```
|
|
853
|
-
|
|
854
|
-
### AssistantImageDto
|
|
855
|
-
|
|
856
|
-
Data structure for assistant images:
|
|
857
|
-
|
|
858
|
-
```typescript
|
|
859
|
-
interface AssistantImageDto {
|
|
860
|
-
_id: string;
|
|
861
|
-
imageUrl: string;
|
|
862
|
-
}
|
|
863
|
-
```
|
|
864
|
-
|
|
865
|
-
### AvatarLanguage
|
|
866
|
-
|
|
867
|
-
Enum representing available avatar languages:
|
|
868
|
-
|
|
869
|
-
```typescript
|
|
870
|
-
enum AvatarLanguage {
|
|
871
|
-
English = 'en',
|
|
872
|
-
German = 'de',
|
|
873
|
-
Spanish = 'es',
|
|
874
|
-
Italian = 'it',
|
|
875
|
-
French = 'fr',
|
|
876
|
-
}
|
|
877
|
-
```
|
|
878
|
-
|
|
879
|
-
## Error Handling
|
|
880
|
-
|
|
881
|
-
The SDK throws errors for invalid configurations and API failures:
|
|
882
|
-
|
|
883
|
-
```typescript
|
|
884
|
-
try {
|
|
885
|
-
const client = new PlatoApiClient({
|
|
886
|
-
baseUrl: 'https://api.plato.com',
|
|
887
|
-
token: 'your-token',
|
|
888
|
-
user: 'your-user',
|
|
889
|
-
});
|
|
890
|
-
|
|
891
|
-
const simulation = await client.createSimulation(simulationConfig);
|
|
892
|
-
const call = await client.startCall(simulation.simulationId);
|
|
893
|
-
} catch (error) {
|
|
894
|
-
console.error('Error:', error.message);
|
|
895
|
-
}
|
|
896
|
-
```
|
|
897
|
-
|
|
898
|
-
## Support
|
|
899
|
-
|
|
900
|
-
For support and questions, please contact the development team.
|