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)}" )