You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

64 lines
2.3 KiB
Python

# backend/app/services/settings_service.py
# app_setting(영속) ↔ runtime_config(인메모리 오버레이) 동기화.
from sqlmodel import Session, select
from .. import runtime_config
from ..models import AppSetting, now
def _upsert(session: Session, key: str, value: str | None) -> None:
"""value=None/빈 → 행 삭제(기본으로 복귀). 그 외 → upsert."""
row = session.get(AppSetting, key)
if value is None or (isinstance(value, str) and value.strip() == ""):
if row:
session.delete(row)
return
if row:
row.value = str(value)
row.updated_at = now()
session.add(row)
else:
session.add(AppSetting(key=key, value=str(value)))
def update_llm(
session: Session,
*,
provider: str | None = None,
model: str | None = None,
host: str | None = None,
timeout: float | None = None,
) -> None:
"""LLM 설정을 영속(app_setting)하고 런타임 오버레이에 즉시 반영.
provider 가 'auto'(=env 기본과 동등하게 둘 수도 있으나) 라도 명시 저장은 허용한다.
None 인 필드는 건드리지 않는다(부분 갱신)."""
fields: dict[str, object | None] = {}
if provider is not None:
if provider.strip() == "":
fields["llm.provider"] = None # 빈 값 → 기본(env)으로 되돌리기
elif provider not in runtime_config._PROVIDERS:
raise ValueError(f"provider must be one of {runtime_config._PROVIDERS}")
else:
fields["llm.provider"] = provider
if model is not None:
fields["llm.model"] = model
if host is not None:
fields["llm.host"] = host
if timeout is not None:
# timeout<=0 은 '기본으로 되돌리기' 신호(프론트 리셋용).
fields["llm.timeout"] = None if timeout <= 0 else timeout
for key, val in fields.items():
_upsert(session, key, None if val is None else str(val))
session.commit()
# 영속 후 DB → 오버레이 재적재(부분 삭제까지 일관되게 반영)
runtime_config.load_from_db(session)
def overlay_active(session: Session) -> bool:
"""LLM 오버레이 행이 하나라도 있으면 True."""
rows = session.exec(select(AppSetting)).all()
return any(r.key in runtime_config.LLM_KEYS for r in rows)