Fundamental_Analysis/backend/app/routers/config.py
xucheng a79efd8150 feat: Enhance configuration management with new LLM provider support and API integration
- Backend: Introduced new endpoints for LLM configuration retrieval and updates in `config.py`, allowing dynamic management of LLM provider settings.
- Updated schemas to include `AlphaEngineConfig` for better integration with the new provider.
- Frontend: Added state management for AlphaEngine API credentials in the configuration page, ensuring seamless user experience.
- Configuration files updated to reflect changes in LLM provider settings and API keys.

BREAKING CHANGE: The default LLM provider has been changed from `new_api` to `alpha_engine`, requiring updates to existing configurations.
2025-11-11 20:49:27 +08:00

142 lines
5.2 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from typing import Dict, Any, Optional
from pydantic import BaseModel
from app.core.dependencies import get_config_manager
from app.schemas.config import ConfigResponse, ConfigUpdateRequest, ConfigTestRequest, ConfigTestResponse
from app.services.config_manager import ConfigManager
router = APIRouter()
class LLMConfigUpdate(BaseModel):
provider: str
model: Optional[str] = None
@router.get("/", response_model=ConfigResponse)
async def get_config(config_manager: ConfigManager = Depends(get_config_manager)):
"""Retrieve the current system configuration."""
return await config_manager.get_config()
@router.get("/llm", response_model=Dict[str, Any])
async def get_llm_config(config_manager: ConfigManager = Depends(get_config_manager)):
"""Get LLM provider and model configuration."""
llm_config = await config_manager.get_llm_config()
return llm_config
@router.put("/llm", response_model=Dict[str, Any])
async def update_llm_config(
llm_update: LLMConfigUpdate,
config_manager: ConfigManager = Depends(get_config_manager)
):
"""Update LLM provider and model configuration."""
import json
import os
provider = llm_update.provider
model = llm_update.model
# Load base config
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
config_path = os.path.join(project_root, "config", "config.json")
base_config = {}
if os.path.exists(config_path):
try:
with open(config_path, "r", encoding="utf-8") as f:
base_config = json.load(f)
except Exception:
pass
# Update llm config
if "llm" not in base_config:
base_config["llm"] = {}
base_config["llm"]["provider"] = provider
if model:
# Update model in the provider-specific config
if provider in base_config["llm"]:
if not isinstance(base_config["llm"][provider], dict):
base_config["llm"][provider] = {}
base_config["llm"][provider]["model"] = model
# Save to file
try:
with open(config_path, "w", encoding="utf-8") as f:
json.dump(base_config, f, ensure_ascii=False, indent=2)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to save config: {str(e)}")
# Also update in database - use same error handling as _load_dynamic_config_from_db
try:
from app.models.system_config import SystemConfig
from sqlalchemy.future import select
result = await config_manager.db.execute(
select(SystemConfig).where(SystemConfig.config_key == "llm")
)
existing_llm_config = result.scalar_one_or_none()
if existing_llm_config:
if isinstance(existing_llm_config.config_value, dict):
existing_llm_config.config_value["provider"] = provider
if model:
if provider not in existing_llm_config.config_value:
existing_llm_config.config_value[provider] = {}
elif not isinstance(existing_llm_config.config_value[provider], dict):
existing_llm_config.config_value[provider] = {}
existing_llm_config.config_value[provider]["model"] = model
else:
existing_llm_config.config_value = {"provider": provider}
if model:
existing_llm_config.config_value[provider] = {"model": model}
else:
new_llm_config = SystemConfig(
config_key="llm",
config_value={"provider": provider}
)
if model:
new_llm_config.config_value[provider] = {"model": model}
config_manager.db.add(new_llm_config)
await config_manager.db.commit()
except Exception as e:
# Rollback on error
try:
await config_manager.db.rollback()
except Exception:
pass
# Log the error but don't fail the request since file was already saved
import logging
logger = logging.getLogger(__name__)
logger.warning(f"Failed to update LLM config in database (file saved successfully): {e}")
# Continue anyway since file config was saved successfully
return await config_manager.get_llm_config()
@router.put("/", response_model=ConfigResponse)
async def update_config(
config_update: ConfigUpdateRequest,
config_manager: ConfigManager = Depends(get_config_manager)
):
"""Update system configuration."""
return await config_manager.update_config(config_update)
@router.post("/test", response_model=ConfigTestResponse)
async def test_config(
test_request: ConfigTestRequest,
config_manager: ConfigManager = Depends(get_config_manager)
):
"""Test a specific configuration (e.g., database connection)."""
try:
test_result = await config_manager.test_config(
test_request.config_type,
test_request.config_data
)
return test_result
except Exception as e:
return ConfigTestResponse(
success=False,
message=f"测试失败: {str(e)}"
)