diff --git a/lollms/server/endpoints/lollms_tts.py b/lollms/server/endpoints/lollms_tts.py index 52177d6..86118e2 100644 --- a/lollms/server/endpoints/lollms_tts.py +++ b/lollms/server/endpoints/lollms_tts.py @@ -112,6 +112,7 @@ async def audio2text(request: LollmsAudio2TextRequest): class LollmsText2AudioRequest(BaseModel): + client_id: str text: str voice: str = None fn:str = None @@ -124,6 +125,7 @@ async def text2Audio(request: LollmsText2AudioRequest): :param request: The HTTP request object. :return: A JSON response with the status of the operation. """ + check_access(lollmsElfServer, request.client_id) if lollmsElfServer.config.headless_server_mode: return {"status":False,"error":"Code execution is blocked when in headless mode for obvious security reasons!"} @@ -148,7 +150,7 @@ async def text2Audio(request: LollmsText2AudioRequest): voice = request.voice else: voice = lollmsElfServer.config.xtts_current_voice - response = lollmsElfServer.tts.tts_audio(request.text, voice, file_name_or_path=request.fn, use_threading=True) + response = lollmsElfServer.tts.tts_audio(request.text, voice, file_name_or_path=request.fn, use_threading=False) return response else: return {"url": None, "error":f"TTS service is not ready yet"} @@ -157,6 +159,29 @@ async def text2Audio(request: LollmsText2AudioRequest): lollmsElfServer.error(ex) return {"status":False,"error":str(ex)} +@router.post("/stopAudio") +async def stopAudio(request: Identification): + """ + Stops playing audio + + :param request: The HTTP request object. + :return: A JSON response with the status of the operation. + """ + check_access(lollmsElfServer, request.client_id) + if lollmsElfServer.config.headless_server_mode: + return {"status":False,"error":"Code execution is blocked when in headless mode for obvious security reasons!"} + + if lollmsElfServer.config.host!="localhost" and lollmsElfServer.config.host!="127.0.0.1": + return {"status":False,"error":"Code execution is blocked when the server is exposed outside for very obvious reasons!"} + + if lollmsElfServer.tts is None: + return {"status": False, "error":f"No TTS service is on"} + if lollmsElfServer.tts.ready: + lollmsElfServer.tts.stop() + return {"status":True} + else: + return {"url": None, "error":f"TTS service is not ready yet"} + @router.post("/text2Wave") async def text2Wave(request: LollmsText2AudioRequest): """ @@ -200,49 +225,6 @@ async def text2Wave(request: LollmsText2AudioRequest): return {"status":False,"error":str(ex)} -@router.post("/install_xtts") -def install_xtts(data:Identification): - check_access(lollmsElfServer, data.client_id) - try: - if lollmsElfServer.config.headless_server_mode: - return {"status":False,"error":"Service installation is blocked when in headless mode for obvious security reasons!"} - - if lollmsElfServer.config.host!="localhost" and lollmsElfServer.config.host!="127.0.0.1": - return {"status":False,"error":"Service installation is blocked when the server is exposed outside for very obvious reasons!"} - - from lollms.services.xtts.lollms_xtts import LollmsXTTS - lollmsElfServer.ShowBlockingMessage("Installing xTTS api server\nPlease stand by") - LollmsXTTS.install(lollmsElfServer) - lollmsElfServer.HideBlockingMessage() - return {"status":True} - except Exception as ex: - trace_exception(ex) - lollmsElfServer.HideBlockingMessage() - return {"status":False, 'error':str(ex)} - -@router.get("/start_xtts") -def start_xtts(): - try: - lollmsElfServer.ShowBlockingMessage("Starting xTTS api server\nPlease stand by") - from lollms.services.xtts.lollms_xtts import LollmsXTTS - if lollmsElfServer.tts is None: - voice=lollmsElfServer.config.xtts_current_voice - if voice!="main_voice": - voices_folder = lollmsElfServer.lollms_paths.custom_voices_path - else: - voices_folder = Path(__file__).parent.parent.parent/"services/xtts/voices" - - lollmsElfServer.tts = LollmsXTTS( - lollmsElfServer, - voices_folders=[voices_folder, lollmsElfServer.lollms_paths.custom_voices_path], - freq=lollmsElfServer.config.xtts_freq - ) - lollmsElfServer.HideBlockingMessage() - except Exception as ex: - trace_exception(ex) - lollmsElfServer.HideBlockingMessage() - return {"url": None, "error":f"{ex}"} - @router.post("/upload_voice/") async def upload_voice_file(file: UploadFile = File(...)): diff --git a/lollms/services/xtts/lollms_xtts.py b/lollms/services/xtts/lollms_xtts.py index faa89f1..d5e0ae8 100644 --- a/lollms/services/xtts/lollms_xtts.py +++ b/lollms/services/xtts/lollms_xtts.py @@ -33,6 +33,13 @@ import time from queue import Queue import re +# List of common sampling rates +common_sampling_rates = [8000, 11025, 16000, 22050, 32000, 44100, 48000, 96000, 192000] + +# Function to find the closest sampling rate +def closest_sampling_rate(freq, common_rates): + return min(common_rates, key=lambda x: abs(x - freq)) + class LollmsXTTS(LollmsTTS): def __init__(self, app: LollmsApplication, voices_folders: List[str|Path], freq = 22050): super().__init__("lollms_xtts", app) @@ -148,7 +155,10 @@ class LollmsXTTS(LollmsTTS): if wav is None: # Play any remaining buffered sentences for buffered_wav in buffer: - self.play_obj = sa.play_buffer(buffered_wav.tobytes(), 1, 2, self.freq) + + # Find the closest sampling rate + closest_freq = closest_sampling_rate(self.freq, common_sampling_rates) + self.play_obj = sa.play_buffer(buffered_wav.tobytes(), 1, 2, closest_freq) self.play_obj.wait_done() time.sleep(0.5) # Pause between sentences ASCIIColors.green("Audio done") @@ -157,7 +167,8 @@ class LollmsXTTS(LollmsTTS): buffered_sentences += 1 if buffered_sentences >= 2: for buffered_wav in buffer: - self.play_obj = sa.play_buffer(buffered_wav.tobytes(), 1, 2, self.freq) + closest_freq = closest_sampling_rate(self.freq, common_sampling_rates) + self.play_obj = sa.play_buffer(buffered_wav.tobytes(), 1, 2, closest_freq) self.play_obj.wait_done() time.sleep(0.5) # Pause between sentences buffer = []