Archime commited on
Commit
d296c7b
·
1 Parent(s): 4f560c0

Updates UI state error

Browse files
Files changed (4) hide show
  1. app.py +6 -1
  2. app/ui_utils.py +266 -91
  3. app/utils.py +25 -18
  4. assets/custom_style.css +1 -1
app.py CHANGED
@@ -27,6 +27,7 @@ from app.utils import (
27
  generate_coturn_config,
28
  read_and_stream_audio,
29
  stop_streaming,
 
30
  )
31
  from app.session_utils import (
32
  on_load,
@@ -102,6 +103,8 @@ with gr.Blocks(theme=theme, css=css_style) as demo:
102
  main_audio.change(fn=on_file_load, inputs=[main_audio], outputs=ui_components_oload_audio)
103
 
104
  go_to_config.click(lambda: gr.Walkthrough(selected=1), outputs=walkthrough)
 
 
105
 
106
  # === STEP 2 ===
107
  with gr.Step("Configuration", id=1)as config_step:
@@ -125,7 +128,7 @@ with gr.Blocks(theme=theme, css=css_style) as demo:
125
  with gr.Row():
126
  gr.Markdown("##### Decoding ")
127
  with gr.Row():
128
- streaming_policy = gr.Dropdown(["waitk", "alignatt"], value="waitk", label="streaming_policy", elem_classes="full-width",
129
  info="“Wait-k: Higher accuracy, requires larger left context, higher latency” \n”AlignAtt: Lower latency, suitable for production, predicts multiple tokens per chunk”")
130
 
131
  with gr.Row():
@@ -215,6 +218,7 @@ with gr.Blocks(theme=theme, css=css_style) as demo:
215
  height=150,
216
  show_label=False
217
  )
 
218
  status_slider = gr.Slider(
219
  0, 100,
220
  value=0,
@@ -226,6 +230,7 @@ with gr.Blocks(theme=theme, css=css_style) as demo:
226
  )
227
  start_stream_button = gr.Button("▶️ Start Streaming", variant="primary")
228
  stop_stream_button = gr.Button("⏹️ Stop Streaming", visible=False,variant="stop")
 
229
  webrtc_stream.stream(
230
  fn=read_and_stream_audio,
231
  inputs=[active_filepath, session_hash_code,gr.State(READ_SIZE)],
 
27
  generate_coturn_config,
28
  read_and_stream_audio,
29
  stop_streaming,
30
+ raise_error
31
  )
32
  from app.session_utils import (
33
  on_load,
 
103
  main_audio.change(fn=on_file_load, inputs=[main_audio], outputs=ui_components_oload_audio)
104
 
105
  go_to_config.click(lambda: gr.Walkthrough(selected=1), outputs=walkthrough)
106
+
107
+
108
 
109
  # === STEP 2 ===
110
  with gr.Step("Configuration", id=1)as config_step:
 
128
  with gr.Row():
129
  gr.Markdown("##### Decoding ")
130
  with gr.Row():
131
+ streaming_policy = gr.Dropdown(["waitk", "alignatt"], value="alignatt", label="streaming_policy", elem_classes="full-width",
132
  info="“Wait-k: Higher accuracy, requires larger left context, higher latency” \n”AlignAtt: Lower latency, suitable for production, predicts multiple tokens per chunk”")
133
 
134
  with gr.Row():
 
218
  height=150,
219
  show_label=False
220
  )
221
+
222
  status_slider = gr.Slider(
223
  0, 100,
224
  value=0,
 
230
  )
231
  start_stream_button = gr.Button("▶️ Start Streaming", variant="primary")
232
  stop_stream_button = gr.Button("⏹️ Stop Streaming", visible=False,variant="stop")
233
+
234
  webrtc_stream.stream(
235
  fn=read_and_stream_audio,
236
  inputs=[active_filepath, session_hash_code,gr.State(READ_SIZE)],
app/ui_utils.py CHANGED
@@ -6,8 +6,9 @@ import os
6
  from app.utils import (
7
  remove_active_task_flag_file,
8
  task_fake,
9
- is_active_task
10
- # task
 
11
  )
12
 
13
  # from app.utils import (
@@ -27,7 +28,7 @@ DEFAULT_CONFIG = {
27
  "chunk_secs": 1.0,
28
  "left_context_secs": 20.0,
29
  "right_context_secs": 0.5,
30
- "streaming_policy": "waitk",
31
  "alignatt_thr": 8,
32
  "waitk_lagging": 2,
33
  "exclude_sink_frames": 8,
@@ -138,68 +139,163 @@ def summarize_config(
138
 
139
  def handle_additional_outputs(webrtc_stream, msg):
140
  """
141
- Update UI elements based on streaming progress or errors.
142
- Controls button states, audio visibility, and progress slider.
 
 
 
 
143
  """
144
- # logging.debug(f"Additional output received: {msg}")
145
- # ui_components = [start_stream_button, stop_stream_button,start_task_button,go_to_task, audio_source_step, status_slider,walkthrough]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
- progress = float(0)
148
- # Handle structured error message
149
 
150
- if isinstance(msg, dict) and msg.get("errored"):
151
- value = msg.get("value", "Unknown error.")
152
- logging.error(f"[stream_ui] Client-side error: {value}")
153
 
154
- return (
155
- gr.update(visible=True), # start_stream_button enabled
156
- gr.update(visible=False), # stop_stream_button disabled
157
- gr.update(visible=False), #start_task_button
158
- gr.update(visible=False), # go_to_task disabled
159
- gr.update(interactive=True), # audio_source_step re-shown
160
- gr.update(visible=False, value=0), # slider hidden
161
- gr.update(), #walkthrough
162
- gr.update(value=f"**Error:** {value}", visible=True)
163
- )
164
 
165
 
166
- elif msg.get("progressed") :
167
- value = msg.get("value", 0)
168
- progress = float(value)
169
- if progress == 100.00 :
170
- return (
171
- gr.update(visible=True), # start_stream_button disabled
172
- gr.update(visible=False), # stop_stream_button enabled
173
- gr.update(visible=False), #start_task_button
174
- gr.update(visible=True), # go_to_task enabled
175
- gr.update(interactive=True), # hide audio_source_step
176
- gr.update(visible=True, value=progress), # show progress
177
- gr.update(), #walkthrough
178
- gr.update(value="", visible=False)
179
- )
180
- else :
181
- return (
182
- gr.update(visible=False), # start_stream_button disabled
183
- gr.update(visible=True), # stop_stream_button enabled
184
- gr.update() if is_active_task(msg.get("session_hash_code")) else gr.update(visible=True), #start_task_button
185
- gr.update(visible=True), # go_to_task enabled
186
- gr.update(interactive=False), # hide audio_source_step
187
- gr.update(visible=True, value=progress), # show progress
188
- gr.update(), #walkthrough
189
- gr.update(value="", visible=False)
190
- )
191
- elif msg.get("stoped") :
192
 
193
- return (
194
- gr.update(visible=True), # start_stream_button disabled
195
- gr.update(visible=False), # stop_stream_button enabled
196
- gr.update(visible=False), #start_task_button
197
- gr.update(visible=False), # go_to_task enabled
198
- gr.update(interactive=True), # hide audio_source_step
199
- gr.update(visible=True, value=0), # show progress
200
- gr.update(), #walkthrough
201
- gr.update(value="ℹStream stopped by user.", visible=True)
202
- )
203
 
204
 
205
 
@@ -238,46 +334,125 @@ def get_custom_theme() :
238
 
239
 
240
  ########## task
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  def start_task_asr_ast(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  session_hash_code,
243
  task_type, lang_source, lang_target,
244
  chunk_secs, left_context_secs, right_context_secs,
245
  streaming_policy, alignatt_thr, waitk_lagging,
246
  exclude_sink_frames, xatt_scores_layer, hallucinations_detector
247
- ):
248
- """Stream transcription or translation results in real time."""
249
- accumulated = ""
250
- # Boucle sur le générateur de `task2()`
251
- # outputs=[task_output,status_message_task,start_task_button,stop_task_button,config_step]
252
- for result, status, current_chunk in task_fake(
253
- session_hash_code,
254
- task_type, lang_source, lang_target,
255
- chunk_secs, left_context_secs, right_context_secs,
256
- streaming_policy, alignatt_thr, waitk_lagging,
257
- exclude_sink_frames, xatt_scores_layer, hallucinations_detector
258
- ):
 
 
 
 
 
259
  if status == "success":
260
- yield (accumulated + result, #task_output
261
- gr.update(visible=True,value=current_chunk,elem_classes=[status]),#status_message_task
262
- gr.update(visible=False),#start_task_button
263
- gr.update(visible=True), #stop_task_button
264
- gr.update(interactive=False) # config_step
265
- )
266
- accumulated += result
267
- elif status in ["warning","info" ]:
268
- yield (accumulated, #task_output
269
- gr.update(visible=True,value=result , elem_classes=[status]),#status_message_task
270
- gr.update(visible=False),#start_task_button
271
- gr.update(visible=True),#stop_task_button
272
- gr.update(interactive=False) # config_step
273
- )
274
- elif status in [ "done"]:
275
- yield (accumulated, #task_output
276
- gr.update(visible=True,value=result , elem_classes=[status]),#status_message_task
277
- gr.update(visible=True),#start_task_button
278
- gr.update(visible=False),#stop_task_button
279
- gr.update(interactive=True) # config_step
280
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
 
282
  def stop_task_fn(session_hash_code):
283
  remove_active_task_flag_file(session_hash_code)
 
6
  from app.utils import (
7
  remove_active_task_flag_file,
8
  task_fake,
9
+ is_active_task,
10
+ is_active_stream,
11
+ task
12
  )
13
 
14
  # from app.utils import (
 
28
  "chunk_secs": 1.0,
29
  "left_context_secs": 20.0,
30
  "right_context_secs": 0.5,
31
+ "streaming_policy": "alignatt",
32
  "alignatt_thr": 8,
33
  "waitk_lagging": 2,
34
  "exclude_sink_frames": 8,
 
139
 
140
  def handle_additional_outputs(webrtc_stream, msg):
141
  """
142
+ Updates UI elements based on streaming state.
143
+
144
+ Improvements:
145
+ - Uses centralized state logic to avoid code duplication.
146
+ - Handles default values to reduce 'if/else' complexity.
147
+ - Secures reading of dictionary keys.
148
  """
149
+
150
+ # 1. Default state initialization (Neutral or State Conservation Mode)
151
+ # By default, return gr.update() which means "do nothing"
152
+ # This avoids specifying the state of every button each time
153
+ start_btn = gr.update()
154
+ stop_btn = gr.update()
155
+ start_task_btn = gr.update()
156
+ go_to_task_btn = gr.update()
157
+ audio_step = gr.update()
158
+ slider = gr.update()
159
+ walkthrough = gr.update()
160
+ status_msg = gr.update(visible=False, value="")
161
+
162
+ # Safety: if msg is not a valid dictionary
163
+ if not isinstance(msg, dict):
164
+ return (start_btn, stop_btn, start_task_btn, go_to_task_btn, audio_step, slider, walkthrough, status_msg)
165
+
166
+ session_hash = msg.get("session_hash_code", "")
167
+
168
+ # --- CASE 1: ERROR ---
169
+ if msg.get("errored"):
170
+ error_val = msg.get("value", "Unknown error")
171
+ logging.error(f"[stream_ui] Client-side error: {error_val}")
172
+
173
+ start_btn = gr.update(visible=True)
174
+ stop_btn = gr.update(visible=False)
175
+ start_task_btn = gr.update(visible=False)
176
+ go_to_task_btn = gr.update(visible=False)
177
+ audio_step = gr.update(interactive=True)
178
+ slider = gr.update(visible=False, value=0)
179
+ status_msg = gr.update(value=f"⚠️ **Error:** {error_val}", visible=True)
180
+
181
+ # --- CASE 2: MANUAL STOP ---
182
+ # Note: Kept key "stoped" (with one p), but added "stopped" just in case backend is fixed
183
+ elif msg.get("stoped") or msg.get("stopped"):
184
+ start_btn = gr.update(visible=True)
185
+ stop_btn = gr.update(visible=False)
186
+ start_task_btn = gr.update(visible=False)
187
+ go_to_task_btn = gr.update(visible=False)
188
+ audio_step = gr.update(interactive=True)
189
+ slider = gr.update(visible=True, value=0)
190
+ status_msg = gr.update(value="ℹ️ Stream stopped by user.", visible=True)
191
+
192
+ # --- CASE 3: PROGRESS ---
193
+ elif msg.get("progressed"):
194
+ progress = float(msg.get("value", 0))
195
+
196
+ # Common logic for progress (active or finished)
197
+ start_btn = gr.update(visible=False) # Hide Start during stream
198
+ stop_btn = gr.update(visible=True) # Show Stop during stream
199
+ audio_step = gr.update(interactive=False) # Lock input
200
+ slider = gr.update(visible=True, value=progress)
201
+
202
+ # Sub-case: Streaming finished (100%)
203
+ if progress >= 100.0:
204
+ start_btn = gr.update(visible=True)
205
+ stop_btn = gr.update(visible=False)
206
+ start_task_btn = gr.update(visible=False)
207
+ go_to_task_btn = gr.update(visible=True)
208
+ audio_step = gr.update(interactive=True)
209
+ # Status message remains hidden and empty (default values)
210
+
211
+ # Sub-case: Streaming in progress (<100%)
212
+ else:
213
+ go_to_task_btn = gr.update(visible=True)
214
+
215
+ # Your specific logic for start_task_button
216
+ # If task is active, do not touch (empty gr.update), otherwise show
217
+ if (not is_active_task(session_hash)) and is_active_stream(session_hash):
218
+ start_task_btn = gr.update(visible=True)
219
+
220
+ # No status message during normal progress
221
+
222
+ # --- SINGLE RETURN ---
223
+ # Order must match EXACTLY your outputs=[...] list in Gradio
224
+ return (
225
+ start_btn, # 1. start_stream_button
226
+ stop_btn, # 2. stop_stream_button
227
+ start_task_btn, # 3. start_task_button
228
+ go_to_task_btn, # 4. go_to_task
229
+ audio_step, # 5. audio_source_step
230
+ slider, # 6. status_slider
231
+ walkthrough, # 7. walkthrough
232
+ status_msg # 8. status_message (Markdown/HTML)
233
+ )
234
+
235
+
236
+ # def handle_additional_outputs(webrtc_stream, msg):
237
+ # """
238
+ # Update UI elements based on streaming progress or errors.
239
+ # Controls button states, audio visibility, and progress slider.
240
+ # """
241
+ # # ui_components = [start_stream_button, stop_stream_button,start_task_button,go_to_task, audio_source_step, status_slider,walkthrough]
242
 
243
+ # progress = float(0)
244
+ # # Handle structured error message
245
 
246
+ # if isinstance(msg, dict) and msg.get("errored"):
247
+ # value = msg.get("value", "Unknown error.")
248
+ # logging.error(f"[stream_ui] Client-side error: {value}")
249
 
250
+ # return (
251
+ # gr.update(visible=True), # start_stream_button enabled
252
+ # gr.update(visible=False), # stop_stream_button disabled
253
+ # gr.update(visible=False), #start_task_button
254
+ # gr.update(visible=False), # go_to_task disabled
255
+ # gr.update(interactive=True), # audio_source_step re-shown
256
+ # gr.update(visible=False, value=0), # slider hidden
257
+ # gr.update(), #walkthrough
258
+ # gr.update(value=f"**Error:** {value}", visible=True)
259
+ # )
260
 
261
 
262
+ # elif msg.get("progressed") :
263
+ # value = msg.get("value", 0)
264
+ # progress = float(value)
265
+ # if progress == 100.00 :
266
+ # return (
267
+ # gr.update(visible=True), # start_stream_button disabled
268
+ # gr.update(visible=False), # stop_stream_button enabled
269
+ # gr.update(visible=False), #start_task_button
270
+ # gr.update(visible=True), # go_to_task enabled
271
+ # gr.update(interactive=True), # hide audio_source_step
272
+ # gr.update(visible=True, value=progress), # show progress
273
+ # gr.update(), #walkthrough
274
+ # gr.update(value="", visible=False)
275
+ # )
276
+ # else :
277
+ # return (
278
+ # gr.update(visible=False), # start_stream_button disabled
279
+ # gr.update(visible=True), # stop_stream_button enabled
280
+ # gr.update() if is_active_task(msg.get("session_hash_code")) else gr.update(visible=True), #start_task_button
281
+ # gr.update(visible=True), # go_to_task enabled
282
+ # gr.update(interactive=False), # hide audio_source_step
283
+ # gr.update(visible=True, value=progress), # show progress
284
+ # gr.update(), #walkthrough
285
+ # gr.update(value="", visible=False)
286
+ # )
287
+ # elif msg.get("stoped") :
288
 
289
+ # return (
290
+ # gr.update(visible=True), # start_stream_button disabled
291
+ # gr.update(visible=False), # stop_stream_button enabled
292
+ # gr.update(visible=False), #start_task_button
293
+ # gr.update(visible=False), # go_to_task enabled
294
+ # gr.update(interactive=True), # hide audio_source_step
295
+ # gr.update(visible=True, value=0), # show progress
296
+ # gr.update(), #walkthrough
297
+ # gr.update(value="ℹStream stopped by user.", visible=True)
298
+ # )
299
 
300
 
301
 
 
334
 
335
 
336
  ########## task
337
+ # def start_task_asr_ast(
338
+ # session_hash_code,
339
+ # task_type, lang_source, lang_target,
340
+ # chunk_secs, left_context_secs, right_context_secs,
341
+ # streaming_policy, alignatt_thr, waitk_lagging,
342
+ # exclude_sink_frames, xatt_scores_layer, hallucinations_detector
343
+ # ):
344
+ # """Stream transcription or translation results in real time."""
345
+ # accumulated = ""
346
+ # # Boucle sur le générateur de `task2()`
347
+ # # outputs=[task_output,status_message_task,start_task_button,stop_task_button,config_step]
348
+ # for result, status, current_chunk in task_fake(
349
+ # session_hash_code,
350
+ # task_type, lang_source, lang_target,
351
+ # chunk_secs, left_context_secs, right_context_secs,
352
+ # streaming_policy, alignatt_thr, waitk_lagging,
353
+ # exclude_sink_frames, xatt_scores_layer, hallucinations_detector
354
+ # ):
355
+ # if status == "success":
356
+ # yield (accumulated + result, #task_output
357
+ # gr.update(visible=True,value=current_chunk,elem_classes=[status]),#status_message_task
358
+ # gr.update(visible=False),#start_task_button
359
+ # gr.update(visible=True), #stop_task_button
360
+ # gr.update(interactive=False) # config_step
361
+ # )
362
+ # accumulated += result
363
+ # elif status in ["warning","info" ]:
364
+ # yield (accumulated, #task_output
365
+ # gr.update(visible=True,value=result , elem_classes=[status]),#status_message_task
366
+ # gr.update(visible=False),#start_task_button
367
+ # gr.update(visible=True),#stop_task_button
368
+ # gr.update(interactive=False) # config_step
369
+ # )
370
+ # elif status in [ "done"]:
371
+ # yield (accumulated, #task_output
372
+ # gr.update(visible=True,value=result , elem_classes=[status]),#status_message_task
373
+ # gr.update(visible=True) if is_active_stream(session_hash_code) else gr.update(visible=False),#start_task_button
374
+ # gr.update(visible=False),#stop_task_button
375
+ # gr.update(interactive=True) # config_step
376
+ # )
377
+
378
+
379
  def start_task_asr_ast(
380
+ session_hash_code,
381
+ task_type, lang_source, lang_target,
382
+ chunk_secs, left_context_secs, right_context_secs,
383
+ streaming_policy, alignatt_thr, waitk_lagging,
384
+ exclude_sink_frames, xatt_scores_layer, hallucinations_detector
385
+ ):
386
+ """
387
+ Manages streaming of transcription (ASR) or translation (AST) results.
388
+ Orchestrates real-time UI updates (text, status, buttons).
389
+ """
390
+ accumulated_text = ""
391
+
392
+ # Call task generator (backend)
393
+ task_generator = task_fake(
394
  session_hash_code,
395
  task_type, lang_source, lang_target,
396
  chunk_secs, left_context_secs, right_context_secs,
397
  streaming_policy, alignatt_thr, waitk_lagging,
398
  exclude_sink_frames, xatt_scores_layer, hallucinations_detector
399
+ )
400
+
401
+ # Loop over partial results
402
+ # result_data: can be transcribed text OR an info message depending on status
403
+ for result_data, status, debug_info in task_generator:
404
+
405
+ # 1. Default states for this iteration ('In Progress' mode)
406
+ # By default, lock config and allow stopping
407
+ start_btn = gr.update(visible=False)
408
+ stop_btn = gr.update(visible=True)
409
+ config_step = gr.update(interactive=False)
410
+
411
+ # Status message and main text depend on return type
412
+ status_msg = gr.update(visible=True)
413
+ main_output = accumulated_text
414
+
415
+ # --- CASE 1: SUCCESS (New text segment) ---
416
  if status == "success":
417
+ # result_data is the new text chunk here
418
+ partial_text = result_data
419
+
420
+ # Update accumulator
421
+ accumulated_text += partial_text
422
+ main_output = accumulated_text
423
+
424
+ # Status message displays chunk info (e.g., timestamps)
425
+ status_msg = gr.update(visible=True, value=debug_info, elem_classes=[status])
426
+
427
+ # --- CASE 2: WARNING / INFO (System message) ---
428
+ elif status in ["warning", "info"]:
429
+ # result_data is the error or info message here
430
+ # Do not touch accumulated_text
431
+ status_msg = gr.update(visible=True, value=result_data, elem_classes=[status])
432
+
433
+
434
+ # --- CASE 3: DONE / ERROR---
435
+ elif status in ["done", "error"]:
436
+ logging.error(f"[ui] error ")
437
+ # Re-enable controls
438
+ is_streaming = is_active_stream(session_hash_code)
439
+ start_btn = gr.update(visible=is_streaming) # Show Start only if audio stream is active
440
+ stop_btn = gr.update(visible=False)
441
+ config_step = gr.update(interactive=True)
442
+
443
+ # result_data is the completion message
444
+ status_msg = gr.update(visible=True, value=result_data, elem_classes=[status])
445
+
446
+ # 2. Single dispatch to UI
447
+ # Expected order: [task_output, status_message_task, start_task_button, stop_task_button, config_step]
448
+ yield (
449
+ main_output,
450
+ status_msg,
451
+ start_btn,
452
+ stop_btn,
453
+ config_step
454
+ )
455
+
456
 
457
  def stop_task_fn(session_hash_code):
458
  remove_active_task_flag_file(session_hash_code)
app/utils.py CHANGED
@@ -5,7 +5,7 @@ import asyncio
5
  import os
6
  import time
7
  import numpy as np
8
-
9
  import spaces
10
  import hmac
11
  import hashlib
@@ -96,7 +96,6 @@ def read_and_stream_audio(filepath_to_stream: str, session_hash_code: str,read_s
96
  logging.info(f"[{session_hash_code}] Starting stream: {filepath_to_stream} ({total_chunks} chunks, {chunk_duration_ms}ms steps).")
97
 
98
  chunk_dir = get_session_hashe_chunks_dir(session_hash_code)
99
- ensure_dir_exists = False
100
  for i, start_ms in enumerate(range(0, total_duration_ms, chunk_duration_ms)):
101
 
102
 
@@ -130,19 +129,20 @@ def read_and_stream_audio(filepath_to_stream: str, session_hash_code: str,read_s
130
  AdditionalOutputs({"progressed": True, "value": progress, "session_hash_code": session_hash_code})
131
  )
132
  if is_active_task(session_hash_code):
133
- if not ensure_dir_exists:
134
- os.makedirs(chunk_dir, exist_ok=True)
135
- ensure_dir_exists = True
136
 
137
  npz_path = os.path.join(chunk_dir, f"chunk_{i:05d}.npz")
138
  # Compression activée, attention c'est lent (CPU intensif)
139
  if is_active_task(session_hash_code):
140
- np.savez_compressed(npz_path, data=samples_int16, rate=frame_rate)
141
- logging.debug(f"[{session_hash_code}] Saved chunk {i} to {npz_path}")
 
 
 
142
 
143
  time.sleep(chunk_duration_ms/1000)
144
 
145
- raise_error() # Optional injected test exception
146
 
147
  logging.info(f"[{session_hash_code}] Streaming completed.")
148
 
@@ -150,6 +150,7 @@ def read_and_stream_audio(filepath_to_stream: str, session_hash_code: str,read_s
150
  yield from handle_stream_error(session_hash_code, e)
151
  finally:
152
  remove_active_stream_flag_file(session_hash_code)
 
153
  logging.info(f"[{session_hash_code}] Cleanup done.")
154
 
155
 
@@ -211,13 +212,13 @@ def task_fake(session_hash_code: str,
211
  logging.info(f"[{session_hash_code}] task loop started.")
212
  yield (f"Task started for session {session_hash_code}", "info", None)
213
 
214
- while os.path.exists(active_flag):
215
  if not os.path.exists(chunk_dir):
216
  logging.warning(f"[{session_hash_code}] No chunk directory found for task.")
217
  yield ("No audio chunks yet... waiting for stream.", "warning", None)
218
  time.sleep(0.1)
219
  continue
220
-
221
  files = sorted(f for f in os.listdir(chunk_dir) if f.endswith(".npz"))
222
  if not files:
223
  time.sleep(0.1)
@@ -233,15 +234,16 @@ def task_fake(session_hash_code: str,
233
  yield (text, "success", fname)
234
  os.remove(fpath)
235
  logging.debug(f"[{session_hash_code}] Deleted processed chunk: {fname}")
236
- # raise_error()
237
 
238
- except EOFError as e:
239
- logging.warning(f"[{session_hash_code}] Error processing {fname}: {e}")
240
  yield (f"EOFError processing {fname}: {e}", "warning", fname)
241
  except Exception as e:
242
- logging.warning(f"[{session_hash_code}] Error processing {fname}: {e}")
243
- yield (f"Error processing {fname}: {e}", "warning", fname)
244
-
 
245
  # continue
246
  time.sleep(0.1)
247
 
@@ -249,8 +251,9 @@ def task_fake(session_hash_code: str,
249
  logging.info(f"[{session_hash_code}] task loop ended (flag removed).")
250
 
251
  except Exception as e:
252
- logging.error(f"[{session_hash_code}] task error: {e}", exc_info=True)
253
  yield (f"Unexpected error: {e}", "error", None)
 
254
 
255
  finally:
256
  if os.path.exists(active_flag):
@@ -266,7 +269,7 @@ def task_fake(session_hash_code: str,
266
  yield (f"Cleanup error: {e}", "error", None)
267
 
268
  logging.info(f"[{session_hash_code}] Exiting task loop.")
269
- yield ("Task finished and cleaned up.", "done", None)
270
 
271
 
272
  @spaces.GPU
@@ -406,6 +409,10 @@ def is_active_task(session_hash_code) -> bool:
406
  """Check if the stop signal was requested."""
407
  return os.path.exists(get_active_task_flag_file(session_hash_code))
408
 
 
 
 
 
409
 
410
  def raise_error():
411
  """Raise an error randomly (1 out of 10 times)."""
 
5
  import os
6
  import time
7
  import numpy as np
8
+ import zipfile
9
  import spaces
10
  import hmac
11
  import hashlib
 
96
  logging.info(f"[{session_hash_code}] Starting stream: {filepath_to_stream} ({total_chunks} chunks, {chunk_duration_ms}ms steps).")
97
 
98
  chunk_dir = get_session_hashe_chunks_dir(session_hash_code)
 
99
  for i, start_ms in enumerate(range(0, total_duration_ms, chunk_duration_ms)):
100
 
101
 
 
129
  AdditionalOutputs({"progressed": True, "value": progress, "session_hash_code": session_hash_code})
130
  )
131
  if is_active_task(session_hash_code):
132
+ os.makedirs(chunk_dir, exist_ok=True)
 
 
133
 
134
  npz_path = os.path.join(chunk_dir, f"chunk_{i:05d}.npz")
135
  # Compression activée, attention c'est lent (CPU intensif)
136
  if is_active_task(session_hash_code):
137
+ try :
138
+ np.savez_compressed(npz_path, data=samples_int16, rate=frame_rate)
139
+ logging.debug(f"[{session_hash_code}] Saved chunk {i} to {npz_path}")
140
+ except Exception as e :
141
+ logging.error(f"[{session_hash_code}] eroor in Saved chunk {i} to {npz_path}")
142
 
143
  time.sleep(chunk_duration_ms/1000)
144
 
145
+ # raise_error() # Optional injected test exception
146
 
147
  logging.info(f"[{session_hash_code}] Streaming completed.")
148
 
 
150
  yield from handle_stream_error(session_hash_code, e)
151
  finally:
152
  remove_active_stream_flag_file(session_hash_code)
153
+ remove_active_task_flag_file(session_hash_code)
154
  logging.info(f"[{session_hash_code}] Cleanup done.")
155
 
156
 
 
212
  logging.info(f"[{session_hash_code}] task loop started.")
213
  yield (f"Task started for session {session_hash_code}", "info", None)
214
 
215
+ while os.path.exists(active_flag) :
216
  if not os.path.exists(chunk_dir):
217
  logging.warning(f"[{session_hash_code}] No chunk directory found for task.")
218
  yield ("No audio chunks yet... waiting for stream.", "warning", None)
219
  time.sleep(0.1)
220
  continue
221
+ # raise_error()
222
  files = sorted(f for f in os.listdir(chunk_dir) if f.endswith(".npz"))
223
  if not files:
224
  time.sleep(0.1)
 
234
  yield (text, "success", fname)
235
  os.remove(fpath)
236
  logging.debug(f"[{session_hash_code}] Deleted processed chunk: {fname}")
237
+ # raise_error()
238
 
239
+ except (EOFError, OSError, zipfile.BadZipFile, ValueError) as e:
240
+ logging.warning(f"[{session_hash_code}] warning processing {fname}: {e}")
241
  yield (f"EOFError processing {fname}: {e}", "warning", fname)
242
  except Exception as e:
243
+ error_type = type(e).__name__
244
+ logging.error(f"[{session_hash_code}] Error processing {fname}: {e} {error_type}")
245
+ # yield (f"Error processing {fname}: {e}", "error", fname)
246
+ raise Exception(e)
247
  # continue
248
  time.sleep(0.1)
249
 
 
251
  logging.info(f"[{session_hash_code}] task loop ended (flag removed).")
252
 
253
  except Exception as e:
254
+ logging.error(f"[{session_hash_code}] Unexpected task error: {e}", exc_info=True)
255
  yield (f"Unexpected error: {e}", "error", None)
256
+ return
257
 
258
  finally:
259
  if os.path.exists(active_flag):
 
269
  yield (f"Cleanup error: {e}", "error", None)
270
 
271
  logging.info(f"[{session_hash_code}] Exiting task loop.")
272
+ # yield ("Task finished and cleaned up.", "done", None)
273
 
274
 
275
  @spaces.GPU
 
409
  """Check if the stop signal was requested."""
410
  return os.path.exists(get_active_task_flag_file(session_hash_code))
411
 
412
+ def is_active_stream(session_hash_code) -> bool:
413
+ """Check if the stop signal was requested."""
414
+ return os.path.exists(get_active_stream_flag_file(session_hash_code))
415
+
416
 
417
  def raise_error():
418
  """Raise an error randomly (1 out of 10 times)."""
assets/custom_style.css CHANGED
@@ -156,7 +156,7 @@ body {
156
  }
157
 
158
  /* Le style .info (bleu) */
159
- #status-message-task.info{
160
  color: #0c5464; /* Texte bleu foncé */
161
  background-color: #d1ecf1; /* Fond bleu clair */
162
  border-color: #bee5eb; /* Bordure bleue */
 
156
  }
157
 
158
  /* Le style .info (bleu) */
159
+ #status-message-task.info,#status-message-task.success,#status-message-task.done{
160
  color: #0c5464; /* Texte bleu foncé */
161
  background-color: #d1ecf1; /* Fond bleu clair */
162
  border-color: #bee5eb; /* Bordure bleue */