isa-model 0.3.4__py3-none-any.whl → 0.3.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- isa_model/__init__.py +30 -1
- isa_model/client.py +770 -0
- isa_model/core/config/__init__.py +16 -0
- isa_model/core/config/config_manager.py +514 -0
- isa_model/core/config.py +426 -0
- isa_model/core/models/model_billing_tracker.py +476 -0
- isa_model/core/models/model_manager.py +399 -0
- isa_model/core/models/model_repo.py +343 -0
- isa_model/core/pricing_manager.py +426 -0
- isa_model/core/services/__init__.py +19 -0
- isa_model/core/services/intelligent_model_selector.py +547 -0
- isa_model/core/types.py +291 -0
- isa_model/deployment/__init__.py +2 -0
- isa_model/deployment/cloud/__init__.py +9 -0
- isa_model/deployment/cloud/modal/__init__.py +10 -0
- isa_model/deployment/cloud/modal/isa_vision_doc_service.py +766 -0
- isa_model/deployment/cloud/modal/isa_vision_table_service.py +532 -0
- isa_model/deployment/cloud/modal/isa_vision_ui_service.py +406 -0
- isa_model/deployment/cloud/modal/register_models.py +321 -0
- isa_model/deployment/runtime/deployed_service.py +338 -0
- isa_model/deployment/services/__init__.py +9 -0
- isa_model/deployment/services/auto_deploy_vision_service.py +537 -0
- isa_model/deployment/services/model_service.py +332 -0
- isa_model/deployment/services/service_monitor.py +356 -0
- isa_model/deployment/services/service_registry.py +527 -0
- isa_model/eval/__init__.py +80 -44
- isa_model/eval/config/__init__.py +10 -0
- isa_model/eval/config/evaluation_config.py +108 -0
- isa_model/eval/evaluators/__init__.py +18 -0
- isa_model/eval/evaluators/base_evaluator.py +503 -0
- isa_model/eval/evaluators/llm_evaluator.py +472 -0
- isa_model/eval/factory.py +417 -709
- isa_model/eval/infrastructure/__init__.py +24 -0
- isa_model/eval/infrastructure/experiment_tracker.py +466 -0
- isa_model/eval/metrics.py +191 -21
- isa_model/inference/ai_factory.py +187 -387
- isa_model/inference/providers/modal_provider.py +109 -0
- isa_model/inference/providers/yyds_provider.py +108 -0
- isa_model/inference/services/__init__.py +2 -1
- isa_model/inference/services/audio/base_stt_service.py +65 -1
- isa_model/inference/services/audio/base_tts_service.py +75 -1
- isa_model/inference/services/audio/openai_stt_service.py +189 -151
- isa_model/inference/services/audio/openai_tts_service.py +12 -10
- isa_model/inference/services/audio/replicate_tts_service.py +61 -56
- isa_model/inference/services/base_service.py +55 -55
- isa_model/inference/services/embedding/base_embed_service.py +65 -1
- isa_model/inference/services/embedding/ollama_embed_service.py +103 -43
- isa_model/inference/services/embedding/openai_embed_service.py +8 -10
- isa_model/inference/services/helpers/stacked_config.py +148 -0
- isa_model/inference/services/img/__init__.py +18 -0
- isa_model/inference/services/{vision → img}/base_image_gen_service.py +80 -35
- isa_model/inference/services/img/flux_professional_service.py +603 -0
- isa_model/inference/services/img/helpers/base_stacked_service.py +274 -0
- isa_model/inference/services/{vision → img}/replicate_image_gen_service.py +210 -69
- isa_model/inference/services/llm/__init__.py +3 -3
- isa_model/inference/services/llm/base_llm_service.py +519 -35
- isa_model/inference/services/llm/{llm_adapter.py → helpers/llm_adapter.py} +40 -0
- isa_model/inference/services/llm/helpers/llm_prompts.py +258 -0
- isa_model/inference/services/llm/helpers/llm_utils.py +280 -0
- isa_model/inference/services/llm/ollama_llm_service.py +150 -15
- isa_model/inference/services/llm/openai_llm_service.py +134 -31
- isa_model/inference/services/llm/yyds_llm_service.py +255 -0
- isa_model/inference/services/vision/__init__.py +38 -4
- isa_model/inference/services/vision/base_vision_service.py +241 -96
- isa_model/inference/services/vision/disabled/isA_vision_service.py +500 -0
- isa_model/inference/services/vision/doc_analysis_service.py +640 -0
- isa_model/inference/services/vision/helpers/base_stacked_service.py +274 -0
- isa_model/inference/services/vision/helpers/image_utils.py +272 -3
- isa_model/inference/services/vision/helpers/vision_prompts.py +297 -0
- isa_model/inference/services/vision/openai_vision_service.py +109 -170
- isa_model/inference/services/vision/replicate_vision_service.py +508 -0
- isa_model/inference/services/vision/ui_analysis_service.py +823 -0
- isa_model/scripts/register_models.py +370 -0
- isa_model/scripts/register_models_with_embeddings.py +510 -0
- isa_model/serving/__init__.py +19 -0
- isa_model/serving/api/__init__.py +10 -0
- isa_model/serving/api/fastapi_server.py +89 -0
- isa_model/serving/api/middleware/__init__.py +9 -0
- isa_model/serving/api/middleware/request_logger.py +88 -0
- isa_model/serving/api/routes/__init__.py +5 -0
- isa_model/serving/api/routes/health.py +82 -0
- isa_model/serving/api/routes/llm.py +19 -0
- isa_model/serving/api/routes/ui_analysis.py +223 -0
- isa_model/serving/api/routes/unified.py +202 -0
- isa_model/serving/api/routes/vision.py +19 -0
- isa_model/serving/api/schemas/__init__.py +17 -0
- isa_model/serving/api/schemas/common.py +33 -0
- isa_model/serving/api/schemas/ui_analysis.py +78 -0
- {isa_model-0.3.4.dist-info → isa_model-0.3.6.dist-info}/METADATA +4 -1
- isa_model-0.3.6.dist-info/RECORD +147 -0
- isa_model/core/model_manager.py +0 -208
- isa_model/core/model_registry.py +0 -342
- isa_model/inference/billing_tracker.py +0 -406
- isa_model/inference/services/llm/triton_llm_service.py +0 -481
- isa_model/inference/services/vision/ollama_vision_service.py +0 -194
- isa_model-0.3.4.dist-info/RECORD +0 -91
- /isa_model/core/{model_storage.py → models/model_storage.py} +0 -0
- /isa_model/inference/services/{vision → embedding}/helpers/text_splitter.py +0 -0
- {isa_model-0.3.4.dist-info → isa_model-0.3.6.dist-info}/WHEEL +0 -0
- {isa_model-0.3.4.dist-info → isa_model-0.3.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
"""
|
2
|
+
Modal Provider
|
3
|
+
|
4
|
+
Provider for ISA self-hosted Modal services
|
5
|
+
No API keys needed since we deploy our own services
|
6
|
+
"""
|
7
|
+
|
8
|
+
import os
|
9
|
+
import logging
|
10
|
+
from typing import Dict, Any, Optional, List
|
11
|
+
from .base_provider import BaseProvider
|
12
|
+
from isa_model.inference.base import ModelType, Capability
|
13
|
+
|
14
|
+
logger = logging.getLogger(__name__)
|
15
|
+
|
16
|
+
class ModalProvider(BaseProvider):
|
17
|
+
"""Provider for ISA Modal services"""
|
18
|
+
|
19
|
+
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
20
|
+
super().__init__(config)
|
21
|
+
self.name = "modal"
|
22
|
+
self.base_url = "https://modal.com" # Not used directly
|
23
|
+
|
24
|
+
def _load_provider_env_vars(self):
|
25
|
+
"""Load Modal-specific environment variables"""
|
26
|
+
# Modal doesn't need API keys for deployed services
|
27
|
+
# But we can load Modal token if available
|
28
|
+
modal_token = os.getenv("MODAL_TOKEN_ID") or os.getenv("MODAL_TOKEN_SECRET")
|
29
|
+
if modal_token:
|
30
|
+
self.config["modal_token"] = modal_token
|
31
|
+
|
32
|
+
# Set default config
|
33
|
+
if "timeout" not in self.config:
|
34
|
+
self.config["timeout"] = 300
|
35
|
+
if "deployment_region" not in self.config:
|
36
|
+
self.config["deployment_region"] = "us-east-1"
|
37
|
+
if "gpu_type" not in self.config:
|
38
|
+
self.config["gpu_type"] = "T4"
|
39
|
+
|
40
|
+
def get_api_key(self) -> str:
|
41
|
+
"""Modal services don't need API keys for deployed apps"""
|
42
|
+
return "modal-deployed-service" # Placeholder
|
43
|
+
|
44
|
+
def get_base_url(self) -> str:
|
45
|
+
"""Get base URL for Modal services"""
|
46
|
+
return self.base_url
|
47
|
+
|
48
|
+
def validate_credentials(self) -> bool:
|
49
|
+
"""
|
50
|
+
Validate Modal credentials
|
51
|
+
For deployed services, we assume they're accessible
|
52
|
+
"""
|
53
|
+
try:
|
54
|
+
# Check if Modal is available
|
55
|
+
import modal
|
56
|
+
return True
|
57
|
+
except ImportError:
|
58
|
+
logger.warning("Modal package not available")
|
59
|
+
return False
|
60
|
+
|
61
|
+
def get_capabilities(self) -> Dict[ModelType, List[Capability]]:
|
62
|
+
"""Get Modal provider capabilities"""
|
63
|
+
return {
|
64
|
+
ModelType.VISION: [
|
65
|
+
Capability.OBJECT_DETECTION,
|
66
|
+
Capability.IMAGE_ANALYSIS,
|
67
|
+
Capability.UI_DETECTION,
|
68
|
+
Capability.OCR,
|
69
|
+
Capability.DOCUMENT_ANALYSIS
|
70
|
+
]
|
71
|
+
}
|
72
|
+
|
73
|
+
def get_models(self, model_type: ModelType) -> List[str]:
|
74
|
+
"""Get available models for given type"""
|
75
|
+
if model_type == ModelType.VISION:
|
76
|
+
return [
|
77
|
+
"omniparser-v2.0",
|
78
|
+
"table-transformer-detection",
|
79
|
+
"table-transformer-structure-v1.1",
|
80
|
+
"paddleocr-3.0",
|
81
|
+
"yolov8"
|
82
|
+
]
|
83
|
+
return []
|
84
|
+
|
85
|
+
def is_reasoning_model(self, model_name: str) -> bool:
|
86
|
+
"""Check if the model is optimized for reasoning tasks"""
|
87
|
+
# Vision models are not reasoning models
|
88
|
+
return False
|
89
|
+
|
90
|
+
def get_default_config(self) -> Dict[str, Any]:
|
91
|
+
"""Get default configuration for Modal services"""
|
92
|
+
return {
|
93
|
+
"timeout": 300, # 5 minutes
|
94
|
+
"max_retries": 3,
|
95
|
+
"deployment_region": "us-east-1",
|
96
|
+
"gpu_type": "T4"
|
97
|
+
}
|
98
|
+
|
99
|
+
def get_billing_info(self) -> Dict[str, Any]:
|
100
|
+
"""Get billing information for Modal services"""
|
101
|
+
return {
|
102
|
+
"provider": "modal",
|
103
|
+
"billing_model": "compute_usage",
|
104
|
+
"cost_per_hour": {
|
105
|
+
"T4": 0.60,
|
106
|
+
"A100": 4.00
|
107
|
+
},
|
108
|
+
"note": "Costs depend on actual usage time, scales to zero when not in use"
|
109
|
+
}
|
@@ -0,0 +1,108 @@
|
|
1
|
+
from isa_model.inference.providers.base_provider import BaseProvider
|
2
|
+
from isa_model.inference.base import ModelType, Capability
|
3
|
+
from typing import Dict, List, Any
|
4
|
+
import logging
|
5
|
+
import os
|
6
|
+
|
7
|
+
logger = logging.getLogger(__name__)
|
8
|
+
|
9
|
+
class YydsProvider(BaseProvider):
|
10
|
+
"""Provider for YYDS API with proper API key management"""
|
11
|
+
|
12
|
+
def __init__(self, config=None):
|
13
|
+
"""Initialize the YYDS Provider with centralized config management"""
|
14
|
+
super().__init__(config)
|
15
|
+
self.name = "yyds"
|
16
|
+
|
17
|
+
logger.info(f"Initialized YydsProvider with URL: {self.config.get('base_url', 'https://api.yyds.com/v1')}")
|
18
|
+
|
19
|
+
if not self.has_valid_credentials():
|
20
|
+
logger.warning("YYDS API key not found. Set YYDS_API_KEY environment variable or pass api_key in config.")
|
21
|
+
|
22
|
+
def _load_provider_env_vars(self):
|
23
|
+
"""Load YYDS-specific environment variables"""
|
24
|
+
# Set defaults first
|
25
|
+
defaults = {
|
26
|
+
"base_url": "https://api.yyds.com/v1",
|
27
|
+
"timeout": 60,
|
28
|
+
"temperature": 0.7,
|
29
|
+
"top_p": 0.9,
|
30
|
+
"max_tokens": 1024
|
31
|
+
}
|
32
|
+
|
33
|
+
# Apply defaults only if not already set
|
34
|
+
for key, value in defaults.items():
|
35
|
+
if key not in self.config:
|
36
|
+
self.config[key] = value
|
37
|
+
|
38
|
+
# Load from environment variables (override config if present)
|
39
|
+
env_mappings = {
|
40
|
+
"api_key": "YYDS_API_KEY",
|
41
|
+
"base_url": "YYDS_API_BASE",
|
42
|
+
"organization": "YYDS_ORGANIZATION"
|
43
|
+
}
|
44
|
+
|
45
|
+
for config_key, env_var in env_mappings.items():
|
46
|
+
env_value = os.getenv(env_var)
|
47
|
+
if env_value:
|
48
|
+
self.config[config_key] = env_value
|
49
|
+
|
50
|
+
def _validate_config(self):
|
51
|
+
"""Validate YYDS configuration"""
|
52
|
+
if not self.config.get("api_key"):
|
53
|
+
logger.debug("YYDS API key not set - some functionality may not work")
|
54
|
+
|
55
|
+
def get_model_pricing(self, model_name: str) -> Dict[str, float]:
|
56
|
+
"""Get pricing information for a model - delegated to ModelManager"""
|
57
|
+
# Import here to avoid circular imports
|
58
|
+
from isa_model.core.model_manager import ModelManager
|
59
|
+
model_manager = ModelManager()
|
60
|
+
return model_manager.get_model_pricing("yyds", model_name)
|
61
|
+
|
62
|
+
def calculate_cost(self, model_name: str, input_tokens: int, output_tokens: int) -> float:
|
63
|
+
"""Calculate cost for a request - delegated to ModelManager"""
|
64
|
+
# Import here to avoid circular imports
|
65
|
+
from isa_model.core.model_manager import ModelManager
|
66
|
+
model_manager = ModelManager()
|
67
|
+
return model_manager.calculate_cost("yyds", model_name, input_tokens, output_tokens)
|
68
|
+
|
69
|
+
def set_api_key(self, api_key: str):
|
70
|
+
"""Set the API key after initialization"""
|
71
|
+
self.config["api_key"] = api_key
|
72
|
+
logger.info("YYDS API key updated")
|
73
|
+
|
74
|
+
def get_capabilities(self) -> Dict[ModelType, List[Capability]]:
|
75
|
+
"""Get provider capabilities by model type"""
|
76
|
+
return {
|
77
|
+
ModelType.LLM: [
|
78
|
+
Capability.CHAT,
|
79
|
+
Capability.COMPLETION
|
80
|
+
]
|
81
|
+
}
|
82
|
+
|
83
|
+
def get_models(self, model_type: ModelType) -> List[str]:
|
84
|
+
"""Get available models for given type"""
|
85
|
+
if model_type == ModelType.LLM:
|
86
|
+
return ["claude-sonnet-4-20250514", "claude-3-5-sonnet-20241022"]
|
87
|
+
else:
|
88
|
+
return []
|
89
|
+
|
90
|
+
def get_default_model(self, model_type: ModelType) -> str:
|
91
|
+
"""Get default model for a given type"""
|
92
|
+
if model_type == ModelType.LLM:
|
93
|
+
return "claude-sonnet-4-20250514"
|
94
|
+
else:
|
95
|
+
return ""
|
96
|
+
|
97
|
+
def get_config(self) -> Dict[str, Any]:
|
98
|
+
"""Get provider configuration"""
|
99
|
+
# Return a copy without sensitive information
|
100
|
+
config_copy = self.config.copy()
|
101
|
+
if "api_key" in config_copy:
|
102
|
+
config_copy["api_key"] = "***" if config_copy["api_key"] else ""
|
103
|
+
return config_copy
|
104
|
+
|
105
|
+
def is_reasoning_model(self, model_name: str) -> bool:
|
106
|
+
"""Check if the model is optimized for reasoning tasks"""
|
107
|
+
reasoning_models = ["claude-sonnet-4", "claude-3-5-sonnet"]
|
108
|
+
return any(rm in model_name.lower() for rm in reasoning_models)
|
@@ -5,7 +5,8 @@ File: isa_model/inference/services/__init__.py
|
|
5
5
|
This module contains service implementations for different AI model types.
|
6
6
|
"""
|
7
7
|
|
8
|
-
from .base_service import BaseService,
|
8
|
+
from .base_service import BaseService, BaseEmbeddingService
|
9
|
+
from .llm.base_llm_service import BaseLLMService
|
9
10
|
|
10
11
|
__all__ = [
|
11
12
|
"BaseService",
|
@@ -3,7 +3,71 @@ from typing import Dict, Any, List, Union, Optional, BinaryIO
|
|
3
3
|
from isa_model.inference.services.base_service import BaseService
|
4
4
|
|
5
5
|
class BaseSTTService(BaseService):
|
6
|
-
"""Base class for Speech-to-Text services"""
|
6
|
+
"""Base class for Speech-to-Text services with unified task dispatch"""
|
7
|
+
|
8
|
+
async def invoke(
|
9
|
+
self,
|
10
|
+
audio_input: Union[str, BinaryIO, List[Union[str, BinaryIO]]],
|
11
|
+
task: Optional[str] = None,
|
12
|
+
**kwargs
|
13
|
+
) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
|
14
|
+
"""
|
15
|
+
统一的任务分发方法 - Base类提供通用实现
|
16
|
+
|
17
|
+
Args:
|
18
|
+
audio_input: 音频输入,可以是:
|
19
|
+
- str: 音频文件路径
|
20
|
+
- BinaryIO: 音频文件对象
|
21
|
+
- List: 多个音频文件(批量处理)
|
22
|
+
task: 任务类型,支持多种STT任务
|
23
|
+
**kwargs: 任务特定的附加参数
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
Dict or List[Dict] containing task results
|
27
|
+
"""
|
28
|
+
task = task or "transcribe"
|
29
|
+
|
30
|
+
# ==================== 语音转文本类任务 ====================
|
31
|
+
if task == "transcribe":
|
32
|
+
if isinstance(audio_input, list):
|
33
|
+
return await self.transcribe_batch(
|
34
|
+
audio_input,
|
35
|
+
kwargs.get("language"),
|
36
|
+
kwargs.get("prompt")
|
37
|
+
)
|
38
|
+
else:
|
39
|
+
return await self.transcribe(
|
40
|
+
audio_input,
|
41
|
+
kwargs.get("language"),
|
42
|
+
kwargs.get("prompt")
|
43
|
+
)
|
44
|
+
elif task == "translate":
|
45
|
+
if isinstance(audio_input, list):
|
46
|
+
raise ValueError("translate task requires single audio input")
|
47
|
+
return await self.translate(audio_input)
|
48
|
+
elif task == "batch_transcribe":
|
49
|
+
if not isinstance(audio_input, list):
|
50
|
+
audio_input = [audio_input]
|
51
|
+
return await self.transcribe_batch(
|
52
|
+
audio_input,
|
53
|
+
kwargs.get("language"),
|
54
|
+
kwargs.get("prompt")
|
55
|
+
)
|
56
|
+
elif task == "detect_language":
|
57
|
+
if isinstance(audio_input, list):
|
58
|
+
raise ValueError("detect_language task requires single audio input")
|
59
|
+
return await self.detect_language(audio_input)
|
60
|
+
else:
|
61
|
+
raise NotImplementedError(f"{self.__class__.__name__} does not support task: {task}")
|
62
|
+
|
63
|
+
def get_supported_tasks(self) -> List[str]:
|
64
|
+
"""
|
65
|
+
获取支持的任务列表
|
66
|
+
|
67
|
+
Returns:
|
68
|
+
List of supported task names
|
69
|
+
"""
|
70
|
+
return ["transcribe", "translate", "batch_transcribe", "detect_language"]
|
7
71
|
|
8
72
|
@abstractmethod
|
9
73
|
async def transcribe(
|
@@ -3,7 +3,81 @@ from typing import Dict, Any, List, Union, Optional, BinaryIO
|
|
3
3
|
from isa_model.inference.services.base_service import BaseService
|
4
4
|
|
5
5
|
class BaseTTSService(BaseService):
|
6
|
-
"""Base class for Text-to-Speech services"""
|
6
|
+
"""Base class for Text-to-Speech services with unified task dispatch"""
|
7
|
+
|
8
|
+
async def invoke(
|
9
|
+
self,
|
10
|
+
text: Union[str, List[str]],
|
11
|
+
task: Optional[str] = None,
|
12
|
+
**kwargs
|
13
|
+
) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
|
14
|
+
"""
|
15
|
+
统一的任务分发方法 - Base类提供通用实现
|
16
|
+
|
17
|
+
Args:
|
18
|
+
text: 输入文本,可以是:
|
19
|
+
- str: 单个文本
|
20
|
+
- List[str]: 多个文本(批量处理)
|
21
|
+
task: 任务类型,支持多种TTS任务
|
22
|
+
**kwargs: 任务特定的附加参数
|
23
|
+
|
24
|
+
Returns:
|
25
|
+
Dict or List[Dict] containing task results
|
26
|
+
"""
|
27
|
+
task = task or "synthesize"
|
28
|
+
|
29
|
+
# ==================== 语音合成类任务 ====================
|
30
|
+
if task == "synthesize":
|
31
|
+
if isinstance(text, list):
|
32
|
+
return await self.synthesize_speech_batch(
|
33
|
+
text,
|
34
|
+
kwargs.get("voice"),
|
35
|
+
kwargs.get("speed", 1.0),
|
36
|
+
kwargs.get("pitch", 1.0),
|
37
|
+
kwargs.get("format", "mp3")
|
38
|
+
)
|
39
|
+
else:
|
40
|
+
return await self.synthesize_speech(
|
41
|
+
text,
|
42
|
+
kwargs.get("voice"),
|
43
|
+
kwargs.get("speed", 1.0),
|
44
|
+
kwargs.get("pitch", 1.0),
|
45
|
+
kwargs.get("format", "mp3")
|
46
|
+
)
|
47
|
+
elif task == "synthesize_to_file":
|
48
|
+
if not kwargs.get("output_path"):
|
49
|
+
raise ValueError("output_path is required for synthesize_to_file task")
|
50
|
+
if isinstance(text, list):
|
51
|
+
raise ValueError("synthesize_to_file task requires single text input")
|
52
|
+
return await self.synthesize_speech_to_file(
|
53
|
+
text,
|
54
|
+
kwargs["output_path"],
|
55
|
+
kwargs.get("voice"),
|
56
|
+
kwargs.get("speed", 1.0),
|
57
|
+
kwargs.get("pitch", 1.0),
|
58
|
+
kwargs.get("format", "mp3")
|
59
|
+
)
|
60
|
+
elif task == "batch_synthesize":
|
61
|
+
if not isinstance(text, list):
|
62
|
+
text = [text]
|
63
|
+
return await self.synthesize_speech_batch(
|
64
|
+
text,
|
65
|
+
kwargs.get("voice"),
|
66
|
+
kwargs.get("speed", 1.0),
|
67
|
+
kwargs.get("pitch", 1.0),
|
68
|
+
kwargs.get("format", "mp3")
|
69
|
+
)
|
70
|
+
else:
|
71
|
+
raise NotImplementedError(f"{self.__class__.__name__} does not support task: {task}")
|
72
|
+
|
73
|
+
def get_supported_tasks(self) -> List[str]:
|
74
|
+
"""
|
75
|
+
获取支持的任务列表
|
76
|
+
|
77
|
+
Returns:
|
78
|
+
List of supported task names
|
79
|
+
"""
|
80
|
+
return ["synthesize", "synthesize_to_file", "batch_synthesize"]
|
7
81
|
|
8
82
|
@abstractmethod
|
9
83
|
async def synthesize_speech(
|