Spaces:
Running
Running
| 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}") | |
| def health(): | |
| return {"api": "ok", "ollama": "ok", "chromadb": "ok"} | |
| 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)} | |
| 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."} | |
| 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" | |
| def serve_ui(): | |
| if ui_file.exists(): | |
| return FileResponse(str(ui_file)) | |
| return HTMLResponse("<h1>UI not found</h1>") | |
| 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) | |