126 lines
3.3 KiB
Python

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