7a34807fa0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
85 lines
2.6 KiB
Python
85 lines
2.6 KiB
Python
import time
|
|
from fastapi import APIRouter, HTTPException
|
|
from pydantic import BaseModel
|
|
from services import storage
|
|
from config import DEFAULT_SYSTEM_PROMPT
|
|
from ai import get_provider
|
|
|
|
router = APIRouter(prefix="/api/settings", tags=["settings"])
|
|
|
|
|
|
class SettingsPatch(BaseModel):
|
|
system_prompt: str | None = None
|
|
active_provider: str | None = None
|
|
providers: dict | None = None
|
|
|
|
|
|
class TestProviderRequest(BaseModel):
|
|
provider: str
|
|
|
|
|
|
@router.get("")
|
|
async def get_settings():
|
|
settings = storage.load_settings()
|
|
return storage.settings_masked(settings)
|
|
|
|
|
|
@router.patch("")
|
|
async def patch_settings(body: SettingsPatch):
|
|
settings = storage.load_settings()
|
|
|
|
if body.system_prompt is not None:
|
|
settings["system_prompt"] = body.system_prompt
|
|
|
|
if body.active_provider is not None:
|
|
valid = {"anthropic", "openai", "ollama", "lmstudio"}
|
|
if body.active_provider not in valid:
|
|
raise HTTPException(400, f"Invalid provider. Must be one of: {valid}")
|
|
settings["active_provider"] = body.active_provider
|
|
|
|
if body.providers is not None:
|
|
# Deep merge per-provider config
|
|
for prov_name, prov_cfg in body.providers.items():
|
|
if prov_name not in settings.get("providers", {}):
|
|
settings.setdefault("providers", {})[prov_name] = {}
|
|
existing = settings["providers"][prov_name]
|
|
for key, val in prov_cfg.items():
|
|
# Don't overwrite api_key if it comes in masked (contains ****)
|
|
if key == "api_key" and val and "****" in str(val):
|
|
continue
|
|
existing[key] = val
|
|
|
|
storage.save_settings(settings)
|
|
return storage.settings_masked(settings)
|
|
|
|
|
|
@router.post("/test-provider")
|
|
async def test_provider(body: TestProviderRequest):
|
|
settings = storage.load_settings()
|
|
# Temporarily switch active provider for the test
|
|
test_settings = dict(settings)
|
|
test_settings["active_provider"] = body.provider
|
|
|
|
try:
|
|
provider = get_provider(test_settings)
|
|
except ValueError as e:
|
|
raise HTTPException(400, str(e))
|
|
|
|
start = time.monotonic()
|
|
try:
|
|
ok = await provider.health_check()
|
|
except Exception as e:
|
|
return {"ok": False, "message": str(e), "latency_ms": 0}
|
|
|
|
latency_ms = int((time.monotonic() - start) * 1000)
|
|
return {
|
|
"ok": ok,
|
|
"message": "Connection successful" if ok else "Health check failed",
|
|
"latency_ms": latency_ms,
|
|
}
|
|
|
|
|
|
@router.get("/default-prompt")
|
|
async def get_default_prompt():
|
|
return {"system_prompt": DEFAULT_SYSTEM_PROMPT}
|