feat: auto-build FAISS index on startup if missing

Add lifespan handler that checks for FAISS index at startup
and automatically builds it if not found. This ensures the
service works on fresh deployments without manual indexing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Danny 2026-01-30 10:47:03 -06:00
parent 1d11deb813
commit 2f172ddaf9
1 changed files with 26 additions and 1 deletions

View File

@ -1,5 +1,6 @@
import logging import logging
import uuid import uuid
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException, BackgroundTasks from fastapi import FastAPI, HTTPException, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
@ -7,7 +8,7 @@ from fastapi.responses import StreamingResponse
from app.auth import ServiceAuthDependency from app.auth import ServiceAuthDependency
from app.config import settings, MAX_MESSAGE_LENGTH from app.config import settings, MAX_MESSAGE_LENGTH
from app.embeddings import RetrieverDependency, IndexerDependency, get_retriever, reset_retriever from app.embeddings import RetrieverDependency, IndexerDependency, get_retriever, reset_retriever, get_indexer
from app.embeddings.retriever import RetrievedChunk from app.embeddings.retriever import RetrievedChunk
from app.intent import IntentClassifierDependency from app.intent import IntentClassifierDependency
from app.llm import AdapterDependency, LLMError, llm_exception_to_http from app.llm import AdapterDependency, LLMError, llm_exception_to_http
@ -31,11 +32,35 @@ logging.basicConfig(
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Startup and shutdown lifecycle management."""
# Startup: auto-index if FAISS index is missing
retriever = get_retriever()
if not retriever.is_loaded:
logger.info("FAISS index not found, building index on startup...")
try:
indexer = get_indexer()
result = await indexer.build_index()
reset_retriever() # Reset to load newly built index
logger.info(f"Startup indexing completed: {result.chunks_indexed} chunks from {result.artifacts_processed} artifacts")
except Exception as e:
logger.error(f"Startup indexing failed: {e}")
else:
logger.info(f"FAISS index loaded: {retriever.index_size} vectors")
yield # App runs here
# Shutdown: nothing to clean up
# Create FastAPI app # Create FastAPI app
app = FastAPI( app = FastAPI(
title="Tyndale AI Service", title="Tyndale AI Service",
description="LLM Chat Service for algorithmic trading support", description="LLM Chat Service for algorithmic trading support",
version="0.1.0", version="0.1.0",
lifespan=lifespan,
) )
# Add CORS middleware # Add CORS middleware