mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-08 08:44:43 +02:00
feat(finlab): import de relevé par image (upload dashboard → scan Console IA) (#69)
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
8bbfe88a30
3 changed files with 89 additions and 2 deletions
|
|
@ -101,7 +101,10 @@
|
|||
<!-- Colonne gauche : portefeuille + watchlists -->
|
||||
<div>
|
||||
<div class="panel">
|
||||
<h3>Mes comptes <span class="muted" id="pfCount"></span></h3>
|
||||
<h3>Mes comptes <span class="muted" id="pfCount"></span>
|
||||
<button class="btn perbtn" style="font-size:11px" title="Importer une capture de relevé (la Console IA la scanne)" onclick="document.getElementById('importFile').click()">📥 Importer un relevé</button>
|
||||
</h3>
|
||||
<input type="file" id="importFile" accept="image/*" style="display:none" onchange="uploadImport(this.files[0])">
|
||||
<div class="acct-tabs" id="acctTabs"></div>
|
||||
<div id="pfList"><div class="loading">Chargement…</div></div>
|
||||
</div>
|
||||
|
|
@ -190,6 +193,17 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal import de relevé -->
|
||||
<div class="modal" id="importModal" onclick="if(event.target===this)this.classList.remove('on')">
|
||||
<div class="box">
|
||||
<h3 style="margin-bottom:10px">Importer un relevé (image)</h3>
|
||||
<div id="importOut" class="muted">—</div>
|
||||
<div class="controls" style="margin-top:12px">
|
||||
<button class="btn" onclick="document.getElementById('importModal').classList.remove('on')">Fermer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let CHART, S = {}, SEL=null, PERIOD='6mo', CCY='$';
|
||||
const fmt = (n,d=0)=> n==null? '—' : Number(n).toLocaleString('fr-FR',{minimumFractionDigits:d,maximumFractionDigits:d});
|
||||
|
|
@ -384,6 +398,26 @@ async function runPlan(){
|
|||
}catch(e){ out.textContent='Erreur: '+e.message; }
|
||||
}
|
||||
|
||||
// ── Import de relevé (image → scannée par la Console IA) ────
|
||||
async function uploadImport(f){
|
||||
const inp=document.getElementById('importFile');
|
||||
if(!f){ return; }
|
||||
const m=document.getElementById('importModal'), out=document.getElementById('importOut');
|
||||
m.classList.add('on'); out.innerHTML='<div class="loading">Envoi de '+f.name+'…</div>';
|
||||
try{
|
||||
const fd=new FormData(); fd.append('file', f);
|
||||
const r=await fetch('/api/import',{method:'POST',body:fd});
|
||||
const j=await r.json();
|
||||
if(j.error) throw new Error(j.error);
|
||||
out.innerHTML = `<p style="color:var(--up)">✅ Relevé enregistré : <code>${j.rel}</code></p>
|
||||
<p>Ouvre la <b>Console IA</b> et demande :</p>
|
||||
<pre>importe le relevé ${j.rel} et mets à jour mon portefeuille</pre>
|
||||
<p class="muted" style="font-size:12px">Je lirai l'image, je mapperai chaque ligne vers son ticker Yahoo (en vérifiant le cours), puis je mettrai à jour <code>portfolio.yaml</code> <b>après ta confirmation</b>.</p>
|
||||
<a class="btn acc" href="/console/" target="_blank">Ouvrir la Console IA ↗</a>`;
|
||||
}catch(e){ out.innerHTML='<div class="err">Erreur: '+e.message+'</div>'; }
|
||||
finally{ inp.value=''; }
|
||||
}
|
||||
|
||||
// ── Chaîne de valeur IA (couches) ──────────────────────────
|
||||
const LAYER_META = {
|
||||
energy_power: {ic:'⚡', lb:'Énergie', ds:'alimente les datacenters'},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue