docs: v1.5.7 动态API提供商管理,OpenCode Go集成,Bug修复
This commit is contained in:
+97
-38
@@ -5,25 +5,52 @@ import pathlib
|
||||
# 检测是否在Docker容器中
|
||||
IS_DOCKER = os.environ.get("FLASK_ENV") == "production"
|
||||
|
||||
# 默认提供商列表
|
||||
DEFAULT_PROVIDERS = {
|
||||
"minimax": {
|
||||
"name": "MiniMax",
|
||||
"endpoint": "https://api.minimaxi.com/anthropic/v1",
|
||||
"models": ["MiniMax-M2.7-highspeed"],
|
||||
},
|
||||
"volcengine": {
|
||||
"name": "火山引擎",
|
||||
"endpoint": "https://ark.cn-beijing.volces.com/api/coding/v3",
|
||||
"models": ["doubao-seed-2.0-pro", "doubao-seed-code", "doubao-seed-2.0-lite"],
|
||||
},
|
||||
"deepseek": {
|
||||
"name": "DeepSeek",
|
||||
"endpoint": "https://api.deepseek.com/v1",
|
||||
"models": ["deepseek-chat"],
|
||||
},
|
||||
"openai": {
|
||||
"name": "OpenAI",
|
||||
"endpoint": "https://api.openai.com/v1",
|
||||
"models": ["gpt-4o-mini", "gpt-4o"],
|
||||
},
|
||||
"openrouter": {
|
||||
"name": "OpenRouter",
|
||||
"endpoint": "https://openrouter.ai/api/v1",
|
||||
"models": ["anthropic/claude-3-haiku"],
|
||||
},
|
||||
"opencodego": {
|
||||
"name": "OpenCode Go",
|
||||
"endpoint": "https://opencode.ai/zen/go/v1",
|
||||
"models": ["deepseek-v4-pro", "deepseek-v4-flash", "qwen3.6-plus"],
|
||||
},
|
||||
}
|
||||
|
||||
def load_api_config(app_config=None):
|
||||
"""加载API配置"""
|
||||
import json
|
||||
# 兼容旧配置:从 default_model 迁移到 models
|
||||
def _migrate_provider_models(providers):
|
||||
"""确保每个 provider 都有 models 数组"""
|
||||
for pid, pdata in list(providers.items()):
|
||||
if "models" not in pdata:
|
||||
if "default_model" in pdata and pdata["default_model"]:
|
||||
pdata["models"] = [pdata.pop("default_model")]
|
||||
else:
|
||||
pdata["models"] = []
|
||||
return providers
|
||||
|
||||
# 优先从 app_config 获取路径,否则使用基于 __file__ 的绝对路径
|
||||
if app_config and app_config.get("API_CONFIG_FILE"):
|
||||
config_file = pathlib.Path(app_config["API_CONFIG_FILE"])
|
||||
else:
|
||||
config_file = pathlib.Path(__file__).resolve().parent.parent / "config" / "api_config.json"
|
||||
|
||||
default_config = {
|
||||
"provider": "volcengine",
|
||||
"api_key": "",
|
||||
"base_url": "https://ark.cn-beijing.volces.com/api/coding/v3",
|
||||
"model": "doubao-seed-2.0-pro",
|
||||
"temperature": 0.7,
|
||||
"watermark_text": "",
|
||||
"prompt_template": """你是一位专业的钢琴教师,请为学员生成一份简洁的个性化练习方案报告。
|
||||
DEFAULT_PROMPT_TEMPLATE = """你是一位专业的钢琴教师,请为学员生成一份简洁的个性化练习方案报告。
|
||||
|
||||
## 学员信息
|
||||
- 姓名:{student_name}
|
||||
@@ -39,22 +66,56 @@ def load_api_config(app_config=None):
|
||||
3. 针对每个问题的核心练习建议
|
||||
4. 重点注意事项
|
||||
|
||||
语言要专业、简洁、有鼓励性。使用Markdown格式。""",
|
||||
语言要专业、简洁、有鼓励性。使用Markdown格式。"""
|
||||
|
||||
|
||||
def _get_config_path(app_config=None):
|
||||
if app_config and app_config.get("API_CONFIG_FILE"):
|
||||
return pathlib.Path(app_config["API_CONFIG_FILE"])
|
||||
return pathlib.Path(__file__).resolve().parent.parent / "config" / "api_config.json"
|
||||
|
||||
|
||||
def _build_default_config():
|
||||
return {
|
||||
"provider": "volcengine",
|
||||
"providers": dict(DEFAULT_PROVIDERS),
|
||||
"api_key": "",
|
||||
"base_url": "https://ark.cn-beijing.volces.com/api/coding/v3",
|
||||
"model": "doubao-seed-2.0-pro",
|
||||
"temperature": 0.7,
|
||||
"watermark_text": "",
|
||||
"prompt_template": DEFAULT_PROMPT_TEMPLATE,
|
||||
}
|
||||
|
||||
|
||||
def load_api_config(app_config=None):
|
||||
"""加载API配置"""
|
||||
import json
|
||||
|
||||
config_file = _get_config_path(app_config)
|
||||
default_config = _build_default_config()
|
||||
|
||||
if config_file.exists():
|
||||
try:
|
||||
with open(config_file, "r", encoding="utf-8") as f:
|
||||
loaded_config = json.load(f)
|
||||
# 确保 providers 字段存在(兼容旧配置)
|
||||
if "providers" not in loaded_config:
|
||||
loaded_config["providers"] = dict(DEFAULT_PROVIDERS)
|
||||
# 迁移旧 default_model → models
|
||||
loaded_config["providers"] = _migrate_provider_models(loaded_config["providers"])
|
||||
# 合并缺失的默认 provider
|
||||
for pid, pdata in DEFAULT_PROVIDERS.items():
|
||||
if pid not in loaded_config["providers"]:
|
||||
loaded_config["providers"][pid] = pdata
|
||||
# 如果 api_keys 映射存在,根据当前 provider 自动设置 api_key
|
||||
if "api_keys" in loaded_config:
|
||||
provider = loaded_config.get("provider", "volcengine")
|
||||
loaded_config["api_key"] = loaded_config["api_keys"].get(provider, "")
|
||||
return loaded_config
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 返回默认配置
|
||||
return default_config
|
||||
|
||||
|
||||
@@ -62,40 +123,38 @@ def save_api_config(config, app_config=None):
|
||||
"""保存API配置"""
|
||||
import json
|
||||
|
||||
# 优先从 app_config 获取路径,否则使用基于 __file__ 的绝对路径
|
||||
if app_config and app_config.get("API_CONFIG_FILE"):
|
||||
config_file = pathlib.Path(app_config["API_CONFIG_FILE"])
|
||||
else:
|
||||
config_file = pathlib.Path(__file__).resolve().parent.parent / "config" / "api_config.json"
|
||||
|
||||
config_file = pathlib.Path(config_file)
|
||||
config_file = _get_config_path(app_config)
|
||||
config_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 先读取现有配置,保留 api_keys 映射
|
||||
existing_config = {}
|
||||
if config_file.exists():
|
||||
try:
|
||||
with open(config_file, "r", encoding="utf-8") as f:
|
||||
existing_config = json.load(f)
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 如果 config 中有 api_key,保存到 api_keys 映射(保留其他 provider 的 key)
|
||||
# 确保 providers 存在
|
||||
if "providers" not in existing_config:
|
||||
existing_config["providers"] = dict(DEFAULT_PROVIDERS)
|
||||
existing_config["providers"] = _migrate_provider_models(existing_config["providers"])
|
||||
|
||||
# 如果 config 中有 providers,完整替换
|
||||
if "providers" in config:
|
||||
existing_config["providers"] = config["providers"]
|
||||
|
||||
# 保存 api_key 到 api_keys 映射
|
||||
if "api_key" in config and config["api_key"]:
|
||||
if "api_keys" not in existing_config:
|
||||
existing_config["api_keys"] = {}
|
||||
provider = config.get("provider", "volcengine")
|
||||
existing_config["api_keys"][provider] = config["api_key"]
|
||||
|
||||
# 合并配置:保留 api_keys,更新其他字段
|
||||
existing_config["provider"] = config.get("provider", existing_config.get("provider", "volcengine"))
|
||||
existing_config["base_url"] = config.get("base_url", existing_config.get("base_url", ""))
|
||||
existing_config["model"] = config.get("model", existing_config.get("model", ""))
|
||||
existing_config["temperature"] = config.get("temperature", existing_config.get("temperature", 0.7))
|
||||
existing_config["prompt_template"] = config.get("prompt_template", existing_config.get("prompt_template", ""))
|
||||
existing_config["watermark_text"] = config.get("watermark_text", existing_config.get("watermark_text", ""))
|
||||
# 更新当前选中的配置
|
||||
for key in ["provider", "base_url", "model", "temperature", "prompt_template", "watermark_text"]:
|
||||
if key in config:
|
||||
existing_config[key] = config[key]
|
||||
|
||||
# 当前选中的 provider 的 key 直接存储(用于兼容旧逻辑)
|
||||
if config.get("api_key"):
|
||||
existing_config["api_key"] = config["api_key"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user