ttp-agent-sdk 2.1.8 → 2.1.10
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/dist/agent-widget.js +1 -1
- package/dist/agent-widget.js.map +1 -1
- package/dist/audio-processor.js +1 -0
- package/{examples/test.html → dist/examples/test-agent-app.html} +111 -45
- package/dist/examples/test-signed-link.html +453 -0
- package/{dist/examples/test.html → examples/test-agent-app.html} +111 -45
- package/examples/test-signed-link.html +453 -0
- package/package.json +1 -1
- package/dist/examples/enhanced-widget-examples.html +0 -471
- package/dist/examples/multi-platform-examples.html +0 -1119
- package/dist/examples/react-example.html +0 -774
- package/dist/examples/react-example.jsx +0 -307
- package/dist/examples/vanilla-example.html +0 -464
- package/examples/enhanced-widget-examples.html +0 -471
- package/examples/multi-platform-examples.html +0 -1119
- package/examples/react-example.html +0 -774
- package/examples/react-example.jsx +0 -307
- package/examples/vanilla-example.html +0 -464
|
@@ -0,0 +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=.005,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,console.log("🎤 AudioProcessor: Initialized with sample rate:",this.sampleRate),console.log("🎤 AudioProcessor: Buffer size:",this.bufferSize),console.log("🎤 AudioProcessor: Force continuous mode:",this.forceContinuous),this.port.onmessage=e=>{const{type:s,data:t}=e.data;switch(console.log("🎤 AudioProcessor: Received message:",s,t),s){case"start":this.isProcessing=!0,this.isCurrentlyStreaming=!0,console.log("🎤 AudioProcessor: Started processing");break;case"stop":this.isProcessing=!1,this.isCurrentlyStreaming=!1,this.isVoiceActive=!1,this.forceContinuous=!1,this.flushBuffer(),console.log("🎤 AudioProcessor: Stopped processing and flushed buffer");break;case"setForceContinuous":this.forceContinuous=t.enabled,this.isProcessing=!0,this.isCurrentlyStreaming=!0,console.log("🎤 AudioProcessor: Enabled continuous mode");break;case"flush":this.flushBuffer(),console.log("🎤 AudioProcessor: Flushing buffer");break;case"config":Object.assign(this.config,t),console.log("🎤 AudioProcessor: Updated config:",this.config)}}}process(e,s,t){const i=e[0],o=s[0];return i.length>0&&o.length>0&&o[0].set(i[0]),i.length>0&&i[0].length>0&&this.processAudioData(i[0]),!0}processAudioData(e){this.frameCount++;for(let s=0;s<e.length;s+=this.bufferSize){const t=Math.min(this.bufferSize,e.length-s);for(let i=0;i<t;i++)this.buffer[i]=e[s+i];for(let e=t;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 o=Math.sqrt(i/this.bufferSize);let r=0,n=0;for(let e=1;e<this.bufferSize;e++){const s=Math.abs(this.buffer[e]-this.buffer[e-1]);r+=s,s>.1&&n++}r/=this.bufferSize,this.bufferSize;const h=Date.now();let c=o>this.silenceThreshold;if(h-this.lastLogTime>2e3){const e=c?"VOICE":"SILENCE";console.log(`🎤 AudioProcessor: RMS: ${o.toFixed(4)}, Threshold: ${this.silenceThreshold}, Status: ${e}, Streaming: ${this.isCurrentlyStreaming}, ForceContinuous: ${this.forceContinuous}, VoiceActive: ${this.isVoiceActive}`),this.lastLogTime=h}const f=h-this.lastVoiceTime;this.forceContinuous||c?(this.consecutiveSilenceFrames=0,this.isVoiceActive||(this.isVoiceActive=!0,this.voiceStartTime=h,this.isCurrentlyStreaming=!0,console.log(`🗣️ Voice detected (RMS: ${o.toFixed(4)})`)),this.lastVoiceTime=h):this.consecutiveSilenceFrames++,!this.forceContinuous&&!c&&this.isVoiceActive&&f>=200&&(this.isVoiceActive=!1,this.isCurrentlyStreaming=!1,console.log(`⏸️ AudioProcessor: Silence detected, stopping streaming (${f.toFixed(0)}ms silence)`),this.voiceStartTime=0,this.lastVoiceTime=0,this.consecutiveSilenceFrames=0),this.isCurrentlyStreaming&&this.isProcessing&&this.sendPCMAudioData(this.buffer)}}sendPCMAudioData(e){const s=new Int16Array(e.length);for(let t=0;t<e.length;t++){const i=Math.max(-1,Math.min(1,e[t]));s[t]=Math.round(32767*i)}for(this.sendBuffer||(this.sendBuffer=[],this.sendBufferBytes=0),this.sendBuffer.push(s),this.sendBufferBytes+=s.byteLength;this.sendBufferBytes>=4096;){let e=0,s=0;for(let t=0;t<this.sendBuffer.length;t++){const i=this.sendBuffer[t].byteLength;if(!(s+i<=4096))break;e++,s+=i}const t=this.sendBuffer.slice(0,e),i=t.reduce((e,s)=>e+s.length,0),o=new Int16Array(i);let r=0;for(const e of t)o.set(e,r),r+=e.length;Math.random()<.01&&console.log(`🎤 AudioProcessor: Sending PCM batch - ${o.byteLength} bytes (${e} chunks)`),this.port.postMessage({type:"pcm_audio_data",data:o,sampleRate:this.sampleRate,channelCount:1,frameCount:this.frameCount,batchSize:e,totalBytes:o.byteLength}),this.sendBuffer=this.sendBuffer.slice(e),this.sendBufferBytes-=s}}flushBuffer(){if(this.sendBuffer&&this.sendBuffer.length>0){const e=this.sendBuffer.reduce((e,s)=>e+s.length,0),s=new Int16Array(e);let t=0;for(const e of this.sendBuffer)s.set(e,t),t+=e.length;this.port.postMessage({type:"pcm_audio_data",data:s,sampleRate:this.sampleRate,channelCount:1,frameCount:this.frameCount,batchSize:this.sendBuffer.length,totalBytes:s.byteLength,isFlush:!0}),this.sendBuffer=[],this.sendBufferBytes=0}}}registerProcessor("audio-processor",AudioProcessor);
|
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
============================================
|
|
3
|
-
FILE: examples/test.html
|
|
4
|
-
Test page for the widget
|
|
5
|
-
============================================
|
|
6
|
-
-->
|
|
7
1
|
<!DOCTYPE html>
|
|
8
2
|
<html lang="en">
|
|
9
3
|
<head>
|
|
10
4
|
<meta charset="UTF-8">
|
|
11
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
12
|
-
<title>Voice Agent Widget - Test
|
|
6
|
+
<title>Voice Agent Widget - Agent ID + App ID Test</title>
|
|
13
7
|
<style>
|
|
14
8
|
body {
|
|
15
9
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
@@ -39,6 +33,14 @@ Test page for the widget
|
|
|
39
33
|
border-radius: 4px;
|
|
40
34
|
}
|
|
41
35
|
|
|
36
|
+
.config-info {
|
|
37
|
+
background: #F0FDF4;
|
|
38
|
+
border-left: 4px solid #10B981;
|
|
39
|
+
padding: 16px;
|
|
40
|
+
margin: 20px 0;
|
|
41
|
+
border-radius: 4px;
|
|
42
|
+
}
|
|
43
|
+
|
|
42
44
|
.status {
|
|
43
45
|
margin: 20px 0;
|
|
44
46
|
padding: 12px;
|
|
@@ -72,20 +74,39 @@ Test page for the widget
|
|
|
72
74
|
button:hover {
|
|
73
75
|
background: #4338CA;
|
|
74
76
|
}
|
|
77
|
+
|
|
78
|
+
.code-block {
|
|
79
|
+
background: #1F2937;
|
|
80
|
+
color: #F9FAFB;
|
|
81
|
+
padding: 16px;
|
|
82
|
+
border-radius: 6px;
|
|
83
|
+
font-family: monospace;
|
|
84
|
+
font-size: 12px;
|
|
85
|
+
overflow-x: auto;
|
|
86
|
+
margin: 20px 0;
|
|
87
|
+
}
|
|
75
88
|
</style>
|
|
76
89
|
</head>
|
|
77
90
|
<body>
|
|
78
91
|
<div class="container">
|
|
79
|
-
<h1>🎤 Voice Agent Widget - Test
|
|
92
|
+
<h1>🎤 Voice Agent Widget - Agent ID + App ID Test</h1>
|
|
93
|
+
|
|
94
|
+
<div class="config-info">
|
|
95
|
+
<strong>📝 Configuration:</strong>
|
|
96
|
+
<ul style="margin: 10px 0 0 20px; line-height: 1.8;">
|
|
97
|
+
<li><strong>Agent ID:</strong> agent_87c4a55a1</li>
|
|
98
|
+
<li><strong>App ID:</strong> app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC</li>
|
|
99
|
+
<li><strong>Method:</strong> Direct connection (no signed link)</li>
|
|
100
|
+
</ul>
|
|
101
|
+
</div>
|
|
80
102
|
|
|
81
103
|
<div class="info">
|
|
82
104
|
<strong>📝 Testing Instructions:</strong>
|
|
83
105
|
<ol style="margin: 10px 0 0 20px; line-height: 1.8;">
|
|
84
|
-
<li><strong>No backend required!</strong> This demo uses a mock session URL</li>
|
|
85
106
|
<li>Look for the floating voice button in the bottom-right corner</li>
|
|
86
107
|
<li>Click the button to open the widget</li>
|
|
87
108
|
<li>Click the microphone to start (will request mic permission)</li>
|
|
88
|
-
<li>Widget will connect
|
|
109
|
+
<li>Widget will connect directly using agent ID + app ID</li>
|
|
89
110
|
<li>Check the status updates below</li>
|
|
90
111
|
</ol>
|
|
91
112
|
</div>
|
|
@@ -100,13 +121,39 @@ Test page for the widget
|
|
|
100
121
|
Console messages will appear here...
|
|
101
122
|
</div>
|
|
102
123
|
|
|
124
|
+
<h2>Implementation Code:</h2>
|
|
125
|
+
<div class="code-block">
|
|
126
|
+
const widget = new TTPAgentSDK.AgentWidget({
|
|
127
|
+
agentId: 'agent_87c4a55a1',
|
|
128
|
+
appId: 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC',
|
|
129
|
+
|
|
130
|
+
// Direct connection without signed link
|
|
131
|
+
getSessionUrl: async ({ agentId, appId, variables }) => {
|
|
132
|
+
// Direct WebSocket URL construction with demo flag
|
|
133
|
+
const wsUrl = `wss://speech.talktopc.com/ws/conv?agentId=${agentId}&appId=${appId}&demo=true`;
|
|
134
|
+
return wsUrl;
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
variables: {
|
|
138
|
+
testMode: true,
|
|
139
|
+
userName: 'Test User',
|
|
140
|
+
page: 'test-agent-app.html'
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
primaryColor: '#10B981',
|
|
144
|
+
position: 'bottom-right'
|
|
145
|
+
});
|
|
146
|
+
</div>
|
|
147
|
+
|
|
103
148
|
<h2>Manual Tests:</h2>
|
|
104
|
-
<button onclick="
|
|
149
|
+
<button onclick="testMicButton()">Test Mic Button Click</button>
|
|
150
|
+
<button onclick="testToggleVoice()">Test ToggleVoice Method</button>
|
|
151
|
+
<button onclick="checkWidgetState()">Check Widget State</button>
|
|
105
152
|
<button onclick="testMicrophone()">Test Microphone Access</button>
|
|
106
153
|
</div>
|
|
107
154
|
|
|
108
155
|
<!-- Load the widget -->
|
|
109
|
-
<script src="../agent-widget.js" onload="console.log('SDK script loaded successfully')" onerror="console.error('Failed to load SDK script')"></script>
|
|
156
|
+
<script src="../agent-widget.js?v=24" onload="console.log('SDK script loaded successfully')" onerror="console.error('Failed to load SDK script')"></script>
|
|
110
157
|
|
|
111
158
|
<script>
|
|
112
159
|
// Override console.log to show in page
|
|
@@ -140,7 +187,7 @@ Test page for the widget
|
|
|
140
187
|
|
|
141
188
|
// Initialize the widget
|
|
142
189
|
try {
|
|
143
|
-
console.log('Initializing widget...');
|
|
190
|
+
console.log('Initializing widget with agent ID + app ID...');
|
|
144
191
|
console.log('TTPAgentSDK available:', typeof TTPAgentSDK);
|
|
145
192
|
console.log('TTPAgentSDK.AgentWidget available:', typeof TTPAgentSDK?.AgentWidget);
|
|
146
193
|
|
|
@@ -152,31 +199,32 @@ Test page for the widget
|
|
|
152
199
|
throw new Error('TTPAgentSDK.AgentWidget is not defined. Check the SDK build.');
|
|
153
200
|
}
|
|
154
201
|
|
|
155
|
-
// Create a new AgentWidget instance
|
|
202
|
+
// Create a new AgentWidget instance with agent ID + app ID
|
|
203
|
+
// Now supports extensive customization with sensible defaults!
|
|
204
|
+
// You can customize: icon, button, position, header, messages, animation, behavior, accessibility
|
|
156
205
|
const widget = new TTPAgentSDK.AgentWidget({
|
|
157
|
-
agentId: '
|
|
206
|
+
agentId: 'agent_87c4a55a1',
|
|
207
|
+
appId: 'app_Bc01EqMQt2Euehl4qqZSi6l3FJP42Q9vJ0pC',
|
|
158
208
|
|
|
159
|
-
//
|
|
160
|
-
getSessionUrl: async ({ agentId, variables }) => {
|
|
161
|
-
console.log('
|
|
209
|
+
// Direct connection without signed link
|
|
210
|
+
getSessionUrl: async ({ agentId, appId, variables }) => {
|
|
211
|
+
console.log('Creating direct session URL for agent:', agentId);
|
|
212
|
+
console.log('App ID:', appId);
|
|
162
213
|
console.log('Variables:', variables);
|
|
163
214
|
|
|
164
|
-
updateStatus('Creating
|
|
215
|
+
updateStatus('Creating direct session URL...', 'info');
|
|
165
216
|
|
|
166
217
|
try {
|
|
167
|
-
//
|
|
168
|
-
|
|
218
|
+
// Direct WebSocket URL construction with demo flag
|
|
219
|
+
const wsUrl = `wss://speech.talktopc.com/ws/conv?agentId=${agentId}&appId=${appId}&demo=true`;
|
|
169
220
|
|
|
170
|
-
|
|
171
|
-
|
|
221
|
+
console.log('Generated direct session URL:', wsUrl);
|
|
222
|
+
updateStatus('Direct session URL created ✓', 'success');
|
|
172
223
|
|
|
173
|
-
|
|
174
|
-
updateStatus('Mock session URL created ✓', 'success');
|
|
175
|
-
|
|
176
|
-
return mockSignedUrl;
|
|
224
|
+
return wsUrl;
|
|
177
225
|
} catch (error) {
|
|
178
|
-
console.error('Failed to create
|
|
179
|
-
updateStatus('Failed to create
|
|
226
|
+
console.error('Failed to create direct session URL:', error);
|
|
227
|
+
updateStatus('Failed to create direct session URL ✗', 'error');
|
|
180
228
|
throw error;
|
|
181
229
|
}
|
|
182
230
|
},
|
|
@@ -185,7 +233,8 @@ Test page for the widget
|
|
|
185
233
|
variables: {
|
|
186
234
|
testMode: true,
|
|
187
235
|
userName: 'Test User',
|
|
188
|
-
page: 'test.html'
|
|
236
|
+
page: 'test-agent-app.html',
|
|
237
|
+
connectionType: 'direct'
|
|
189
238
|
},
|
|
190
239
|
|
|
191
240
|
// Customize appearance
|
|
@@ -193,7 +242,12 @@ Test page for the widget
|
|
|
193
242
|
position: 'bottom-right'
|
|
194
243
|
});
|
|
195
244
|
|
|
196
|
-
|
|
245
|
+
// Store widget reference for testing (like the working implementation)
|
|
246
|
+
window.testWidget = widget;
|
|
247
|
+
|
|
248
|
+
console.log('Widget initialized successfully with agent ID + app ID!');
|
|
249
|
+
console.log('Widget instance:', widget);
|
|
250
|
+
console.log('Test methods available at window.testWidget');
|
|
197
251
|
updateStatus('Widget loaded and ready ✓', 'success');
|
|
198
252
|
|
|
199
253
|
} catch (error) {
|
|
@@ -201,23 +255,35 @@ Test page for the widget
|
|
|
201
255
|
updateStatus('Widget failed to load ✗', 'error');
|
|
202
256
|
}
|
|
203
257
|
|
|
204
|
-
//
|
|
205
|
-
|
|
206
|
-
console.log('Testing
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
258
|
+
// Test functions (matching the working implementation)
|
|
259
|
+
function testMicButton() {
|
|
260
|
+
console.log('🎤 Testing mic button manually...');
|
|
261
|
+
const micButton = document.getElementById('agent-mic-button');
|
|
262
|
+
if (micButton) {
|
|
263
|
+
console.log('🎤 Found mic button, clicking...');
|
|
264
|
+
micButton.click();
|
|
265
|
+
} else {
|
|
266
|
+
console.log('🎤 Mic button not found');
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function testToggleVoice() {
|
|
271
|
+
console.log('🎤 Testing toggleVoice method...');
|
|
272
|
+
if (window.testWidget && window.testWidget.toggleVoice) {
|
|
273
|
+
window.testWidget.toggleVoice();
|
|
274
|
+
} else {
|
|
275
|
+
console.log('🎤 toggleVoice method not available');
|
|
218
276
|
}
|
|
219
277
|
}
|
|
220
278
|
|
|
279
|
+
function checkWidgetState() {
|
|
280
|
+
console.log('🎤 Widget state:', {
|
|
281
|
+
isActive: window.testWidget?.isActive,
|
|
282
|
+
isOpen: window.testWidget?.isOpen,
|
|
283
|
+
sdk: window.testWidget?.sdk
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
221
287
|
async function testMicrophone() {
|
|
222
288
|
console.log('Testing microphone access...');
|
|
223
289
|
try {
|