ttp-agent-sdk 2.0.0
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/GETTING_STARTED.md +429 -0
- package/README.md +303 -0
- package/dist/agent-widget.js +3 -0
- package/dist/agent-widget.js.LICENSE.txt +21 -0
- package/dist/agent-widget.js.map +1 -0
- package/dist/examples/react-example.html +455 -0
- package/dist/examples/react-example.jsx +307 -0
- package/dist/examples/test.html +235 -0
- package/dist/examples/vanilla-example.html +464 -0
- package/dist/index.html +224 -0
- package/examples/react-example.html +455 -0
- package/examples/react-example.jsx +307 -0
- package/examples/test.html +235 -0
- package/examples/vanilla-example.html +464 -0
- package/package.json +63 -0
- package/src/core/AudioPlayer.js +185 -0
- package/src/core/AudioRecorder.js +128 -0
- package/src/core/ConnectionManager.js +86 -0
- package/src/core/EventEmitter.js +53 -0
- package/src/core/VoiceSDK.js +390 -0
- package/src/core/WebSocketManager.js +218 -0
- package/src/core/WebSocketManagerV2.js +211 -0
- package/src/core/WebSocketSingleton.js +171 -0
- package/src/index.js +64 -0
- package/src/legacy/AgentSDK.js +462 -0
- package/src/react/VoiceButton.jsx +163 -0
- package/src/vanilla/VoiceButton.js +190 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Example - VoiceSDK Integration
|
|
3
|
+
*
|
|
4
|
+
* This example shows how to use the VoiceSDK with React components
|
|
5
|
+
* for a modern web application.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
9
|
+
import { VoiceSDK, VoiceButton } from 'ttp-agent-sdk';
|
|
10
|
+
|
|
11
|
+
function VoiceChatApp() {
|
|
12
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
13
|
+
const [isRecording, setIsRecording] = useState(false);
|
|
14
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
15
|
+
const [messages, setMessages] = useState([]);
|
|
16
|
+
const [connectionStatus, setConnectionStatus] = useState('Disconnected');
|
|
17
|
+
|
|
18
|
+
const voiceSDKRef = useRef(null);
|
|
19
|
+
|
|
20
|
+
// Initialize VoiceSDK
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const voiceSDK = new VoiceSDK({
|
|
23
|
+
websocketUrl: 'wss://speech.bidme.co.il/ws/conv',
|
|
24
|
+
agentId: 'demo_agent_123',
|
|
25
|
+
appId: 'demo_app_456',
|
|
26
|
+
voice: 'default',
|
|
27
|
+
language: 'en',
|
|
28
|
+
autoReconnect: true
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Set up event handlers
|
|
32
|
+
voiceSDK.on('connected', () => {
|
|
33
|
+
setIsConnected(true);
|
|
34
|
+
setConnectionStatus('Connected');
|
|
35
|
+
addMessage('system', 'Connected to voice agent');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
voiceSDK.on('disconnected', () => {
|
|
39
|
+
setIsConnected(false);
|
|
40
|
+
setIsRecording(false);
|
|
41
|
+
setIsPlaying(false);
|
|
42
|
+
setConnectionStatus('Disconnected');
|
|
43
|
+
addMessage('system', 'Disconnected from voice agent');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
voiceSDK.on('recordingStarted', () => {
|
|
47
|
+
setIsRecording(true);
|
|
48
|
+
addMessage('user', 'đ¤ Recording...');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
voiceSDK.on('recordingStopped', () => {
|
|
52
|
+
setIsRecording(false);
|
|
53
|
+
addMessage('user', 'âšī¸ Recording stopped');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
voiceSDK.on('playbackStarted', () => {
|
|
57
|
+
setIsPlaying(true);
|
|
58
|
+
addMessage('agent', 'đ Agent is speaking...');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
voiceSDK.on('playbackStopped', () => {
|
|
62
|
+
setIsPlaying(false);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
voiceSDK.on('message', (message) => {
|
|
66
|
+
if (message.type === 'agent_response') {
|
|
67
|
+
addMessage('agent', message.agent_response);
|
|
68
|
+
} else if (message.type === 'user_transcript') {
|
|
69
|
+
addMessage('user', message.user_transcription);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
voiceSDK.on('error', (error) => {
|
|
74
|
+
console.error('VoiceSDK Error:', error);
|
|
75
|
+
addMessage('error', `Error: ${error.message}`);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
voiceSDKRef.current = voiceSDK;
|
|
79
|
+
|
|
80
|
+
// Cleanup on unmount
|
|
81
|
+
return () => {
|
|
82
|
+
if (voiceSDKRef.current) {
|
|
83
|
+
voiceSDKRef.current.destroy();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}, []);
|
|
87
|
+
|
|
88
|
+
const addMessage = (type, text) => {
|
|
89
|
+
setMessages(prev => [...prev, { type, text, timestamp: new Date() }]);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const handleConnect = async () => {
|
|
93
|
+
if (voiceSDKRef.current) {
|
|
94
|
+
try {
|
|
95
|
+
setConnectionStatus('Connecting...');
|
|
96
|
+
await voiceSDKRef.current.connect();
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error('Connection failed:', error);
|
|
99
|
+
setConnectionStatus('Connection failed');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const handleDisconnect = () => {
|
|
105
|
+
if (voiceSDKRef.current) {
|
|
106
|
+
voiceSDKRef.current.disconnect();
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const handleToggleRecording = async () => {
|
|
111
|
+
if (voiceSDKRef.current) {
|
|
112
|
+
try {
|
|
113
|
+
if (isRecording) {
|
|
114
|
+
await voiceSDKRef.current.stopRecording();
|
|
115
|
+
} else {
|
|
116
|
+
await voiceSDKRef.current.startRecording();
|
|
117
|
+
}
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error('Recording toggle failed:', error);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<div style={{
|
|
126
|
+
maxWidth: '800px',
|
|
127
|
+
margin: '0 auto',
|
|
128
|
+
padding: '20px',
|
|
129
|
+
fontFamily: 'system-ui, -apple-system, sans-serif'
|
|
130
|
+
}}>
|
|
131
|
+
<h1>đ¤ Voice Chat App</h1>
|
|
132
|
+
|
|
133
|
+
{/* Connection Status */}
|
|
134
|
+
<div style={{
|
|
135
|
+
padding: '12px',
|
|
136
|
+
borderRadius: '8px',
|
|
137
|
+
marginBottom: '20px',
|
|
138
|
+
backgroundColor: isConnected ? '#D1FAE5' : '#FEE2E2',
|
|
139
|
+
color: isConnected ? '#065F46' : '#991B1B',
|
|
140
|
+
border: `1px solid ${isConnected ? '#10B981' : '#EF4444'}`
|
|
141
|
+
}}>
|
|
142
|
+
<strong>Status:</strong> {connectionStatus}
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
{/* Controls */}
|
|
146
|
+
<div style={{
|
|
147
|
+
display: 'flex',
|
|
148
|
+
gap: '12px',
|
|
149
|
+
marginBottom: '20px',
|
|
150
|
+
flexWrap: 'wrap'
|
|
151
|
+
}}>
|
|
152
|
+
<button
|
|
153
|
+
onClick={handleConnect}
|
|
154
|
+
disabled={isConnected}
|
|
155
|
+
style={{
|
|
156
|
+
padding: '12px 24px',
|
|
157
|
+
backgroundColor: isConnected ? '#9CA3AF' : '#4F46E5',
|
|
158
|
+
color: 'white',
|
|
159
|
+
border: 'none',
|
|
160
|
+
borderRadius: '6px',
|
|
161
|
+
cursor: isConnected ? 'not-allowed' : 'pointer'
|
|
162
|
+
}}
|
|
163
|
+
>
|
|
164
|
+
Connect
|
|
165
|
+
</button>
|
|
166
|
+
|
|
167
|
+
<button
|
|
168
|
+
onClick={handleDisconnect}
|
|
169
|
+
disabled={!isConnected}
|
|
170
|
+
style={{
|
|
171
|
+
padding: '12px 24px',
|
|
172
|
+
backgroundColor: !isConnected ? '#9CA3AF' : '#EF4444',
|
|
173
|
+
color: 'white',
|
|
174
|
+
border: 'none',
|
|
175
|
+
borderRadius: '6px',
|
|
176
|
+
cursor: !isConnected ? 'not-allowed' : 'pointer'
|
|
177
|
+
}}
|
|
178
|
+
>
|
|
179
|
+
Disconnect
|
|
180
|
+
</button>
|
|
181
|
+
|
|
182
|
+
<button
|
|
183
|
+
onClick={handleToggleRecording}
|
|
184
|
+
disabled={!isConnected}
|
|
185
|
+
style={{
|
|
186
|
+
padding: '12px 24px',
|
|
187
|
+
backgroundColor: !isConnected ? '#9CA3AF' : (isRecording ? '#EF4444' : '#10B981'),
|
|
188
|
+
color: 'white',
|
|
189
|
+
border: 'none',
|
|
190
|
+
borderRadius: '6px',
|
|
191
|
+
cursor: !isConnected ? 'not-allowed' : 'pointer'
|
|
192
|
+
}}
|
|
193
|
+
>
|
|
194
|
+
{isRecording ? 'Stop Recording' : 'Start Recording'}
|
|
195
|
+
</button>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
{/* Voice Button Component */}
|
|
199
|
+
<div style={{ marginBottom: '20px' }}>
|
|
200
|
+
<h3>Voice Button Component:</h3>
|
|
201
|
+
<VoiceButton
|
|
202
|
+
websocketUrl="wss://speech.bidme.co.il/ws/conv"
|
|
203
|
+
agentId="demo_agent_123"
|
|
204
|
+
appId="demo_app_456"
|
|
205
|
+
onConnected={() => console.log('VoiceButton connected')}
|
|
206
|
+
onRecordingStarted={() => console.log('VoiceButton recording started')}
|
|
207
|
+
onPlaybackStarted={() => console.log('VoiceButton playback started')}
|
|
208
|
+
/>
|
|
209
|
+
</div>
|
|
210
|
+
|
|
211
|
+
{/* Messages */}
|
|
212
|
+
<div style={{
|
|
213
|
+
border: '1px solid #E5E7EB',
|
|
214
|
+
borderRadius: '8px',
|
|
215
|
+
height: '400px',
|
|
216
|
+
overflowY: 'auto',
|
|
217
|
+
padding: '16px',
|
|
218
|
+
backgroundColor: '#F9FAFB'
|
|
219
|
+
}}>
|
|
220
|
+
<h3>Messages:</h3>
|
|
221
|
+
{messages.length === 0 ? (
|
|
222
|
+
<p style={{ color: '#6B7280', fontStyle: 'italic' }}>
|
|
223
|
+
No messages yet. Connect and start recording to begin the conversation.
|
|
224
|
+
</p>
|
|
225
|
+
) : (
|
|
226
|
+
messages.map((message, index) => (
|
|
227
|
+
<div
|
|
228
|
+
key={index}
|
|
229
|
+
style={{
|
|
230
|
+
marginBottom: '12px',
|
|
231
|
+
padding: '8px 12px',
|
|
232
|
+
borderRadius: '6px',
|
|
233
|
+
backgroundColor: message.type === 'user' ? '#E5E7EB' :
|
|
234
|
+
message.type === 'agent' ? '#F3F4F6' :
|
|
235
|
+
message.type === 'error' ? '#FEE2E2' : '#EFF6FF',
|
|
236
|
+
color: message.type === 'error' ? '#991B1B' : '#111827',
|
|
237
|
+
alignSelf: message.type === 'user' ? 'flex-end' : 'flex-start',
|
|
238
|
+
maxWidth: '80%',
|
|
239
|
+
marginLeft: message.type === 'user' ? 'auto' : '0',
|
|
240
|
+
marginRight: message.type === 'user' ? '0' : 'auto'
|
|
241
|
+
}}
|
|
242
|
+
>
|
|
243
|
+
<div style={{ fontWeight: 'bold', marginBottom: '4px' }}>
|
|
244
|
+
{message.type === 'user' ? 'đ¤ You' :
|
|
245
|
+
message.type === 'agent' ? 'đ¤ Agent' :
|
|
246
|
+
message.type === 'error' ? 'â Error' : 'âšī¸ System'}
|
|
247
|
+
</div>
|
|
248
|
+
<div>{message.text}</div>
|
|
249
|
+
<div style={{
|
|
250
|
+
fontSize: '12px',
|
|
251
|
+
color: '#6B7280',
|
|
252
|
+
marginTop: '4px'
|
|
253
|
+
}}>
|
|
254
|
+
{message.timestamp.toLocaleTimeString()}
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
))
|
|
258
|
+
)}
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
{/* Status Indicators */}
|
|
262
|
+
<div style={{
|
|
263
|
+
display: 'flex',
|
|
264
|
+
gap: '20px',
|
|
265
|
+
marginTop: '20px',
|
|
266
|
+
fontSize: '14px',
|
|
267
|
+
color: '#6B7280'
|
|
268
|
+
}}>
|
|
269
|
+
<div>
|
|
270
|
+
<span style={{
|
|
271
|
+
display: 'inline-block',
|
|
272
|
+
width: '8px',
|
|
273
|
+
height: '8px',
|
|
274
|
+
borderRadius: '50%',
|
|
275
|
+
backgroundColor: isConnected ? '#10B981' : '#EF4444',
|
|
276
|
+
marginRight: '8px'
|
|
277
|
+
}}></span>
|
|
278
|
+
Connection
|
|
279
|
+
</div>
|
|
280
|
+
<div>
|
|
281
|
+
<span style={{
|
|
282
|
+
display: 'inline-block',
|
|
283
|
+
width: '8px',
|
|
284
|
+
height: '8px',
|
|
285
|
+
borderRadius: '50%',
|
|
286
|
+
backgroundColor: isRecording ? '#EF4444' : '#9CA3AF',
|
|
287
|
+
marginRight: '8px'
|
|
288
|
+
}}></span>
|
|
289
|
+
Recording
|
|
290
|
+
</div>
|
|
291
|
+
<div>
|
|
292
|
+
<span style={{
|
|
293
|
+
display: 'inline-block',
|
|
294
|
+
width: '8px',
|
|
295
|
+
height: '8px',
|
|
296
|
+
borderRadius: '50%',
|
|
297
|
+
backgroundColor: isPlaying ? '#10B981' : '#9CA3AF',
|
|
298
|
+
marginRight: '8px'
|
|
299
|
+
}}></span>
|
|
300
|
+
Playing
|
|
301
|
+
</div>
|
|
302
|
+
</div>
|
|
303
|
+
</div>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export default VoiceChatApp;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
============================================
|
|
3
|
+
FILE: examples/test.html
|
|
4
|
+
Test page for the widget
|
|
5
|
+
============================================
|
|
6
|
+
-->
|
|
7
|
+
<!DOCTYPE html>
|
|
8
|
+
<html lang="en">
|
|
9
|
+
<head>
|
|
10
|
+
<meta charset="UTF-8">
|
|
11
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
12
|
+
<title>Voice Agent Widget - Test Page</title>
|
|
13
|
+
<style>
|
|
14
|
+
body {
|
|
15
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
16
|
+
max-width: 800px;
|
|
17
|
+
margin: 40px auto;
|
|
18
|
+
padding: 20px;
|
|
19
|
+
background: #F9FAFB;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.container {
|
|
23
|
+
background: white;
|
|
24
|
+
padding: 30px;
|
|
25
|
+
border-radius: 12px;
|
|
26
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
h1 {
|
|
30
|
+
color: #111827;
|
|
31
|
+
margin-top: 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.info {
|
|
35
|
+
background: #EFF6FF;
|
|
36
|
+
border-left: 4px solid #3B82F6;
|
|
37
|
+
padding: 16px;
|
|
38
|
+
margin: 20px 0;
|
|
39
|
+
border-radius: 4px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.status {
|
|
43
|
+
margin: 20px 0;
|
|
44
|
+
padding: 12px;
|
|
45
|
+
background: #F3F4F6;
|
|
46
|
+
border-radius: 6px;
|
|
47
|
+
font-family: monospace;
|
|
48
|
+
font-size: 14px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.status.success {
|
|
52
|
+
background: #D1FAE5;
|
|
53
|
+
color: #065F46;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.status.error {
|
|
57
|
+
background: #FEE2E2;
|
|
58
|
+
color: #991B1B;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
button {
|
|
62
|
+
background: #4F46E5;
|
|
63
|
+
color: white;
|
|
64
|
+
border: none;
|
|
65
|
+
padding: 12px 24px;
|
|
66
|
+
border-radius: 6px;
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
font-size: 16px;
|
|
69
|
+
margin: 10px 10px 10px 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
button:hover {
|
|
73
|
+
background: #4338CA;
|
|
74
|
+
}
|
|
75
|
+
</style>
|
|
76
|
+
</head>
|
|
77
|
+
<body>
|
|
78
|
+
<div class="container">
|
|
79
|
+
<h1>đ¤ Voice Agent Widget - Test Page</h1>
|
|
80
|
+
|
|
81
|
+
<div class="info">
|
|
82
|
+
<strong>đ Testing Instructions:</strong>
|
|
83
|
+
<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
|
+
<li>Look for the floating voice button in the bottom-right corner</li>
|
|
86
|
+
<li>Click the button to open the widget</li>
|
|
87
|
+
<li>Click the microphone to start (will request mic permission)</li>
|
|
88
|
+
<li>Widget will connect to production backend at speech.bidme.co.il</li>
|
|
89
|
+
<li>Check the status updates below</li>
|
|
90
|
+
</ol>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<h2>Widget Status:</h2>
|
|
94
|
+
<div id="status" class="status">
|
|
95
|
+
Waiting for widget to load...
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<h2>Console Log:</h2>
|
|
99
|
+
<div id="log" style="background: #1F2937; color: #F9FAFB; padding: 16px; border-radius: 6px; font-family: monospace; font-size: 12px; max-height: 300px; overflow-y: auto;">
|
|
100
|
+
Console messages will appear here...
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<h2>Manual Tests:</h2>
|
|
104
|
+
<button onclick="testConnection()">Test Backend Connection</button>
|
|
105
|
+
<button onclick="testMicrophone()">Test Microphone Access</button>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<!-- 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>
|
|
110
|
+
|
|
111
|
+
<script>
|
|
112
|
+
// Override console.log to show in page
|
|
113
|
+
const originalLog = console.log;
|
|
114
|
+
const originalError = console.error;
|
|
115
|
+
const logDiv = document.getElementById('log');
|
|
116
|
+
|
|
117
|
+
function addLog(message, type = 'log') {
|
|
118
|
+
const time = new Date().toLocaleTimeString();
|
|
119
|
+
const color = type === 'error' ? '#EF4444' : '#10B981';
|
|
120
|
+
logDiv.innerHTML += `<div style="color: ${color};">[${time}] ${message}</div>`;
|
|
121
|
+
logDiv.scrollTop = logDiv.scrollHeight;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
console.log = (...args) => {
|
|
125
|
+
originalLog(...args);
|
|
126
|
+
addLog(args.join(' '));
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
console.error = (...args) => {
|
|
130
|
+
originalError(...args);
|
|
131
|
+
addLog(args.join(' '), 'error');
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Update status display
|
|
135
|
+
function updateStatus(message, type = 'info') {
|
|
136
|
+
const statusDiv = document.getElementById('status');
|
|
137
|
+
statusDiv.textContent = message;
|
|
138
|
+
statusDiv.className = 'status ' + type;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Initialize the widget
|
|
142
|
+
try {
|
|
143
|
+
console.log('Initializing widget...');
|
|
144
|
+
console.log('TTPAgentSDK available:', typeof TTPAgentSDK);
|
|
145
|
+
console.log('TTPAgentSDK.AgentWidget available:', typeof TTPAgentSDK?.AgentWidget);
|
|
146
|
+
|
|
147
|
+
if (typeof TTPAgentSDK === 'undefined') {
|
|
148
|
+
throw new Error('TTPAgentSDK is not defined. Check if the script loaded correctly.');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (typeof TTPAgentSDK.AgentWidget === 'undefined') {
|
|
152
|
+
throw new Error('TTPAgentSDK.AgentWidget is not defined. Check the SDK build.');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Create a new AgentWidget instance
|
|
156
|
+
const widget = new TTPAgentSDK.AgentWidget({
|
|
157
|
+
agentId: 'agent_test_123',
|
|
158
|
+
|
|
159
|
+
// Mock backend for local testing (no real backend needed!)
|
|
160
|
+
getSessionUrl: async ({ agentId, variables }) => {
|
|
161
|
+
console.log('Requesting session URL for agent:', agentId);
|
|
162
|
+
console.log('Variables:', variables);
|
|
163
|
+
|
|
164
|
+
updateStatus('Creating mock session URL...', 'info');
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
// Simulate a small delay like a real backend
|
|
168
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
169
|
+
|
|
170
|
+
// Create a mock WebSocket URL for testing
|
|
171
|
+
const mockSignedUrl = `wss://speech.bidme.co.il/ws/conv?agentId=${agentId}&appId=test_app_123`;
|
|
172
|
+
|
|
173
|
+
console.log('Generated mock session URL:', mockSignedUrl);
|
|
174
|
+
updateStatus('Mock session URL created â', 'success');
|
|
175
|
+
|
|
176
|
+
return mockSignedUrl;
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.error('Failed to create mock session URL:', error);
|
|
179
|
+
updateStatus('Failed to create mock session URL â', 'error');
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
// Pass some test variables
|
|
185
|
+
variables: {
|
|
186
|
+
testMode: true,
|
|
187
|
+
userName: 'Test User',
|
|
188
|
+
page: 'test.html'
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
// Customize appearance
|
|
192
|
+
primaryColor: '#10B981',
|
|
193
|
+
position: 'bottom-right'
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
console.log('Widget initialized successfully!');
|
|
197
|
+
updateStatus('Widget loaded and ready â', 'success');
|
|
198
|
+
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error('Failed to initialize widget:', error);
|
|
201
|
+
updateStatus('Widget failed to load â', 'error');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Manual test functions
|
|
205
|
+
async function testConnection() {
|
|
206
|
+
console.log('Testing backend connection...');
|
|
207
|
+
try {
|
|
208
|
+
const response = await fetch('http://localhost:3000/health');
|
|
209
|
+
if (response.ok) {
|
|
210
|
+
console.log('Backend is reachable â');
|
|
211
|
+
alert('Backend connection OK!');
|
|
212
|
+
} else {
|
|
213
|
+
throw new Error('Backend returned error');
|
|
214
|
+
}
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error('Cannot reach backend:', error);
|
|
217
|
+
alert('Widget initialization FAILED! Check console for details.');
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function testMicrophone() {
|
|
222
|
+
console.log('Testing microphone access...');
|
|
223
|
+
try {
|
|
224
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
225
|
+
console.log('Microphone access granted â');
|
|
226
|
+
stream.getTracks().forEach(track => track.stop());
|
|
227
|
+
alert('Microphone access OK!');
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.error('Microphone access denied:', error);
|
|
230
|
+
alert('Microphone access DENIED! Please allow microphone in browser settings.');
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
</script>
|
|
234
|
+
</body>
|
|
235
|
+
</html>
|