Upload files to "Sprachausgabe"
This commit is contained in:
parent
712e43cfbe
commit
18a94d2a2f
60
Sprachausgabe/osc_receiver.py
Normal file
60
Sprachausgabe/osc_receiver.py
Normal file
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
06_osc_receiver.py
|
||||
|
||||
Very simple OSC receiver demo.
|
||||
|
||||
It shows that different OSC addresses are mapped
|
||||
to different handler functions.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from pythonosc.dispatcher import Dispatcher
|
||||
from pythonosc.osc_server import BlockingOSCUDPServer
|
||||
from piper_module import Narrator, Language, Quality, LLM
|
||||
|
||||
|
||||
IP = "100.83.246.218"
|
||||
PORT = 9001
|
||||
|
||||
def on_read(address, *args):
|
||||
print(f"on_read() address={address} args={args}")
|
||||
narrator.read(str(args[0]))
|
||||
|
||||
def on_write_story(address, *args):
|
||||
print(f"on_write_story() address={address} args={args}")
|
||||
story = narrator.write_story(str(args[0]), str(args[1]))
|
||||
print(story)
|
||||
|
||||
def on_read_story(address, *args):
|
||||
print(f"on_read_story() address={address} args={args}")
|
||||
story = narrator.write_story(str(args[0]), str(args[1]))
|
||||
narrator.read(story)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
dispatcher = Dispatcher()
|
||||
|
||||
dispatcher.map("/read", on_read)
|
||||
dispatcher.map("/write_story", on_write_story)
|
||||
dispatcher.map("/read_story", on_read_story)
|
||||
|
||||
server = BlockingOSCUDPServer((IP, PORT), dispatcher)
|
||||
|
||||
global narrator
|
||||
llm = LLM("qwen2.5-7b-instruct-1m","http://100.83.153.234:1234/api/v1/chat" )
|
||||
narrator = Narrator(Language.de_DE, "thorsten", Path("C:\Interaktion\WerWolf\piper-voices"), llm)
|
||||
|
||||
print(f"Listening for OSC on {IP}:{PORT}")
|
||||
print("Try sending:")
|
||||
print(" /read")
|
||||
print(" /write_story")
|
||||
print(" /read_story")
|
||||
|
||||
|
||||
server.serve_forever()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
Sprachausgabe/output0.wav
Normal file
BIN
Sprachausgabe/output0.wav
Normal file
Binary file not shown.
126
Sprachausgabe/piper_module.py
Normal file
126
Sprachausgabe/piper_module.py
Normal file
@ -0,0 +1,126 @@
|
||||
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
|
||||
Loading…
x
Reference in New Issue
Block a user