- 新增小红书前端模块(启动服务、内容分析、爆款创作、发布记录、技能卡片、拟人设置、AI 助手) - 新增 xhs-agent-desktop 独立桌面 Agent,对接 OMS 任务调度 - 登录页重构,整合微信登录与 OMS JWT 认证 - 订单、渠道、用户中心等页面与 API 增强 Co-authored-by: Cursor <cursoragent@cursor.com>
140 lines
3.8 KiB
Python
140 lines
3.8 KiB
Python
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")
|