diff --git a/cortex/routers/settings.py b/cortex/routers/settings.py index b2e8a88..fde57c3 100644 --- a/cortex/routers/settings.py +++ b/cortex/routers/settings.py @@ -16,7 +16,7 @@ import jwt from fastapi import APIRouter, Form, Request from fastapi.responses import HTMLResponse, RedirectResponse -from auth_utils import COOKIE_NAME, decode_token, check_credentials, set_password +from auth_utils import COOKIE_NAME, decode_token, check_credentials, set_password, _read_auth, _write_auth from persona import list_user_personas from config import settings as app_settings @@ -41,6 +41,20 @@ def _get_session_user(request: Request) -> str | None: def _settings_page(username: str, personas: list[str], success: str = "", error: str = "") -> str: html = (_STATIC / "settings.html").read_text() html = html.replace("{{ username }}", username) + + # Connected Google account + auth_data = _read_auth(username) + google_email = auth_data.get("google_email") or "" + html = html.replace("{{ google_email }}", google_email) + + # Gemini API key — show masked hint only, never the full key + gemini_key = auth_data.get("gemini_api_key") or "" + if gemini_key: + hint = f"Saved (…{gemini_key[-4:]})" + else: + hint = "Using server key" + html = html.replace("{{ gemini_key_hint }}", hint) + html = html.replace("{{ gemini_key_set }}", "true" if gemini_key else "false") persona_items = "\n".join( f'''
  • {p} @@ -139,6 +153,30 @@ async def rename_username( return resp +@router.post("/settings/gemini-key", include_in_schema=False) +async def save_gemini_key( + request: Request, + gemini_api_key: str = Form(...), +): + username = _get_session_user(request) + if not username: + return RedirectResponse("/login", status_code=302) + + personas = list_user_personas(username) + gemini_api_key = gemini_api_key.strip() + + data = _read_auth(username) + if gemini_api_key: + data["gemini_api_key"] = gemini_api_key + msg = "Gemini API key saved." + else: + data.pop("gemini_api_key", None) + msg = "Gemini API key removed — using server key." + _write_auth(username, data) + logger.info("gemini key updated: %s", username) + return HTMLResponse(_settings_page(username, personas, success=msg)) + + @router.post("/settings/persona/rename", include_in_schema=False) async def rename_persona( request: Request, diff --git a/cortex/static/settings.html b/cortex/static/settings.html index 246a627..f33c319 100644 --- a/cortex/static/settings.html +++ b/cortex/static/settings.html @@ -232,6 +232,45 @@ + +
    +

    Connected Accounts

    +
    + + +
    +

    + To link or change your Google account, contact Scott. +

    +
    + + +
    +

    Gemini API Key

    +

    + Paste your personal key from + aistudio.google.com/apikey + to use your own Gemini quota. Leave blank to use the shared server key. +

    +
    +
    + + +
    + +
    +

    + Current: {{ gemini_key_hint }} + + — remove + +

    +
    +

    Change Password

    @@ -287,6 +326,16 @@ document.getElementById('show-rename-user').style.display = ''; }); + // Gemini key — "remove" link clears the input and submits the form + const geminiRemove = document.getElementById('gemini-remove-link'); + if (geminiRemove) { + geminiRemove.addEventListener('click', e => { + e.preventDefault(); + document.getElementById('gemini_api_key').value = ''; + document.querySelector('form[action="/settings/gemini-key"]').submit(); + }); + } + // Persona rename toggle document.querySelectorAll('.persona-rename-toggle').forEach(btn => { btn.addEventListener('click', () => {