File size: 1,560 Bytes
f9569f4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b066638
f9569f4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""ModelAdapter interface and supporting types.

Re-exports `Lang` and `ParamSpec` from `server.schemas` so that
adapter modules and the API layer share a single source of truth.
"""
from __future__ import annotations

from typing import Any, ClassVar, Protocol, runtime_checkable

from server.schemas import Lang, ParamSpec


@runtime_checkable
class ModelAdapter(Protocol):
    id: ClassVar[str]
    label: ClassVar[str]
    description: ClassVar[str]
    languages: ClassVar[list[Lang]]
    paralinguistic_tags: ClassVar[list[str]]
    supports_voice_clone: ClassVar[bool]
    params: ClassVar[list[ParamSpec]]

    def __init__(self, device: str) -> None: ...
    def load(self) -> None: ...
    def unload(self) -> None: ...
    def generate(
        self,
        text: str,
        reference_wav_path: str | None,
        language: str | None,
        params: dict[str, Any],
    ) -> tuple[bytes, int, int]: ...   # (wav_bytes, sample_rate, seed_used)


def is_valid_adapter(cls: type) -> bool:
    """Quick declarative-fields check (does not require instantiation)."""
    required = (
        "id",
        "label",
        "description",
        "languages",
        "paralinguistic_tags",
        "supports_voice_clone",
        "params",
    )
    if not all(hasattr(cls, n) for n in required):
        return False
    if not getattr(cls, "id", "").strip():
        return False
    if not isinstance(getattr(cls, "languages"), list):
        return False
    if not isinstance(getattr(cls, "params"), list):
        return False
    return True