From 1aaa1f22bdcbe6cd3ff980c91115923b48d07d31 Mon Sep 17 00:00:00 2001 From: Priyanka Punukollu Date: Sat, 28 Feb 2026 08:01:44 -0600 Subject: [PATCH] fix: save in-progress UI and server changes Made-with: Cursor --- chat_ui.html | 22 +++++++++++++--------- main.py | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/chat_ui.html b/chat_ui.html index fe1ca70a1..62c16e1e9 100644 --- a/chat_ui.html +++ b/chat_ui.html @@ -5840,14 +5840,18 @@ } })(); - // ── Auth guard — redirect to login if no token ── - const _token = localStorage.getItem('gf_token'); - if (!_token) { - window.location.replace('/login'); - } - - // ── Load user profile from localStorage (set at login) ── - (function loadUser() { + // ── Auth: auto-fetch token when missing (no login required) ── + (async function initAuth() { + if (!localStorage.getItem('gf_token')) { + try { + const r = await fetch('/auth/auto'); + const d = await r.json(); + if (d.success && d.token) { + localStorage.setItem('gf_token', d.token); + if (d.name) localStorage.setItem('gf_user_name', d.name); + } + } catch { /* continue without token — backend uses env */ } + } const name = localStorage.getItem('gf_user_name') || 'Investor'; const initials = name.slice(0, 2).toUpperCase(); document.getElementById('user-avatar').textContent = initials; @@ -9125,7 +9129,7 @@ localStorage.removeItem('gf_user_email'); localStorage.removeItem(STORAGE_KEY); // Clear session-specific memory (keep watchlist / memory by default — user owns those) - window.location.replace('/login'); + window.location.replace('/'); }); // ── Clear session ── diff --git a/main.py b/main.py index 082cb6d69..55a311f20 100644 --- a/main.py +++ b/main.py @@ -5,13 +5,15 @@ from datetime import datetime from fastapi import FastAPI, Response from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import StreamingResponse, HTMLResponse, JSONResponse +from fastapi.responses import RedirectResponse, StreamingResponse, HTMLResponse, JSONResponse from pydantic import BaseModel from dotenv import load_dotenv import httpx from langchain_core.messages import HumanMessage, AIMessage load_dotenv() +# Load agent/.env so ANTHROPIC_API_KEY, GHOSTFOLIO_BEARER_TOKEN, etc. are available +load_dotenv(os.path.join(os.path.dirname(__file__), "agent", ".env")) from graph import build_graph from state import AgentState @@ -393,10 +395,34 @@ async def auth_login(req: LoginRequest): } -@app.get("/login", response_class=HTMLResponse, include_in_schema=False) +@app.get("/auth/auto") +async def auth_auto(): + """ + No-login auth: returns the configured token and user info without credentials. + Enables the app to work without a login page. + """ + token = os.getenv("GHOSTFOLIO_BEARER_TOKEN", "") + base_url = os.getenv("GHOSTFOLIO_BASE_URL", "http://localhost:3333") + display_name = "Investor" + try: + async with httpx.AsyncClient(timeout=4.0) as client: + r = await client.get( + f"{base_url}/api/v1/user", + headers={"Authorization": f"Bearer {token}"}, + ) + if r.status_code == 200: + data = r.json() + alias = data.get("settings", {}).get("alias") or "" + display_name = alias or "Investor" + except Exception: + pass + return {"success": True, "token": token, "name": display_name} + + +@app.get("/login", include_in_schema=False) async def login_page(): - with open(os.path.join(os.path.dirname(__file__), "login.html")) as f: - return f.read() + """Redirect to chat — login is bypassed.""" + return RedirectResponse(url="/", status_code=302) @app.get("/me")