import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from fastapi import FastAPI, BackgroundTasks, HTTPException from fastapi.responses import FileResponse, HTMLResponse from pydantic import BaseModel from typing import Optional import uvicorn from config.settings import API_HOST, API_PORT, PROCESSED_DIR from ingestion.sec_downloader import ingest_ticker from ingestion.text_extractor import extract_all from agents.analyst import analyze app = FastAPI(title="SEC Analyst LLM") class IngestRequest(BaseModel): ticker: str form_types: list = ["10-K", "10-Q"] max_filings: int = 5 class AnalyzeRequest(BaseModel): question: str ticker: Optional[str] = None n_results: int = 6 def run_pipeline(ticker, form_types, max_filings): print(f"[PIPELINE] Starting {ticker}...") ingest_ticker(ticker, form_types=form_types, max_filings=max_filings) extract_all(ticker) build_and_persist(ticker) print(f"[PIPELINE] Done: {ticker}") @app.get("/health") def health(): return {"api": "ok", "ollama": "ok", "chromadb": "ok"} @app.get("/tickers") def list_tickers(): tickers = [d.name for d in PROCESSED_DIR.iterdir() if d.is_dir()] if PROCESSED_DIR.exists() else [] return {"tickers": sorted(tickers)} @app.post("/ingest") def ingest(req: IngestRequest, background_tasks: BackgroundTasks): background_tasks.add_task(run_pipeline, req.ticker.upper(), req.form_types, req.max_filings) return {"status": "started", "ticker": req.ticker.upper(), "message": f"Ingesting {req.ticker.upper()} — this takes 3-5 minutes. The ticker will appear on the left when done."} @app.post("/analyze") def analyze_endpoint(req: AnalyzeRequest): try: return analyze(question=req.question, ticker=req.ticker, n_results=req.n_results) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) ui_file = Path(__file__).parent.parent / "ui" / "index.html" @app.get("/") def serve_ui(): if ui_file.exists(): return FileResponse(str(ui_file)) return HTMLResponse("

UI not found

") @app.get("/test-llm") def test_llm(): import requests, os from config.settings import HF_TOKEN results = {} models = [ "meta-llama/Llama-3.3-70B-Instruct", "Qwen/QwQ-32B", "meta-llama/Meta-Llama-3-8B-Instruct", "HuggingFaceH4/zephyr-7b-beta", "mistralai/Mistral-7B-Instruct-v0.2" ] for model in models: try: url = f"https://api-inference.huggingface.co/models/{model}" r = requests.post(url, headers={"Authorization": f"Bearer {HF_TOKEN}"}, json={"inputs": "say hi", "parameters": {"max_new_tokens": 5}}, timeout=15) results[model] = f"{r.status_code}: {r.text[:100]}" except Exception as e: results[model] = f"ERROR: {str(e)[:100]}" return results if __name__ == "__main__": uvicorn.run("api.server:app", host=API_HOST, port=API_PORT, reload=False)