294 lines
9.9 KiB
Python
294 lines
9.9 KiB
Python
"""
|
||
EPEEKit 集中配置。
|
||
所有可调参数从环境变量读取,每次调用实时读取(不缓存),确保 load_dotenv() 后生效。
|
||
"""
|
||
|
||
import os
|
||
from typing import Any
|
||
|
||
|
||
def get_llm_max_iterations() -> int:
|
||
return int(os.getenv("LLM_MAX_ITERATIONS", "5"))
|
||
|
||
|
||
# ─── LLM 模型注册表 ─────────────────────────────────────
|
||
#
|
||
# 每个模型的配置说明:
|
||
# id — 前端/API 使用的短 ID
|
||
# name — 显示名称
|
||
# provider — API 提供者(对应 _get_client 的分发键)
|
||
# model_id — 传给 OpenAI SDK 的 model 参数
|
||
# description — 前端下拉列表说明文字
|
||
# vision — 是否支持多模态图片输入
|
||
|
||
LLM_MODELS: dict[str, dict[str, Any]] = {
|
||
"gpt-5.4": {
|
||
"id": "gpt-5.4",
|
||
"name": "GPT-5.4",
|
||
"provider": "vectorengine",
|
||
"model_id": "gpt-5.4",
|
||
"description": "知识工作与计算机操控最强,1M 上下文",
|
||
"vision": True,
|
||
},
|
||
"claude-sonnet-4-6": {
|
||
"id": "claude-sonnet-4-6",
|
||
"name": "Claude Sonnet 4.6",
|
||
"provider": "vectorengine",
|
||
"model_id": "claude-sonnet-4-6",
|
||
"description": "高性价比编码与日常任务",
|
||
"vision": True,
|
||
},
|
||
"claude-opus-4-6": {
|
||
"id": "claude-opus-4-6",
|
||
"name": "Claude Opus 4.6",
|
||
"provider": "vectorengine",
|
||
"model_id": "claude-opus-4-6",
|
||
"description": "编码与专家级推理最强,128K 输出",
|
||
"vision": True,
|
||
},
|
||
"gemini-3.1-pro-preview": {
|
||
"id": "gemini-3.1-pro-preview",
|
||
"name": "Gemini 3.1 Pro",
|
||
"provider": "vectorengine",
|
||
"model_id": "gemini-3.1-pro-preview",
|
||
"description": "推理最强、价格最低,2M 上下文",
|
||
"vision": True,
|
||
},
|
||
"glm-4.7": {
|
||
"id": "glm-4.7",
|
||
"name": "GLM-4.7",
|
||
"provider": "vectorengine",
|
||
"model_id": "glm-4.7",
|
||
"description": "智谱 AI,中文能力突出,免费额度",
|
||
"vision": False,
|
||
},
|
||
"gpt-4o-mini": {
|
||
"id": "gpt-4o-mini",
|
||
"name": "GPT-4o Mini",
|
||
"provider": "vectorengine",
|
||
"model_id": "gpt-4o-mini",
|
||
"description": "轻量快速、高性价比",
|
||
"vision": True,
|
||
},
|
||
"deepseek-chat": {
|
||
"id": "deepseek-chat",
|
||
"name": "DeepSeek Chat",
|
||
"provider": "deepseek",
|
||
"model_id": "deepseek-chat",
|
||
"description": "中文对话优化(直连)",
|
||
"vision": False,
|
||
},
|
||
}
|
||
|
||
|
||
def get_default_llm_model_id() -> str:
|
||
"""返回 .env 中配置的默认 LLM 短 ID,不在注册表中则回退到 gpt-5.4。"""
|
||
env_model = os.getenv("LLM_MODEL", "gpt-5.4")
|
||
if env_model in LLM_MODELS:
|
||
return env_model
|
||
return "gpt-5.4"
|
||
|
||
|
||
def get_llm_model_config(model_id: str | None = None) -> dict[str, Any]:
|
||
"""根据短 ID 获取 LLM 模型配置,未指定或不存在则使用默认模型。"""
|
||
if model_id and model_id in LLM_MODELS:
|
||
return LLM_MODELS[model_id]
|
||
return LLM_MODELS[get_default_llm_model_id()]
|
||
|
||
|
||
def get_llm_models_list() -> list[dict]:
|
||
"""返回前端下拉列表所需的 LLM 模型摘要信息。"""
|
||
return [
|
||
{
|
||
"id": cfg["id"],
|
||
"name": cfg["name"],
|
||
"description": cfg["description"],
|
||
"vision": cfg.get("vision", False),
|
||
}
|
||
for cfg in LLM_MODELS.values()
|
||
]
|
||
|
||
|
||
# ─── 图像模型注册表 ─────────────────────────────────────
|
||
#
|
||
# 每个模型的配置说明:
|
||
# id — 前端/API 使用的短 ID
|
||
# name — 显示名称
|
||
# provider — 生成服务提供者(对应 image_gen.py 中的 Provider)
|
||
# model_id — Replicate 上的完整模型 ID
|
||
# description — 前端下拉列表中的说明文字
|
||
# supports_ref_image — 是否原生支持参考图输入(IP-Adapter 等)
|
||
# ref_image_param — 传给 Replicate 的参考图参数名(模型间可能不同)
|
||
# num_images_param — 批量生成参数名(Flux 用 num_outputs,Kolors 用 number_of_images)
|
||
# default_params — 默认推理参数
|
||
|
||
IMAGE_MODELS: dict[str, dict[str, Any]] = {
|
||
"gpt-image-1.5": {
|
||
"id": "gpt-image-1.5",
|
||
"name": "GPT Image 1.5",
|
||
"provider": "openai",
|
||
"model_id": "gpt-image-1.5",
|
||
"description": "OpenAI 最强生图,文字渲染与 prompt 理解最佳,支持多图参考",
|
||
"supports_ref_image": True,
|
||
"max_ref_images": 16,
|
||
"default_params": {
|
||
"size": "1024x1024",
|
||
"quality": "high",
|
||
},
|
||
},
|
||
"gemini-3.1-flash-image": {
|
||
"id": "gemini-3.1-flash-image",
|
||
"name": "Gemini 3.1 Flash Image",
|
||
"provider": "gemini_native",
|
||
"model_id": "gemini-3.1-flash-image-preview",
|
||
"description": "Google 原生生图,速度快、价格低,支持多图参考(最多 14 张)",
|
||
"supports_ref_image": True,
|
||
"max_ref_images": 14,
|
||
"default_params": {},
|
||
},
|
||
"flux-schnell": {
|
||
"id": "flux-schnell",
|
||
"name": "Flux Schnell",
|
||
"provider": "replicate",
|
||
"model_id": "black-forest-labs/flux-schnell",
|
||
"description": "快速生成,适合快速迭代",
|
||
"supports_ref_image": False,
|
||
"num_images_param": "num_outputs",
|
||
"default_params": {
|
||
"aspect_ratio": "1:1",
|
||
"output_format": "png",
|
||
},
|
||
},
|
||
"flux-dev": {
|
||
"id": "flux-dev",
|
||
"name": "Flux Dev",
|
||
"provider": "replicate",
|
||
"model_id": "black-forest-labs/flux-dev",
|
||
"description": "高质量生成,细节更好",
|
||
"supports_ref_image": False,
|
||
"num_images_param": "num_outputs",
|
||
"default_params": {
|
||
"aspect_ratio": "1:1",
|
||
"output_format": "png",
|
||
},
|
||
},
|
||
"sdxl": {
|
||
"id": "sdxl",
|
||
"name": "Stable Diffusion XL",
|
||
"provider": "replicate",
|
||
"model_id": "stability-ai/sdxl:39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b",
|
||
"description": "经典 SDXL,支持 negative prompt",
|
||
"supports_ref_image": False,
|
||
"num_images_param": "num_outputs",
|
||
"default_params": {
|
||
"width": 1024,
|
||
"height": 1024,
|
||
"num_inference_steps": 50,
|
||
"guidance_scale": 7.5,
|
||
},
|
||
},
|
||
"instant-style": {
|
||
"id": "instant-style",
|
||
"name": "InstantStyle",
|
||
"provider": "replicate",
|
||
"model_id": "jyoung105/instant-style:c6f01e12f31cb99f9ee774a78992a71294f630a6f433d9aecfdc33b816fc4baa",
|
||
"description": "强风格迁移,画风还原度高(较慢)",
|
||
"supports_ref_image": True,
|
||
"ref_image_param": "style_image",
|
||
"num_images_param": "num_outputs",
|
||
"default_params": {
|
||
"width": 1024,
|
||
"height": 1024,
|
||
"num_inference_steps": 30,
|
||
"guidance_scale": 5,
|
||
"style_strength": 1.0,
|
||
"block_mode": "style-only",
|
||
"adapter_mode": "original",
|
||
},
|
||
},
|
||
"kolors-ipadapter": {
|
||
"id": "kolors-ipadapter",
|
||
"name": "Kolors IP-Adapter",
|
||
"provider": "replicate",
|
||
"model_id": "fofr/kolors-with-ipadapter:5a1a92b2c0f81813225d48ed8e411813da41aa84e7582fb705d1af46eea36eed",
|
||
"description": "风格参考生成,上传参考图效果最佳",
|
||
"supports_ref_image": True,
|
||
"ref_image_param": "image",
|
||
"num_images_param": "number_of_images",
|
||
"default_params": {
|
||
"width": 1024,
|
||
"height": 1024,
|
||
"steps": 25,
|
||
"cfg": 4,
|
||
"ip_adapter_weight": 0.8,
|
||
"ip_adapter_weight_type": "style transfer precise",
|
||
"output_format": "png",
|
||
},
|
||
},
|
||
}
|
||
|
||
|
||
def get_default_image_model_id() -> str:
|
||
"""返回 .env 中配置的默认模型短 ID,若不在注册表中则回退到 flux-schnell。"""
|
||
env_model = os.getenv("IMAGE_MODEL", "flux-schnell")
|
||
for mid, cfg in IMAGE_MODELS.items():
|
||
if cfg["model_id"] == env_model or mid == env_model:
|
||
return mid
|
||
return "flux-schnell"
|
||
|
||
|
||
def get_image_model_config(model_id: str | None = None) -> dict[str, Any]:
|
||
"""根据短 ID 获取模型配置,未指定或不存在则使用默认模型。"""
|
||
if model_id and model_id in IMAGE_MODELS:
|
||
return IMAGE_MODELS[model_id]
|
||
return IMAGE_MODELS[get_default_image_model_id()]
|
||
|
||
|
||
def get_ref_image_model_id() -> str | None:
|
||
"""返回有参考图时推荐使用的模型 ID(第一个 supports_ref_image=True 的模型)。"""
|
||
for mid, cfg in IMAGE_MODELS.items():
|
||
if cfg.get("supports_ref_image"):
|
||
return mid
|
||
return None
|
||
|
||
|
||
def get_image_models_list() -> list[dict]:
|
||
"""返回前端下拉列表所需的模型摘要信息。"""
|
||
return [
|
||
{
|
||
"id": cfg["id"],
|
||
"name": cfg["name"],
|
||
"description": cfg["description"],
|
||
"supports_ref_image": cfg.get("supports_ref_image", False),
|
||
}
|
||
for cfg in IMAGE_MODELS.values()
|
||
]
|
||
|
||
|
||
# ─── 记忆系统配置 ─────────────────────────────────────
|
||
|
||
def get_deepseek_api_key() -> str:
|
||
return os.getenv("DEEPSEEK_API_KEY", "")
|
||
|
||
|
||
def get_ollama_base_url() -> str:
|
||
return os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")
|
||
|
||
|
||
def get_mem0_embedding_model() -> str:
|
||
return os.getenv("MEM0_EMBEDDING_MODEL", "nomic-embed-text")
|
||
|
||
|
||
def get_max_recent_turns() -> int:
|
||
return int(os.getenv("MAX_RECENT_TURNS", "20"))
|
||
|
||
|
||
# ─── 图像输出配置 ─────────────────────────────────────
|
||
|
||
def get_image_aspect_ratio() -> str:
|
||
return os.getenv("IMAGE_ASPECT_RATIO", "1:1")
|
||
|
||
|
||
def get_image_output_format() -> str:
|
||
return os.getenv("IMAGE_OUTPUT_FORMAT", "png")
|