Refactor backend to support interface-definition driven model resources
- Introduce a new model structure for managing interface definitions and model resources, enhancing the backend's capability to handle various service integrations. - Update the Makefile to reflect changes in database seeding and resource management commands. - Remove the deprecated credentials management routes and replace them with a unified model registry API. - Modify existing routes and schemas to align with the new model structure, ensuring seamless integration with the frontend. - Enhance database seeding scripts to populate new model resources and their configurations. - Update README documentation to reflect the new architecture and usage instructions for model resources and interface definitions.
This commit is contained in:
155
backend/services/interface_catalog.py
Normal file
155
backend/services/interface_catalog.py
Normal file
@@ -0,0 +1,155 @@
|
||||
"""Built-in concrete interface definitions used by backend and dynamic forms."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
def field(
|
||||
key: str,
|
||||
label: str,
|
||||
*,
|
||||
group: str = "values",
|
||||
type_: str = "text",
|
||||
required: bool = False,
|
||||
default: Any = None,
|
||||
options: list[str] | None = None,
|
||||
) -> dict:
|
||||
value = {
|
||||
"key": key,
|
||||
"label": label,
|
||||
"group": group,
|
||||
"type": type_,
|
||||
"required": required,
|
||||
}
|
||||
if default is not None:
|
||||
value["default"] = default
|
||||
if options:
|
||||
value["options"] = options
|
||||
return value
|
||||
|
||||
|
||||
OPENAI_COMMON = [
|
||||
field("modelId", "Model ID", required=True),
|
||||
field("apiUrl", "API URL", type_="url", required=True),
|
||||
field("apiKey", "API Key", group="secrets", type_="password", required=True),
|
||||
]
|
||||
XFYUN_AUTH = [
|
||||
field("apiUrl", "WebSocket URL", type_="url", required=True),
|
||||
field("appId", "App ID", group="secrets", type_="password", required=True),
|
||||
field("apiKey", "API Key", group="secrets", type_="password", required=True),
|
||||
field("apiSecret", "API Secret", group="secrets", type_="password", required=True),
|
||||
]
|
||||
|
||||
INTERFACE_DEFINITIONS: list[dict] = [
|
||||
{
|
||||
"interface_type": "openai-llm",
|
||||
"name": "OpenAI Compatible LLM",
|
||||
"capability": "LLM",
|
||||
"fields": OPENAI_COMMON
|
||||
+ [field("temperature", "Temperature", type_="number", default=0.7)],
|
||||
},
|
||||
{
|
||||
"interface_type": "openai-asr",
|
||||
"name": "OpenAI Compatible ASR",
|
||||
"capability": "ASR",
|
||||
"fields": OPENAI_COMMON + [field("language", "Language", default="zh")],
|
||||
},
|
||||
{
|
||||
"interface_type": "openai-tts",
|
||||
"name": "OpenAI Compatible TTS",
|
||||
"capability": "TTS",
|
||||
"fields": OPENAI_COMMON
|
||||
+ [
|
||||
field("voice", "Voice"),
|
||||
field("speed", "Speed", type_="number", default=1.0),
|
||||
field("sourceSampleRate", "Source Sample Rate", type_="number", default=24000),
|
||||
],
|
||||
},
|
||||
{
|
||||
"interface_type": "openai-embedding",
|
||||
"name": "OpenAI Compatible Embedding",
|
||||
"capability": "Embedding",
|
||||
"fields": OPENAI_COMMON + [field("dimensions", "Dimensions", type_="number")],
|
||||
},
|
||||
{
|
||||
"interface_type": "openai-realtime",
|
||||
"name": "OpenAI Realtime",
|
||||
"capability": "Realtime",
|
||||
"fields": OPENAI_COMMON + [field("voice", "Voice")],
|
||||
},
|
||||
{
|
||||
"interface_type": "xfyun-asr",
|
||||
"name": "Xfyun Streaming ASR",
|
||||
"capability": "ASR",
|
||||
"fields": XFYUN_AUTH
|
||||
+ [
|
||||
field("language", "Language", default="zh_cn"),
|
||||
field("domain", "Domain", default="iat"),
|
||||
field("accent", "Accent", default="mandarin"),
|
||||
field("dynamicCorrection", "Dynamic Correction", type_="boolean", default=False),
|
||||
field("frameSize", "Frame Size", type_="number", default=1280),
|
||||
],
|
||||
},
|
||||
{
|
||||
"interface_type": "xfyun-tts",
|
||||
"name": "Xfyun TTS",
|
||||
"capability": "TTS",
|
||||
"fields": XFYUN_AUTH
|
||||
+ [
|
||||
field("voice", "Voice"),
|
||||
field("speed", "Speed", type_="number", default=50),
|
||||
field("volume", "Volume", type_="number", default=50),
|
||||
field("pitch", "Pitch", type_="number", default=50),
|
||||
field("sourceSampleRate", "Source Sample Rate", type_="number", default=16000),
|
||||
],
|
||||
},
|
||||
{
|
||||
"interface_type": "xfyun-super-tts",
|
||||
"name": "Xfyun Super TTS",
|
||||
"capability": "TTS",
|
||||
"fields": XFYUN_AUTH
|
||||
+ [
|
||||
field("voice", "Voice"),
|
||||
field("speed", "Speed", type_="number", default=50),
|
||||
field("volume", "Volume", type_="number", default=50),
|
||||
field("pitch", "Pitch", type_="number", default=50),
|
||||
field("oralLevel", "Oral Level", default="mid"),
|
||||
field("sourceSampleRate", "Source Sample Rate", type_="number", default=24000),
|
||||
field("textAggregationMode", "Text Aggregation Mode", default="token"),
|
||||
],
|
||||
},
|
||||
{
|
||||
"interface_type": "dashscope-llm",
|
||||
"name": "DashScope LLM",
|
||||
"capability": "LLM",
|
||||
"fields": OPENAI_COMMON
|
||||
+ [field("temperature", "Temperature", type_="number", default=0.7)],
|
||||
},
|
||||
{
|
||||
"interface_type": "dashscope-asr",
|
||||
"name": "DashScope ASR",
|
||||
"capability": "ASR",
|
||||
"fields": OPENAI_COMMON + [field("language", "Language", default="zh")],
|
||||
},
|
||||
{
|
||||
"interface_type": "dashscope-tts",
|
||||
"name": "DashScope TTS",
|
||||
"capability": "TTS",
|
||||
"fields": OPENAI_COMMON + [field("voice", "Voice")],
|
||||
},
|
||||
{
|
||||
"interface_type": "gemini-realtime",
|
||||
"name": "Gemini Realtime",
|
||||
"capability": "Realtime",
|
||||
"fields": OPENAI_COMMON,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def validate_fields(definition: dict, values: dict, secrets: dict) -> None:
|
||||
for item in definition["fields"]:
|
||||
source = secrets if item["group"] == "secrets" else values
|
||||
value = source.get(item["key"])
|
||||
if item.get("required") and (value is None or value == ""):
|
||||
raise ValueError(f"{item['label']} is required")
|
||||
Reference in New Issue
Block a user