mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-09 08:24:42 +02:00
feat(finlab): import de relevé par image (upload dashboard → scan Console IA)
Process dédié pour actualiser le portefeuille à partir d'une capture de relevé :
- Dashboard : bouton « 📥 Importer un relevé » (panneau Mes comptes) → upload de
l'image vers le workspace (imports/) via POST /api/import ; une modale donne la
phrase exacte à dire à la console + un lien direct
- Backend : endpoints /api/import (UploadFile, refuse les non-images) et /api/imports
(listing), dossier imports/ sous FINLAB_HOME (workspace, persistant)
- Persona console (CLAUDE.md) : workflow « Import d'un relevé » — lire l'image,
extraire compte/positions, mapper vers tickers Yahoo en VÉRIFIANT les cours,
confirmer, puis mettre à jour portfolio.yaml
Le scan vision se fait dans la Console IA (abonnement, pas de clé API). Le dashboard
n'est que le pont d'upload. Testé : POST image→200 + listing OK, non-image→400 ;
JS node --check OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
2228613050
commit
72f22a7063
3 changed files with 89 additions and 2 deletions
|
|
@ -8,12 +8,13 @@ Lancement : uvicorn dashboard.server:app --host 0.0.0.0 --port 8800
|
|||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime as dt
|
||||
import math
|
||||
from pathlib import Path
|
||||
|
||||
import pandas as pd
|
||||
import yaml
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi import FastAPI, File, Request, UploadFile
|
||||
from fastapi.responses import FileResponse, JSONResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
|
|
@ -167,6 +168,34 @@ def api_plan(ticker: str, capital: float = 1427.0):
|
|||
return _clean({"plan": p, "render": plan_mod.render(p)})
|
||||
|
||||
|
||||
# ── Import de relevés (image → analysée par la Console IA) ─────────────────────
|
||||
IMPORTS_DIR = data.ROOT / "imports"
|
||||
_IMG_EXT = {".png", ".jpg", ".jpeg", ".webp", ".gif"}
|
||||
|
||||
|
||||
@app.post("/api/import")
|
||||
async def api_import(file: UploadFile = File(...)):
|
||||
"""Enregistre une capture de relevé dans le workspace (imports/) ; la Console IA la scanne
|
||||
ensuite pour mettre à jour portfolio.yaml (vision côté abonnement, pas de clé API ici)."""
|
||||
ext = Path(file.filename or "").suffix.lower()
|
||||
if ext not in _IMG_EXT:
|
||||
return JSONResponse(status_code=400, content={"error": f"format image non supporté: {ext or '?'}"})
|
||||
IMPORTS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
ts = dt.datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||
name = f"releve-{ts}{ext}"
|
||||
(IMPORTS_DIR / name).write_bytes(await file.read())
|
||||
return {"saved": name, "rel": f"imports/{name}"}
|
||||
|
||||
|
||||
@app.get("/api/imports")
|
||||
def api_imports():
|
||||
if not IMPORTS_DIR.exists():
|
||||
return {"imports": []}
|
||||
files = sorted((f for f in IMPORTS_DIR.iterdir() if f.suffix.lower() in _IMG_EXT),
|
||||
key=lambda f: f.stat().st_mtime, reverse=True)
|
||||
return {"imports": [f.name for f in files]}
|
||||
|
||||
|
||||
# ── Statique ──────────────────────────────────────────────────────────────────
|
||||
@app.get("/")
|
||||
def index():
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue