import os from sqlalchemy.orm import Session as DBSession from app.db.models import AppSetting # GUIから編集可能な環境変数の許可リスト。ここに無いキーは save()/clear() で拒否する。 CONFIGURABLE_KEYS = [ "OPENAI_API_KEY", "ANTHROPIC_API_KEY", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN", "AWS_BEARER_TOKEN_BEDROCK", "AWS_REGION_NAME", "OLLAMA_API_BASE", "TAVILY_API_KEY", "LOCAL_KB_EMBEDDING_MODEL", ] # .env由来の起動時の値のスナップショット。clear() で戻す先として使う。 _env_defaults: dict[str, str | None] = {} _snapshot_taken = False def _ensure_snapshot() -> None: global _snapshot_taken if _snapshot_taken: return for key in CONFIGURABLE_KEYS: _env_defaults[key] = os.environ.get(key) _snapshot_taken = True def _mask(value: str) -> str: if len(value) <= 4: return "••••" return f"••••{value[-4:]}" def load_into_env(db: DBSession) -> None: """DBに保存済みの値をos.environに適用する。起動時に一度呼ぶ。""" _ensure_snapshot() for row in db.query(AppSetting).all(): if row.key in CONFIGURABLE_KEYS: os.environ[row.key] = row.value def list_masked(db: DBSession) -> list[dict]: _ensure_snapshot() saved = {row.key: row.value for row in db.query(AppSetting).all()} result = [] for key in CONFIGURABLE_KEYS: current = os.environ.get(key) result.append({ "key": key, "is_set": bool(current), "masked": _mask(current) if current else None, "overridden": key in saved, }) return result def save(db: DBSession, key: str, value: str) -> None: if key not in CONFIGURABLE_KEYS: raise ValueError(f"Unknown setting key: {key}") _ensure_snapshot() row = db.get(AppSetting, key) if row: row.value = value else: db.add(AppSetting(key=key, value=value)) db.commit() os.environ[key] = value def clear(db: DBSession, key: str) -> None: if key not in CONFIGURABLE_KEYS: raise ValueError(f"Unknown setting key: {key}") _ensure_snapshot() row = db.get(AppSetting, key) if row: db.delete(row) db.commit() original = _env_defaults.get(key) if original is None: os.environ.pop(key, None) else: os.environ[key] = original