import wave from piper import PiperVoice import pygame import time import os import sys import pyaudio import requests from pathlib import Path from enum import Enum class Language(Enum): en_US = "en_US" de_DE = "de_DE" en_GB = "en_GB" class Quality(Enum): high = 3 medium = 2 low = 1 x_low = 0 class LLM: def __init__(self, model: str, url: str): self.url = url self.model = model class Narrator: def __init__(self, language: Language, name: str, repo: Path, llm: LLM): for quality in Quality: filename = f"{language.name}-{name}-{quality.name}.onnx" self.path = repo / language.name / name / quality.name / filename print("Teste:", self.path) if self.path.exists(): print("Gefunden:", self.path) break else: raise FileNotFoundError("Keine passende Voice-Datei gefunden") print("load voice") self.voice = PiperVoice.load(self.path) # for narrator texts -> connect to LLM print(" create llm") self.llm = llm # Stream audio chunks and play them immediately def read(self, text: str): p = pyaudio.PyAudio() stream = None for audio_chunk in self.voice.synthesize(text): # Stream erst öffnen, wenn erster Chunk da ist if stream is None: stream = p.open( format=p.get_format_from_width(audio_chunk.sample_width), channels=audio_chunk.sample_channels, rate=audio_chunk.sample_rate, output=True ) # Audio sofort abspielen stream.write(audio_chunk.audio_int16_bytes) if stream: stream.stop_stream() stream.close() p.terminate() # play selected audiofile and delete it after playing def read_audio(self, number: int): #setup filename = f"output{number}.wav" pygame.mixer.init() #play next audio sound = pygame.mixer.Sound(filename) channel = sound.play() # wait until the sound has finished playing while channel.get_busy(): time.sleep(0.1) # delete now obsolete file os.remove(filename) pygame.mixer.quit() # create wavefile from text def create_audio(self, texts: list[str]): for i, text in enumerate(texts): filename = f"output{i}.wav" with wave.open(f"output{i}.wav", "wb") as wav_file: self.voice.synthesize_wav(text, wav_file) # create a story from a base text def write_story(self, text, count): session = requests.Session() session.trust_env = False payload = { "model" : self.llm.model, "input": "Formuliere:" + text +" zu einem erzählerischen Sprachtext um. Nicht mehr als " + count + " Sätze. Handlungsaufforderungen sollen klar heraushörbar sein." } response = requests.post(self.llm.url, json=payload, timeout=30) response.raise_for_status() data = response.json() story = data["output"][0]["content"] return story