freddyaboulton HF Staff commited on
Commit
a654399
·
verified ·
1 Parent(s): 2d6adbd

Upload folder using huggingface_hub

Browse files
Files changed (4) hide show
  1. README_gradio.md +1 -1
  2. app.py +0 -1
  3. index.html +119 -18
  4. requirements.txt +1 -1
README_gradio.md CHANGED
@@ -9,7 +9,7 @@ app_file: app.py
9
  pinned: false
10
  license: mit
11
  short_description: Talk to OpenAI (Gradio UI)
12
- tags: [webrtc, websocket, gradio, secret|TWILIO_ACCOUNT_SID, secret|TWILIO_AUTH_TOKEN, secret|OPENAI_API_KEY]
13
  ---
14
 
15
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
9
  pinned: false
10
  license: mit
11
  short_description: Talk to OpenAI (Gradio UI)
12
+ tags: [webrtc, websocket, gradio, secret|HF_TOKEN, secret|OPENAI_API_KEY]
13
  ---
14
 
15
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py CHANGED
@@ -33,7 +33,6 @@ class OpenAIHandler(AsyncStreamHandler):
33
  super().__init__(
34
  expected_layout="mono",
35
  output_sample_rate=SAMPLE_RATE,
36
- output_frame_size=480,
37
  input_sample_rate=SAMPLE_RATE,
38
  )
39
  self.connection = None
 
33
  super().__init__(
34
  expected_layout="mono",
35
  output_sample_rate=SAMPLE_RATE,
 
36
  input_sample_rate=SAMPLE_RATE,
37
  )
38
  self.connection = None
index.html CHANGED
@@ -67,16 +67,21 @@
67
  }
68
 
69
  button {
 
 
 
 
 
70
  background-color: transparent;
71
  color: #ffffff;
72
  border: 1px solid #ffffff;
73
- padding: 12px 24px;
74
  font-family: inherit;
75
  font-size: 16px;
76
  cursor: pointer;
77
  transition: all 0.3s;
78
  text-transform: uppercase;
79
  letter-spacing: 1px;
 
80
  }
81
 
82
  button:hover {
@@ -116,9 +121,7 @@
116
  .pulse-container {
117
  display: flex;
118
  align-items: center;
119
- justify-content: center;
120
  gap: 12px;
121
- min-width: 180px;
122
  }
123
 
124
  .pulse-circle {
@@ -128,10 +131,47 @@
128
  background-color: #ffffff;
129
  opacity: 0.2;
130
  flex-shrink: 0;
131
- transform: translateX(-0%) scale(var(--audio-level, 1));
132
  transition: transform 0.1s ease;
133
  }
134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  /* Add styles for toast notifications */
136
  .toast {
137
  position: fixed;
@@ -177,6 +217,7 @@
177
  <script>
178
  let peerConnection;
179
  let webrtc_id;
 
180
  const audioOutput = document.getElementById('audio-output');
181
  const startButton = document.getElementById('start-button');
182
  const chatMessages = document.getElementById('chat-messages');
@@ -185,27 +226,82 @@
185
  let animationFrame;
186
  let audioContext, analyser, audioSource;
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  function updateButtonState() {
189
  const button = document.getElementById('start-button');
 
 
 
 
190
  if (peerConnection && (peerConnection.connectionState === 'connecting' || peerConnection.connectionState === 'new')) {
191
- button.innerHTML = `
192
- <div class="icon-with-spinner">
193
- <div class="spinner"></div>
194
- <span>Connecting...</span>
195
- </div>
196
- `;
 
 
197
  } else if (peerConnection && peerConnection.connectionState === 'connected') {
198
- button.innerHTML = `
199
- <div class="pulse-container">
200
- <div class="pulse-circle"></div>
201
- <span>Stop Conversation</span>
202
- </div>
203
- `;
 
 
 
 
 
 
 
 
 
 
 
 
204
  } else {
205
- button.innerHTML = 'Start Conversation';
 
 
206
  }
207
  }
208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  function setupAudioVisualization(stream) {
210
  audioContext = new (window.AudioContext || window.webkitAudioContext)();
211
  analyser = audioContext.createAnalyser();
@@ -388,7 +484,12 @@
388
  audioLevel = 0;
389
  }
390
 
391
- startButton.addEventListener('click', () => {
 
 
 
 
 
392
  console.log('clicked');
393
  console.log(peerConnection, peerConnection?.connectionState);
394
  if (!peerConnection || peerConnection.connectionState !== 'connected') {
 
67
  }
68
 
69
  button {
70
+ display: inline-flex;
71
+ align-items: center;
72
+ justify-content: center;
73
+ gap: 10px;
74
+ padding: 12px 24px;
75
  background-color: transparent;
76
  color: #ffffff;
77
  border: 1px solid #ffffff;
 
78
  font-family: inherit;
79
  font-size: 16px;
80
  cursor: pointer;
81
  transition: all 0.3s;
82
  text-transform: uppercase;
83
  letter-spacing: 1px;
84
+ position: relative;
85
  }
86
 
87
  button:hover {
 
121
  .pulse-container {
122
  display: flex;
123
  align-items: center;
 
124
  gap: 12px;
 
125
  }
126
 
127
  .pulse-circle {
 
131
  background-color: #ffffff;
132
  opacity: 0.2;
133
  flex-shrink: 0;
134
+ transform: scale(var(--audio-level, 1));
135
  transition: transform 0.1s ease;
136
  }
137
 
138
+ /* Fix button layout */
139
+ button {
140
+ display: inline-flex;
141
+ align-items: center;
142
+ justify-content: center;
143
+ gap: 10px;
144
+ padding: 12px 24px;
145
+ background-color: transparent;
146
+ color: #ffffff;
147
+ border: 1px solid #ffffff;
148
+ font-family: inherit;
149
+ font-size: 16px;
150
+ cursor: pointer;
151
+ transition: all 0.3s;
152
+ text-transform: uppercase;
153
+ letter-spacing: 1px;
154
+ position: relative;
155
+ }
156
+
157
+ .mute-toggle {
158
+ width: 24px;
159
+ height: 24px;
160
+ cursor: pointer;
161
+ flex-shrink: 0;
162
+ }
163
+
164
+ .mute-toggle svg {
165
+ display: block;
166
+ width: 100%;
167
+ height: 100%;
168
+ }
169
+
170
+ #start-button {
171
+ margin-left: auto;
172
+ margin-right: auto;
173
+ }
174
+
175
  /* Add styles for toast notifications */
176
  .toast {
177
  position: fixed;
 
217
  <script>
218
  let peerConnection;
219
  let webrtc_id;
220
+ let isMuted = false;
221
  const audioOutput = document.getElementById('audio-output');
222
  const startButton = document.getElementById('start-button');
223
  const chatMessages = document.getElementById('chat-messages');
 
226
  let animationFrame;
227
  let audioContext, analyser, audioSource;
228
 
229
+ // SVG Icons
230
+ const micIconSVG = `
231
+ <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
232
+ <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
233
+ <path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
234
+ <line x1="12" y1="19" x2="12" y2="23"></line>
235
+ <line x1="8" y1="23" x2="16" y2="23"></line>
236
+ </svg>`;
237
+
238
+ const micMutedIconSVG = `
239
+ <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
240
+ <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"></path>
241
+ <path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
242
+ <line x1="12" y1="19" x2="12" y2="23"></line>
243
+ <line x1="8" y1="23" x2="16" y2="23"></line>
244
+ <line x1="1" y1="1" x2="23" y2="23"></line>
245
+ </svg>`;
246
+
247
  function updateButtonState() {
248
  const button = document.getElementById('start-button');
249
+
250
+ // Clear previous content
251
+ button.innerHTML = '';
252
+
253
  if (peerConnection && (peerConnection.connectionState === 'connecting' || peerConnection.connectionState === 'new')) {
254
+ const spinner = document.createElement('div');
255
+ spinner.className = 'spinner';
256
+
257
+ const text = document.createElement('span');
258
+ text.textContent = 'Connecting...';
259
+
260
+ button.appendChild(spinner);
261
+ button.appendChild(text);
262
  } else if (peerConnection && peerConnection.connectionState === 'connected') {
263
+ // Create pulse circle
264
+ const pulseCircle = document.createElement('div');
265
+ pulseCircle.className = 'pulse-circle';
266
+
267
+ // Create mic icon
268
+ const micIcon = document.createElement('div');
269
+ micIcon.className = 'mute-toggle';
270
+ micIcon.innerHTML = isMuted ? micMutedIconSVG : micIconSVG;
271
+ micIcon.addEventListener('click', toggleMute);
272
+
273
+ // Create text
274
+ const text = document.createElement('span');
275
+ text.textContent = 'Stop Conversation';
276
+
277
+ // Add elements in correct order
278
+ button.appendChild(pulseCircle);
279
+ button.appendChild(micIcon);
280
+ button.appendChild(text);
281
  } else {
282
+ const text = document.createElement('span');
283
+ text.textContent = 'Start Conversation';
284
+ button.appendChild(text);
285
  }
286
  }
287
 
288
+ function toggleMute(event) {
289
+ event.stopPropagation();
290
+ if (!peerConnection || peerConnection.connectionState !== 'connected') return;
291
+
292
+ isMuted = !isMuted;
293
+ console.log("Mute toggled:", isMuted);
294
+
295
+ peerConnection.getSenders().forEach(sender => {
296
+ if (sender.track && sender.track.kind === 'audio') {
297
+ sender.track.enabled = !isMuted;
298
+ console.log(`Audio track ${sender.track.id} enabled: ${!isMuted}`);
299
+ }
300
+ });
301
+
302
+ updateButtonState();
303
+ }
304
+
305
  function setupAudioVisualization(stream) {
306
  audioContext = new (window.AudioContext || window.webkitAudioContext)();
307
  analyser = audioContext.createAnalyser();
 
484
  audioLevel = 0;
485
  }
486
 
487
+ startButton.addEventListener('click', (event) => {
488
+ // Skip if clicking the mute toggle
489
+ if (event.target.closest('.mute-toggle')) {
490
+ return;
491
+ }
492
+
493
  console.log('clicked');
494
  console.log(peerConnection, peerConnection?.connectionState);
495
  if (!peerConnection || peerConnection.connectionState !== 'connected') {
requirements.txt CHANGED
@@ -1,4 +1,4 @@
1
- fastrtc[vad]
2
  openai
3
  twilio
4
  python-dotenv
 
1
+ fastrtc[vad]==0.0.20.rc2
2
  openai
3
  twilio
4
  python-dotenv