# backend/app/routers/settings.py — 설정: 시스템 스냅샷(읽기전용) + LLM 연결(편집/적용/테스트) from fastapi import APIRouter, Depends, HTTPException from sqlmodel import Session from .. import runtime_config from ..config import get_settings from ..db import get_session from ..llm.ollama import OllamaProvider from ..llm.provider import LLMProvider from ..schemas import ( LLMConfigOut, LLMTestIn, LLMTestOut, LLMUpdateIn, SystemConfigOut, ) from ..services import settings_service router = APIRouter() # prefix 없음. main.py 에서 prefix="/api" 등록. def _db_dialect(url: str) -> str: return url.split(":", 1)[0].split("+", 1)[0] if url else "unknown" @router.get("/settings/system", response_model=SystemConfigOut) def get_system(s: Session = Depends(get_session)): """런타임/환경 구성 스냅샷(읽기전용 — .env 로 관리).""" st = get_settings() return SystemConfigOut( env=st.ari_env, auth_enabled=st.auth_enabled, worker_enabled=st.worker_enabled, database=_db_dialect(st.database_url), sync_interval_minutes=st.sync_interval_minutes, sync_page_size=st.sync_page_size, connector_modes={ "calendar": st.connector_calendar, "mail": st.connector_mail, }, ) def _llm_config(s: Session) -> LLMConfigOut: st = get_settings() eff = runtime_config.effective_llm() return LLMConfigOut( provider=eff.provider, model=eff.model, host=eff.host, timeout=eff.timeout, overridden=settings_service.overlay_active(s), stt_provider=st.stt_provider, vision_provider=st.vision_provider, ) @router.get("/settings/llm", response_model=LLMConfigOut) def get_llm(s: Session = Depends(get_session)): return _llm_config(s) @router.put("/settings/llm", response_model=LLMConfigOut) def update_llm(body: LLMUpdateIn, s: Session = Depends(get_session)): try: settings_service.update_llm( s, provider=body.provider, model=body.model, host=body.host, timeout=body.timeout, ) except ValueError as e: raise HTTPException(400, str(e)) from e return _llm_config(s) @router.post("/settings/llm/test", response_model=LLMTestOut) def test_llm(body: LLMTestIn): """저장 없이 연결만 테스트. provider/host/model 미지정 시 유효 설정값 사용.""" eff = runtime_config.effective_llm() provider = body.provider or eff.provider # 실 LLM 전용(휴리스틱 제거): 항상 Ollama 도달성으로 테스트. impl: LLMProvider = OllamaProvider(host=body.host or eff.host, model=body.model or eff.model) h = impl.health() return LLMTestOut( reachable=bool(h.get("reachable")), provider=h.get("provider", provider), model=h.get("model", ""), host=h.get("host"), models=impl.list_models(), detail=h.get("detail", ""), )