File size: 2,313 Bytes
a960dea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import base64
import io
import sys
import tempfile
from pathlib import Path

import torch
import torchaudio

REPO_DIR = Path(__file__).resolve().parent
sys.path.insert(0, str(REPO_DIR))
sys.path.insert(0, str(REPO_DIR / "third_party" / "Matcha-TTS"))

from accent_config import ACCENT_INSTRUCTIONS  # noqa: E402


class EndpointHandler:
    def __init__(self, path=""):
        self.model_dir = Path(path or __file__).resolve()
        if self.model_dir.is_file():
            self.model_dir = self.model_dir.parent
        from cosyvoice.cli.cosyvoice import AutoModel

        self.model = AutoModel(
            model_dir=str(self.model_dir),
            fp16=torch.cuda.is_available(),
            load_vllm=False,
        )

    def __call__(self, data):
        text = data.get("inputs", "")
        parameters = data.get("parameters", {})
        accent = parameters.get("accent", "singapore")
        if not text:
            raise ValueError("inputs must contain Chinese text")
        if accent not in ACCENT_INSTRUCTIONS:
            raise ValueError(f"accent must be one of: {', '.join(ACCENT_INSTRUCTIONS)}")

        prompt_path = self.model_dir / "zero_shot_prompt.wav"
        prompt_audio = parameters.get("prompt_audio_base64")
        temp_path = None
        if prompt_audio:
            with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as handle:
                handle.write(base64.b64decode(prompt_audio))
                temp_path = Path(handle.name)
                prompt_path = temp_path
        try:
            chunks = [item["tts_speech"] for item in self.model.inference_instruct2(
                text,
                ACCENT_INSTRUCTIONS[accent],
                str(prompt_path),
                stream=False,
                speed=float(parameters.get("speed", 1.0)),
            )]
            speech = torch.cat(chunks, dim=1).cpu()
            buffer = io.BytesIO()
            torchaudio.save(buffer, speech, self.model.sample_rate, format="wav")
            return {
                "audio_base64": base64.b64encode(buffer.getvalue()).decode("ascii"),
                "sample_rate": self.model.sample_rate,
                "accent": accent,
            }
        finally:
            if temp_path is not None:
                temp_path.unlink(missing_ok=True)