Ein OpenAI-kompatibler TTS-Server auf Ihrem eigenen Rechner
Viele Programme sprechen über die Sprach-API von OpenAI: Open WebUI, SillyTavern und alles, was auf dem OpenAI-SDK aufbaut, lassen Sie die Basis-URL ändern und POST /v1/audio/speech an einen anderen Server schicken. Zeigen Sie auf Ihren eigenen Server, und die Stimmen laufen auf Ihrem Rechner, kostenlos und offline.
Diese Anleitung baut diesen Server in rund 70 Zeilen Python mit der kostenlosen SuperClonica-Engine. Wir haben ihn mit dem offiziellen OpenAI-Python-Client getestet: Er liefert MP3, WAV oder rohes PCM und prüft einen optionalen Schlüssel.
Installation
Sie brauchen Python 3.10 oder neuer. Installieren Sie Engine, Webserver und Audio-Encoder:
pip install superclonica-cpu fastapi uvicorn av
Beim ersten Start lädt die Engine das Modell Supertonic 3, etwa 400 MB; danach läuft sie offline auf einem normalen Prozessor, eine NVIDIA-Grafikkarte macht sie nur schneller.
Der Server
Speichern Sie das als openai_tts.py:
import io, os, wave
import av
import numpy as np
from fastapi import FastAPI, Header, HTTPException
from fastapi.concurrency import run_in_threadpool
from fastapi.responses import Response
from pydantic import BaseModel
from superclonica import Superclonica
VOICES = {name: name for name in ["M1", "M2", "M3", "M4", "M5", "F1", "F2", "F3", "F4", "F5"]}
# a catalog voice: VOICES["narrator"] = "/path/to/voice-file-from-the-catalog"
LANGUAGE = os.environ.get("TTS_LANGUAGE", "en")
KEY = os.environ.get("TTS_KEY", "") # leave empty on a private machine
app = FastAPI()
tts = Superclonica()
class Speech(BaseModel):
input: str
voice: str = "F1"
model: str = "superclonica"
response_format: str = "mp3"
def to_wav(pcm, rate):
buffer = io.BytesIO()
with wave.open(buffer, "wb") as file:
file.setnchannels(1)
file.setsampwidth(2)
file.setframerate(rate)
file.writeframes(pcm.tobytes())
return buffer.getvalue()
def to_mp3(pcm, rate):
buffer = io.BytesIO()
with av.open(buffer, "w", format="mp3") as container:
stream = container.add_stream("libmp3lame", rate=rate, layout="mono")
frame = av.AudioFrame.from_ndarray(pcm.reshape(1, -1), format="s16", layout="mono")
frame.rate = rate
for packet in stream.encode(frame):
container.mux(packet)
for packet in stream.encode(None):
container.mux(packet)
return buffer.getvalue()
def speak(request):
voice = VOICES.get(request.voice, "F1")
audio, rate = tts.synthesize(request.input, voice=voice, lang=LANGUAGE)
pcm = (np.clip(np.asarray(audio, dtype=np.float32).reshape(-1), -1, 1) * 32767).astype(np.int16)
if request.response_format == "wav":
return to_wav(pcm, rate), "audio/wav"
if request.response_format == "pcm":
return pcm.tobytes(), "audio/pcm"
return to_mp3(pcm, rate), "audio/mpeg"
@app.post("/v1/audio/speech")
async def speech(request: Speech, authorization: str = Header("")):
if KEY and authorization != "Bearer " + KEY:
raise HTTPException(401)
audio, media_type = await run_in_threadpool(speak, request)
return Response(audio, media_type=media_type)
@app.get("/v1/models")
def models():
return {"object": "list", "data": [{"id": "superclonica", "object": "model"}]}
@app.get("/v1/audio/voices")
def voices():
return {"voices": list(VOICES)}Starten Sie ihn, er antwortet auf Port 8880:
uvicorn openai_tts:app --host 127.0.0.1 --port 8880
Das Feld voice nimmt eine der zehn Standardstimmen, M1 bis M5 und F1 bis F5; unbekannte Namen fallen auf F1 zurück, ein Client, der alloy schickt, bekommt also trotzdem eine Antwort. Setzen Sie TTS_LANGUAGE auf die Sprache Ihrer App: Die Engine spricht 31 Sprachen, aber noch kein Chinesisch. Setzen Sie TTS_KEY, wenn außer Ihnen jemand den Port erreicht.
Open WebUI verbinden
Öffnen Sie Admin Panel, Settings, Audio. Stellen Sie die Text-to-Speech Engine auf OpenAI, die API Base URL auf http://localhost:8880/v1, das TTS Model auf superclonica und die TTS Voice auf eine Standardstimme. Open WebUI will einen nicht leeren API-Schlüssel: Tragen Sie Ihren TTS_KEY ein oder beliebigen Text, wenn Sie ihn leer gelassen haben. Läuft Open WebUI in Docker, starten Sie den Server mit --host 0.0.0.0 und nutzen http://host.docker.internal:8880/v1; unter Linux braucht der Container --add-host=host.docker.internal:host-gateway. Lassen Sie Response Splitting auf punctuation, damit lange Antworten nach dem ersten Satz zu sprechen beginnen.
SillyTavern verbinden
Öffnen Sie Extensions, TTS und wählen Sie den Anbieter OpenAI Compatible. Tragen Sie http://localhost:8880/v1/audio/speech als Endpoint ein, superclonica als Modell, Ihren Schlüssel, und schreiben Sie die Stimmenliste selbst, weil dieser Anbieter sie nicht abruft: M1,M2,M3,M4,M5,F1,F2,F3,F4,F5. Geben Sie dann jeder Figur und Ihrer Persona in der Voice Map eine eigene Stimme und klicken Sie Apply.
Figurenstimmen und andere Clients
Für eine Stimme aus dem SuperClonica-Katalog laden Sie ihre Stimmdatei herunter und fügen eine Zeile wie VOICES["narrator"] = "/path/to/the/file" hinzu; der Name narrator funktioniert dann in jedem Client, auch in der Stimmenliste von SillyTavern. Auch jedes Programm mit dem OpenAI-SDK funktioniert: Erstellen Sie den Client mit base_url http://localhost:8880/v1 und rufen Sie audio.speech.create wie gewohnt auf.