ttp-agent-sdk 2.5.6 → 2.5.8

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.
@@ -1 +1 @@
1
- class AudioProcessor extends AudioWorkletProcessor{constructor(e){super(),this.config=e.processorOptions||{},this.sampleRate=this.config.sampleRate||16e3,this.bufferSize=128,this.buffer=new Float32Array(this.bufferSize),this.bufferIndex=0,this.silenceThreshold=.01,this.minVoiceDuration=100,this.pauseThreshold=3e3,this.isVoiceActive=!1,this.voiceStartTime=0,this.lastVoiceTime=0,this.consecutiveSilenceFrames=0,this.silenceFramesThreshold=5,this.frameCount=0,this.lastLogTime=0,this.continuousMode=!0,this.forceContinuous=!0,this.isCurrentlyStreaming=!1,this.sendBuffer=null,this.sendBufferBytes=0,this.port.onmessage=e=>{const{type:t,data:s}=e.data;switch(t){case"start":this.isProcessing=!0,this.isCurrentlyStreaming=!0;break;case"stop":this.isProcessing=!1,this.isCurrentlyStreaming=!1,this.isVoiceActive=!1,this.forceContinuous=!1,this.flushBuffer();break;case"setForceContinuous":this.forceContinuous=s.enabled,this.isProcessing=!0,this.isCurrentlyStreaming=!0;break;case"flush":this.flushBuffer();break;case"config":Object.assign(this.config,s)}}}process(e,t,s){const i=e[0],r=t[0];return i.length>0&&r.length>0&&r[0].set(i[0]),i.length>0&&i[0].length>0&&this.processAudioData(i[0]),!0}processAudioData(e){this.frameCount++;for(let t=0;t<e.length;t+=this.bufferSize){const s=Math.min(this.bufferSize,e.length-t);for(let i=0;i<s;i++)this.buffer[i]=e[t+i];for(let e=s;e<this.bufferSize;e++)this.buffer[e]=0;let i=0;for(let e=0;e<this.bufferSize;e++)i+=this.buffer[e]*this.buffer[e];const r=Math.sqrt(i/this.bufferSize);let h=0,n=0;for(let e=1;e<this.bufferSize;e++){const t=Math.abs(this.buffer[e]-this.buffer[e-1]);h+=t,t>.1&&n++}h/=this.bufferSize,this.bufferSize;const o=Date.now();let f=r>this.silenceThreshold;const a=o-this.lastVoiceTime;if(f)this.consecutiveSilenceFrames=0,this.isVoiceActive||(this.isVoiceActive=!0,this.voiceStartTime=o,this.isCurrentlyStreaming=!0),this.lastVoiceTime=o;else{this.consecutiveSilenceFrames++;const e=this.forceContinuous?1500:200;!f&&this.isVoiceActive&&a>=e&&(this.isVoiceActive=!1,this.isCurrentlyStreaming=!1,this.voiceStartTime=0,this.lastVoiceTime=0,this.consecutiveSilenceFrames=0)}this.isCurrentlyStreaming&&this.isProcessing&&this.sendPCMAudioData(this.buffer)}}sendPCMAudioData(e){const t=new Int16Array(e.length);for(let s=0;s<e.length;s++){const i=Math.max(-1,Math.min(1,e[s]));t[s]=Math.round(32767*i)}for(this.sendBuffer||(this.sendBuffer=[],this.sendBufferBytes=0),this.sendBuffer.push(t),this.sendBufferBytes+=t.byteLength;this.sendBufferBytes>=4096;){let e=0,t=0;for(let s=0;s<this.sendBuffer.length;s++){const i=this.sendBuffer[s].byteLength;if(!(t+i<=4096))break;e++,t+=i}const s=this.sendBuffer.slice(0,e),i=s.reduce((e,t)=>e+t.length,0),r=new Int16Array(i);let h=0;for(const e of s)r.set(e,h),h+=e.length;this.port.postMessage({type:"pcm_audio_data",data:r,sampleRate:this.sampleRate,channelCount:1,frameCount:this.frameCount,batchSize:e,totalBytes:r.byteLength}),this.sendBuffer=this.sendBuffer.slice(e),this.sendBufferBytes-=t}}flushBuffer(){if(this.sendBuffer&&this.sendBuffer.length>0){const e=this.sendBuffer.reduce((e,t)=>e+t.length,0),t=new Int16Array(e);let s=0;for(const e of this.sendBuffer)t.set(e,s),s+=e.length;this.port.postMessage({type:"pcm_audio_data",data:t,sampleRate:this.sampleRate,channelCount:1,frameCount:this.frameCount,batchSize:this.sendBuffer.length,totalBytes:t.byteLength,isFlush:!0}),this.sendBuffer=[],this.sendBufferBytes=0}}}registerProcessor("audio-processor",AudioProcessor);
1
+ class AudioProcessor extends AudioWorkletProcessor{constructor(e){super(),this.config=e.processorOptions||{},this.sampleRate="undefined"!=typeof sampleRate?sampleRate:this.config.sampleRate||this.config.outputSampleRate||44100,this.bufferSize=128,this.buffer=new Float32Array(this.bufferSize),this.bufferIndex=0,this.silenceThreshold=.01,this.minVoiceDuration=100,this.pauseThreshold=3e3,this.isVoiceActive=!1,this.voiceStartTime=0,this.lastVoiceTime=0,this.consecutiveSilenceFrames=0,this.silenceFramesThreshold=5,this.frameCount=0,this.lastLogTime=0,this.continuousMode=!0,this.forceContinuous=!0,this.isCurrentlyStreaming=!1,this.sendBuffer=null,this.sendBufferBytes=0,this.port.onmessage=e=>{const{type:t,data:s}=e.data;switch(t){case"start":this.isProcessing=!0,this.isCurrentlyStreaming=!0;break;case"stop":this.isProcessing=!1,this.isCurrentlyStreaming=!1,this.isVoiceActive=!1,this.forceContinuous=!1,this.flushBuffer();break;case"setForceContinuous":this.forceContinuous=s.enabled,this.isProcessing=!0,this.isCurrentlyStreaming=!0;break;case"flush":this.flushBuffer();break;case"config":Object.assign(this.config,s)}}}process(e,t,s){const i=e[0],r=t[0];return i.length>0&&r.length>0&&r[0].set(i[0]),i.length>0&&i[0].length>0&&this.processAudioData(i[0]),!0}processAudioData(e){this.frameCount++;for(let t=0;t<e.length;t+=this.bufferSize){const s=Math.min(this.bufferSize,e.length-t);for(let i=0;i<s;i++)this.buffer[i]=e[t+i];for(let e=s;e<this.bufferSize;e++)this.buffer[e]=0;let i=0;for(let e=0;e<this.bufferSize;e++)i+=this.buffer[e]*this.buffer[e];const r=Math.sqrt(i/this.bufferSize);let h=0,n=0;for(let e=1;e<this.bufferSize;e++){const t=Math.abs(this.buffer[e]-this.buffer[e-1]);h+=t,t>.1&&n++}h/=this.bufferSize,this.bufferSize;const o=Date.now();let f=r>this.silenceThreshold;const a=o-this.lastVoiceTime;if(f)this.consecutiveSilenceFrames=0,this.isVoiceActive||(this.isVoiceActive=!0,this.voiceStartTime=o,this.isCurrentlyStreaming=!0),this.lastVoiceTime=o;else{this.consecutiveSilenceFrames++;const e=this.forceContinuous?1500:200;!f&&this.isVoiceActive&&a>=e&&(this.isVoiceActive=!1,this.isCurrentlyStreaming=!1,this.voiceStartTime=0,this.lastVoiceTime=0,this.consecutiveSilenceFrames=0)}this.isCurrentlyStreaming&&this.isProcessing&&this.sendPCMAudioData(this.buffer)}}sendPCMAudioData(e){const t=new Int16Array(e.length);for(let s=0;s<e.length;s++){const i=Math.max(-1,Math.min(1,e[s]));t[s]=Math.round(32767*i)}for(this.sendBuffer||(this.sendBuffer=[],this.sendBufferBytes=0),this.sendBuffer.push(t),this.sendBufferBytes+=t.byteLength;this.sendBufferBytes>=4096;){let e=0,t=0;for(let s=0;s<this.sendBuffer.length;s++){const i=this.sendBuffer[s].byteLength;if(!(t+i<=4096))break;e++,t+=i}const s=this.sendBuffer.slice(0,e),i=s.reduce((e,t)=>e+t.length,0),r=new Int16Array(i);let h=0;for(const e of s)r.set(e,h),h+=e.length;this.port.postMessage({type:"pcm_audio_data",data:r,sampleRate:this.sampleRate,channelCount:1,frameCount:this.frameCount,batchSize:e,totalBytes:r.byteLength}),this.sendBuffer=this.sendBuffer.slice(e),this.sendBufferBytes-=t}}flushBuffer(){if(this.sendBuffer&&this.sendBuffer.length>0){const e=this.sendBuffer.reduce((e,t)=>e+t.length,0),t=new Int16Array(e);let s=0;for(const e of this.sendBuffer)t.set(e,s),s+=e.length;this.port.postMessage({type:"pcm_audio_data",data:t,sampleRate:this.sampleRate,channelCount:1,frameCount:this.frameCount,batchSize:this.sendBuffer.length,totalBytes:t.byteLength,isFlush:!0}),this.sendBuffer=[],this.sendBufferBytes=0}}}registerProcessor("audio-processor",AudioProcessor);
@@ -141,41 +141,54 @@
141
141
 
142
142
  <h2>Implementation Code:</h2>
143
143
  <div class="code-block">
144
- const widget = new TTPAgentSDK.AgentWidget({
145
- agentId: 'agent_87c4a55a1',
146
- appId: 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC',
144
+ // Step 1: Get signed URL from backend
145
+ async function initializeWidget() {
146
+ const response = await fetch('https://backend.talktopc.com/api/public/agents/signed-url', {
147
+ method: 'POST',
148
+ headers: {
149
+ 'Content-Type': 'application/json',
150
+ },
151
+ body: JSON.stringify({
152
+ agentId: 'agent_87c4a55a1',
153
+ appId: 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC',
154
+ variables: {
155
+ testMode: true,
156
+ userName: 'Test User',
157
+ page: 'test-signed-link.html'
158
+ }
159
+ })
160
+ });
147
161
 
148
- // Signed link via backend API
149
- getSessionUrl: async ({ agentId, appId, variables }) => {
150
- const response = await fetch('https://backend.talktopc.com/api/public/agents/signed-url', {
151
- method: 'POST',
152
- headers: {
153
- 'Content-Type': 'application/json',
154
- },
155
- body: JSON.stringify({
156
- agentId: agentId,
157
- appId: appId,
158
- variables: variables
159
- })
160
- });
162
+ if (!response.ok) {
163
+ throw new Error(`Backend API error: ${response.status}`);
164
+ }
165
+
166
+ const data = await response.json();
167
+ if (!data.signedUrl) {
168
+ throw new Error('Backend response must contain "signedUrl" field');
169
+ }
170
+
171
+ // Step 2: Initialize widget with signedUrl
172
+ const widget = new TTPAgentSDK.AgentWidget({
173
+ agentId: 'agent_87c4a55a1',
174
+ appId: 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC',
175
+ signedUrl: data.signedUrl, // Use signed URL from backend
161
176
 
162
- if (!response.ok) {
163
- throw new Error(`Backend API error: ${response.status}`);
164
- }
177
+ variables: {
178
+ testMode: true,
179
+ userName: 'Test User',
180
+ page: 'test-signed-link.html'
181
+ },
165
182
 
166
- const data = await response.json();
167
- return data.signedUrl || data.url || data.websocketUrl || data.sessionUrl;
168
- },
169
-
170
- variables: {
171
- testMode: true,
172
- userName: 'Test User',
173
- page: 'test-signed-link.html'
174
- },
183
+ primaryColor: '#F59E0B',
184
+ position: 'bottom-right'
185
+ });
175
186
 
176
- primaryColor: '#F59E0B',
177
- position: 'bottom-right'
178
- });
187
+ return widget;
188
+ }
189
+
190
+ // Initialize when ready
191
+ const widget = await initializeWidget();
179
192
  </div>
180
193
 
181
194
  <h2>Manual Tests:</h2>
@@ -266,89 +279,95 @@ const widget = new TTPAgentSDK.AgentWidget({
266
279
  throw new Error('TTPAgentSDK.AgentWidget is not defined. Check the SDK build.');
267
280
  }
268
281
 
269
- // Create a new AgentWidget instance with signed link
270
- const widget = new window.TTPAgentSDK.AgentWidget({
271
- agentId: 'agent_87c4a55a1',
272
- appId: 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC',
282
+ // Step 1: Get signed URL from backend
283
+ console.log('Requesting signed URL from backend API...');
284
+ updateStatus('Requesting signed URL from backend...', 'info');
285
+
286
+ const agentId = 'agent_87c4a55a1';
287
+ const appId = 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC';
288
+ const variables = {
289
+ testMode: true,
290
+ userName: 'Test User',
291
+ page: 'test-signed-link.html'
292
+ };
293
+
294
+ console.log('Agent ID:', agentId);
295
+ console.log('App ID:', appId);
296
+ console.log('Variables:', variables);
273
297
 
274
- // Signed link via backend API
275
- getSessionUrl: async ({ agentId, appId, variables }) => {
276
- console.log('Requesting signed URL from backend API...');
277
- console.log('Agent ID:', agentId);
278
- console.log('App ID:', appId);
279
- console.log('Variables:', variables);
298
+ try {
299
+ const response = await fetch('https://backend.talktopc.com/api/public/agents/signed-url', {
300
+ method: 'POST',
301
+ headers: {
302
+ 'Content-Type': 'application/json',
303
+ },
304
+ body: JSON.stringify({
305
+ agentId: agentId,
306
+ appId: appId,
307
+ variables: variables
308
+ })
309
+ });
280
310
 
281
- updateStatus('Requesting signed URL from backend...', 'info');
311
+ console.log('Backend API response status:', response.status);
282
312
 
283
- try {
284
- const response = await fetch('https://backend.talktopc.com/api/public/agents/signed-url', {
285
- method: 'POST',
286
- headers: {
287
- 'Content-Type': 'application/json',
288
- },
289
- body: JSON.stringify({
290
- agentId: agentId,
291
- appId: appId,
292
- variables: variables
293
- })
294
- });
295
-
296
- console.log('Backend API response status:', response.status);
297
-
298
- if (!response.ok) {
299
- const errorText = await response.text();
300
- throw new Error(`Backend API error: ${response.status} - ${errorText}`);
301
- }
302
-
303
- const data = await response.json();
304
- console.log('Backend API response data:', data);
305
-
306
- // Handle different possible response formats
307
- const signedUrl = data.signedUrl || data.url || data.websocketUrl || data.sessionUrl;
308
-
309
- if (!signedUrl) {
310
- throw new Error('No signed URL found in API response');
311
- }
312
-
313
- console.log('Generated signed URL:', signedUrl);
314
- updateStatus('Signed URL received from backend ✓', 'success');
315
-
316
- return signedUrl;
317
- } catch (error) {
318
- console.error('Failed to get signed URL from backend:', error);
319
- updateStatus('Failed to get signed URL from backend ✗', 'error');
313
+ if (!response.ok) {
314
+ const errorText = await response.text();
315
+ throw new Error(`Backend API error: ${response.status} - ${errorText}`);
316
+ }
317
+
318
+ const data = await response.json();
319
+ console.log('Backend API response data:', data);
320
+
321
+ // Backend must return signedUrl field
322
+ if (!data.signedUrl) {
323
+ throw new Error('Backend response must contain "signedUrl" field');
324
+ }
325
+
326
+ const signedUrl = data.signedUrl;
327
+ console.log('Generated signed URL:', signedUrl);
328
+ updateStatus('Signed URL received from backend ✓', 'success');
329
+
330
+ // Step 2: Create widget with signedUrl
331
+ const widget = new window.TTPAgentSDK.AgentWidget({
332
+ agentId: agentId,
333
+ appId: appId,
334
+ signedUrl: signedUrl, // Use signed URL from backend
320
335
 
321
- // Fallback to direct connection if backend fails
322
- console.log('Falling back to direct connection...');
323
- const fallbackUrl = `wss://speech.talktopc.com/ws/conv?agentId=${agentId}&appId=${appId}&demo=true`;
324
- console.log('Using fallback URL:', fallbackUrl);
325
- updateStatus('Using fallback direct connection', 'info');
336
+ // Pass some test variables
337
+ variables: variables,
326
338
 
327
- return fallbackUrl;
328
- }
329
- },
330
-
331
- // Pass some test variables
332
- variables: {
333
- testMode: true,
334
- userName: 'Test User',
335
- page: 'test-signed-link.html',
336
- connectionType: 'signed-link'
337
- },
338
-
339
- // Customize appearance
340
- primaryColor: '#F59E0B',
341
- position: 'bottom-right'
342
- });
343
-
344
- // Store widget reference for testing (like the working implementation)
345
- window.testWidget = widget;
346
-
347
- console.log('Widget initialized successfully with signed link!');
348
- console.log('Widget instance:', widget);
349
- console.log('Test methods available at window.testWidget');
350
- updateStatus('Widget loaded and ready ✓', 'success');
351
-
339
+ // Customize appearance
340
+ primaryColor: '#F59E0B',
341
+ position: 'bottom-right'
342
+ });
343
+
344
+ // Store widget reference for testing
345
+ window.testWidget = widget;
346
+
347
+ console.log('Widget initialized successfully with signed link!');
348
+ console.log('Widget instance:', widget);
349
+ console.log('Test methods available at window.testWidget');
350
+ updateStatus('Widget loaded and ready ✓', 'success');
351
+
352
+ } catch (error) {
353
+ console.error('Failed to get signed URL or initialize widget:', error);
354
+ updateStatus('Failed: ' + error.message, 'error');
355
+
356
+ // Fallback to direct connection if backend fails
357
+ console.log('Falling back to direct connection...');
358
+ updateStatus('Using fallback direct connection', 'info');
359
+
360
+ const widget = new window.TTPAgentSDK.AgentWidget({
361
+ agentId: agentId,
362
+ appId: appId,
363
+ variables: variables,
364
+ primaryColor: '#F59E0B',
365
+ position: 'bottom-right'
366
+ });
367
+
368
+ window.testWidget = widget;
369
+ console.log('Widget initialized with direct connection (fallback)');
370
+ }
352
371
  } catch (error) {
353
372
  console.error('Failed to initialize widget:', error);
354
373
  updateStatus('Failed to initialize widget: ' + error.message, 'error');
@@ -450,14 +469,14 @@ const widget = new TTPAgentSDK.AgentWidget({
450
469
 
451
470
  if (response.ok) {
452
471
  const data = await response.json();
453
- const signedUrl = data.signedUrl || data.url || data.websocketUrl || data.sessionUrl;
454
472
 
455
- if (signedUrl) {
456
- console.log('Generated signed URL:', signedUrl);
457
- alert(`Signed URL generated successfully!\n\nURL: ${signedUrl.substring(0, 100)}...`);
458
- } else {
459
- throw new Error('No signed URL in response');
473
+ if (!data.signedUrl) {
474
+ throw new Error('Backend response must contain "signedUrl" field');
460
475
  }
476
+
477
+ const signedUrl = data.signedUrl;
478
+ console.log('Generated signed URL:', signedUrl);
479
+ alert(`Signed URL generated successfully!\n\nURL: ${signedUrl.substring(0, 100)}...\n\nYou can now use this signedUrl when initializing the widget:\n\nconst widget = new TTPAgentSDK.AgentWidget({\n agentId: 'agent_87c4a55a1',\n appId: 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC',\n signedUrl: '${signedUrl.substring(0, 50)}...'\n});`);
461
480
  } else {
462
481
  throw new Error(`API error: ${response.status}`);
463
482
  }