Initial commit: Korean voice-cloning TTS prototype
FastAPI backend, web UI, CosyVoice3/F5-TTS setup scripts, and handoff docs for GPU PC continuation. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
65
backend/app/config.py
Normal file
65
backend/app/config.py
Normal file
@@ -0,0 +1,65 @@
|
||||
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
|
||||
Reference in New Issue
Block a user