Rajhuggingface4253 commited on
Commit
2c4e22c
·
verified ·
1 Parent(s): 5d68bda

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +7 -20
app.py CHANGED
@@ -26,7 +26,7 @@ import queue
26
  import sys
27
  sys.path.append(os.path.join(os.getcwd(), 'neutts-air'))
28
  from neuttsair.neutts import NeuTTSAir
29
-
30
  # Configure logging
31
  logging.basicConfig(level=logging.INFO)
32
  logger = logging.getLogger("NeuTTS-API")
@@ -358,62 +358,49 @@ async def stream_text_to_speech_cloning(
358
  raise HTTPException(status_code=503, detail="Service unavailable: Model not loaded")
359
 
360
  try:
361
- # Initial audio conversion is still done once, in memory.
362
  converted_wav_buffer = await convert_to_wav_in_memory(reference_audio)
363
  ref_audio_bytes = converted_wav_buffer.getvalue()
364
 
365
  def stream_generator():
366
- # 1. Create a queue to communicate between the producer and consumer.
367
- # A small maxsize acts as a "look-ahead" buffer.
368
  q = queue.Queue(maxsize=2)
369
 
370
- # 2. Define the PRODUCER (The "Grill Chef")
371
- # This function runs in a background thread to generate audio continuously.
372
  def producer():
373
  try:
374
- # Get reference encoding once for the whole stream
375
  audio_hash = hashlib.sha256(ref_audio_bytes).hexdigest()
376
  ref_s = app.state.tts_wrapper._get_or_create_reference_encoding(audio_hash, ref_audio_bytes)
377
 
378
  sentences = app.state.tts_wrapper._split_text_into_chunks(text)
379
 
380
  for sentence in sentences:
381
- # Generate the raw audio (CPU-heavy part)
382
  with torch.no_grad():
383
  audio_chunk = app.state.tts_wrapper.tts_model.infer(sentence, ref_s, reference_text)
384
- # Put the finished audio (a numpy array) into the queue
385
  q.put(audio_chunk)
386
 
387
  except Exception as e:
388
  logger.error(f"Error in producer thread: {e}")
389
- # If an error occurs, put the exception in the queue to notify the consumer
390
  q.put(e)
391
  finally:
392
- # 3. Signal that production is finished by putting None in the queue
393
  q.put(None)
394
 
395
- # 4. Start the producer in the background ThreadPoolExecutor
396
- loop = asyncio.get_event_loop()
397
- loop.run_in_executor(tts_executor, producer)
 
 
 
398
 
399
- # 5. The main thread becomes the CONSUMER (The "Finisher")
400
  while True:
401
- # Get the next audio chunk from the queue (this will wait if the queue is empty)
402
  result = q.get()
403
 
404
- # Check for the "end of stream" signal
405
  if result is None:
406
  break
407
 
408
- # Check if the producer sent an error
409
  if isinstance(result, Exception):
410
  logger.error(f"Terminating stream due to producer error: {result}")
411
  raise result
412
 
413
- # Convert the raw audio to the desired format and yield it to the user
414
  yield app.state.tts_wrapper._convert_to_streamable_format(result, output_format)
415
 
416
- # Return the StreamingResponse with our new high-performance generator
417
  return StreamingResponse(
418
  stream_generator(),
419
  media_type=f"audio/{'mpeg' if output_format == 'mp3' else output_format}"
 
26
  import sys
27
  sys.path.append(os.path.join(os.getcwd(), 'neutts-air'))
28
  from neuttsair.neutts import NeuTTSAir
29
+ from threading import Thread
30
  # Configure logging
31
  logging.basicConfig(level=logging.INFO)
32
  logger = logging.getLogger("NeuTTS-API")
 
358
  raise HTTPException(status_code=503, detail="Service unavailable: Model not loaded")
359
 
360
  try:
 
361
  converted_wav_buffer = await convert_to_wav_in_memory(reference_audio)
362
  ref_audio_bytes = converted_wav_buffer.getvalue()
363
 
364
  def stream_generator():
 
 
365
  q = queue.Queue(maxsize=2)
366
 
 
 
367
  def producer():
368
  try:
 
369
  audio_hash = hashlib.sha256(ref_audio_bytes).hexdigest()
370
  ref_s = app.state.tts_wrapper._get_or_create_reference_encoding(audio_hash, ref_audio_bytes)
371
 
372
  sentences = app.state.tts_wrapper._split_text_into_chunks(text)
373
 
374
  for sentence in sentences:
 
375
  with torch.no_grad():
376
  audio_chunk = app.state.tts_wrapper.tts_model.infer(sentence, ref_s, reference_text)
 
377
  q.put(audio_chunk)
378
 
379
  except Exception as e:
380
  logger.error(f"Error in producer thread: {e}")
 
381
  q.put(e)
382
  finally:
 
383
  q.put(None)
384
 
385
+ # === THIS IS THE FIX ===
386
+ # Start the producer in a standard, separate thread.
387
+ # This avoids the asyncio loop error.
388
+ producer_thread = Thread(target=producer)
389
+ producer_thread.start()
390
+ # =======================
391
 
 
392
  while True:
 
393
  result = q.get()
394
 
 
395
  if result is None:
396
  break
397
 
 
398
  if isinstance(result, Exception):
399
  logger.error(f"Terminating stream due to producer error: {result}")
400
  raise result
401
 
 
402
  yield app.state.tts_wrapper._convert_to_streamable_format(result, output_format)
403
 
 
404
  return StreamingResponse(
405
  stream_generator(),
406
  media_type=f"audio/{'mpeg' if output_format == 'mp3' else output_format}"