mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-09-05 23:56:37 +08:00
feat(config): 添加模型助手功能以选择和管理模型
本次提交主要包含以下更改: 1. **后端更新**: - 在 `app/service/config/config_service.py` 中新增 `fetch_ui_models` 方法,用于获取可用于 UI 的模型列表,并处理相关的错误情况。 - 在 `app/router/config_routes.py` 中新增 `/ui/models` 路由,提供模型列表的 API 接口,并添加身份验证逻辑。 2. **前端更新**: - 在 `app/static/js/config_editor.js` 中实现模型助手的功能,包括模型列表的加载、搜索和选择。 - 在 `app/templates/config_editor.html` 中添加模型助手的模态框和相关的 UI 元素,允许用户从列表中选择模型。 这些更改旨在增强用户体验,使用户能够更方便地选择和管理模型,提高配置界面的交互性和功能性。
This commit is contained in:
@@ -1,41 +1,49 @@
|
||||
"""
|
||||
配置服务模块
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import json
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from dotenv import find_dotenv, load_dotenv
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy import insert, update
|
||||
|
||||
from app.config.config import Settings as ConfigSettings
|
||||
from app.config.config import settings
|
||||
from app.database.connection import database
|
||||
from app.database.models import Settings
|
||||
from app.config.config import Settings as ConfigSettings
|
||||
from app.database.services import get_all_settings
|
||||
from app.service.key.key_manager import get_key_manager_instance, reset_key_manager_instance
|
||||
from app.log.logger import get_config_routes_logger
|
||||
from app.service.key.key_manager import (
|
||||
get_key_manager_instance,
|
||||
reset_key_manager_instance,
|
||||
)
|
||||
from app.service.model.model_service import ModelService
|
||||
|
||||
logger = get_config_routes_logger()
|
||||
|
||||
|
||||
class ConfigService:
|
||||
"""配置服务类,用于管理应用程序配置"""
|
||||
|
||||
|
||||
@staticmethod
|
||||
async def get_config() -> Dict[str, Any]:
|
||||
return settings.model_dump()
|
||||
|
||||
|
||||
@staticmethod
|
||||
async def update_config(config_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
for key, value in config_data.items():
|
||||
if hasattr(settings, key):
|
||||
setattr(settings, key, value)
|
||||
logger.debug(f"Updated setting in memory: {key}")
|
||||
|
||||
logger.debug(f"Updated setting in memory: {key}")
|
||||
|
||||
# 获取现有设置
|
||||
existing_settings_raw: List[Dict[str, Any]] = await get_all_settings()
|
||||
existing_settings_map: Dict[str, Dict[str, Any]] = {s['key']: s for s in existing_settings_raw}
|
||||
existing_settings_map: Dict[str, Dict[str, Any]] = {
|
||||
s["key"]: s for s in existing_settings_raw
|
||||
}
|
||||
existing_keys = set(existing_settings_map.keys())
|
||||
|
||||
settings_to_update: List[Dict[str, Any]] = []
|
||||
@@ -47,7 +55,7 @@ class ConfigService:
|
||||
# 处理不同类型的值
|
||||
if isinstance(value, list):
|
||||
db_value = json.dumps(value)
|
||||
elif isinstance(value, dict): # 新增对 dict 类型的处理
|
||||
elif isinstance(value, dict): # 新增对 dict 类型的处理
|
||||
db_value = json.dumps(value)
|
||||
elif isinstance(value, bool):
|
||||
db_value = str(value).lower()
|
||||
@@ -55,24 +63,26 @@ class ConfigService:
|
||||
db_value = str(value)
|
||||
|
||||
# 仅当值发生变化时才更新
|
||||
if key in existing_keys and existing_settings_map[key]['value'] == db_value:
|
||||
continue
|
||||
if key in existing_keys and existing_settings_map[key]["value"] == db_value:
|
||||
continue
|
||||
|
||||
description = f"{key}配置项"
|
||||
description = f"{key}配置项"
|
||||
|
||||
data = {
|
||||
'key': key,
|
||||
'value': db_value,
|
||||
'description': description,
|
||||
'updated_at': now
|
||||
"key": key,
|
||||
"value": db_value,
|
||||
"description": description,
|
||||
"updated_at": now,
|
||||
}
|
||||
|
||||
if key in existing_keys:
|
||||
# Preserve original description if not explicitly provided
|
||||
data['description'] = existing_settings_map[key].get('description', description)
|
||||
data["description"] = existing_settings_map[key].get(
|
||||
"description", description
|
||||
)
|
||||
settings_to_update.append(data)
|
||||
else:
|
||||
data['created_at'] = now
|
||||
data["created_at"] = now
|
||||
settings_to_insert.append(data)
|
||||
|
||||
# 在事务中执行批量插入和更新
|
||||
@@ -82,17 +92,19 @@ class ConfigService:
|
||||
if settings_to_insert:
|
||||
query_insert = insert(Settings).values(settings_to_insert)
|
||||
await database.execute(query=query_insert)
|
||||
logger.info(f"Bulk inserted {len(settings_to_insert)} settings.")
|
||||
logger.info(
|
||||
f"Bulk inserted {len(settings_to_insert)} settings."
|
||||
)
|
||||
|
||||
if settings_to_update:
|
||||
for setting_data in settings_to_update:
|
||||
query_update = (
|
||||
update(Settings)
|
||||
.where(Settings.key == setting_data['key'])
|
||||
.where(Settings.key == setting_data["key"])
|
||||
.values(
|
||||
value=setting_data['value'],
|
||||
description=setting_data['description'],
|
||||
updated_at=setting_data['updated_at']
|
||||
value=setting_data["value"],
|
||||
description=setting_data["description"],
|
||||
updated_at=setting_data["updated_at"],
|
||||
)
|
||||
)
|
||||
await database.execute(query=query_update)
|
||||
@@ -112,7 +124,7 @@ class ConfigService:
|
||||
# For now, we log the error and continue
|
||||
|
||||
return await ConfigService.get_config()
|
||||
|
||||
|
||||
@staticmethod
|
||||
async def reset_config() -> Dict[str, Any]:
|
||||
"""
|
||||
@@ -124,7 +136,9 @@ class ConfigService:
|
||||
"""
|
||||
# 1. 重新加载配置对象,它应该处理环境变量和 .env 的优先级
|
||||
_reload_settings()
|
||||
logger.info("Settings object reloaded, prioritizing system environment variables then .env file.")
|
||||
logger.info(
|
||||
"Settings object reloaded, prioritizing system environment variables then .env file."
|
||||
)
|
||||
|
||||
# 2. 重置并重新初始化 KeyManager
|
||||
try:
|
||||
@@ -140,6 +154,36 @@ class ConfigService:
|
||||
# 3. 返回更新后的配置
|
||||
return await ConfigService.get_config()
|
||||
|
||||
@staticmethod
|
||||
async def fetch_ui_models() -> List[Dict[str, Any]]:
|
||||
"""获取用于UI显示的模型列表"""
|
||||
try:
|
||||
key_manager = await get_key_manager_instance()
|
||||
model_service = ModelService()
|
||||
|
||||
api_key = await key_manager.get_first_valid_key()
|
||||
if not api_key:
|
||||
logger.error("No valid API keys available to fetch model list for UI.")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="No valid API keys available to fetch model list.",
|
||||
)
|
||||
|
||||
models = await model_service.get_gemini_openai_models(api_key)
|
||||
return models
|
||||
except HTTPException as e:
|
||||
# Re-raise HTTPExceptions directly if they are already specific
|
||||
raise e
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Failed to fetch models for UI in ConfigService: {e}", exc_info=True
|
||||
)
|
||||
# Raise a generic HTTPException for other errors
|
||||
raise HTTPException(
|
||||
status_code=500, detail=f"Failed to fetch models for UI: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
# 重新加载配置的函数
|
||||
def _reload_settings():
|
||||
"""重新加载环境变量并更新配置"""
|
||||
@@ -147,4 +191,4 @@ def _reload_settings():
|
||||
load_dotenv(find_dotenv(), override=True)
|
||||
# 更新现有 settings 对象的属性,而不是新建实例
|
||||
for key, value in ConfigSettings().model_dump().items():
|
||||
setattr(settings, key, value)
|
||||
setattr(settings, key, value)
|
||||
|
||||
Reference in New Issue
Block a user