front/xhs-agent-desktop/engine/xhs_bridge/ai_provider_catalog.py
zzh 5a26ae0048 feat: 小红书模块迁移、登录重构与 xhs-agent-desktop 桌面 Agent
- 新增小红书前端模块(启动服务、内容分析、爆款创作、发布记录、技能卡片、拟人设置、AI 助手)

- 新增 xhs-agent-desktop 独立桌面 Agent,对接 OMS 任务调度

- 登录页重构,整合微信登录与 OMS JWT 认证

- 订单、渠道、用户中心等页面与 API 增强

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 16:13:13 +08:00

140 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from dataclasses import dataclass
from typing import Literal, TypedDict
ModelPurpose = Literal["text", "image", "vision"]
class ProviderTypeDef(TypedDict):
id: str
label: str
default_url: str
PROVIDER_TYPES: list[ProviderTypeDef] = [
{
"id": "chatgpt",
"label": "ChatGPT",
"default_url": "https://api.openai.com/v1",
},
{
"id": "doubao",
"label": "豆包",
"default_url": "https://ark.cn-beijing.volces.com/api/v3",
},
{
"id": "deepseek",
"label": "DeepSeek",
"default_url": "https://api.deepseek.com",
},
{
"id": "zhipu",
"label": "智谱",
"default_url": "https://open.bigmodel.cn/api/paas/v4",
},
]
_PROVIDER_MAP = {p["id"]: p for p in PROVIDER_TYPES}
# 默认平台卡片(稳定 id,首次启动写入)
DEFAULT_PROVIDER_IDS: list[tuple[str, str]] = [
("ai_chatgpt", "chatgpt"),
("ai_doubao", "doubao"),
("ai_deepseek", "deepseek"),
("ai_zhipu", "zhipu"),
]
# 使用 zai-sdk 官方客户端(非 OpenAI 兼容 HTTP)
ZHIPU_SDK_TYPES = frozenset({"zhipu"})
ZHIPU_CHAT_MODEL = "glm-5.1"
ZHIPU_VISION_MODEL = "glm-5v-turbo"
ZHIPU_IMAGE_MODEL = "glm-image"
ZHIPU_IMAGE_SIZE = "1280x1280"
MODEL_ROLE_TEXT = "文字"
MODEL_ROLE_IMAGE = "图片"
MODEL_ROLE_VISION = "图文"
IMAGE_MODEL_DEFAULTS: dict[str, str] = {
"chatgpt": "dall-e-3",
}
@dataclass(frozen=True)
class AiModelOption:
model_id: str
role: str
purpose: ModelPurpose
def is_vision_model(model_id: str) -> bool:
return (model_id or "").strip() == ZHIPU_VISION_MODEL
def selectable_models(provider_type: str, purpose: ModelPurpose) -> list[AiModelOption]:
"""爆款创作 / AI 分析等场景下可勾选的模型列表。"""
if purpose == "text":
model_id = default_model(provider_type)
return [AiModelOption(model_id, MODEL_ROLE_TEXT, "text")]
if purpose == "image":
if provider_type in ZHIPU_SDK_TYPES:
return [AiModelOption(ZHIPU_IMAGE_MODEL, MODEL_ROLE_IMAGE, "image")]
image_model = IMAGE_MODEL_DEFAULTS.get(provider_type, "dall-e-3")
return [AiModelOption(image_model, MODEL_ROLE_IMAGE, "image")]
# vision — AI 分析(图文理解)
if provider_type in ZHIPU_SDK_TYPES:
return [
AiModelOption(ZHIPU_VISION_MODEL, MODEL_ROLE_VISION, "vision"),
AiModelOption(ZHIPU_CHAT_MODEL, MODEL_ROLE_TEXT, "text"),
]
model_id = default_model(provider_type)
return [AiModelOption(model_id, MODEL_ROLE_TEXT, "text")]
def provider_model_tags(type_id: str) -> list[tuple[str, str]]:
"""(model_id, role) for provider card chips."""
seen: set[str] = set()
tags: list[tuple[str, str]] = []
for purpose in ("text", "image", "vision"):
for opt in selectable_models(type_id, purpose): # type: ignore[arg-type]
if opt.model_id in seen:
continue
seen.add(opt.model_id)
tags.append((opt.model_id, opt.role))
return tags
def list_provider_types() -> list[tuple[str, str]]:
"""(type_id, label)"""
return [(p["id"], p["label"]) for p in PROVIDER_TYPES]
def provider_label(type_id: str) -> str:
p = _PROVIDER_MAP.get(type_id)
return p["label"] if p else type_id
def default_base_url(type_id: str) -> str:
p = _PROVIDER_MAP.get(type_id)
return p["default_url"] if p else ""
def is_valid_provider_type(type_id: str) -> bool:
return type_id in _PROVIDER_MAP
def uses_zhipu_sdk(type_id: str) -> bool:
return type_id in ZHIPU_SDK_TYPES
def default_model(type_id: str) -> str:
defaults = {
"chatgpt": "gpt-4o-mini",
"deepseek": "deepseek-chat",
"doubao": "doubao-1-5-pro-32k-250115",
"zhipu": ZHIPU_CHAT_MODEL,
}
return defaults.get(type_id, "gpt-4o-mini")