72 lines
2.8 KiB
Python
72 lines
2.8 KiB
Python
from __future__ import annotations
|
|||
|
|
|
||
|
|
import io
|
||
|
|
import json
|
||
|
|
import sys
|
||
|
|
import wave
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
from hub_support import server
|
||
|
|
|
||
|
|
VOICES = ["de_DE-solo-medium:0", "en_US-test-high:0", "en_US-test-high:1", "en_US-test-high:2", "en_US-test-high:3"]
|
||
|
|
OPERATOR_VOICE = "en_US-test-high:0"
|
||
|
|
FAKE_PIPER = """
|
||
|
|
import argparse, json, os, sys, wave
|
||
|
|
parser = argparse.ArgumentParser()
|
||
|
|
parser.add_argument("--model", required=True)
|
||
|
|
parser.add_argument("--config", required=True)
|
||
|
|
parser.add_argument("--output-file", required=True)
|
||
|
|
parser.add_argument("--speaker", type=int)
|
||
|
|
args = parser.parse_args()
|
||
|
|
text = sys.stdin.read()
|
||
|
|
with open(os.path.join(os.environ["HOME"], "piper.jsonl"), "a", encoding="utf-8") as log:
|
||
|
|
log.write(json.dumps({"argv": sys.argv[1:], "text": text, "tmp": os.environ["TMPDIR"], "cwd": os.getcwd()}) + "\\n")
|
||
|
|
if "FAIL" in text:
|
||
|
|
sys.exit(3)
|
||
|
|
with wave.open(args.output_file, "wb") as out:
|
||
|
|
out.setnchannels(1)
|
||
|
|
out.setsampwidth(2)
|
||
|
|
out.setframerate(22050)
|
||
|
|
out.writeframes(bytes(2 * len(text)))
|
||
|
|
"""
|
||
|
|
FAKE_WHISPER = """
|
||
|
|
import json, os, sys
|
||
|
|
data = sys.stdin.buffer.read()
|
||
|
|
with open(os.path.join(os.environ["HOME"], "whisper.jsonl"), "a", encoding="utf-8") as log:
|
||
|
|
log.write(json.dumps({"argv": sys.argv[1:], "sha256": __import__("hashlib").sha256(data).hexdigest()}) + "\\n")
|
||
|
|
if b"FAIL" in data:
|
||
|
|
sys.exit(4)
|
||
|
|
print(" hello from the [BLANK_AUDIO] mic")
|
||
|
|
print("second line")
|
||
|
|
"""
|
||
|
|
|
||
|
|
|
||
|
|
def write_engines(base: Path) -> server.Engines:
|
||
|
|
bin_dir, voices, scratch = base / "bin", base / "voices", base / "scratch"
|
||
|
|
for folder in (bin_dir, voices, scratch):
|
||
|
|
folder.mkdir()
|
||
|
|
for name, body in (("piper", FAKE_PIPER), ("whisper-cli", FAKE_WHISPER)):
|
||
|
|
path = bin_dir / name
|
||
|
|
path.write_text(f"#!{sys.executable}\n{body}", encoding="utf-8")
|
||
|
|
path.chmod(0o755)
|
||
|
|
for model, config in (("en_US-test-high", {"num_speakers": 4}), ("de_DE-solo-medium", {"num_speakers": 1}), ("zero", {"num_speakers": 0}), ("bad name!", {"num_speakers": 2})):
|
||
|
|
(voices / f"{model}.onnx").write_bytes(b"onnx")
|
||
|
|
(voices / f"{model}.onnx.json").write_text(json.dumps(config), encoding="utf-8")
|
||
|
|
(voices / "broken.onnx").write_bytes(b"onnx")
|
||
|
|
model = base / "ggml-base.bin"
|
||
|
|
model.write_bytes(b"ggml")
|
||
|
|
return server.Engines(piper=bin_dir / "piper", voices=voices, operator_voice=OPERATOR_VOICE, whisper=bin_dir / "whisper-cli", whisper_model=model, scratch=scratch)
|
||
|
|
|
||
|
|
|
||
|
|
def wav_bytes(channels: int, width: int, rate: int, frames: bytes) -> bytes:
|
||
|
|
buffer = io.BytesIO()
|
||
|
|
with wave.open(buffer, "wb") as writer:
|
||
|
|
writer.setnchannels(channels)
|
||
|
|
writer.setsampwidth(width)
|
||
|
|
writer.setframerate(rate)
|
||
|
|
writer.writeframes(frames)
|
||
|
|
return buffer.getvalue()
|
||
|
|
|
||
|
|
|
||
|
|
def log_rows(path: Path) -> list[dict]:
|
||
|
|
return [json.loads(line) for line in path.read_text(encoding="utf-8").splitlines()] if path.is_file() else []
|