KoljaB / RealtimeTTS

Converts text to speech in realtime
2.08k stars 210 forks source link

RecursionError: maximum recursion depth exceeded #222

Open phamson02 opened 3 days ago

phamson02 commented 3 days ago

Using CoquiEngine for synthesizing Japanese and occasionally I got this RecursionError. The error trace message is included below.

Exception in thread Thread-39 (play):                                                                                                                                                                                                                                 
Traceback (most recent call last):                                                                                                                                                                                                                                    
  File "xxx/.venv/lib/python3.12/site-packages/RealtimeTTS/text_to_stream.py", line 431, in play                                                                                                                             
    for sentence in chunk_generator:                                                                                                                                                                                                                                  
                    ^^^^^^^^^^^^^^^                                                                                                                                                                                                                                   
  File "xxx/.venv/lib/python3.12/site-packages/RealtimeTTS/text_to_stream.py", line 694, in _synthesis_chunk_generator                                                                                                       
    for chunk in generator:                                                                                                                                                                                                                                           
                 ^^^^^^^^^                                                                                                                                                                                                                                            
  File "xxx/.venv/lib/python3.12/site-packages/stream2sentence/stream2sentence.py", line 458, in _async_iter_to_sync                                                                                                         
    yield _await_sync(f.__anext__())                                                                                                                                                                                                                                  
          ^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                                                                                                                                                  
  File "xxx/.venv/lib/python3.12/site-packages/stream2sentence/stream2sentence.py", line 449, in _await_sync                                                                                                                 
    next(gen)                                                                                                                                                                                                                                                         
  File "xxx/.venv/lib/python3.12/site-packages/stream2sentence/stream2sentence.py", line 303, in generate_sentences_async                                                                                                    
    async for char in _generate_characters(generator, log_characters):                                                                                                                                                                                                
  File "xxx/.venv/lib/python3.12/site-packages/stream2sentence/stream2sentence.py", line 118, in _generate_characters                                                                                                        
    async for chunk in generator:                                                                                                                                                                                                                                     
  File "xxx/.venv/lib/python3.12/site-packages/stream2sentence/stream2sentence.py", line 472, in gen_wrap                                                                                                                    
    for x in generator:                                                                                                                                                                                                                                               
             ^^^^^^^^^                                                                                                                                                                                                                                                
  File "xxx/.venv/lib/python3.12/site-packages/RealtimeTTS/threadsafe_generators.py", line 154, in __next__                                                                                                                  
    token = next(self.generator)                                                                                                                                                                                                                                      
            ^^^^^^^^^^^^^^^^^^^^                                                                                                                                                                                                                                      
  File "xxx/.venv/lib/python3.12/site-packages/RealtimeTTS/threadsafe_generators.py", line 72, in __next__                                                                                                                   
    if self.immediate_stop.is_set():                                                                                                                                                                                                                                  
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                                                                                                                                                   
RecursionError: maximum recursion depth exceeded                                                                                                                                                                                                                      

During handling of the above exception, another exception occurred: 

Traceback (most recent call last):                                                                                                                                                                                                                                    
  File "xxx/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/threading.py", line 1075, in _bootstrap_inner                                                                                                                               
    self.run()                                                                                                                                                                                                                                                        
  File "xxx/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/threading.py", line 1012, in run                                                                                                                                            
    self._target(*self._args, **self._kwargs)                                                                                                                                                                                                                         
  File "xxx/.venv/lib/python3.12/site-packages/RealtimeTTS/text_to_stream.py", line 474, in play                                                                                                                             
    self.play(                                                                                                                                                                                                                                                        
  File "xxx/.venv/lib/python3.12/site-packages/RealtimeTTS/text_to_stream.py", line 474, in play                                                                                                                             
    self.play(                                                                                                                                                                                                                                                        
  File "xxx/.venv/lib/python3.12/site-packages/RealtimeTTS/text_to_stream.py", line 474, in play                                                                                                                             
    self.play(                                                                                                                                                                                                                                                        
  [Previous line repeated 985 more times]                                                                                                                                                                                                                             
  File "xxx/.venv/lib/python3.12/site-packages/RealtimeTTS/text_to_stream.py", line 445, in play                                                                                                                             
    logging.warning(
  File "xxx/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/logging/__init__.py", line 2201, in warning
    root.warning(msg, *args, **kwargs)
  File "xxx/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/logging/__init__.py", line 1551, in warning
    self._log(WARNING, msg, args, **kwargs)
  File "xxx/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/logging/__init__.py", line 1684, in _log
    self.handle(record)
  File "xxx/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/logging/__init__.py", line 1700, in handle
    self.callHandlers(record)
  File "xxx/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/logging/__init__.py", line 1762, in callHandlers
    hdlr.handle(record)
  File "xxx/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/logging/__init__.py", line 1028, in handle
    self.emit(record)
  File "xxx/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/logging/__init__.py", line 1160, in emit
    msg = self.format(record)
          ^^^^^^^^^^^^^^^^^^^
  File "xxx/.local/share/uv/python/cpython-3.12.7-linux-x86_64-gnu/lib/python3.12/logging/__init__.py", line 999, in format 
    return fmt.format(record)
           ^^^^^^^^^^^^^^^^^^
RecursionError: maximum recursion depth exceeded

Upon further investigation, it seems the issue arises because self.char_iter.immediate_stop is set to True in the error scenario. Despite this, the play() function continues to be called, even though self.char_iter cannot proceed (due to immediate_stop is set). A possible fix is to reset this immediate_stop flag here, but I am not sure if this is indended.

# RealtimeTTS\text_to_stream.py

            if len(self.char_iter.items) > 0 and self.char_iter.iterated_text == "":
                # new text was feeded while playing audio but after the last character was processed
                # we need to start another play() call (!recursively!)
                print(f"self.char_iter.items: {self.char_iter.items}") # ['か?']
                print(f"self.char_iter.iterated_text: {self.char_iter.iterated_text}") # (Nothing)
                print(f"self.char_iter.immediate_stop: {self.char_iter.immediate_stop}") # True
                # possible fix would be resetting this immediate_stop flag: self.char_iter.immediate_stop.clear()
                self.play(
                    fast_sentence_fragment=fast_sentence_fragment,
                    buffer_threshold_seconds=buffer_threshold_seconds,
                    minimum_sentence_length=minimum_sentence_length,
                    minimum_first_fragment_length=minimum_first_fragment_length,
                    log_synthesized_text=log_synthesized_text,
                    reset_generated_text=False,
                    output_wavfile=output_wavfile,
                    on_sentence_synthesized=on_sentence_synthesized,
                    on_audio_chunk=on_audio_chunk,
                    tokenizer=tokenizer,
                    language=language,
                    context_size=context_size,
                    muted=muted,
                    sentence_fragment_delimiters=sentence_fragment_delimiters,
                    force_first_fragment_after_words=force_first_fragment_after_words,
                    is_external_call=False,
                )
phamson02 commented 3 days ago

As this error happened after I stop the stream, maybe it is better to improve this condition

            if (
                len(self.char_iter.items) > 0
                and self.char_iter.iterated_text == ""
                and (not self.char_iter.immediate_stop.is_set())
            ):
KoljaB commented 3 days ago

Thank you very much for reporting this issue and especially for that really helpful analysis. Will look into that.