first commit
This commit is contained in:
34
.dockerignore
Normal file
34
.dockerignore
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Git / version control
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
# Virtual environment
|
||||||
|
.venv
|
||||||
|
venv/
|
||||||
|
.env/
|
||||||
|
|
||||||
|
# IDE / Editor folders
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Python cache
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
|
||||||
|
# Build artifacts
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
*.egg-info
|
||||||
|
|
||||||
|
# Test artifacts
|
||||||
|
.pytest_cache/
|
||||||
|
.coverage
|
||||||
|
|
||||||
|
# Docker files
|
||||||
|
Dockerfile
|
||||||
|
docker-compose.yml
|
||||||
|
|
||||||
|
# Local environment settings
|
||||||
|
.env
|
||||||
7
.env.example
Normal file
7
.env.example
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Comma-separated list of engines to activate.
|
||||||
|
# Available options (potentially): piper, styletts, f5_tts, chattts
|
||||||
|
ACTIVE_ENGINES='["piper", "styletts"]'
|
||||||
|
|
||||||
|
# Server configuration
|
||||||
|
HOST=0.0.0.0
|
||||||
|
PORT=8000
|
||||||
52
.gitignore
vendored
Normal file
52
.gitignore
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# .gitignore für Python-Projekt
|
||||||
|
# Version: v1.1
|
||||||
|
# Erstellt: 2025-07-25
|
||||||
|
|
||||||
|
# Bytecode & Caches
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# Virtuelle Umgebungen
|
||||||
|
venv/
|
||||||
|
.env/
|
||||||
|
.virtualenv/
|
||||||
|
.venv/
|
||||||
|
|
||||||
|
# IDE/Editor
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Test- & Coverage-Dateien
|
||||||
|
htmlcov/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.pytest_cache/
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
|
||||||
|
# Build & Distribution
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
*.egg-info/
|
||||||
|
.eggs/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
|
||||||
|
# Logs & Temp
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Umgebungsvariablen
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Sprachmodelle (TTS)
|
||||||
|
tts_models/
|
||||||
|
voice_models/
|
||||||
|
*.pt
|
||||||
|
*.onnx
|
||||||
|
*.bin
|
||||||
|
*.safetensors
|
||||||
|
asset/
|
||||||
42
Dockerfile
Normal file
42
Dockerfile
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# Stage 1: Builder
|
||||||
|
FROM python:3.11 as builder
|
||||||
|
WORKDIR /opt/venv
|
||||||
|
|
||||||
|
# Create a virtual environment and install dependencies
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN python -m venv . && . /opt/venv/bin/activate && pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# Stage 2: Runner (The final image)
|
||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
# Install system dependencies needed at runtime
|
||||||
|
# ffmpeg is required for audio conversion
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
ffmpeg \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Create an unprivileged user
|
||||||
|
RUN useradd --create-home --shell /bin/bash appuser
|
||||||
|
|
||||||
|
# Set working directory for the application code
|
||||||
|
WORKDIR /home/appuser
|
||||||
|
|
||||||
|
# Copy the virtual environment from the builder stage
|
||||||
|
COPY --from=builder /opt/venv /opt/venv
|
||||||
|
|
||||||
|
# Copy the application code into the container
|
||||||
|
COPY app/ ./app
|
||||||
|
|
||||||
|
# Set the PATH to include the virtual environment's bin directory
|
||||||
|
ENV PATH="/opt/venv/bin:$PATH"
|
||||||
|
|
||||||
|
# Expose the application port
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# Run as the unprivileged user
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
# Command to run the application using gunicorn for production
|
||||||
|
CMD ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "-w", "2", "-b", "0.0.0.0:8000", "app.main:app"]
|
||||||
|
|
||||||
|
|
||||||
150
Makefile
Normal file
150
Makefile
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
# --- Configuration ---
|
||||||
|
IMAGE_NAME := audio-engine-hub
|
||||||
|
TAG := latest
|
||||||
|
# Default internal application port (exposed to Traefik)
|
||||||
|
PORT := 8000
|
||||||
|
# Traefik's external entrypoints
|
||||||
|
TRAEFIK_WEB_PORT := 80
|
||||||
|
TRAEFIK_DASHBOARD_PORT := 8080
|
||||||
|
|
||||||
|
# --- Port Checking Functions ---
|
||||||
|
|
||||||
|
# Function to check if required Traefik ports are free
|
||||||
|
# Exits if any are busy, does not suggest alternatives.
|
||||||
|
define check_traefik_ports_free
|
||||||
|
@echo "Checking if Traefik ports ($(TRAEFIK_WEB_PORT}, $(TRAEFIK_DASHBOARD_PORT}) are free..." >&2
|
||||||
|
@local busy_ports=""; \
|
||||||
|
if ss -tulnp | grep ":$(TRAEFIK_WEB_PORT) " > /dev/null; then \
|
||||||
|
busy_ports="$$busy_ports $(TRAEFIK_WEB_PORT)"; \
|
||||||
|
fi; \
|
||||||
|
if ss -tulnp | grep ":$(TRAEFIK_DASHBOARD_PORT) " > /dev/null; then \
|
||||||
|
busy_ports="$$busy_ports $(TRAEFIK_DASHBOARD_PORT)"; \
|
||||||
|
fi; \
|
||||||
|
if [ -n "$$busy_ports" ]; then \
|
||||||
|
echo "ERROR: The following Traefik ports are already in use: $$busy_ports. Please free them or stop Traefik if already running." >&2; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
@echo "Traefik ports are free." >&2
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Function to find next free host port for the app and ask user
|
||||||
|
# This function will echo the chosen port if successful, or exit with an error.
|
||||||
|
define check_app_port_free
|
||||||
|
@local start_port=$(PORT); \
|
||||||
|
local found_port=$$start_port; \
|
||||||
|
local is_free=false; \
|
||||||
|
\
|
||||||
|
if ! ss -tulnp | grep ":$$start_port " > /dev/null; then \
|
||||||
|
echo "$$start_port"; \
|
||||||
|
exit 0; \
|
||||||
|
fi; \
|
||||||
|
\
|
||||||
|
echo "Port $$start_port is busy. Searching for a free port for the app..." >&2; \
|
||||||
|
while ! $$is_free; do \
|
||||||
|
if ! ss -tulnp | grep ":$$found_port " > /dev/null; then \
|
||||||
|
is_free=true; \
|
||||||
|
else \
|
||||||
|
((found_port++)); \
|
||||||
|
if [ "$$found_port" -gt 65535 ]; then \
|
||||||
|
echo "ERROR: No free ports found up to 65535. Aborting." >&2; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
fi; \
|
||||||
|
done; \
|
||||||
|
\
|
||||||
|
echo "Port $$start_port is busy. I found port $$found_port to be free for the app." >&2; \
|
||||||
|
read -p "Do you want to use port $$found_port for the app? (y/N): " choice; \
|
||||||
|
case "$$choice" in \
|
||||||
|
y|Y ) \
|
||||||
|
echo "$$found_port"; \
|
||||||
|
;; \
|
||||||
|
* ) \
|
||||||
|
echo "Operation cancelled by user." >&2; \
|
||||||
|
exit 1; \
|
||||||
|
;; \
|
||||||
|
esac;
|
||||||
|
endef
|
||||||
|
|
||||||
|
# --- Docker Commands ---
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
@echo "Building Docker image: $(IMAGE_NAME):$(TAG)"
|
||||||
|
docker build -t $(IMAGE_NAME):$(TAG) .
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run:
|
||||||
|
@export SELECTED_HOST_PORT=$$(bash -c 'func() { $(check_app_port_free) }; func') && \
|
||||||
|
echo "Using host port $$SELECTED_HOST_PORT for single app container" && \
|
||||||
|
docker run -d -p $$SELECTED_HOST_PORT:$(PORT) --name $(IMAGE_NAME) $(IMAGE_NAME):$(TAG)
|
||||||
|
|
||||||
|
.PHONY: stop
|
||||||
|
stop:
|
||||||
|
@echo "Stopping Docker container: $(IMAGE_NAME)"
|
||||||
|
docker stop $(IMAGE_NAME) || true
|
||||||
|
docker rm $(IMAGE_NAME) || true
|
||||||
|
|
||||||
|
.PHONY: logs
|
||||||
|
logs:
|
||||||
|
@echo "Showing logs for container: $(IMAGE_NAME)"
|
||||||
|
docker logs -f $(IMAGE_NAME)
|
||||||
|
|
||||||
|
.PHONY: shell
|
||||||
|
shell:
|
||||||
|
@echo "Accessing shell in container: $(IMAGE_NAME)"
|
||||||
|
docker exec -it $(IMAGE_NAME) /bin/bash
|
||||||
|
|
||||||
|
# --- Docker Compose Commands ---
|
||||||
|
|
||||||
|
.PHONY: up
|
||||||
|
up:
|
||||||
|
$(call check_traefik_ports_free) # Check Traefik ports before starting
|
||||||
|
@echo "Starting development environment with Docker Compose (Traefik enabled)..."
|
||||||
|
docker-compose up --build -d
|
||||||
|
|
||||||
|
.PHONY: down
|
||||||
|
down:
|
||||||
|
@echo "Stopping development environment with Docker Compose..."
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# --- Image Management ---
|
||||||
|
|
||||||
|
.PHONY: tag
|
||||||
|
tag:
|
||||||
|
@echo "Tagging image $(IMAGE_NAME):$(TAG) as $(REGISTRY)/$(IMAGE_NAME):$(TAG)"
|
||||||
|
docker tag $(IMAGE_NAME):$(TAG) $(REGISTRY)/$(IMAGE_NAME):$(TAG)
|
||||||
|
|
||||||
|
.PHONY: push
|
||||||
|
push: tag
|
||||||
|
@echo "Pushing image $(REGISTRY)/$(IMAGE_NAME):$(TAG) to registry..."
|
||||||
|
docker push $(REGISTRY)/$(IMAGE_NAME):$(TAG)
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
@echo "Running tests with coverage..."
|
||||||
|
pytest --cov=. app/ tests/
|
||||||
|
|
||||||
|
# --- Cleanup ---
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
@echo "Cleaning up stopped containers and dangling images..."
|
||||||
|
docker container prune -f
|
||||||
|
docker image prune -f
|
||||||
|
|
||||||
|
.PHONY: help
|
||||||
|
help:
|
||||||
|
@echo "Available commands:"
|
||||||
|
@echo " build - Build the Docker image"
|
||||||
|
@echo " run - Run the Docker container (single app, no Traefik)"
|
||||||
|
@echo " stop - Stop and remove the Docker container"
|
||||||
|
@echo " logs - Follow the logs of the container"
|
||||||
|
@echo " shell - Get a shell inside the running container"
|
||||||
|
@echo " up - Start the dev environment with docker-compose (with Traefik)"
|
||||||
|
@echo " down - Stop the dev environment with docker-compose"
|
||||||
|
@echo " tag - Tag the image for a registry"
|
||||||
|
@echo " push - Push the image to a registry (after tagging)"
|
||||||
|
@echo " clean - Clean up unused containers and images"
|
||||||
|
@echo " help - Show this help message"
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
222
README.md
Normal file
222
README.md
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
"""
|
||||||
|
NovaAi – TTS-Engine-Hub
|
||||||
|
main.py
|
||||||
|
Version: v0.0.7
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Adds /speakers endpoint to list speakers for a given engine/model.
|
||||||
|
Returns list of available speakers from engine.list_voices(model).
|
||||||
|
All previous endpoints and logic included.
|
||||||
|
|
||||||
|
Author: Abby (ChatGPT)
|
||||||
|
Date: 2025-07-23
|
||||||
|
Canvas: main.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
from fastapi import FastAPI, HTTPException, Query
|
||||||
|
from fastapi.responses import JSONResponse, FileResponse
|
||||||
|
from pydantic import BaseModel
|
||||||
|
import os
|
||||||
|
import base64
|
||||||
|
from engines.piper import PiperEngine
|
||||||
|
from engines.styletts import StyleTTSEngine
|
||||||
|
from engines.chattts import ChatTTSEngine
|
||||||
|
import shutil
|
||||||
|
import uuid
|
||||||
|
import hashlib
|
||||||
|
import tempfile
|
||||||
|
import ffmpeg
|
||||||
|
|
||||||
|
app = FastAPI(
|
||||||
|
title="NovaAi – TTS-Engine-Hub",
|
||||||
|
version="0.0.7",
|
||||||
|
description="Local-first, modular multi-engine TTS server for your homelab and automation."
|
||||||
|
)
|
||||||
|
|
||||||
|
ENGINE_REGISTRY = {
|
||||||
|
"piper": PiperEngine(),
|
||||||
|
"styletts": StyleTTSEngine(),
|
||||||
|
"chattts": ChatTTSEngine(),
|
||||||
|
}
|
||||||
|
|
||||||
|
AUDIO_OUT_DIR = "/tmp/tts_output"
|
||||||
|
CACHE_DIR = "/tmp/tts_cache"
|
||||||
|
os.makedirs(AUDIO_OUT_DIR, exist_ok=True)
|
||||||
|
os.makedirs(CACHE_DIR, exist_ok=True)
|
||||||
|
|
||||||
|
class TTSRequest(BaseModel):
|
||||||
|
text: str
|
||||||
|
engine: str
|
||||||
|
model: str = None
|
||||||
|
speaker: str = None
|
||||||
|
format: str = "ogg"
|
||||||
|
chunking: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
def build_cache_key(req: TTSRequest) -> str:
|
||||||
|
data = f"{req.text}|{req.engine}|{req.model}|{req.speaker}|{req.format}|{req.chunking}"
|
||||||
|
return hashlib.sha256(data.encode()).hexdigest()
|
||||||
|
|
||||||
|
def chunk_text(text, maxlen=250):
|
||||||
|
import re
|
||||||
|
sentences = re.split(r'([.!?]\s)', text)
|
||||||
|
chunks = []
|
||||||
|
buf = ""
|
||||||
|
for s in sentences:
|
||||||
|
if len(buf) + len(s) > maxlen:
|
||||||
|
if buf:
|
||||||
|
chunks.append(buf.strip())
|
||||||
|
buf = ""
|
||||||
|
buf += s
|
||||||
|
if buf.strip():
|
||||||
|
chunks.append(buf.strip())
|
||||||
|
return [c for c in chunks if c.strip()]
|
||||||
|
|
||||||
|
def concat_audio(files, fmt):
|
||||||
|
if len(files) == 1:
|
||||||
|
return files[0]
|
||||||
|
output_file = tempfile.mktemp(suffix=f'.{fmt}', prefix="chunked_", dir="/tmp")
|
||||||
|
if fmt == "wav":
|
||||||
|
import wave
|
||||||
|
data = []
|
||||||
|
params = None
|
||||||
|
for f in files:
|
||||||
|
with wave.open(f, 'rb') as wf:
|
||||||
|
if params is None:
|
||||||
|
params = wf.getparams()
|
||||||
|
data.append(wf.readframes(wf.getnframes()))
|
||||||
|
with wave.open(output_file, 'wb') as wf:
|
||||||
|
wf.setparams(params)
|
||||||
|
for d in data:
|
||||||
|
wf.writeframes(d)
|
||||||
|
else:
|
||||||
|
with tempfile.NamedTemporaryFile("w", delete=False) as tf:
|
||||||
|
for f in files:
|
||||||
|
tf.write(f"file '{f}'\n")
|
||||||
|
tf.flush()
|
||||||
|
(
|
||||||
|
ffmpeg
|
||||||
|
.input(tf.name, format='concat', safe=0)
|
||||||
|
.output(output_file, acodec='copy')
|
||||||
|
.run(overwrite_output=True, quiet=True)
|
||||||
|
)
|
||||||
|
os.unlink(tf.name)
|
||||||
|
return output_file
|
||||||
|
|
||||||
|
@app.post("/tts")
|
||||||
|
def tts_endpoint(req: TTSRequest, as_base64: bool = Query(False, alias="as")):
|
||||||
|
cache_key = build_cache_key(req)
|
||||||
|
ext = f'.{req.format.lower()}'
|
||||||
|
cached_file = os.path.join(CACHE_DIR, f"tts_{cache_key}{ext}")
|
||||||
|
if os.path.isfile(cached_file):
|
||||||
|
fname = f"tts_{cache_key}{ext}"
|
||||||
|
dest = os.path.join(AUDIO_OUT_DIR, fname)
|
||||||
|
shutil.copy(cached_file, dest)
|
||||||
|
if as_base64:
|
||||||
|
with open(cached_file, "rb") as f:
|
||||||
|
audio_b64 = base64.b64encode(f.read()).decode("utf-8")
|
||||||
|
return JSONResponse({
|
||||||
|
"engine": req.engine,
|
||||||
|
"model": req.model,
|
||||||
|
"speaker": req.speaker,
|
||||||
|
"format": req.format,
|
||||||
|
"audio_base64": audio_b64,
|
||||||
|
"chunking": req.chunking,
|
||||||
|
"message": "Audio from cache, base64 included"
|
||||||
|
})
|
||||||
|
return JSONResponse({
|
||||||
|
"engine": req.engine,
|
||||||
|
"model": req.model,
|
||||||
|
"speaker": req.speaker,
|
||||||
|
"format": req.format,
|
||||||
|
"audio_url": f"/audio/{fname}",
|
||||||
|
"cached": True,
|
||||||
|
"chunking": req.chunking,
|
||||||
|
"message": "Audio served from cache. Download from audio_url"
|
||||||
|
})
|
||||||
|
engine = ENGINE_REGISTRY.get(req.engine.lower())
|
||||||
|
if not engine:
|
||||||
|
raise HTTPException(status_code=404, detail=f"Engine '{req.engine}' not found.")
|
||||||
|
if req.chunking and len(req.text) > 250:
|
||||||
|
chunks = chunk_text(req.text, maxlen=250)
|
||||||
|
chunk_files = [engine.synthesize(c, speaker=req.speaker, model=req.model, fmt=req.format) for c in chunks]
|
||||||
|
audio_path = concat_audio(chunk_files, req.format.lower())
|
||||||
|
else:
|
||||||
|
audio_path = engine.synthesize(req.text, speaker=req.speaker, model=req.model, fmt=req.format)
|
||||||
|
shutil.copy(audio_path, cached_file)
|
||||||
|
fname = f"tts_{cache_key}{ext}"
|
||||||
|
dest = os.path.join(AUDIO_OUT_DIR, fname)
|
||||||
|
shutil.copy(audio_path, dest)
|
||||||
|
if as_base64:
|
||||||
|
with open(cached_file, "rb") as f:
|
||||||
|
audio_b64 = base64.b64encode(f.read()).decode("utf-8")
|
||||||
|
return JSONResponse({
|
||||||
|
"engine": req.engine,
|
||||||
|
"model": req.model,
|
||||||
|
"speaker": req.speaker,
|
||||||
|
"format": req.format,
|
||||||
|
"audio_base64": audio_b64,
|
||||||
|
"chunking": req.chunking,
|
||||||
|
"message": "Audio from synth, base64 included"
|
||||||
|
})
|
||||||
|
return JSONResponse({
|
||||||
|
"engine": req.engine,
|
||||||
|
"model": req.model,
|
||||||
|
"speaker": req.speaker,
|
||||||
|
"format": req.format,
|
||||||
|
"audio_url": f"/audio/{fname}",
|
||||||
|
"cached": False,
|
||||||
|
"chunking": req.chunking,
|
||||||
|
"message": "Synthesized new audio. Download from audio_url"
|
||||||
|
})
|
||||||
|
|
||||||
|
@app.get("/audio/{filename}")
|
||||||
|
def audio_file(filename: str):
|
||||||
|
fpath = os.path.join(AUDIO_OUT_DIR, filename)
|
||||||
|
if not os.path.isfile(fpath):
|
||||||
|
raise HTTPException(status_code=404, detail="Audio file not found")
|
||||||
|
media_type = "audio/wav" if filename.endswith(".wav") else (
|
||||||
|
"audio/ogg" if filename.endswith(".ogg") else "audio/mpeg"
|
||||||
|
)
|
||||||
|
return FileResponse(fpath, media_type=media_type, filename=filename)
|
||||||
|
|
||||||
|
@app.get("/engines")
|
||||||
|
def engines_endpoint():
|
||||||
|
engines = {}
|
||||||
|
for name, engine in ENGINE_REGISTRY.items():
|
||||||
|
engines[name] = engine.healthcheck()
|
||||||
|
return engines
|
||||||
|
|
||||||
|
@app.get("/models")
|
||||||
|
def models_endpoint():
|
||||||
|
result = {}
|
||||||
|
for name, engine in ENGINE_REGISTRY.items():
|
||||||
|
try:
|
||||||
|
result[name] = engine.list_models()
|
||||||
|
except Exception as e:
|
||||||
|
result[name] = []
|
||||||
|
return result
|
||||||
|
|
||||||
|
@app.get("/speakers")
|
||||||
|
def speakers_endpoint(engine: str, model: str = None):
|
||||||
|
e = ENGINE_REGISTRY.get(engine.lower())
|
||||||
|
if not e:
|
||||||
|
raise HTTPException(status_code=404, detail=f"Engine '{engine}' not found.")
|
||||||
|
try:
|
||||||
|
speakers = e.list_voices(model)
|
||||||
|
except Exception as err:
|
||||||
|
speakers = []
|
||||||
|
return {"engine": engine, "model": model, "speakers": speakers}
|
||||||
|
|
||||||
|
@app.get("/version")
|
||||||
|
def version():
|
||||||
|
return {"version": app.version}
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
def health():
|
||||||
|
status = {name: engine.healthcheck()["status"] for name, engine in ENGINE_REGISTRY.items()}
|
||||||
|
return {"status": status, "detail": "API and engines loaded"}
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import uvicorn
|
||||||
|
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
|
||||||
0
app/__init__.py
Normal file
0
app/__init__.py
Normal file
204
app/main.py
Normal file
204
app/main.py
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
"""
|
||||||
|
NovaAi – TTS-Engine-Hub
|
||||||
|
main.py
|
||||||
|
Version: v0.1.0
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Refactored main.py: uses utils modules for chunking, concat, and cache key generation.
|
||||||
|
All endpoints, features, and logic as before, but cleaner and more modular.
|
||||||
|
|
||||||
|
Author: Abby (ChatGPT)
|
||||||
|
Date: 2025-07-23
|
||||||
|
Canvas: main.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from fastapi import FastAPI, HTTPException, Query
|
||||||
|
from fastapi.responses import JSONResponse, FileResponse
|
||||||
|
from pydantic import BaseModel
|
||||||
|
import os
|
||||||
|
import base64
|
||||||
|
import shutil
|
||||||
|
import uvicorn
|
||||||
|
|
||||||
|
from config import settings
|
||||||
|
from engines.piper import PiperEngine
|
||||||
|
from engines.styletts import StyleTTSEngine
|
||||||
|
from engines.chattts import ChatTTSEngine
|
||||||
|
from engines.f5_tts import F5TTSEngine
|
||||||
|
from utils.text import chunk_text
|
||||||
|
from utils.audio import concat_audio
|
||||||
|
from utils.cache import build_cache_key
|
||||||
|
|
||||||
|
# --- Master list of all possible engine classes. ---
|
||||||
|
ALL_ENGINES = {
|
||||||
|
"piper": PiperEngine,
|
||||||
|
"styletts": StyleTTSEngine,
|
||||||
|
"chattts": ChatTTSEngine,
|
||||||
|
"f5-tts": F5TTSEngine,
|
||||||
|
}
|
||||||
|
|
||||||
|
def create_app():
|
||||||
|
app = FastAPI(
|
||||||
|
title="NovaAi – TTS-Engine-Hub",
|
||||||
|
version="0.3.0",
|
||||||
|
description="Local-first, modular multi-engine TTS server for your homelab and automation."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Dynamically build the registry of active engines based on settings.
|
||||||
|
# This registry is local to the app instance created by this function.
|
||||||
|
app.ENGINE_REGISTRY = {}
|
||||||
|
for engine_name in settings.ACTIVE_ENGINES:
|
||||||
|
if engine_name in ALL_ENGINES:
|
||||||
|
print(f"Activating engine: {engine_name}")
|
||||||
|
app.ENGINE_REGISTRY[engine_name] = ALL_ENGINES[engine_name]()
|
||||||
|
else:
|
||||||
|
print(f"Warning: Engine '{engine_name}' requested in config but not found in ALL_ENGINES.")
|
||||||
|
|
||||||
|
# Ensure the audio asset/cache directory exists.
|
||||||
|
os.makedirs(settings.AUDIO_CACHE_DIR, exist_ok=True)
|
||||||
|
|
||||||
|
class TTSRequest(BaseModel):
|
||||||
|
text: str
|
||||||
|
engine: str
|
||||||
|
model: str = None
|
||||||
|
speaker: str = None
|
||||||
|
format: str = "ogg"
|
||||||
|
chunking: bool = False
|
||||||
|
|
||||||
|
@app.post("/tts")
|
||||||
|
async def tts_endpoint(req: TTSRequest, as_base64: bool = Query(False, alias="as")):
|
||||||
|
# --- 1. Check for engine and handle health ---
|
||||||
|
engine = app.ENGINE_REGISTRY.get(req.engine.lower())
|
||||||
|
if not engine:
|
||||||
|
raise HTTPException(status_code=404, detail=f"Engine '{req.engine}' not found.")
|
||||||
|
|
||||||
|
health = engine.healthcheck()
|
||||||
|
if health.get("status") != "ok":
|
||||||
|
raise HTTPException(status_code=503, detail=f"Engine '{req.engine}' is not available. Status: {health.get('status')}")
|
||||||
|
|
||||||
|
# --- 2. Input validation ---
|
||||||
|
available_models = engine.list_models()
|
||||||
|
if req.model and available_models and req.model not in available_models:
|
||||||
|
raise HTTPException(status_code=400, detail=f"Model '{req.model}' not found for engine '{req.engine}'. Available models: {available_models}")
|
||||||
|
|
||||||
|
available_voices = engine.list_voices(req.model)
|
||||||
|
if req.speaker and available_voices and req.speaker not in available_voices:
|
||||||
|
raise HTTPException(status_code=400, detail=f"Speaker '{req.speaker}' not found for model '{req.model}'. Available speakers: {available_voices}")
|
||||||
|
|
||||||
|
# --- 3. Check cache ---
|
||||||
|
cache_key = build_cache_key(req)
|
||||||
|
ext = f'.{req.format.lower()}'
|
||||||
|
output_filename = f"tts_{cache_key}{ext}"
|
||||||
|
output_filepath = os.path.join(settings.AUDIO_CACHE_DIR, output_filename)
|
||||||
|
|
||||||
|
is_cached = await asyncio.to_thread(os.path.isfile, output_filepath)
|
||||||
|
if is_cached:
|
||||||
|
if as_base64:
|
||||||
|
audio_bytes = await asyncio.to_thread(lambda: open(output_filepath, "rb").read())
|
||||||
|
audio_b64 = base64.b64encode(audio_bytes).decode("utf-8")
|
||||||
|
return JSONResponse({
|
||||||
|
"engine": req.engine, "model": req.model, "speaker": req.speaker, "format": req.format,
|
||||||
|
"audio_base64": audio_b64, "chunking": req.chunking, "message": "Audio from cache, base64 included"
|
||||||
|
})
|
||||||
|
return JSONResponse({
|
||||||
|
"engine": req.engine, "model": req.model, "speaker": req.speaker, "format": req.format,
|
||||||
|
"audio_url": f"/audio/{output_filename}", "cached": True, "chunking": req.chunking,
|
||||||
|
"message": "Audio served from cache. Download from audio_url"
|
||||||
|
})
|
||||||
|
|
||||||
|
# --- 4. Synthesize audio ---
|
||||||
|
try:
|
||||||
|
if req.chunking and len(req.text) > 250:
|
||||||
|
chunks = chunk_text(req.text, maxlen=250)
|
||||||
|
synthesis_tasks = [engine.synthesize(c, speaker=req.speaker, model=req.model, fmt=req.format) for c in chunks]
|
||||||
|
chunk_files = await asyncio.gather(*synthesis_tasks)
|
||||||
|
synthesized_path = await asyncio.to_thread(concat_audio, chunk_files, req.format.lower())
|
||||||
|
else:
|
||||||
|
synthesized_path = await engine.synthesize(req.text, speaker=req.speaker, model=req.model, fmt=req.format)
|
||||||
|
except (RuntimeError, ValueError, FileNotFoundError) as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Error during synthesis: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {e}")
|
||||||
|
|
||||||
|
# --- 5. Cache and return result ---
|
||||||
|
await asyncio.to_thread(shutil.copy, synthesized_path, output_filepath)
|
||||||
|
|
||||||
|
# If the synth created a temp file in a different directory, clean it up
|
||||||
|
if settings.AUDIO_CACHE_DIR not in os.path.abspath(synthesized_path):
|
||||||
|
await asyncio.to_thread(os.remove, synthesized_path)
|
||||||
|
|
||||||
|
if as_base64:
|
||||||
|
audio_bytes = await asyncio.to_thread(lambda: open(output_filepath, "rb").read())
|
||||||
|
audio_b64 = base64.b64encode(audio_bytes).decode("utf-8")
|
||||||
|
return JSONResponse({
|
||||||
|
"engine": req.engine, "model": req.model, "speaker": req.speaker, "format": req.format,
|
||||||
|
"audio_base64": audio_b64, "chunking": req.chunking, "message": "Audio from synth, base64 included"
|
||||||
|
})
|
||||||
|
|
||||||
|
return JSONResponse({
|
||||||
|
"engine": req.engine, "model": req.model, "speaker": req.speaker, "format": req.format,
|
||||||
|
"audio_url": f"/audio/{output_filename}", "cached": False, "chunking": req.chunking,
|
||||||
|
"message": "Synthesized new audio. Download from audio_url"
|
||||||
|
})
|
||||||
|
|
||||||
|
@app.get("/audio/{filename}")
|
||||||
|
async def audio_file(filename: str): # Made async
|
||||||
|
fpath = os.path.join(settings.AUDIO_CACHE_DIR, filename)
|
||||||
|
if not await asyncio.to_thread(os.path.isfile, fpath) or not await asyncio.to_thread(lambda: fpath.startswith(os.path.abspath(settings.AUDIO_CACHE_DIR))):
|
||||||
|
raise HTTPException(status_code=404, detail="Audio file not found")
|
||||||
|
media_type = "audio/wav" if filename.endswith(".wav") else (
|
||||||
|
"audio/ogg" if filename.endswith(".ogg") else "audio/mpeg"
|
||||||
|
)
|
||||||
|
return FileResponse(fpath, media_type=media_type, filename=filename)
|
||||||
|
|
||||||
|
@app.get("/engines")
|
||||||
|
def engines_endpoint():
|
||||||
|
engines = {}
|
||||||
|
for name, engine in app.ENGINE_REGISTRY.items():
|
||||||
|
engines[name] = engine.healthcheck()
|
||||||
|
return engines
|
||||||
|
|
||||||
|
@app.get("/models")
|
||||||
|
def models_endpoint():
|
||||||
|
result = {}
|
||||||
|
for name, engine in app.ENGINE_REGISTRY.items():
|
||||||
|
try:
|
||||||
|
result[name] = engine.list_models()
|
||||||
|
except Exception as e:
|
||||||
|
result[name] = {"error": str(e)}
|
||||||
|
return result
|
||||||
|
|
||||||
|
@app.get("/speakers")
|
||||||
|
def speakers_endpoint(engine: str, model: str = None):
|
||||||
|
e = app.ENGINE_REGISTRY.get(engine.lower())
|
||||||
|
if not e:
|
||||||
|
raise HTTPException(status_code=404, detail=f"Engine '{engine}' not found.")
|
||||||
|
try:
|
||||||
|
speakers = e.list_voices(model)
|
||||||
|
except Exception as err:
|
||||||
|
speakers = []
|
||||||
|
return {"engine": engine, "model": model, "speakers": speakers}
|
||||||
|
|
||||||
|
@app.get("/version")
|
||||||
|
def version():
|
||||||
|
return {"version": app.version}
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
def health():
|
||||||
|
status = {name: engine.healthcheck()["status"] for name, engine in app.ENGINE_REGISTRY.items()}
|
||||||
|
return {"status": status, "detail": "API and engines loaded"}
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
# If main.py is executed directly, create the app and run uvicorn
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app_instance = create_app()
|
||||||
|
uvicorn.run(
|
||||||
|
app_instance, # Pass the app instance
|
||||||
|
host=settings.HOST,
|
||||||
|
port=settings.PORT,
|
||||||
|
reload=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
25
config.py
Normal file
25
config.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
"""
|
||||||
|
NovaAi – TTS-Engine-Hub
|
||||||
|
config.py
|
||||||
|
Version: v0.0.1
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Centralized configuration management using pydantic-settings.
|
||||||
|
Loads settings from a .env file and environment variables.
|
||||||
|
"""
|
||||||
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
from typing import List, Set
|
||||||
|
|
||||||
|
class Settings(BaseSettings):
|
||||||
|
# Server Configuration
|
||||||
|
HOST: str = "0.0.0.0"
|
||||||
|
PORT: int = 8000
|
||||||
|
|
||||||
|
# Application Configuration
|
||||||
|
ACTIVE_ENGINES: Set[str] = {"piper"}
|
||||||
|
ASSET_DIR: str = "asset"
|
||||||
|
AUDIO_CACHE_DIR: str = "asset/audio"
|
||||||
|
|
||||||
|
model_config = SettingsConfigDict(env_file=".env", env_file_encoding='utf-8')
|
||||||
|
|
||||||
|
settings = Settings()
|
||||||
44
docker-compose.yml
Normal file
44
docker-compose.yml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
container_name: audio_engine_hub_app
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
# Mount local app directory for hot-reloading in dev
|
||||||
|
- ./app:/home/appuser/app
|
||||||
|
# Mount models directory to provide models to the container
|
||||||
|
- ./models:/home/appuser/models
|
||||||
|
# Mount asset directory to persist generated audio files
|
||||||
|
- ./asset:/home/appuser/asset
|
||||||
|
command: ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.app-router.rule=Host(`localhost`)"
|
||||||
|
- "traefik.http.routers.app-router.entrypoints=web"
|
||||||
|
- "traefik.http.services.app-service.loadbalancer.server.port=8000"
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
|
||||||
|
traefik:
|
||||||
|
image: "traefik:v2.10"
|
||||||
|
container_name: traefik_proxy
|
||||||
|
command:
|
||||||
|
- "--api.dashboard=true"
|
||||||
|
- "--providers.docker=true"
|
||||||
|
- "--providers.docker.exposedbydefault=false"
|
||||||
|
- "--entrypoints.web.address=:80"
|
||||||
|
ports:
|
||||||
|
- "80:80" # The HTTP port Traefik listens on
|
||||||
|
- "8080:8080" # The Traefik Web UI (Dashboard)
|
||||||
|
volumes:
|
||||||
|
- "/var/run/docker.sock:/var/run/docker.sock:ro" # Traefik needs access to the Docker daemon
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
|
||||||
|
networks:
|
||||||
|
web:
|
||||||
|
external: false
|
||||||
48
engines/chattts.py
Normal file
48
engines/chattts.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
"""
|
||||||
|
NovaAi – TTS-Engine-Hub
|
||||||
|
engines/chattts.py
|
||||||
|
Version: v0.0.1
|
||||||
|
|
||||||
|
Description:
|
||||||
|
ChatTTS engine adapter.
|
||||||
|
Implements TTSEngineBase interface for ChatTTS integration (dummy implementation).
|
||||||
|
|
||||||
|
Author: Abby (ChatGPT)
|
||||||
|
Date: 2025-07-23
|
||||||
|
Canvas: chattts.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from engines.engine_base import TTSEngineBase
|
||||||
|
|
||||||
|
class ChatTTSEngine(TTSEngineBase):
|
||||||
|
async def synthesize(self, text: str, speaker: str = None, model: str = None, fmt: str = "mp3"):
|
||||||
|
# Dummy implementation: returns an empty string as it doesn't produce a file.
|
||||||
|
print("Warning: ChatTTSEngine.synthesize is a dummy and does not produce audio.")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def list_models(self):
|
||||||
|
# Dummy implementation
|
||||||
|
return ["chattts-v1", "chattts-v2"]
|
||||||
|
|
||||||
|
def list_voices(self, model: str = None):
|
||||||
|
# Dummy implementation
|
||||||
|
return ["default", "custom1", "custom2"]
|
||||||
|
|
||||||
|
def healthcheck(self):
|
||||||
|
# Dummy implementation
|
||||||
|
return {"status": "ok", "engine": "chattts"}
|
||||||
|
|
||||||
|
async def selftest(self):
|
||||||
|
# Dummy implementation
|
||||||
|
return {"selftest": True, "engine": "chattts"}
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
async def main():
|
||||||
|
engine = ChatTTSEngine()
|
||||||
|
print("Selftest:", await engine.selftest())
|
||||||
|
print("Models:", engine.list_models())
|
||||||
|
print("Voices:", engine.list_voices())
|
||||||
|
print("Healthcheck:", engine.healthcheck())
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
45
engines/engine_base.py
Normal file
45
engines/engine_base.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
"""
|
||||||
|
NovaAi – TTS-Engine-Hub
|
||||||
|
engine_base.py
|
||||||
|
Version: v0.0.1
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Abstract base class for all TTS engine modules.
|
||||||
|
Defines the required interface for engine adapters.
|
||||||
|
|
||||||
|
Author: Abby (ChatGPT)
|
||||||
|
Date: 2025-07-23
|
||||||
|
Canvas: engine_base.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
class TTSEngineBase(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
async def synthesize(self, text: str, speaker: str = None, model: str = None, fmt: str = "ogg"):
|
||||||
|
"""
|
||||||
|
Asynchronously generate speech audio from text input.
|
||||||
|
Returns path to audio file.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def list_models(self):
|
||||||
|
"""Return a list of available models."""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def list_voices(self, model: str = None):
|
||||||
|
"""Return a list of available voices for a model."""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def healthcheck(self):
|
||||||
|
"""Return health/status info for this engine."""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def selftest(self):
|
||||||
|
"""Asynchronously run internal self-test (basic functionality check)."""
|
||||||
|
raise NotImplementedError
|
||||||
1
engines/f5-tts-voices/default.txt
Normal file
1
engines/f5-tts-voices/default.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Some call me nature, others call me mother nature.
|
||||||
143
engines/f5_tts.py
Normal file
143
engines/f5_tts.py
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
"""
|
||||||
|
NovaAi – TTS-Engine-Hub
|
||||||
|
f5_tts.py
|
||||||
|
Version: v0.0.2
|
||||||
|
|
||||||
|
Description:
|
||||||
|
F5-TTS engine module.
|
||||||
|
Implements the TTSEngineBase for F5-TTS text-to-speech synthesis.
|
||||||
|
Now with robust speaker handling.
|
||||||
|
|
||||||
|
Author: Your Name (or leave as generated)
|
||||||
|
Date: 2025-12-03
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import torch
|
||||||
|
import torchaudio
|
||||||
|
import numpy as np
|
||||||
|
import soundfile as sf
|
||||||
|
import asyncio
|
||||||
|
from .engine_base import TTSEngineBase
|
||||||
|
from importlib.resources import files
|
||||||
|
|
||||||
|
try:
|
||||||
|
from f5_tts.api import F5TTS
|
||||||
|
except ImportError:
|
||||||
|
print("Warning: F5TTS could not be imported. F5-TTS engine will not be available.")
|
||||||
|
F5TTS = None
|
||||||
|
|
||||||
|
class F5TTSEngine(TTSEngineBase):
|
||||||
|
def __init__(self):
|
||||||
|
# Initialize F5-TTS specific resources, models, etc.
|
||||||
|
print("F5-TTS Engine Initializing...")
|
||||||
|
self.speakers = {}
|
||||||
|
self.model = None
|
||||||
|
|
||||||
|
if F5TTS:
|
||||||
|
try:
|
||||||
|
self.model = F5TTS(model="F5TTS_v1_Base")
|
||||||
|
print("F5-TTS Engine Initialized.")
|
||||||
|
self._load_speakers()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error initializing F5-TTS Engine: {e}")
|
||||||
|
self.model = None
|
||||||
|
else:
|
||||||
|
print("F5-TTS Engine not initialized because F5TTS is not available.")
|
||||||
|
|
||||||
|
def _load_speakers(self):
|
||||||
|
# Add the default speaker
|
||||||
|
default_wav = str(files("f5_tts").joinpath("infer/examples/basic/basic_ref_en.wav"))
|
||||||
|
default_txt = "engines/f5-tts-voices/default.txt"
|
||||||
|
if os.path.exists(default_txt):
|
||||||
|
self.speakers["default"] = {"wav": default_wav, "txt": default_txt}
|
||||||
|
|
||||||
|
# Scan for custom speakers
|
||||||
|
voices_dir = "engines/f5-tts-voices"
|
||||||
|
if not os.path.isdir(voices_dir):
|
||||||
|
return
|
||||||
|
for file in os.listdir(voices_dir):
|
||||||
|
if file.endswith(".wav"):
|
||||||
|
speaker_name = file.rsplit('.', 1)[0]
|
||||||
|
wav_path = os.path.join(voices_dir, file)
|
||||||
|
txt_path = os.path.join(voices_dir, f"{speaker_name}.txt")
|
||||||
|
if os.path.exists(txt_path):
|
||||||
|
self.speakers[speaker_name] = {"wav": wav_path, "txt": txt_path}
|
||||||
|
print(f"Found custom speaker: {speaker_name}")
|
||||||
|
|
||||||
|
def _blocking_synthesize(self, text: str, speaker: str, fmt: str):
|
||||||
|
"""The actual blocking synthesis logic."""
|
||||||
|
speaker_data = self.speakers[speaker]
|
||||||
|
ref_file = speaker_data["wav"]
|
||||||
|
|
||||||
|
with open(speaker_data["txt"], 'r') as f:
|
||||||
|
ref_text = f.read()
|
||||||
|
|
||||||
|
print(f"F5-TTS: Synthesizing '{text}' with reference voice from '{ref_file}'.")
|
||||||
|
|
||||||
|
wav, sr, spec = self.model.infer(
|
||||||
|
ref_file=ref_file,
|
||||||
|
ref_text=ref_text,
|
||||||
|
gen_text=text,
|
||||||
|
)
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(delete=False, suffix=f".{fmt}") as temp_file:
|
||||||
|
if fmt == "wav":
|
||||||
|
torchaudio.save(temp_file.name, torch.from_numpy(wav).unsqueeze(0), sr, format="wav")
|
||||||
|
else:
|
||||||
|
# Convert to float32 for soundfile
|
||||||
|
wav_float = wav.astype(np.float32) / np.iinfo(wav.dtype).max
|
||||||
|
sf.write(temp_file.name, wav_float, sr)
|
||||||
|
return temp_file.name
|
||||||
|
|
||||||
|
async def synthesize(self, text: str, speaker: str = None, model: str = None, fmt: str = "ogg"):
|
||||||
|
"""
|
||||||
|
Asynchronously generate speech audio from text input using F5-TTS.
|
||||||
|
"""
|
||||||
|
if not self.model:
|
||||||
|
raise RuntimeError("F5-TTS Engine not initialized.")
|
||||||
|
|
||||||
|
speaker_to_use = speaker if speaker in self.speakers else "default"
|
||||||
|
if speaker and speaker not in self.speakers:
|
||||||
|
print(f"Warning: Speaker '{speaker}' not found. Falling back to default speaker.")
|
||||||
|
|
||||||
|
if speaker_to_use not in self.speakers:
|
||||||
|
raise RuntimeError("No default speaker found for F5-TTS. Please add a 'default.wav' and 'default.txt' to the 'engines/f5-tts-voices' directory.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Run the blocking synthesis in a separate thread
|
||||||
|
return await asyncio.to_thread(self._blocking_synthesize, text, speaker_to_use, fmt)
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(f"F5-TTS synthesis failed: {e}")
|
||||||
|
|
||||||
|
def list_models(self):
|
||||||
|
"""Return a list of available F5-TTS models."""
|
||||||
|
if not self.model:
|
||||||
|
return []
|
||||||
|
return ["F5TTS_v1_Base"]
|
||||||
|
|
||||||
|
def list_voices(self, model: str = None):
|
||||||
|
"""Return a list of available F5-TTS voices for a model."""
|
||||||
|
return list(self.speakers.keys())
|
||||||
|
|
||||||
|
def healthcheck(self):
|
||||||
|
"""Return health/status info for F5-TTS engine."""
|
||||||
|
if self.model:
|
||||||
|
return {"status": "ok", "message": "F5-TTS engine is ready"}
|
||||||
|
else:
|
||||||
|
return {"status": "error", "message": "F5-TTS engine failed to initialize"}
|
||||||
|
|
||||||
|
async def selftest(self):
|
||||||
|
"""Run internal self-test for F5-TTS."""
|
||||||
|
if not self.model:
|
||||||
|
return {"status": "failed", "message": "F5-TTS Engine not initialized."}
|
||||||
|
try:
|
||||||
|
# Await the async synthesize method
|
||||||
|
audio_file = await self.synthesize("this is a test.")
|
||||||
|
selftest_passed = os.path.exists(audio_file) and os.path.getsize(audio_file) > 0
|
||||||
|
if selftest_passed:
|
||||||
|
os.remove(audio_file)
|
||||||
|
return {"status": "passed" if selftest_passed else "failed", "message": "F5-TTS self-test successful"}
|
||||||
|
except Exception as e:
|
||||||
|
return {"status": "failed", "message": f"F5-TTS self-test failed: {e}"}
|
||||||
163
engines/piper.py
Normal file
163
engines/piper.py
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
"""
|
||||||
|
NovaAi – TTS-Engine-Hub
|
||||||
|
engines/piper.py
|
||||||
|
Version: v0.1.1
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Piper TTS engine adapter: real CLI invocation + output as WAV, OGG, or MP3.
|
||||||
|
Synthesizes WAV via Piper, converts to OGG/MP3 via ffmpeg-python if needed.
|
||||||
|
Uses dynamic model path: ./models/piper/[model]/model.onnx
|
||||||
|
|
||||||
|
Author: Abby (ChatGPT)
|
||||||
|
Date: 2025-07-23
|
||||||
|
Canvas: piper.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import json
|
||||||
|
from engines.engine_base import TTSEngineBase
|
||||||
|
import ffmpeg
|
||||||
|
|
||||||
|
class PiperEngine(TTSEngineBase):
|
||||||
|
def __init__(self):
|
||||||
|
self.piper_executable = shutil.which("piper")
|
||||||
|
self.ffmpeg_executable = shutil.which("ffmpeg")
|
||||||
|
|
||||||
|
def _load_config(self, model: str):
|
||||||
|
"""Load the model config JSON file to get speaker mappings."""
|
||||||
|
model_dir = f"./models/piper/{model}"
|
||||||
|
config_file = os.path.join(model_dir, f"{model}.onnx.json")
|
||||||
|
if os.path.isfile(config_file):
|
||||||
|
with open(config_file, 'r') as f:
|
||||||
|
return json.load(f)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def _get_speaker_id(self, speaker: str, model: str):
|
||||||
|
"""Convert speaker name to speaker ID using the model's config."""
|
||||||
|
if not speaker or speaker == "default":
|
||||||
|
return None
|
||||||
|
if speaker.isdigit():
|
||||||
|
return speaker
|
||||||
|
config = self._load_config(model)
|
||||||
|
speaker_id_map = config.get('speaker_id_map', {})
|
||||||
|
return str(speaker_id_map.get(speaker))
|
||||||
|
|
||||||
|
def _run_ffmpeg_blocking(self, input_path, output_path):
|
||||||
|
"""Wrapper for the blocking ffmpeg call."""
|
||||||
|
(
|
||||||
|
ffmpeg
|
||||||
|
.input(input_path)
|
||||||
|
.output(output_path)
|
||||||
|
.run(overwrite_output=True, quiet=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def synthesize(self, text: str, speaker: str = None, model: str = None, fmt: str = "ogg"):
|
||||||
|
if not self.piper_executable:
|
||||||
|
raise RuntimeError("Piper executable not found. Please install it and ensure it's in your PATH.")
|
||||||
|
if not model:
|
||||||
|
raise ValueError("Model must be specified for Piper.")
|
||||||
|
model_dir = f"./models/piper/{model}"
|
||||||
|
model_file = os.path.join(model_dir, f"{model}.onnx")
|
||||||
|
if not os.path.isfile(model_file):
|
||||||
|
raise FileNotFoundError(f"Piper model not found: {model_file}")
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(suffix=".wav", prefix="piper_", delete=False) as wav_file:
|
||||||
|
output_wav_path = wav_file.name
|
||||||
|
|
||||||
|
cmd = [self.piper_executable, "--model", model_file, "--output_file", output_wav_path, "--stdin_text"]
|
||||||
|
|
||||||
|
if speaker:
|
||||||
|
speaker_id = self._get_speaker_id(speaker, model)
|
||||||
|
if speaker_id:
|
||||||
|
cmd += ["--speaker", speaker_id]
|
||||||
|
|
||||||
|
process = await asyncio.create_subprocess_exec(
|
||||||
|
*cmd,
|
||||||
|
stdin=asyncio.subprocess.PIPE,
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE
|
||||||
|
)
|
||||||
|
stdout, stderr = await process.communicate(input=text.encode('utf-8'))
|
||||||
|
|
||||||
|
if process.returncode != 0:
|
||||||
|
os.remove(output_wav_path)
|
||||||
|
raise RuntimeError(f"Piper synth failed: {stderr.decode()}")
|
||||||
|
|
||||||
|
fmt = (fmt or "ogg").lower()
|
||||||
|
if fmt == "wav":
|
||||||
|
return output_wav_path
|
||||||
|
|
||||||
|
if not self.ffmpeg_executable:
|
||||||
|
os.remove(output_wav_path)
|
||||||
|
raise RuntimeError("ffmpeg not found, cannot convert audio format.")
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(suffix=f'.{fmt}', prefix="piper_conv_", delete=False) as converted_file:
|
||||||
|
output_other_path = converted_file.name
|
||||||
|
|
||||||
|
try:
|
||||||
|
await asyncio.to_thread(self._run_ffmpeg_blocking, output_wav_path, output_other_path)
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(f"ffmpeg conversion failed: {e}")
|
||||||
|
finally:
|
||||||
|
os.remove(output_wav_path)
|
||||||
|
|
||||||
|
return output_other_path
|
||||||
|
|
||||||
|
def list_models(self):
|
||||||
|
models_dir = "./models/piper/"
|
||||||
|
if not os.path.isdir(models_dir):
|
||||||
|
return []
|
||||||
|
return [name for name in os.listdir(models_dir)
|
||||||
|
if os.path.isdir(os.path.join(models_dir, name))]
|
||||||
|
|
||||||
|
def list_voices(self, model: str = None):
|
||||||
|
if not model:
|
||||||
|
return ["default"]
|
||||||
|
config = self._load_config(model)
|
||||||
|
speaker_id_map = config.get('speaker_id_map', {})
|
||||||
|
if speaker_id_map:
|
||||||
|
return ["default"] + sorted(speaker_id_map.keys())
|
||||||
|
return ["default"]
|
||||||
|
|
||||||
|
def healthcheck(self):
|
||||||
|
status = "ok"
|
||||||
|
if not self.piper_executable:
|
||||||
|
status = "missing_piper_executable"
|
||||||
|
return {"status": status, "engine": "piper"}
|
||||||
|
|
||||||
|
async def selftest(self):
|
||||||
|
if not self.piper_executable:
|
||||||
|
return {"selftest": False, "error": "Piper executable not found.", "engine": "piper"}
|
||||||
|
try:
|
||||||
|
models = self.list_models()
|
||||||
|
if not models:
|
||||||
|
return {"selftest": False, "error": "No Piper models found.", "engine": "piper"}
|
||||||
|
|
||||||
|
test_text = "This is a selftest."
|
||||||
|
first_model = models[0]
|
||||||
|
voices = self.list_voices(first_model)
|
||||||
|
test_voice = voices[0] if voices else None
|
||||||
|
|
||||||
|
audio_file = await self.synthesize(test_text, speaker=test_voice, model=first_model, fmt="wav")
|
||||||
|
|
||||||
|
selftest_passed = os.path.exists(audio_file) and os.path.getsize(audio_file) > 0
|
||||||
|
if selftest_passed:
|
||||||
|
os.remove(audio_file)
|
||||||
|
|
||||||
|
return {"selftest": selftest_passed, "models": models, "engine": "piper"}
|
||||||
|
except Exception as e:
|
||||||
|
return {"selftest": False, "error": str(e), "engine": "piper"}
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
async def main():
|
||||||
|
engine = PiperEngine()
|
||||||
|
print("Selftest:", await engine.selftest())
|
||||||
|
print("Models:", engine.list_models())
|
||||||
|
print("Voices:", engine.list_voices(engine.list_models()[0]))
|
||||||
|
print("Healthcheck:", engine.healthcheck())
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
48
engines/styletts.py
Normal file
48
engines/styletts.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
"""
|
||||||
|
NovaAi – TTS-Engine-Hub
|
||||||
|
engines/styletts.py
|
||||||
|
Version: v0.0.1
|
||||||
|
|
||||||
|
Description:
|
||||||
|
StyleTTS engine adapter.
|
||||||
|
Implements TTSEngineBase interface for StyleTTS integration (dummy implementation).
|
||||||
|
|
||||||
|
Author: Abby (ChatGPT)
|
||||||
|
Date: 2025-07-23
|
||||||
|
Canvas: styletts.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from engines.engine_base import TTSEngineBase
|
||||||
|
|
||||||
|
class StyleTTSEngine(TTSEngineBase):
|
||||||
|
async def synthesize(self, text: str, speaker: str = None, model: str = None, fmt: str = "mp3"):
|
||||||
|
# Dummy implementation: returns an empty string as it doesn't produce a file.
|
||||||
|
print("Warning: StyleTTSEngine.synthesize is a dummy and does not produce audio.")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def list_models(self):
|
||||||
|
# Dummy implementation
|
||||||
|
return ["styletts_v2_de", "styletts_v2_en"]
|
||||||
|
|
||||||
|
def list_voices(self, model: str = None):
|
||||||
|
# Dummy implementation
|
||||||
|
return ["neutral", "emotional", "female"]
|
||||||
|
|
||||||
|
def healthcheck(self):
|
||||||
|
# Dummy implementation
|
||||||
|
return {"status": "ok", "engine": "styletts"}
|
||||||
|
|
||||||
|
async def selftest(self):
|
||||||
|
# Dummy implementation
|
||||||
|
return {"selftest": True, "engine": "styletts"}
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
async def main():
|
||||||
|
engine = StyleTTSEngine()
|
||||||
|
print("Selftest:", await engine.selftest())
|
||||||
|
print("Models:", engine.list_models())
|
||||||
|
print("Voices:", engine.list_voices())
|
||||||
|
print("Healthcheck:", engine.healthcheck())
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
296
guide.md
Normal file
296
guide.md
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
# Leitfaden: Best Practices zur Containerisierung von Python-Backends
|
||||||
|
|
||||||
|
Dieser Leitfaden zeigt einen professionellen Workflow zur Containerisierung einer Python-Backend-Anwendung mit Docker, inklusive Integration eines Reverse Proxys (Traefik) für die lokale Entwicklung. Wir verwenden eine minimale FastAPI-Anwendung als Beispiel.
|
||||||
|
|
||||||
|
Die vorgestellten Methoden umfassen:
|
||||||
|
- Optimierte, sichere Docker-Images durch Multi-Stage-Builds.
|
||||||
|
- Einen einfachen Workflow durch die Verwendung eines `Makefile`.
|
||||||
|
- Trennung von Entwicklungs- und Produktionsumgebungen.
|
||||||
|
- Korrekte Verwaltung von Code und Images mit Git und einer Container Registry.
|
||||||
|
- Integration von Traefik für dynamisches Routing in der lokalen Entwicklung.
|
||||||
|
|
||||||
|
## 1. Projektstruktur
|
||||||
|
|
||||||
|
Wir haben die folgende Struktur erstellt:
|
||||||
|
|
||||||
|
```
|
||||||
|
/
|
||||||
|
├── .dockerignore # Listet Dateien auf, die Docker ignorieren soll.
|
||||||
|
├── .gitignore # Listet Dateien auf, die Git ignorieren soll.
|
||||||
|
├── Dockerfile # Die Blaupause für unser produktives Docker-Image.
|
||||||
|
├── Makefile # Vereinfacht die Ausführung von Docker-Befehlen.
|
||||||
|
├── app/
|
||||||
|
│ ├── __init__.py # Macht 'app' zu einem Python-Paket.
|
||||||
|
│ └── main.py # Unser FastAPI-Anwendungscode.
|
||||||
|
├── docker-compose.yml # Definiert die lokale Entwicklungsumgebung mit Traefik.
|
||||||
|
├── guide.md # Dieser Leitfaden.
|
||||||
|
└── requirements.txt # Liste der Python-Abhängigkeiten.
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Die Komponenten im Detail
|
||||||
|
|
||||||
|
### `requirements.txt`
|
||||||
|
Hier definieren wir die Python-Bibliotheken, die unser Projekt benötigt.
|
||||||
|
```
|
||||||
|
fastapi
|
||||||
|
uvicorn[standard]
|
||||||
|
gunicorn
|
||||||
|
```
|
||||||
|
- `fastapi`: Das Web-Framework.
|
||||||
|
- `uvicorn`: Ein schneller ASGI-Server, ideal für die Entwicklung.
|
||||||
|
- `gunicorn`: Ein robuster WSGI-Produktionsserver, der Uvicorn-Worker zur Ausführung unserer ASGI-Anwendung nutzt.
|
||||||
|
|
||||||
|
### `.gitignore` & `.dockerignore`
|
||||||
|
- **`.gitignore`**: Verhindert, dass sensible Daten (`.env`), temporäre Dateien (`__pycache__`) oder lokale Konfigurationen (`.vscode/`) in Git eingecheckt werden.
|
||||||
|
- **`.dockerignore`**: Verhindert, dass unnötige oder sensible Dateien in das Docker-Image kopiert werden. Dies hält das Image klein und sicher. Wir schließen z.B. das `.git`-Verzeichnis, das `Dockerfile` selbst und lokale Umgebungsdateien aus.
|
||||||
|
|
||||||
|
### `app/main.py`
|
||||||
|
Eine minimale FastAPI-Anwendung mit zwei Endpunkten.
|
||||||
|
```python
|
||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
def read_root():
|
||||||
|
return {"message": "Hello World"}
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
def health_check():
|
||||||
|
return {"status": "ok"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Dockerfile` (Multi-Stage-Build)
|
||||||
|
Dies ist das Herzstück unserer Containerisierung. Ein Multi-Stage-Build trennt die Build-Umgebung von der Laufzeitumgebung.
|
||||||
|
|
||||||
|
**Stufe 1: `builder`**
|
||||||
|
```dockerfile
|
||||||
|
FROM python:3.11 as builder
|
||||||
|
WORKDIR /opt/venv
|
||||||
|
RUN python -m venv .
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN . /opt/venv/bin/activate && pip install --no-cache-dir -r requirements.txt
|
||||||
|
```
|
||||||
|
- Wir starten mit einem vollständigen Python-Image.
|
||||||
|
- Erstellen ein virtuelles Environment (`venv`) und installieren die Abhängigkeiten hinein.
|
||||||
|
- Das Ergebnis ist ein Ordner `/opt/venv` mit einer sauberen Python-Umgebung.
|
||||||
|
|
||||||
|
**Stufe 2: `runner` (Das finale Image)**
|
||||||
|
```dockerfile
|
||||||
|
FROM python:3.11-slim
|
||||||
|
RUN useradd --create-home --shell /bin/bash appuser
|
||||||
|
WORKDIR /home/appuser/app
|
||||||
|
COPY --from=builder /opt/venv /opt/venv
|
||||||
|
COPY app/ .
|
||||||
|
ENV PATH="/opt/venv/bin:$PATH"
|
||||||
|
EXPOSE 8000
|
||||||
|
USER appuser
|
||||||
|
CMD ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "-w", "2", "-b", "0.0.0.0:8000", "main:app"]
|
||||||
|
```
|
||||||
|
- Wir starten mit einem minimalen `-slim`-Image.
|
||||||
|
- **Sicherheit**: Wir erstellen einen unprivilegierten Benutzer `appuser`. Die Anwendung wird als dieser Benutzer ausgeführt.
|
||||||
|
- Wir kopieren das `venv` aus der `builder`-Stufe und unseren App-Code.
|
||||||
|
- **Produktions-Server**: Wir starten die App mit `gunicorn` und 2 `uvicorn`-Workern. Dies ist ein stabiles Setup für die Produktion.
|
||||||
|
|
||||||
|
### `docker-compose.yml` (Für die lokale Entwicklung mit Traefik)
|
||||||
|
Diese Datei definiert unsere lokale Entwicklungsumgebung, die nun auch Traefik als Reverse Proxy enthält.
|
||||||
|
|
||||||
|
**Was ist Traefik?**
|
||||||
|
Traefik ist ein moderner Edge Router und Reverse Proxy, der dynamisch Dienste auf der Grundlage ihrer Konfiguration (z.B. Docker-Labels) entdeckt. Er leitet Anfragen an die richtigen Container weiter, ohne dass man manuelle Konfigurationen in einer separaten Datei vornehmen muss.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
volumes:
|
||||||
|
- ./app:/home/appuser/app
|
||||||
|
command: ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
# Definiert einen Router für den App-Dienst
|
||||||
|
- "traefik.http.routers.app-router.rule=Host(`localhost`)"
|
||||||
|
- "traefik.http.routers.app-router.entrypoints=web"
|
||||||
|
# Definiert den internen Port des Dienstes (im Container)
|
||||||
|
- "traefik.http.services.app-service.loadbalancer.server.port=8000"
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
|
||||||
|
traefik:
|
||||||
|
image: "traefik:v2.10"
|
||||||
|
command:
|
||||||
|
- "--api.dashboard=true"
|
||||||
|
- "--providers.docker=true"
|
||||||
|
- "--providers.docker.exposedbydefault=false" # Nur Dienste mit traefik.enable=true exposen
|
||||||
|
- "--entrypoints.web.address=:80"
|
||||||
|
ports:
|
||||||
|
- "80:80" # Der HTTP-Port, über den Traefik lauscht
|
||||||
|
- "8080:8080" # Das Web UI (Dashboard) von Traefik
|
||||||
|
volumes:
|
||||||
|
- "/var/run/docker.sock:/var/run/docker.sock:ro" # Traefik braucht Zugriff auf den Docker-Daemon
|
||||||
|
networks:
|
||||||
|
- web
|
||||||
|
|
||||||
|
networks:
|
||||||
|
web:
|
||||||
|
external: false
|
||||||
|
```
|
||||||
|
- **`app` Service**: Die direkte Port-Exponierung wurde entfernt. Stattdessen nutzt Traefik die `labels`, um das Routing zu konfigurieren.
|
||||||
|
- `traefik.enable=true`: Aktiviert die Erkennung durch Traefik.
|
||||||
|
- `traefik.http.routers.app-router.rule=Host('localhost')`: Sagt Traefik, dass Anfragen an die Host `localhost` an diesen Dienst geleitet werden sollen.
|
||||||
|
- `traefik.http.routers.app-router.entrypoints=web`: Verknüpft diesen Router mit dem `web`-Entrypoint von Traefik (Port 80).
|
||||||
|
- `traefik.http.services.app-service.loadbalancer.server.port=8000`: Informiert Traefik über den internen Port des FastAPI-Dienstes.
|
||||||
|
- **`traefik` Service**: Dies ist der Traefik-Container selbst.
|
||||||
|
- Er konfiguriert das Dashboard (`--api.dashboard=true`) und aktiviert den Docker-Provider (`--providers.docker=true`), der Container anhand ihrer Labels entdeckt.
|
||||||
|
- Er lauscht auf Port 80 (HTTP) und 8080 (Dashboard).
|
||||||
|
- `/var/run/docker.sock`: Ermöglicht Traefik die Kommunikation mit dem Docker-Daemon, um Container und deren Labels zu erkennen.
|
||||||
|
- **`networks: web`**: Erstellt ein gemeinsames Netzwerk, in dem Traefik und die `app` kommunizieren können.
|
||||||
|
|
||||||
|
### `Makefile` (Der Kommando-Runner)
|
||||||
|
Das `Makefile` gibt uns einfache Befehle für komplexe Aktionen. Es wurde angepasst, um die Traefik-Ports zu berücksichtigen.
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
# --- Configuration ---
|
||||||
|
# Default internal application port (exposed to Traefik)
|
||||||
|
PORT := 8000
|
||||||
|
# Traefik's external entrypoints
|
||||||
|
TRAEFIK_WEB_PORT := 80
|
||||||
|
TRAEFIK_DASHBOARD_PORT := 8080
|
||||||
|
|
||||||
|
# --- Port Checking Functions ---
|
||||||
|
|
||||||
|
# Function to check if required Traefik ports are free
|
||||||
|
# Exits if any are busy, does not suggest alternatives.
|
||||||
|
define check_traefik_ports_free
|
||||||
|
@echo "Checking if Traefik ports ($(TRAEFIK_WEB_PORT}, $(TRAEFIK_DASHBOARD_PORT}) are free..." >&2
|
||||||
|
@local busy_ports=""; \
|
||||||
|
if ss -tulnp | grep ":$(TRAEFIK_WEB_PORT) " > /dev/null; then \
|
||||||
|
busy_ports="$$busy_ports $(TRAEFIK_WEB_PORT)"; \
|
||||||
|
fi; \
|
||||||
|
if ss -tulnp | grep ":$(TRAEFIK_DASHBOARD_PORT) " > /dev/null; then \
|
||||||
|
busy_ports="$$busy_ports $(TRAEFIK_DASHBOARD_PORT)"; \
|
||||||
|
fi; \
|
||||||
|
if [ -n "$$busy_ports" ]; then \
|
||||||
|
echo "ERROR: The following Traefik ports are already in use: $$busy_ports. Please free them or stop Traefik if already running." >&2; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
@echo "Traefik ports are free." >&2
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Function to find next free host port for the app and ask user
|
||||||
|
# This function will echo the chosen port if successful, or exit with an error.
|
||||||
|
define check_app_port_free
|
||||||
|
@local start_port=$(PORT); \
|
||||||
|
local found_port=$$start_port; \
|
||||||
|
local is_free=false; \
|
||||||
|
\
|
||||||
|
if ! ss -tulnp | grep ":$$start_port " > /dev/null; then \
|
||||||
|
echo "$$start_port"; \
|
||||||
|
exit 0; \
|
||||||
|
fi; \
|
||||||
|
\
|
||||||
|
echo "Port $$start_port is busy. Searching for a free port for the app..." >&2; \
|
||||||
|
while ! $$is_free; do \
|
||||||
|
if ! ss -tulnp | grep ":$$found_port " > /dev/null; then \
|
||||||
|
is_free=true; \
|
||||||
|
else \
|
||||||
|
((found_port++)); \
|
||||||
|
if [ "$$found_port" -gt 65535 ]; then \
|
||||||
|
echo "ERROR: No free ports found up to 65535. Aborting." >&2; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
fi; \
|
||||||
|
done; \
|
||||||
|
\
|
||||||
|
echo "Port $$start_port is busy. I found port $$found_port to be free for the app." >&2; \
|
||||||
|
read -p "Do you want to use port $$found_port for the app? (y/N): " choice; \
|
||||||
|
case "$$choice" in \
|
||||||
|
y|Y ) \
|
||||||
|
echo "$$found_port"; \
|
||||||
|
;; \
|
||||||
|
* ) \
|
||||||
|
echo "Operation cancelled by user." >&2; \
|
||||||
|
exit 1; \
|
||||||
|
;; \
|
||||||
|
esac;
|
||||||
|
endef
|
||||||
|
|
||||||
|
# --- Docker Commands ---
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
@echo "Building Docker image: $(IMAGE_NAME):$(TAG)"
|
||||||
|
docker build -t $(IMAGE_NAME):$(TAG) .
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run:
|
||||||
|
@export SELECTED_HOST_PORT=$$(bash -c 'func() { $(check_app_port_free) }; func') && \
|
||||||
|
echo "Using host port $$SELECTED_HOST_PORT for single app container" && \
|
||||||
|
docker run -d -p $$SELECTED_HOST_PORT:$(PORT) --name $(IMAGE_NAME) $(IMAGE_NAME):$(TAG)
|
||||||
|
|
||||||
|
.PHONY: stop
|
||||||
|
stop:
|
||||||
|
@echo "Stopping Docker container: $(IMAGE_NAME)"
|
||||||
|
docker stop $(IMAGE_NAME) || true
|
||||||
|
docker rm $(IMAGE_NAME) || true
|
||||||
|
|
||||||
|
.PHONY: logs
|
||||||
|
logs:
|
||||||
|
@echo "Showing logs for container: $(IMAGE_NAME)"
|
||||||
|
docker logs -f $(IMAGE_NAME)
|
||||||
|
|
||||||
|
.PHONY: shell
|
||||||
|
shell:
|
||||||
|
@echo "Accessing shell in container: $(IMAGE_NAME)"
|
||||||
|
docker exec -it $(IMAGE_NAME) /bin/bash
|
||||||
|
|
||||||
|
# --- Docker Compose Commands ---
|
||||||
|
|
||||||
|
.PHONY: up
|
||||||
|
up:
|
||||||
|
$(call check_traefik_ports_free) # Check Traefik ports before starting
|
||||||
|
@echo "Starting development environment with Docker Compose (Traefik enabled)..."
|
||||||
|
docker-compose up --build -d
|
||||||
|
|
||||||
|
.PHONY: down
|
||||||
|
down:
|
||||||
|
@echo "Stopping development environment with Docker Compose..."
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# --- Image Management ---
|
||||||
|
|
||||||
|
.PHONY: tag
|
||||||
|
tag:
|
||||||
|
@echo "Tagging image $(IMAGE_NAME):$(TAG) as $(REGISTRY)/$(IMAGE_NAME):$(TAG)"
|
||||||
|
docker tag $(IMAGE_NAME):$(TAG) $(REGISTRY)/$(IMAGE_NAME):$(TAG)
|
||||||
|
|
||||||
|
.PHONY: push
|
||||||
|
push: tag
|
||||||
|
@echo "Pushing image $(REGISTRY)/$(IMAGE_NAME):$(TAG) to registry..."
|
||||||
|
docker push $(REGISTRY)/$(IMAGE_NAME):$(TAG)
|
||||||
|
|
||||||
|
# --- Cleanup ---
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
@echo "Cleaning up stopped containers and dangling images..."
|
||||||
|
docker container prune -f
|
||||||
|
docker image prune -f
|
||||||
|
|
||||||
|
.PHONY: help
|
||||||
|
help:
|
||||||
|
@echo "Available commands:"
|
||||||
|
@echo " build - Build the Docker image"
|
||||||
|
@echo " run - Run the Docker container (single app, no Traefik)"
|
||||||
|
@echo " stop - Stop and remove the Docker container"
|
||||||
|
@echo " logs - Follow the logs of the container"
|
||||||
|
@echo " shell - Get a shell inside the running container"
|
||||||
|
@echo " up - Start the dev environment with docker-compose (with Traefik)"
|
||||||
|
@echo " down - Stop the dev environment with docker-compose"
|
||||||
|
@echo " tag - Tag the image for a registry"
|
||||||
|
@echo " push - Push the image to a registry (after tagging)"
|
||||||
|
@echo " clean - Clean up unused containers and images"
|
||||||
|
@echo " help - Show this help message"
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
493
models/de_DE-thorsten-high/de_DE-thorsten-high.onnx.json
Normal file
493
models/de_DE-thorsten-high/de_DE-thorsten-high.onnx.json
Normal file
@ -0,0 +1,493 @@
|
|||||||
|
{
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "high"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "de"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.667,
|
||||||
|
"length_scale": 1,
|
||||||
|
"noise_w": 0.8
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
],
|
||||||
|
"̺": [
|
||||||
|
152
|
||||||
|
],
|
||||||
|
"̻": [
|
||||||
|
153
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 1,
|
||||||
|
"speaker_id_map": {},
|
||||||
|
"piper_version": "1.0.0",
|
||||||
|
"language": {
|
||||||
|
"code": "de_DE",
|
||||||
|
"family": "de",
|
||||||
|
"region": "DE",
|
||||||
|
"name_native": "Deutsch",
|
||||||
|
"name_english": "German",
|
||||||
|
"country_english": "Germany"
|
||||||
|
},
|
||||||
|
"dataset": "thorsten"
|
||||||
|
}
|
||||||
@ -0,0 +1,502 @@
|
|||||||
|
{
|
||||||
|
"piper_version": "1.1.0",
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "medium"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "de"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.667,
|
||||||
|
"length_scale": 1,
|
||||||
|
"noise_w": 0.8
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
],
|
||||||
|
"̺": [
|
||||||
|
152
|
||||||
|
],
|
||||||
|
"̻": [
|
||||||
|
153
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 8,
|
||||||
|
"speaker_id_map": {
|
||||||
|
"amused": 0,
|
||||||
|
"angry": 1,
|
||||||
|
"disgusted": 2,
|
||||||
|
"drunk": 3,
|
||||||
|
"neutral": 4,
|
||||||
|
"sleepy": 5,
|
||||||
|
"surprised": 6,
|
||||||
|
"whisper": 7
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"code": "de_DE",
|
||||||
|
"family": "de",
|
||||||
|
"region": "DE",
|
||||||
|
"name_native": "Deutsch",
|
||||||
|
"name_english": "German",
|
||||||
|
"country_english": "Germany"
|
||||||
|
},
|
||||||
|
"dataset": "thorsten_emotional"
|
||||||
|
}
|
||||||
502
models/en_GB-cori-high/en_GB-cori-high.onnx.json
Normal file
502
models/en_GB-cori-high/en_GB-cori-high.onnx.json
Normal file
@ -0,0 +1,502 @@
|
|||||||
|
{
|
||||||
|
"dataset": "cori",
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "high"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "en"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"code": "en_GB",
|
||||||
|
"family": "en",
|
||||||
|
"region": "GB",
|
||||||
|
"name_native": "English",
|
||||||
|
"name_english": "English",
|
||||||
|
"country_english": "Great Britain"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.667,
|
||||||
|
"length_scale": 1,
|
||||||
|
"noise_w": 0.8
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"X": [
|
||||||
|
156
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"g": [
|
||||||
|
154
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʦ": [
|
||||||
|
155
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̺": [
|
||||||
|
152
|
||||||
|
],
|
||||||
|
"̻": [
|
||||||
|
153
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 1,
|
||||||
|
"speaker_id_map": {},
|
||||||
|
"piper_version": "1.0.0"
|
||||||
|
}
|
||||||
603
models/en_GB-vctk-medium/en_GB-vctk-medium.onnx.json
Normal file
603
models/en_GB-vctk-medium/en_GB-vctk-medium.onnx.json
Normal file
@ -0,0 +1,603 @@
|
|||||||
|
{
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "medium"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "en-gb-x-rp"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.333,
|
||||||
|
"length_scale": 1.4,
|
||||||
|
"noise_w": 0.333
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
],
|
||||||
|
"̺": [
|
||||||
|
152
|
||||||
|
],
|
||||||
|
"̻": [
|
||||||
|
153
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 109,
|
||||||
|
"speaker_id_map": {
|
||||||
|
"p239": 0,
|
||||||
|
"p236": 1,
|
||||||
|
"p264": 2,
|
||||||
|
"p250": 3,
|
||||||
|
"p259": 4,
|
||||||
|
"p247": 5,
|
||||||
|
"p261": 6,
|
||||||
|
"p263": 7,
|
||||||
|
"p283": 8,
|
||||||
|
"p286": 9,
|
||||||
|
"p274": 10,
|
||||||
|
"p276": 11,
|
||||||
|
"p270": 12,
|
||||||
|
"p281": 13,
|
||||||
|
"p277": 14,
|
||||||
|
"p231": 15,
|
||||||
|
"p271": 16,
|
||||||
|
"p238": 17,
|
||||||
|
"p257": 18,
|
||||||
|
"p273": 19,
|
||||||
|
"p284": 20,
|
||||||
|
"p329": 21,
|
||||||
|
"p361": 22,
|
||||||
|
"p287": 23,
|
||||||
|
"p360": 24,
|
||||||
|
"p374": 25,
|
||||||
|
"p376": 26,
|
||||||
|
"p310": 27,
|
||||||
|
"p304": 28,
|
||||||
|
"p334": 29,
|
||||||
|
"p340": 30,
|
||||||
|
"p323": 31,
|
||||||
|
"p347": 32,
|
||||||
|
"p330": 33,
|
||||||
|
"p308": 34,
|
||||||
|
"p314": 35,
|
||||||
|
"p317": 36,
|
||||||
|
"p339": 37,
|
||||||
|
"p311": 38,
|
||||||
|
"p294": 39,
|
||||||
|
"p305": 40,
|
||||||
|
"p266": 41,
|
||||||
|
"p335": 42,
|
||||||
|
"p318": 43,
|
||||||
|
"p351": 44,
|
||||||
|
"p333": 45,
|
||||||
|
"p313": 46,
|
||||||
|
"p316": 47,
|
||||||
|
"p244": 48,
|
||||||
|
"p307": 49,
|
||||||
|
"p363": 50,
|
||||||
|
"p336": 51,
|
||||||
|
"p297": 52,
|
||||||
|
"p312": 53,
|
||||||
|
"p267": 54,
|
||||||
|
"p275": 55,
|
||||||
|
"p295": 56,
|
||||||
|
"p258": 57,
|
||||||
|
"p288": 58,
|
||||||
|
"p301": 59,
|
||||||
|
"p232": 60,
|
||||||
|
"p292": 61,
|
||||||
|
"p272": 62,
|
||||||
|
"p280": 63,
|
||||||
|
"p278": 64,
|
||||||
|
"p341": 65,
|
||||||
|
"p268": 66,
|
||||||
|
"p298": 67,
|
||||||
|
"p299": 68,
|
||||||
|
"p279": 69,
|
||||||
|
"p285": 70,
|
||||||
|
"p326": 71,
|
||||||
|
"p300": 72,
|
||||||
|
"s5": 73,
|
||||||
|
"p230": 74,
|
||||||
|
"p345": 75,
|
||||||
|
"p254": 76,
|
||||||
|
"p269": 77,
|
||||||
|
"p293": 78,
|
||||||
|
"p252": 79,
|
||||||
|
"p262": 80,
|
||||||
|
"p243": 81,
|
||||||
|
"p227": 82,
|
||||||
|
"p343": 83,
|
||||||
|
"p255": 84,
|
||||||
|
"p229": 85,
|
||||||
|
"p240": 86,
|
||||||
|
"p248": 87,
|
||||||
|
"p253": 88,
|
||||||
|
"p233": 89,
|
||||||
|
"p228": 90,
|
||||||
|
"p282": 91,
|
||||||
|
"p251": 92,
|
||||||
|
"p246": 93,
|
||||||
|
"p234": 94,
|
||||||
|
"p226": 95,
|
||||||
|
"p260": 96,
|
||||||
|
"p245": 97,
|
||||||
|
"p241": 98,
|
||||||
|
"p303": 99,
|
||||||
|
"p265": 100,
|
||||||
|
"p306": 101,
|
||||||
|
"p237": 102,
|
||||||
|
"p249": 103,
|
||||||
|
"p256": 104,
|
||||||
|
"p302": 105,
|
||||||
|
"p364": 106,
|
||||||
|
"p225": 107,
|
||||||
|
"p362": 108
|
||||||
|
},
|
||||||
|
"piper_version": "1.0.0",
|
||||||
|
"language": {
|
||||||
|
"code": "en_GB",
|
||||||
|
"family": "en",
|
||||||
|
"region": "GB",
|
||||||
|
"name_native": "English",
|
||||||
|
"name_english": "English",
|
||||||
|
"country_english": "Great Britain"
|
||||||
|
},
|
||||||
|
"dataset": "vctk"
|
||||||
|
}
|
||||||
508
models/en_US-hfc_female-medium/en_US-hfc_female-medium.onnx.json
Normal file
508
models/en_US-hfc_female-medium/en_US-hfc_female-medium.onnx.json
Normal file
@ -0,0 +1,508 @@
|
|||||||
|
{
|
||||||
|
"dataset": "hfc_female",
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "medium"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "en-us"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"code": "en_US",
|
||||||
|
"family": "en",
|
||||||
|
"region": "US",
|
||||||
|
"name_native": "English",
|
||||||
|
"name_english": "English",
|
||||||
|
"country_english": "United States"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.667,
|
||||||
|
"length_scale": 1,
|
||||||
|
"noise_w": 0.8
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"X": [
|
||||||
|
156
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"g": [
|
||||||
|
154
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʦ": [
|
||||||
|
155
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̊": [
|
||||||
|
158
|
||||||
|
],
|
||||||
|
"̝": [
|
||||||
|
157
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̺": [
|
||||||
|
152
|
||||||
|
],
|
||||||
|
"̻": [
|
||||||
|
153
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 1,
|
||||||
|
"speaker_id_map": {},
|
||||||
|
"piper_version": "1.0.0"
|
||||||
|
}
|
||||||
502
models/en_US-kristin-medium/en_US-kristin-medium.onnx.json
Normal file
502
models/en_US-kristin-medium/en_US-kristin-medium.onnx.json
Normal file
@ -0,0 +1,502 @@
|
|||||||
|
{
|
||||||
|
"dataset": "kristin",
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "medium"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "en"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"code": "en_US",
|
||||||
|
"family": "en",
|
||||||
|
"region": "US",
|
||||||
|
"name_native": "English",
|
||||||
|
"name_english": "English",
|
||||||
|
"country_english": "United States"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.667,
|
||||||
|
"length_scale": 1,
|
||||||
|
"noise_w": 0.8
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"X": [
|
||||||
|
156
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"g": [
|
||||||
|
154
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʦ": [
|
||||||
|
155
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̺": [
|
||||||
|
152
|
||||||
|
],
|
||||||
|
"̻": [
|
||||||
|
153
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 1,
|
||||||
|
"speaker_id_map": {},
|
||||||
|
"piper_version": "1.0.0"
|
||||||
|
}
|
||||||
493
models/piper/de_DE-thorsten-high/de_DE-thorsten-high.onnx.json
Normal file
493
models/piper/de_DE-thorsten-high/de_DE-thorsten-high.onnx.json
Normal file
@ -0,0 +1,493 @@
|
|||||||
|
{
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "high"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "de"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.667,
|
||||||
|
"length_scale": 1,
|
||||||
|
"noise_w": 0.8
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
],
|
||||||
|
"̺": [
|
||||||
|
152
|
||||||
|
],
|
||||||
|
"̻": [
|
||||||
|
153
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 1,
|
||||||
|
"speaker_id_map": {},
|
||||||
|
"piper_version": "1.0.0",
|
||||||
|
"language": {
|
||||||
|
"code": "de_DE",
|
||||||
|
"family": "de",
|
||||||
|
"region": "DE",
|
||||||
|
"name_native": "Deutsch",
|
||||||
|
"name_english": "German",
|
||||||
|
"country_english": "Germany"
|
||||||
|
},
|
||||||
|
"dataset": "thorsten"
|
||||||
|
}
|
||||||
@ -0,0 +1,502 @@
|
|||||||
|
{
|
||||||
|
"piper_version": "1.1.0",
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "medium"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "de"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.667,
|
||||||
|
"length_scale": 1,
|
||||||
|
"noise_w": 0.8
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
],
|
||||||
|
"̺": [
|
||||||
|
152
|
||||||
|
],
|
||||||
|
"̻": [
|
||||||
|
153
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 8,
|
||||||
|
"speaker_id_map": {
|
||||||
|
"amused": 0,
|
||||||
|
"angry": 1,
|
||||||
|
"disgusted": 2,
|
||||||
|
"drunk": 3,
|
||||||
|
"neutral": 4,
|
||||||
|
"sleepy": 5,
|
||||||
|
"surprised": 6,
|
||||||
|
"whisper": 7
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"code": "de_DE",
|
||||||
|
"family": "de",
|
||||||
|
"region": "DE",
|
||||||
|
"name_native": "Deutsch",
|
||||||
|
"name_english": "German",
|
||||||
|
"country_english": "Germany"
|
||||||
|
},
|
||||||
|
"dataset": "thorsten_emotional"
|
||||||
|
}
|
||||||
502
models/piper/en_GB-cori-high/en_GB-cori-high.onnx.json
Normal file
502
models/piper/en_GB-cori-high/en_GB-cori-high.onnx.json
Normal file
@ -0,0 +1,502 @@
|
|||||||
|
{
|
||||||
|
"dataset": "cori",
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "high"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "en"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"code": "en_GB",
|
||||||
|
"family": "en",
|
||||||
|
"region": "GB",
|
||||||
|
"name_native": "English",
|
||||||
|
"name_english": "English",
|
||||||
|
"country_english": "Great Britain"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.667,
|
||||||
|
"length_scale": 1,
|
||||||
|
"noise_w": 0.8
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"X": [
|
||||||
|
156
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"g": [
|
||||||
|
154
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʦ": [
|
||||||
|
155
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̺": [
|
||||||
|
152
|
||||||
|
],
|
||||||
|
"̻": [
|
||||||
|
153
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 1,
|
||||||
|
"speaker_id_map": {},
|
||||||
|
"piper_version": "1.0.0"
|
||||||
|
}
|
||||||
603
models/piper/en_GB-vctk-medium/en_GB-vctk-medium.onnx.json
Normal file
603
models/piper/en_GB-vctk-medium/en_GB-vctk-medium.onnx.json
Normal file
@ -0,0 +1,603 @@
|
|||||||
|
{
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "medium"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "en-gb-x-rp"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.333,
|
||||||
|
"length_scale": 1.4,
|
||||||
|
"noise_w": 0.333
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
],
|
||||||
|
"̺": [
|
||||||
|
152
|
||||||
|
],
|
||||||
|
"̻": [
|
||||||
|
153
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 109,
|
||||||
|
"speaker_id_map": {
|
||||||
|
"p239": 0,
|
||||||
|
"p236": 1,
|
||||||
|
"p264": 2,
|
||||||
|
"p250": 3,
|
||||||
|
"p259": 4,
|
||||||
|
"p247": 5,
|
||||||
|
"p261": 6,
|
||||||
|
"p263": 7,
|
||||||
|
"p283": 8,
|
||||||
|
"p286": 9,
|
||||||
|
"p274": 10,
|
||||||
|
"p276": 11,
|
||||||
|
"p270": 12,
|
||||||
|
"p281": 13,
|
||||||
|
"p277": 14,
|
||||||
|
"p231": 15,
|
||||||
|
"p271": 16,
|
||||||
|
"p238": 17,
|
||||||
|
"p257": 18,
|
||||||
|
"p273": 19,
|
||||||
|
"p284": 20,
|
||||||
|
"p329": 21,
|
||||||
|
"p361": 22,
|
||||||
|
"p287": 23,
|
||||||
|
"p360": 24,
|
||||||
|
"p374": 25,
|
||||||
|
"p376": 26,
|
||||||
|
"p310": 27,
|
||||||
|
"p304": 28,
|
||||||
|
"p334": 29,
|
||||||
|
"p340": 30,
|
||||||
|
"p323": 31,
|
||||||
|
"p347": 32,
|
||||||
|
"p330": 33,
|
||||||
|
"p308": 34,
|
||||||
|
"p314": 35,
|
||||||
|
"p317": 36,
|
||||||
|
"p339": 37,
|
||||||
|
"p311": 38,
|
||||||
|
"p294": 39,
|
||||||
|
"p305": 40,
|
||||||
|
"p266": 41,
|
||||||
|
"p335": 42,
|
||||||
|
"p318": 43,
|
||||||
|
"p351": 44,
|
||||||
|
"p333": 45,
|
||||||
|
"p313": 46,
|
||||||
|
"p316": 47,
|
||||||
|
"p244": 48,
|
||||||
|
"p307": 49,
|
||||||
|
"p363": 50,
|
||||||
|
"p336": 51,
|
||||||
|
"p297": 52,
|
||||||
|
"p312": 53,
|
||||||
|
"p267": 54,
|
||||||
|
"p275": 55,
|
||||||
|
"p295": 56,
|
||||||
|
"p258": 57,
|
||||||
|
"p288": 58,
|
||||||
|
"p301": 59,
|
||||||
|
"p232": 60,
|
||||||
|
"p292": 61,
|
||||||
|
"p272": 62,
|
||||||
|
"p280": 63,
|
||||||
|
"p278": 64,
|
||||||
|
"p341": 65,
|
||||||
|
"p268": 66,
|
||||||
|
"p298": 67,
|
||||||
|
"p299": 68,
|
||||||
|
"p279": 69,
|
||||||
|
"p285": 70,
|
||||||
|
"p326": 71,
|
||||||
|
"p300": 72,
|
||||||
|
"s5": 73,
|
||||||
|
"p230": 74,
|
||||||
|
"p345": 75,
|
||||||
|
"p254": 76,
|
||||||
|
"p269": 77,
|
||||||
|
"p293": 78,
|
||||||
|
"p252": 79,
|
||||||
|
"p262": 80,
|
||||||
|
"p243": 81,
|
||||||
|
"p227": 82,
|
||||||
|
"p343": 83,
|
||||||
|
"p255": 84,
|
||||||
|
"p229": 85,
|
||||||
|
"p240": 86,
|
||||||
|
"p248": 87,
|
||||||
|
"p253": 88,
|
||||||
|
"p233": 89,
|
||||||
|
"p228": 90,
|
||||||
|
"p282": 91,
|
||||||
|
"p251": 92,
|
||||||
|
"p246": 93,
|
||||||
|
"p234": 94,
|
||||||
|
"p226": 95,
|
||||||
|
"p260": 96,
|
||||||
|
"p245": 97,
|
||||||
|
"p241": 98,
|
||||||
|
"p303": 99,
|
||||||
|
"p265": 100,
|
||||||
|
"p306": 101,
|
||||||
|
"p237": 102,
|
||||||
|
"p249": 103,
|
||||||
|
"p256": 104,
|
||||||
|
"p302": 105,
|
||||||
|
"p364": 106,
|
||||||
|
"p225": 107,
|
||||||
|
"p362": 108
|
||||||
|
},
|
||||||
|
"piper_version": "1.0.0",
|
||||||
|
"language": {
|
||||||
|
"code": "en_GB",
|
||||||
|
"family": "en",
|
||||||
|
"region": "GB",
|
||||||
|
"name_native": "English",
|
||||||
|
"name_english": "English",
|
||||||
|
"country_english": "Great Britain"
|
||||||
|
},
|
||||||
|
"dataset": "vctk"
|
||||||
|
}
|
||||||
@ -0,0 +1,508 @@
|
|||||||
|
{
|
||||||
|
"dataset": "hfc_female",
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "medium"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "en-us"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"code": "en_US",
|
||||||
|
"family": "en",
|
||||||
|
"region": "US",
|
||||||
|
"name_native": "English",
|
||||||
|
"name_english": "English",
|
||||||
|
"country_english": "United States"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.667,
|
||||||
|
"length_scale": 1,
|
||||||
|
"noise_w": 0.8
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"X": [
|
||||||
|
156
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"g": [
|
||||||
|
154
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʦ": [
|
||||||
|
155
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̊": [
|
||||||
|
158
|
||||||
|
],
|
||||||
|
"̝": [
|
||||||
|
157
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̺": [
|
||||||
|
152
|
||||||
|
],
|
||||||
|
"̻": [
|
||||||
|
153
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 1,
|
||||||
|
"speaker_id_map": {},
|
||||||
|
"piper_version": "1.0.0"
|
||||||
|
}
|
||||||
502
models/piper/en_US-kristin-medium/en_US-kristin-medium.onnx.json
Normal file
502
models/piper/en_US-kristin-medium/en_US-kristin-medium.onnx.json
Normal file
@ -0,0 +1,502 @@
|
|||||||
|
{
|
||||||
|
"dataset": "kristin",
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "medium"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "en"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"code": "en_US",
|
||||||
|
"family": "en",
|
||||||
|
"region": "US",
|
||||||
|
"name_native": "English",
|
||||||
|
"name_english": "English",
|
||||||
|
"country_english": "United States"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.667,
|
||||||
|
"length_scale": 1,
|
||||||
|
"noise_w": 0.8
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"X": [
|
||||||
|
156
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"g": [
|
||||||
|
154
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʦ": [
|
||||||
|
155
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̺": [
|
||||||
|
152
|
||||||
|
],
|
||||||
|
"̻": [
|
||||||
|
153
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 1,
|
||||||
|
"speaker_id_map": {},
|
||||||
|
"piper_version": "1.0.0"
|
||||||
|
}
|
||||||
22
requirements.txt
Normal file
22
requirements.txt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# NovaAi – TTS-Engine-Hub
|
||||||
|
# requirements.txt
|
||||||
|
# Version: v0.0.1
|
||||||
|
|
||||||
|
fastapi
|
||||||
|
uvicorn
|
||||||
|
gunicorn
|
||||||
|
pydantic
|
||||||
|
pydantic-settings
|
||||||
|
ffmpeg-python
|
||||||
|
piper-tts
|
||||||
|
|
||||||
|
|
||||||
|
f5-tts
|
||||||
|
torch
|
||||||
|
torchaudio
|
||||||
|
|
||||||
|
# Development & Testing
|
||||||
|
pytest-cov
|
||||||
|
pytest-asyncio
|
||||||
|
|
||||||
|
|
||||||
21
run.sh
Executable file
21
run.sh
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# NovaAi – TTS-Engine-Hub
|
||||||
|
# run.sh
|
||||||
|
# Version: v0.0.1
|
||||||
|
#
|
||||||
|
# Activates venv and runs main.py via uvicorn (with reload for dev convenience).
|
||||||
|
# Author: Abby (ChatGPT)
|
||||||
|
# Date: 2025-07-23
|
||||||
|
# Canvas: run.sh
|
||||||
|
|
||||||
|
if [ ! -d ".venv" ]; then
|
||||||
|
echo "Virtual environment not found! Please run setup_env.sh first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
source .venv/bin/activate
|
||||||
|
|
||||||
|
export PYTHONPATH=$(pwd)
|
||||||
|
|
||||||
|
python main.py
|
||||||
|
|
||||||
34
setup_env.sh
Normal file
34
setup_env.sh
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# NovaAi – TTS-Engine-Hub
|
||||||
|
# setup_env.sh
|
||||||
|
# Version: v0.0.1
|
||||||
|
#
|
||||||
|
# Deletes old venv (if exists), creates new one, and installs dependencies from requirements.txt.
|
||||||
|
# Author: Abby (ChatGPT)
|
||||||
|
# Date: 2025-07-23
|
||||||
|
# Canvas: setup_env.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -d ".venv" ]; then
|
||||||
|
echo "Removing existing venv..."
|
||||||
|
rm -rf .venv
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Creating new virtual environment..."
|
||||||
|
python3 -m venv .venv
|
||||||
|
|
||||||
|
echo "Activating virtual environment..."
|
||||||
|
source .venv/bin/activate
|
||||||
|
|
||||||
|
if [ ! -f requirements.txt ]; then
|
||||||
|
echo "requirements.txt not found!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Installing requirements..."
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
echo "Setup complete!"
|
||||||
|
|
||||||
34
tests/conftest.py
Normal file
34
tests/conftest.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import pytest
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
from main import create_app # Import the app factory function
|
||||||
|
from config import settings # Import settings to monkeypatch
|
||||||
|
import os
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def tmp_audio_dir(tmp_path):
|
||||||
|
"""Provides a temporary directory for audio caching for each test."""
|
||||||
|
audio_dir = tmp_path / "test_audio_cache"
|
||||||
|
audio_dir.mkdir()
|
||||||
|
return audio_dir
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def app_instance(tmp_audio_dir, monkeypatch):
|
||||||
|
"""
|
||||||
|
Provides a fresh FastAPI application instance for each test,
|
||||||
|
with its AUDIO_CACHE_DIR redirected to a temporary location.
|
||||||
|
"""
|
||||||
|
monkeypatch.setattr(settings, "AUDIO_CACHE_DIR", str(tmp_audio_dir))
|
||||||
|
app = create_app()
|
||||||
|
return app
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def app_client(app_instance):
|
||||||
|
"""Provides a TestClient instance for the FastAPI application."""
|
||||||
|
with TestClient(app_instance) as client:
|
||||||
|
yield client
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def piper_engine(app_instance):
|
||||||
|
"""Provides the PiperEngine instance from the registry of the fresh app instance."""
|
||||||
|
# Access the engine registry from the app_instance
|
||||||
|
return app_instance.ENGINE_REGISTRY.get("piper")
|
||||||
123
tests/test_api.py
Normal file
123
tests/test_api.py
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
from fastapi.testclient import TestClient
|
||||||
|
import pytest
|
||||||
|
# from main import app, ENGINE_REGISTRY # No longer needed, using fixtures
|
||||||
|
import shutil
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
TEST_TEXT = "Dies ist ein NovaAi Test."
|
||||||
|
# Ensure the engine being tested is in the default .env config
|
||||||
|
ENGINE = "piper"
|
||||||
|
MODEL = "de_DE-thorsten-high"
|
||||||
|
FORMAT = "ogg"
|
||||||
|
|
||||||
|
# === Happy Path Tests ===
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_tts_link_success(app_client):
|
||||||
|
"""Tests successful synthesis returning a URL."""
|
||||||
|
resp = app_client.post("/tts", json={
|
||||||
|
"text": TEST_TEXT,
|
||||||
|
"engine": ENGINE,
|
||||||
|
"model": MODEL,
|
||||||
|
"format": FORMAT
|
||||||
|
})
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert "audio_url" in data
|
||||||
|
|
||||||
|
# Also test the audio download endpoint
|
||||||
|
audio_url = data['audio_url']
|
||||||
|
audio_resp = app_client.get(audio_url)
|
||||||
|
assert audio_resp.status_code == 200
|
||||||
|
assert len(audio_resp.content) > 1000
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_tts_base64_success(app_client):
|
||||||
|
"""Tests successful synthesis returning base64 data."""
|
||||||
|
resp = app_client.post("/tts?as=true", json={
|
||||||
|
"text": TEST_TEXT,
|
||||||
|
"engine": ENGINE,
|
||||||
|
"model": MODEL,
|
||||||
|
"format": FORMAT
|
||||||
|
})
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert "audio_base64" in data
|
||||||
|
assert len(data["audio_base64"]) > 1000
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_health_and_engines_endpoints(app_client):
|
||||||
|
"""Tests the /health and /engines endpoints for correct responses."""
|
||||||
|
resp_engines = app_client.get("/engines")
|
||||||
|
assert resp_engines.status_code == 200
|
||||||
|
engines = resp_engines.json()
|
||||||
|
assert ENGINE in engines
|
||||||
|
|
||||||
|
resp_health = app_client.get("/health")
|
||||||
|
assert resp_health.status_code == 200
|
||||||
|
health = resp_health.json()
|
||||||
|
assert health["status"][ENGINE] == "ok"
|
||||||
|
|
||||||
|
# === Failure Path Tests ===
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_tts_fails_with_invalid_engine(app_client):
|
||||||
|
"""Tests that a request with a non-existent engine fails with HTTP 404."""
|
||||||
|
response = app_client.post("/tts", json={
|
||||||
|
"text": TEST_TEXT,
|
||||||
|
"engine": "non_existent_engine",
|
||||||
|
"model": MODEL,
|
||||||
|
})
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert "Engine 'non_existent_engine' not found" in response.json()["detail"]
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_tts_fails_with_invalid_model(app_client):
|
||||||
|
"""Tests that a request with a non-existent model fails with HTTP 400."""
|
||||||
|
response = app_client.post("/tts", json={
|
||||||
|
"text": TEST_TEXT,
|
||||||
|
"engine": ENGINE,
|
||||||
|
"model": "non_existent_model",
|
||||||
|
})
|
||||||
|
assert response.status_code == 400
|
||||||
|
assert "Model 'non_existent_model' not found" in response.json()["detail"]
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_tts_fails_with_invalid_speaker(app_client, piper_engine):
|
||||||
|
"""Tests that a request with a non-existent speaker fails with HTTP 400."""
|
||||||
|
# This model has speakers, so requesting a non-existent one should fail.
|
||||||
|
# We need to pick a model that is known to have multiple speakers
|
||||||
|
# The default piper engine models should have this.
|
||||||
|
model_with_speakers = "en_US-kristin-medium" # Example model with speakers
|
||||||
|
|
||||||
|
# First, check if the model is actually available to test against
|
||||||
|
if model_with_speakers not in piper_engine.list_models():
|
||||||
|
pytest.skip(f"Model '{model_with_speakers}' not available for '{ENGINE}' to test against.")
|
||||||
|
|
||||||
|
response = app_client.post("/tts", json={
|
||||||
|
"text": "This is a test.",
|
||||||
|
"engine": ENGINE,
|
||||||
|
"model": model_with_speakers,
|
||||||
|
"speaker": "non_existent_speaker"
|
||||||
|
})
|
||||||
|
assert response.status_code == 400
|
||||||
|
assert "Speaker 'non_existent_speaker' not found" in response.json()["detail"]
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_tts_fails_with_unavailable_engine(app_client, piper_engine, monkeypatch):
|
||||||
|
"""Tests that a request fails with HTTP 503 if an engine is unhealthy."""
|
||||||
|
# Simulate the piper executable being not found by monkeypatching the specific instance
|
||||||
|
monkeypatch.setattr(piper_engine, "piper_executable", None)
|
||||||
|
|
||||||
|
response = app_client.post("/tts", json={
|
||||||
|
"text": TEST_TEXT,
|
||||||
|
"engine": ENGINE,
|
||||||
|
"model": MODEL,
|
||||||
|
})
|
||||||
|
|
||||||
|
assert response.status_code == 503
|
||||||
|
assert "is not available" in response.json()["detail"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
70
tests/test_f5_tts.py
Normal file
70
tests/test_f5_tts.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import asyncio
|
||||||
|
from importlib.resources import files
|
||||||
|
from engines.f5_tts import F5TTSEngine
|
||||||
|
|
||||||
|
class TestF5TTSEngine(unittest.TestCase):
|
||||||
|
async def asyncSetUp(self):
|
||||||
|
self.engine = F5TTSEngine()
|
||||||
|
self.voices_dir = "engines/f5-tts-voices"
|
||||||
|
self.test_speaker_name = "test_speaker"
|
||||||
|
self.test_speaker_wav = os.path.join(self.voices_dir, f"{self.test_speaker_name}.wav")
|
||||||
|
self.test_speaker_txt = os.path.join(self.voices_dir, f"{self.test_speaker_name}.txt")
|
||||||
|
|
||||||
|
# Create a dummy speaker for testing
|
||||||
|
if not await asyncio.to_thread(os.path.exists, self.test_speaker_wav):
|
||||||
|
default_wav_path = str(files("f5_tts").joinpath("infer/examples/basic/basic_ref_en.wav"))
|
||||||
|
await asyncio.to_thread(shutil.copy, default_wav_path, self.test_speaker_wav)
|
||||||
|
if not await asyncio.to_thread(os.path.exists, self.test_speaker_txt):
|
||||||
|
await asyncio.to_thread(lambda: open(self.test_speaker_txt, "w").write("Some call me nature, others call me mother nature."))
|
||||||
|
|
||||||
|
# Reload speakers to include the new test speaker
|
||||||
|
self.engine._load_speakers()
|
||||||
|
|
||||||
|
async def asyncTearDown(self):
|
||||||
|
# Clean up the dummy speaker files
|
||||||
|
if await asyncio.to_thread(os.path.exists, self.test_speaker_wav):
|
||||||
|
await asyncio.to_thread(os.remove, self.test_speaker_wav)
|
||||||
|
if await asyncio.to_thread(os.path.exists, self.test_speaker_txt):
|
||||||
|
await asyncio.to_thread(os.remove, self.test_speaker_txt)
|
||||||
|
|
||||||
|
async def test_synthesize_default_wav(self):
|
||||||
|
if not self.engine.model:
|
||||||
|
self.skipTest("F5-TTS model not initialized.")
|
||||||
|
|
||||||
|
text = "Hello, this is a test with the default voice."
|
||||||
|
audio_file = await self.engine.synthesize(text, fmt="wav")
|
||||||
|
|
||||||
|
self.assertTrue(await asyncio.to_thread(os.path.exists, audio_file))
|
||||||
|
self.assertTrue(await asyncio.to_thread(os.path.getsize, audio_file) > 0)
|
||||||
|
|
||||||
|
await asyncio.to_thread(os.remove, audio_file)
|
||||||
|
|
||||||
|
async def test_synthesize_custom_speaker_wav(self):
|
||||||
|
if not self.engine.model:
|
||||||
|
self.skipTest("F5-TTS model not initialized.")
|
||||||
|
|
||||||
|
text = "Hello, this is a test with a custom voice."
|
||||||
|
audio_file = await self.engine.synthesize(text, speaker=self.test_speaker_name, fmt="wav")
|
||||||
|
|
||||||
|
self.assertTrue(await asyncio.to_thread(os.path.exists, audio_file))
|
||||||
|
self.assertTrue(await asyncio.to_thread(os.path.getsize, audio_file) > 0)
|
||||||
|
|
||||||
|
await asyncio.to_thread(os.remove, audio_file)
|
||||||
|
|
||||||
|
async def test_synthesize_ogg(self):
|
||||||
|
if not self.engine.model:
|
||||||
|
self.skipTest("F5-TTS model not initialized.")
|
||||||
|
|
||||||
|
text = "Hello, this is a test in ogg format."
|
||||||
|
audio_file = await self.engine.synthesize(text, fmt="ogg")
|
||||||
|
|
||||||
|
self.assertTrue(await asyncio.to_thread(os.path.exists, audio_file))
|
||||||
|
self.assertTrue(await asyncio.to_thread(os.path.getsize, audio_file) > 0)
|
||||||
|
|
||||||
|
await asyncio.to_thread(os.remove, audio_file)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
76
utils/audio.py
Normal file
76
utils/audio.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
"""
|
||||||
|
NovaAi – TTS-Engine-Hub
|
||||||
|
utils/audio.py
|
||||||
|
Version: v0.0.1
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Audio processing utilities: concat, merging chunks, etc.
|
||||||
|
|
||||||
|
Author: Abby (ChatGPT)
|
||||||
|
Date: 2025-07-23
|
||||||
|
Canvas: utils/audio.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
import ffmpeg
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
def check_ffmpeg():
|
||||||
|
"""Check if ffmpeg is installed and available in the system's PATH."""
|
||||||
|
return shutil.which("ffmpeg") is not None
|
||||||
|
|
||||||
|
def concat_audio(files, fmt):
|
||||||
|
"""
|
||||||
|
Concatenate a list of audio files into a single file of the given format.
|
||||||
|
Supports: wav, ogg, mp3
|
||||||
|
"""
|
||||||
|
if len(files) == 1:
|
||||||
|
# If there's only one file, just return it, no cleanup needed here.
|
||||||
|
return files[0]
|
||||||
|
|
||||||
|
# Securely create a temporary file for the output
|
||||||
|
with tempfile.NamedTemporaryFile(suffix=f'.{fmt}', prefix="chunked_", delete=False) as temp_output_file:
|
||||||
|
output_file_path = temp_output_file.name
|
||||||
|
|
||||||
|
try:
|
||||||
|
if fmt == "wav":
|
||||||
|
import wave
|
||||||
|
data = []
|
||||||
|
params = None
|
||||||
|
for f in files:
|
||||||
|
with wave.open(f, 'rb') as wf:
|
||||||
|
if params is None:
|
||||||
|
params = wf.getparams()
|
||||||
|
data.append(wf.readframes(wf.getnframes()))
|
||||||
|
with wave.open(output_file_path, 'wb') as wf:
|
||||||
|
wf.setparams(params)
|
||||||
|
for d in data:
|
||||||
|
wf.writeframes(d)
|
||||||
|
else:
|
||||||
|
if not check_ffmpeg():
|
||||||
|
raise RuntimeError("ffmpeg not found. Please install ffmpeg and ensure it is in your PATH.")
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile("w", delete=False) as tf:
|
||||||
|
list_file_path = tf.name
|
||||||
|
for f in files:
|
||||||
|
tf.write(f"file '{os.path.abspath(f)}'\\n")
|
||||||
|
tf.flush()
|
||||||
|
|
||||||
|
try:
|
||||||
|
(
|
||||||
|
ffmpeg
|
||||||
|
.input(list_file_path, format='concat', safe=0)
|
||||||
|
.output(output_file_path, acodec='copy')
|
||||||
|
.run(overwrite_output=True, quiet=True)
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
os.unlink(list_file_path)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Clean up the input chunk files
|
||||||
|
for f in files:
|
||||||
|
if os.path.exists(f):
|
||||||
|
os.remove(f)
|
||||||
|
|
||||||
|
return output_file_path
|
||||||
22
utils/cache.py
Normal file
22
utils/cache.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
NovaAi – TTS-Engine-Hub
|
||||||
|
utils/cache.py
|
||||||
|
Version: v0.0.1
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Caching utilities for TTS requests (cache key generation, etc).
|
||||||
|
|
||||||
|
Author: Abby (ChatGPT)
|
||||||
|
Date: 2025-07-23
|
||||||
|
Canvas: utils/cache.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
# Für die API: Wichtig! req muss mindestens die Felder .text, .engine, .model, .speaker, .format, .chunking haben.
|
||||||
|
def build_cache_key(req) -> str:
|
||||||
|
"""
|
||||||
|
Build a cache key from all relevant TTS request parameters.
|
||||||
|
"""
|
||||||
|
data = f"{req.text}|{req.engine}|{req.model}|{req.speaker}|{req.format}|{getattr(req, 'chunking', False)}"
|
||||||
|
return hashlib.sha256(data.encode()).hexdigest()
|
||||||
30
utils/text.py
Normal file
30
utils/text.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
"""
|
||||||
|
NovaAi – TTS-Engine-Hub
|
||||||
|
utils/text.py
|
||||||
|
Version: v0.0.1
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Text processing utilities: chunking, splitting, etc.
|
||||||
|
|
||||||
|
Author: Abby (ChatGPT)
|
||||||
|
Date: 2025-07-23
|
||||||
|
Canvas: utils/text.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
def chunk_text(text, maxlen=250):
|
||||||
|
"""
|
||||||
|
Split text into chunks of roughly maxlen (split at sentence boundaries if possible).
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
sentences = re.split(r'([.!?]\s)', text)
|
||||||
|
chunks = []
|
||||||
|
buf = ""
|
||||||
|
for s in sentences:
|
||||||
|
if len(buf) + len(s) > maxlen:
|
||||||
|
if buf:
|
||||||
|
chunks.append(buf.strip())
|
||||||
|
buf = ""
|
||||||
|
buf += s
|
||||||
|
if buf.strip():
|
||||||
|
chunks.append(buf.strip())
|
||||||
|
return [c for c in chunks if c.strip()]
|
||||||
Reference in New Issue
Block a user