universe: paid-gate + LLM fallback on /portfolio/parse

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Giorgio Gilestro 2026-05-27 12:31:07 +02:00
parent 59b28506df
commit 8bc9dccd40
2 changed files with 80 additions and 3 deletions

View file

@ -189,7 +189,7 @@ async def get_sparkline(
# ---------------------------------------------------------------------------
@router.post("/portfolio/parse")
@router.post("/portfolio/parse", dependencies=[Depends(require_paid)])
async def parse_portfolio(
file: UploadFile = File(...),
session: AsyncSession = Depends(get_session),
@ -210,8 +210,15 @@ async def parse_portfolio(
try:
pie = parse_t212_csv(raw)
except CSVImportError as e:
raise HTTPException(status_code=400, detail=str(e))
except CSVImportError:
# Unrecognised format — try the LLM-fallback parser. It hits a
# global format-fingerprint cache first; only the very first
# upload of each broker format pays an LLM call.
from app.services.llm_csv_parser import LLMParseError, parse_with_llm
try:
pie = await parse_with_llm(raw, session)
except LLMParseError as e:
raise HTTPException(status_code=400, detail=str(e))
positions_out: list[dict] = []
yahoo_tickers: list[str] = []