FastAPI backend, web UI, CosyVoice3/F5-TTS setup scripts, and handoff docs for GPU PC continuation. Co-authored-by: Cursor <cursoragent@cursor.com>
66 lines
2.4 KiB
Python
66 lines
2.4 KiB
Python
from __future__ import annotations
|
|
|
|
from functools import lru_cache
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
from pydantic import Field
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
class AppSettings(BaseSettings):
|
|
model_config = SettingsConfigDict(
|
|
env_file=str(ROOT / ".env"),
|
|
env_file_encoding="utf-8",
|
|
extra="ignore",
|
|
)
|
|
|
|
tts_model: str = Field(default="cosyvoice", validation_alias="TTS_MODEL")
|
|
host: str = Field(default="0.0.0.0", validation_alias="TTS_HOST")
|
|
port: int = Field(default=8000, validation_alias="TTS_PORT")
|
|
samples_dir: Path = Field(default=ROOT / "samples")
|
|
outputs_dir: Path = Field(default=ROOT / "outputs" / "api")
|
|
uploads_dir: Path = Field(default=ROOT / "backend" / "data" / "uploads")
|
|
default_ref_audio: str | None = Field(default=None, validation_alias="TTS_REF_AUDIO")
|
|
default_ref_text: str | None = Field(default=None, validation_alias="TTS_REF_TEXT")
|
|
cosyvoice_model_dir: Path = Field(default=ROOT / "models" / "Fun-CosyVoice3-0.5B")
|
|
cosyvoice_prompt_prefix: str = (
|
|
"You are a helpful assistant.<|endofprompt|>"
|
|
)
|
|
chunk_max_chars: int = 120
|
|
|
|
|
|
@lru_cache
|
|
def get_settings() -> AppSettings:
|
|
yaml_path = ROOT / "config" / "settings.yaml"
|
|
data: dict = {}
|
|
if yaml_path.is_file():
|
|
with open(yaml_path, encoding="utf-8") as f:
|
|
raw = yaml.safe_load(f) or {}
|
|
data["tts_model"] = raw.get("default_model", "cosyvoice")
|
|
gen = raw.get("generation") or {}
|
|
data["chunk_max_chars"] = gen.get("chunk_max_chars", 120)
|
|
cv = raw.get("cosyvoice") or {}
|
|
if cv.get("model_dir"):
|
|
data["cosyvoice_model_dir"] = ROOT / cv["model_dir"]
|
|
if cv.get("prompt_prefix"):
|
|
data["cosyvoice_prompt_prefix"] = cv["prompt_prefix"]
|
|
srv = raw.get("server") or {}
|
|
data["host"] = srv.get("host", "0.0.0.0")
|
|
data["port"] = srv.get("port", 8000)
|
|
paths = raw.get("paths") or {}
|
|
if paths.get("samples_dir"):
|
|
data["samples_dir"] = ROOT / paths["samples_dir"]
|
|
if paths.get("outputs_dir"):
|
|
data["outputs_dir"] = ROOT / paths["outputs_dir"] / "api"
|
|
if paths.get("uploads_dir"):
|
|
data["uploads_dir"] = ROOT / paths["uploads_dir"]
|
|
|
|
return AppSettings(**{k: v for k, v in data.items() if v is not None})
|
|
|
|
|
|
def project_root() -> Path:
|
|
return ROOT
|