Spaces:
Sleeping
Sleeping
File size: 2,936 Bytes
685cc60 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | import os
import sys
import asyncio
from contextlib import asynccontextmanager
from dotenv import load_dotenv
# Psycopg 3 async requires SelectorEventLoop on Windows
if sys.platform == "win32":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from psycopg_pool import AsyncConnectionPool
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
from src.react_agent.agent import get_agent
from src.api.routes import router as chat_router
# Load environment variables (such as DATABASE_URL and GOOGLE_API_KEY)
load_dotenv()
@asynccontextmanager
async def lifespan(app: FastAPI):
database_url = os.getenv("DATABASE_URL")
if not database_url:
raise ValueError("DATABASE_URL environment variable is not set")
# Establish persistent connection pool to Supabase
async with AsyncConnectionPool(
conninfo=database_url,
max_size=10,
kwargs={"autocommit": True}
) as pool:
app.state.pool = pool
checkpointer = AsyncPostgresSaver(pool)
# Create checkpoint tables if they don't exist (migrations)
await checkpointer.setup()
# Create custom chat_sessions table for thread names
async with pool.connection() as conn:
async with conn.cursor() as cur:
await cur.execute("""
CREATE TABLE IF NOT EXISTS chat_sessions (
thread_id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
title TEXT NOT NULL,
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
)
""")
await cur.execute("""
CREATE INDEX IF NOT EXISTS idx_chat_sessions_user_id_updated_at
ON chat_sessions (user_id, updated_at DESC)
""")
# Compile agent with the persistent Postgres checkpointer
app.state.agent = get_agent(checkpointer)
yield
app = FastAPI(
title="Vectorless-RAG API Backend",
description="Local FastAPI backend serving the LangGraph ReAct Legal Assistant",
version="1.0.0",
lifespan=lifespan
)
# Enable CORS for Next.js frontend calls
allowed_origins_env = os.getenv("ALLOWED_ORIGINS", "*")
if allowed_origins_env.strip() == "*":
allowed_origins = ["*"]
else:
allowed_origins = [
o.strip() for o in allowed_origins_env.split(",") if o.strip()
]
app.add_middleware(
CORSMiddleware,
allow_origins=allowed_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include the routes
app.include_router(chat_router, prefix="/api")
@app.get("/")
def read_root():
return {
"status": "online",
"message": "Vectorless-RAG Legal Assistant API is fully operational locally."
}
|