File size: 1,596 Bytes
6bcddd0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import os
import tempfile
import uuid
from pathlib import Path
from urllib.parse import urlparse


DEFAULT_TTS_URL = "https://veronicaulises0--virtual-characters-tts-charactertts-tts.modal.run"


def synthesize_sentence(text: str, character: dict, voice_state: dict | None = None) -> str | None:
    url = _tts_endpoint_url(os.environ.get("VC_MODAL_TTS_URL") or DEFAULT_TTS_URL)
    if not url or not text.strip():
        return None

    import httpx

    voice = character.get("voice", {})
    voice_state = voice_state or {}
    payload = {
        "text": text,
        "voice_id": voice_state.get("voice_id") or voice.get("voice_id", "default"),
        "emotion": voice_state.get("emotion") or voice_state.get("style") or "neutral",
        "speed": voice_state.get("speed", 1.0),
        "energy": voice_state.get("energy", voice.get("energy", 0.5)),
        "audio_prompt_path": voice_state.get("audio_prompt_path") or voice.get("audio_prompt_path"),
        "backend": voice.get("backend", "chatterbox"),
    }
    response = httpx.post(url, json=payload, timeout=180, trust_env=False)
    response.raise_for_status()
    path = Path(tempfile.gettempdir()) / f"virtual_characters_tts_{uuid.uuid4().hex}.wav"
    path.write_bytes(response.content)
    return str(path)


def _tts_endpoint_url(url: str | None) -> str | None:
    if not url:
        return None
    base = url.rstrip("/")
    parsed = urlparse(base)
    if not parsed.path or parsed.path == "/":
        return base
    if parsed.path.rstrip("/").rsplit("/", 1)[-1] == "tts":
        return base
    return base + "/tts"