Files
abogen/abogen/webui/routes/voices.py
T
Artem Akymenko f8f72624f8 refactor(webui): replace direct VOICES_INTERNAL/DEFAULT_SUPERTONIC_VOICES with get_metadata API
- Add get_default_voice() helper to tts_backend_registry
- Replace all VOICES_INTERNAL imports in WebUI with get_metadata().voices
- Replace all DEFAULT_SUPERTONIC_VOICES imports in conversion_runner with get_metadata().voices
- Remove unused VOICES_INTERNAL import from voices.py

Core modules (voice_profiles, voice_formulas, voice_cache) already used
get_metadata(). This completes the WebUI migration.
2026-07-08 15:42:49 +00:00

141 lines
4.4 KiB
Python

from typing import Any, Dict, List, Optional
from flask import Blueprint, render_template, request, jsonify, abort, flash, redirect, url_for
from flask.typing import ResponseReturnValue
from abogen.webui.routes.utils.voice import (
template_options,
resolve_voice_setting,
resolve_voice_choice,
parse_voice_formula,
)
from abogen.webui.routes.utils.settings import load_settings, coerce_bool
from abogen.webui.routes.utils.preview import synthesize_preview
from abogen.speaker_configs import (
list_configs,
get_config,
load_configs,
save_configs,
delete_config,
)
voices_bp = Blueprint("voices", __name__)
@voices_bp.get("/")
def voice_profiles() -> ResponseReturnValue:
return render_template("voices.html", options=template_options())
@voices_bp.post("/test")
def test_voice() -> ResponseReturnValue:
text = (request.form.get("text") or "").strip()
voice = (request.form.get("voice") or "").strip()
speed = float(request.form.get("speed", 1.0))
# This seems to be the form-based preview
settings = load_settings()
use_gpu = coerce_bool(settings.get("use_gpu"), True)
try:
return synthesize_preview(
text=text,
voice_spec=voice,
language="a", # Default language
speed=speed,
use_gpu=use_gpu,
)
except Exception as e:
abort(400, str(e))
@voices_bp.get("/configs")
def speaker_configs() -> ResponseReturnValue:
return jsonify({"configs": list_configs()})
@voices_bp.post("/configs/save")
def save_speaker_config() -> ResponseReturnValue:
payload = request.get_json(force=True)
name = (payload.get("name") or "").strip()
config = payload.get("config")
if not name:
abort(400, "Config name is required")
if not config:
abort(400, "Config data is required")
configs = load_configs()
configs[name] = config
save_configs(configs)
return jsonify({"status": "saved", "configs": list_configs()})
@voices_bp.post("/configs/delete")
def delete_speaker_config() -> ResponseReturnValue:
payload = request.get_json(force=True)
name = (payload.get("name") or "").strip()
if not name:
abort(400, "Config name is required")
delete_config(name)
return jsonify({"status": "deleted", "configs": list_configs()})
@voices_bp.route("/presets", methods=["GET", "POST"])
def speaker_configs_page() -> ResponseReturnValue:
configs = load_configs()
editing_name = request.args.get("config")
message = None
error = None
if request.method == "POST":
try:
name = request.form.get("config_name", "").strip()
if not name:
raise ValueError("Preset name is required")
language = request.form.get("config_language", "en")
speakers = []
row_keys = request.form.getlist("speaker_rows")
for key in row_keys:
s_id = request.form.get(f"speaker-{key}-id", key)
label = request.form.get(f"speaker-{key}-label", "")
gender = request.form.get(f"speaker-{key}-gender", "unknown")
voice = request.form.get(f"speaker-{key}-voice", "")
if label:
speakers.append({
"id": s_id,
"label": label,
"gender": gender,
"voice": voice or None
})
config = {
"name": name,
"language": language,
"speakers": speakers,
"version": 1
}
configs[name] = config
save_configs(configs)
message = f"Preset '{name}' saved."
editing_name = name
except Exception as e:
error = str(e)
editing = configs.get(editing_name, {}) if editing_name else {}
return render_template(
"speakers.html",
options=template_options(),
configs=configs.values(),
editing_name=editing_name,
editing=editing,
message=message,
error=error
)
@voices_bp.post("/presets/<name>/delete")
def delete_speaker_config_named(name: str) -> ResponseReturnValue:
delete_config(name)
return redirect(url_for("voices.speaker_configs_page"))