@ctchealth/plato-sdk 0.0.8 → 0.0.9

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 ADDED
@@ -0,0 +1,322 @@
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
+ ## Features
10
+
11
+ - 🎭 Create AI personas with customizable professional profiles and personalities
12
+ - 🗣️ Real-time voice interactions with AI assistants
13
+ - 📊 Comprehensive event system for call management
14
+ - 🔒 Type-safe API with full TypeScript support
15
+ - 🎯 Medical training simulation configuration
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install plato-sdk
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```typescript
26
+ import { PlatoApiClient } from 'plato-sdk';
27
+
28
+ // Initialize the client
29
+ const client = new PlatoApiClient({
30
+ baseUrl: 'https://your-plato-api.com',
31
+ token: 'your-api-token',
32
+ user: 'test@test.test',
33
+ });
34
+
35
+ // Create a simulation
36
+ const simulation = await client.createSimulation({
37
+ persona: {
38
+ professionalProfile: {
39
+ location: 'City Hospital, New York',
40
+ practiceSettings: 'Outpatient Clinic',
41
+ yearOfExperience: 12,
42
+ specialityAndDepartment: 'Cardiology',
43
+ },
44
+ segment: SegmentType.CostConsciousPrescriber,
45
+ assistantGender: AssistantVoiceGender.Male,
46
+ name: 'Dr Vegapunk',
47
+ personalityAndBehaviour: {
48
+ riskTolerance: 40,
49
+ researchOrientation: 70,
50
+ recognitionNeed: 60,
51
+ brandLoyalty: 55,
52
+ patientEmpathy: 80,
53
+ },
54
+ context: {
55
+ subSpecialityOrTherapyFocus: 'Hypertension management',
56
+ typicalPatientMix: 'Elderly with comorbidities',
57
+ keyClinicalDrivers: 'Reducing cardiovascular risk',
58
+ },
59
+ },
60
+ product: {
61
+ name: 'Ibuprofen 1000mg',
62
+ description:
63
+ 'A nonsteroidal anti-inflammatory drug used to reduce pain, inflammation, and fever',
64
+ },
65
+ presentation: 'Oral tablets, 10 tablets per pack',
66
+ scenario: 'Discussing treatment options for an elderly patient with chronic arthritis',
67
+ objectives: [
68
+ 'Demonstrate efficacy of Ibuprofen in pain management',
69
+ 'Highlight safety profile and contraindications',
70
+ 'Encourage patient adherence',
71
+ ],
72
+ anticipatedObjections: [
73
+ 'Concerns about gastrointestinal side effects',
74
+ 'Preference for lower-cost generic alternatives',
75
+ 'Potential interactions with other medications',
76
+ ],
77
+ });
78
+
79
+ // Check the simulation status - If simulation creation phase is equals to FINISHED, the simulation is ready to use
80
+ // If the simulation creation phase is ERROR the simulation creation failed and you need to retry creating a new one
81
+ // tip: you can also check the simulation status periodically using a polling mechanism
82
+ const status = await client.getSimulationStatus(simulation.simulationId);
83
+
84
+ // Start a voice call
85
+ const call = await client.startCall(simulation.simulationId);
86
+
87
+ // Listen to call events
88
+ call.on('call-start', () => {
89
+ console.log('Call started');
90
+ });
91
+
92
+ call.on('message', message => {
93
+ console.log('Message received:', message.transcript);
94
+ });
95
+
96
+ call.on('call-end', () => {
97
+ console.log('Call ended');
98
+ });
99
+
100
+ // Stop the call when done
101
+ call.stopCall();
102
+ ```
103
+
104
+ ## API Reference
105
+
106
+ ### PlatoApiClient
107
+
108
+ The main class for interacting with the Plato API.
109
+
110
+ #### Constructor
111
+
112
+ ```typescript
113
+ new PlatoApiClient(config: ApiClientConfig)
114
+ ```
115
+
116
+ **Parameters:**
117
+
118
+ - `config.baseUrl` (string): The base URL of the Plato API
119
+ - `config.token` (string): Your API authentication token
120
+ - `config.user` (string): Your user identifier
121
+
122
+ #### Methods
123
+
124
+ ##### createSimulation(params: CreateSimulationDto)
125
+
126
+ Creates a new medical training simulation. It may take a few minutes for the simulation to be ready for use.
127
+
128
+ **Returns:** `Promise<{ simulationId: string, phase: CreationPhase }>`
129
+
130
+ ##### startCall(simulationId: string)
131
+
132
+ Starts a voice call with the AI persona for the specified simulation.
133
+
134
+ **Returns:** Object with:
135
+
136
+ - `stopCall()`: Function to end the call
137
+ - `callId`: Unique identifier for the call
138
+ - `on<K>(event: K, listener: CallEventListener<K>)`: Subscribe to call events
139
+ - `off<K>(event: K, listener: CallEventListener<K>)`: Unsubscribe from call events
140
+
141
+ ##### getCallDetails(callId: string)
142
+
143
+ Retrieves detailed information about a completed call, including transcript, summary, recording URL, ratings, and evaluation metrics.
144
+
145
+ **Parameters:**
146
+
147
+ - `callId` (string): The MongoDB `_id` of the call
148
+
149
+ **Returns:** `Promise<CallDTO>` — An object containing:
150
+
151
+ - `_id`: MongoDB ID of the call
152
+ - `summary`: Summary of the conversation
153
+ - `transcript`: Full transcript of the call
154
+ - `recordingUrl`: URL to access the call recording
155
+ - `rating`: User-provided rating (0-5)
156
+ - `successEvaluation`: Boolean indicating if the call was successful
157
+ - `score`: Overall score for the call
158
+ - `strengths`: Array of identified strengths
159
+ - `weaknesses`: Array of identified weaknesses
160
+ - `metric1`, `metric2`, `metric3`: Evaluation metric names
161
+ - `metric1Value`, `metric2Value`, `metric3Value`: Values for each metric
162
+ - `createdAt`: Timestamp when the call was created
163
+ - `endedAt`: Timestamp when the call ended
164
+ - And other call-related fields
165
+
166
+ **Example:**
167
+
168
+ ```typescript
169
+ // After a call has ended, retrieve its details
170
+ const callDetails = await client.getCallDetails(call._id);
171
+ console.log('Call Summary:', callDetails.summary);
172
+ ```
173
+
174
+ ##### getCallRecordings(queryParams: SimulationRecordingsQueryDto)
175
+
176
+ Retrieves a paginated list of call recordings for the authenticated user.
177
+
178
+ **Parameters:**
179
+
180
+ - `queryParams` (SimulationRecordingsQueryDto): Query parameters for filtering and pagination
181
+ - `limit` (optional): Number of recordings per page (`5`, `10`, or `25`)
182
+ - `page` (optional): Page number for pagination
183
+ - `sort` (optional): Sort order (`'asc'` or `'desc'`)
184
+
185
+ **Returns:** `Promise<SimulationRecordingsDto[]>` — An array of recording objects, each containing:
186
+
187
+ - `_id`: MongoDB ID of the call
188
+ - `createdAt`: Timestamp when the call was created
189
+ - `recordingStatus`: Status of the recording (`'STARTED'`, `'PROCESSING'`, `'FINISHED'`, or `'FAILED'`)
190
+
191
+ **Example:**
192
+
193
+ ```typescript
194
+ // Get the 10 most recent call recordings
195
+ const recordings = await client.getCallRecordings({
196
+ limit: 10,
197
+ page: 1,
198
+ sort: 'desc',
199
+ });
200
+
201
+ recordings.forEach(recording => {
202
+ console.log(`Call ${recording._id} - Status: ${recording.recordingStatus}`);
203
+ });
204
+ ```
205
+
206
+ ##### getCallRecording(callId: string)
207
+
208
+ Retrieves the recording URL for a specific call.
209
+
210
+ **Parameters:**
211
+
212
+ - `callId` (string): The MongoDB `_id` of the call
213
+
214
+ **Returns:** `Promise<string>` — The URL to access the call recording
215
+
216
+ **Example:**
217
+
218
+ ```typescript
219
+ // Get the recording URL for a specific call
220
+ const recordingUrl = await client.getCallRecording(call._id);
221
+ console.log('Recording URL:', recordingUrl);
222
+ ```
223
+
224
+ ## Checking Simulation Status
225
+
226
+ 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.
227
+
228
+ ```typescript
229
+ const status = await client.checkSimulationStatus(simulation.simulationId);
230
+ console.log('Current phase:', status.phase); // e.g., 'FINISHED', 'ERROR', etc.
231
+ ```
232
+
233
+ - **Returns:** `{ phase: CreationPhase }` — The current phase of the simulation creation process.
234
+ - **Typical usage:** Poll this method until the phase is `FINISHED` or `ERROR` before starting a call.
235
+
236
+ ## Event System
237
+
238
+ The SDK provides a comprehensive event system for managing voice calls:
239
+
240
+ ### Available Events
241
+
242
+ - `call-start`: Triggered when a call begins
243
+ - `call-end`: Triggered when a call ends
244
+ - `speech-start`: Triggered when speech detection starts
245
+ - `speech-end`: Triggered when speech detection ends
246
+ - `message`: Triggered when a message is received (contains transcript and metadata)
247
+ - `volume-level`: Triggered with volume level updates (number)
248
+ - `error`: Triggered when an error occurs
249
+
250
+ ### Event Usage
251
+
252
+ ```typescript
253
+ // Subscribe to events
254
+ call.on('message', message => {
255
+ console.log('Transcript:', message.transcript);
256
+ console.log('Type:', message.transcriptType); // 'final' or 'partial'
257
+ });
258
+
259
+ call.on('volume-level', level => {
260
+ console.log('Volume level:', level);
261
+ });
262
+
263
+ call.on('error', error => {
264
+ console.error('Call error:', error);
265
+ });
266
+ ```
267
+
268
+ ## Data Types
269
+
270
+ ### CreateSimulationDto
271
+
272
+ Configuration for creating a simulation:
273
+
274
+ ```typescript
275
+ interface CreateSimulationDto {
276
+ persona: CharacterCreateDto;
277
+ product: ProductConfig;
278
+ presentation?: string;
279
+ scenario: string;
280
+ objectives?: string[];
281
+ anticipatedObjections?: string[];
282
+ trainingConfiguration: TrainingConfigurationDto;
283
+ }
284
+ ```
285
+
286
+ ### CharacterCreateDto
287
+
288
+ AI persona configuration:
289
+
290
+ ```typescript
291
+ interface CharacterCreateDto {
292
+ name: string;
293
+ professionalProfile: ProfessionalProfileDto;
294
+ segment: SegmentType;
295
+ personalityAndBehaviour: PersonalityAndBehaviourDto;
296
+ context: ContextDto;
297
+ assistantGender?: AssistantVoiceGender;
298
+ }
299
+ ```
300
+
301
+ ## Error Handling
302
+
303
+ The SDK throws errors for invalid configurations and API failures:
304
+
305
+ ```typescript
306
+ try {
307
+ const client = new PlatoApiClient({
308
+ baseUrl: 'https://api.plato.com',
309
+ token: 'your-token',
310
+ user: 'your-user',
311
+ });
312
+
313
+ const simulation = await client.createSimulation(simulationConfig);
314
+ const call = await client.startCall(simulation.simulationId);
315
+ } catch (error) {
316
+ console.error('Error:', error.message);
317
+ }
318
+ ```
319
+
320
+ ## Support
321
+
322
+ For support and questions, please contact the development team.
@@ -0,0 +1,121 @@
1
+ const { defineConfig, globalIgnores } = require('eslint/config');
2
+ const path = require('path');
3
+
4
+ const typescriptEslintEslintPlugin = require('@typescript-eslint/eslint-plugin');
5
+ const globals = require('globals');
6
+ const tsParser = require('@typescript-eslint/parser');
7
+ const jest = require('eslint-plugin-jest');
8
+ const js = require('@eslint/js');
9
+ const headers = require('eslint-plugin-headers');
10
+ const { FlatCompat } = require('@eslint/eslintrc');
11
+ const baseRules = require('../../eslint-config-base.cjs');
12
+
13
+ const compat = new FlatCompat({
14
+ baseDirectory: __dirname,
15
+ recommendedConfig: js.configs.recommended,
16
+ allConfig: js.configs.all,
17
+ });
18
+
19
+ module.exports = defineConfig([
20
+ globalIgnores([
21
+ '**/.eslintrc.js',
22
+ 'src/index.d.ts',
23
+ 'scripts/db-migrations/archived/**/*',
24
+ '**/*.spec.ts',
25
+ '**/*.config.js',
26
+ '**/*.config.cjs',
27
+ '**/jest.config.ts',
28
+ ]),
29
+ {
30
+ files: ['**/*.ts'],
31
+ plugins: {
32
+ headers,
33
+ },
34
+ rules: {
35
+ 'headers/header-format': [
36
+ 'error',
37
+ {
38
+ source: 'string',
39
+ content: `Copyright (c) 2025 ctcHealth. All rights reserved.
40
+
41
+ This file is part of the ctcHealth Plato Platform, a proprietary software system developed by ctcHealth.
42
+
43
+ This source code and all related materials are confidential and proprietary to ctcHealth.
44
+ Unauthorized access, use, copying, modification, distribution, or disclosure is strictly prohibited
45
+ and may result in disciplinary action and civil and/or criminal penalties.
46
+
47
+ This software is intended solely for authorized use within ctcHealth and its designated partners.
48
+
49
+ For internal use only.`,
50
+ style: 'jsdoc',
51
+ trailingNewlines: 1,
52
+ preservePragmas: false,
53
+ },
54
+ ],
55
+ },
56
+ },
57
+ {
58
+ extends: compat.extends(
59
+ 'plugin:@typescript-eslint/recommended',
60
+ 'plugin:@typescript-eslint/recommended-requiring-type-checking',
61
+ 'plugin:@typescript-eslint/strict'
62
+ ),
63
+
64
+ files: ['**/*.ts'],
65
+ ignores: ['**/*.json', '**/*.spec.ts'],
66
+
67
+ plugins: {
68
+ '@typescript-eslint': typescriptEslintEslintPlugin,
69
+ },
70
+
71
+ languageOptions: {
72
+ globals: {
73
+ ...globals.node,
74
+ ...globals.jest,
75
+ },
76
+
77
+ parser: tsParser,
78
+ ecmaVersion: 10,
79
+ sourceType: 'module',
80
+
81
+ parserOptions: {
82
+ project: path.join(__dirname, 'tsconfig.lib.json'),
83
+ },
84
+ },
85
+
86
+ rules: {
87
+ ...baseRules.rules, // shared rules
88
+ // project-specific rules
89
+ '@typescript-eslint/ban-ts-comment': 'warn',
90
+ '@typescript-eslint/interface-name-prefix': 'off',
91
+ '@typescript-eslint/explicit-function-return-type': 'warn',
92
+ '@typescript-eslint/promise-function-async': ['error'],
93
+ '@typescript-eslint/no-floating-promises': 'error',
94
+ '@typescript-eslint/await-thenable': 'error',
95
+ semi: ['error', 'always'],
96
+ '@typescript-eslint/unbound-method': 'error',
97
+ 'keyword-spacing': ['error'],
98
+ '@typescript-eslint/restrict-template-expressions': 'error',
99
+ '@typescript-eslint/prefer-regexp-exec': 'warn',
100
+ '@typescript-eslint/require-await': 'warn',
101
+ '@typescript-eslint/no-non-null-assertion': 'error',
102
+ '@typescript-eslint/no-unnecessary-condition': 'warn',
103
+ '@typescript-eslint/prefer-ts-expect-error': 'warn',
104
+ '@typescript-eslint/prefer-nullish-coalescing': 'off',
105
+ 'space-infix-ops': 'off',
106
+ },
107
+ },
108
+ {
109
+ files: ['**/*.spec.ts'],
110
+ extends: compat.extends('plugin:jest/recommended'),
111
+
112
+ plugins: {
113
+ jest,
114
+ },
115
+
116
+ rules: {
117
+ '@typescript-eslint/unbound-method': 'off',
118
+ 'jest/unbound-method': 'error',
119
+ },
120
+ },
121
+ ]);
package/jest.config.ts ADDED
@@ -0,0 +1,10 @@
1
+ export default {
2
+ displayName: 'plato-sdk',
3
+ preset: '../../jest.preset.js',
4
+ testEnvironment: 'node',
5
+ transform: {
6
+ '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
7
+ },
8
+ moduleFileExtensions: ['ts', 'js', 'html'],
9
+ coverageDirectory: '../../coverage/libs/plato-sdk',
10
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctchealth/plato-sdk",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "dependencies": {
5
5
  "tslib": "^2.3.0",
6
6
  "@vapi-ai/web": "2.1.8",
@@ -11,6 +11,5 @@
11
11
  "typings": "./src/index.d.ts",
12
12
  "publishConfig": {
13
13
  "access": "public"
14
- },
15
- "types": "./../libs/plato-sdk/src/index.d.ts"
16
- }
14
+ }
15
+ }
package/project.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "plato-sdk",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "libs/plato-sdk/src",
5
+ "projectType": "library",
6
+ "tags": [],
7
+ "targets": {
8
+ "build": {
9
+ "executor": "@nx/js:tsc",
10
+ "outputs": ["{options.outputPath}"],
11
+ "options": {
12
+ "outputPath": "dist/libs/plato-sdk",
13
+ "main": "libs/plato-sdk/src/index.ts",
14
+ "tsConfig": "libs/plato-sdk/tsconfig.lib.json",
15
+ "assets": ["libs/plato-sdk/*.md"]
16
+ }
17
+ },
18
+ "nx-release-publish": {
19
+ "options": {
20
+ "packageRoot": "dist/{projectRoot}"
21
+ }
22
+ }
23
+ }
24
+ }