- Python 50.5%
- TypeScript 40.4%
- HTML 9.1%
gateway : artifacts structurés mock (quantities/validation/mesh/figures),
endpoint GET /api/v1/jobs/{id}/result, HTML cohérent, CORS paramétrable par env
extension : URL API publique par défaut, bouton Envoyer au chat (panel→background→content),
auto-injection du content script (scripting), injection composer NotebookLM
(shadow DOM + insertText) avec fallback presse-papier, capture sélection retirée
sécurité : clé API hors repo (.env gitignoré)
docs : checklist gate-a-test
|
||
|---|---|---|
| docs | ||
| extension | ||
| gateway | ||
| scripts | ||
| .gitignore | ||
| README.md | ||
FEneC × NotebookLM — Extension Chromium
Ajoute la couche validation physique (simulation par éléments finis) au panneau de NotebookLM — le "chaînon manquant" : NotebookLM explique, FEneC calcule.
Rendu v1 : iframe-widget. Le panneau charge une result_url tokenisée servie par le
gateway FEneC (page compatible framage via CSP frame-ancestors). On teste A ; si les
gates passent, on garde. Replis documentés : B (rendu natif), C (texte + figures backend).
Architecture
extension/ Chromium MV3 (TypeScript + Vite + @crxjs/vite-plugin)
src/background.ts service worker (icône → side panel, menu contextuel)
src/content.ts détection NotebookLM + capture de sélection
src/sidepanel.html|ts panneau (drop zone, capture, status, iframe résultat)
src/lib/api.ts client HTTP (clé API, jobs, polling)
gateway/ FastAPI — surface publique unique, recette interne isolée
app/main.py endpoints + CORS
app/auth.py clés API (header X-API-Key)
app/pipeline.py jobs async + dédoublonnage recettes (flywheel)
app/backends.py MockBackend (défaut) / HomelabBackend (env)
app/render.py page résultat (framable, tokenisée)
Quickstart
Gateway (local)
cd gateway
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
FENEC_API_KEYS=dev-key FENEC_MOCK_DELAY=2 .venv/bin/uvicorn app.main:app --port 8000
Tests : FENEC_API_KEYS=test-key FENEC_MOCK_DELAY=0 .venv/bin/python -m pytest tests -q
Extension
cd extension
npm install
npm run dev # serveur dev Vite (HMR)
npm run build # → dist/ (charger "unpacked" via chrome://extensions)
Test manuel : charger extension/dist en mode "Extension non empaquetée", ouvrir
https://notebooklm.google.com, cliquer l'icône FEneC → le side panel s'ouvre. Saisir la
clé API dans le panneau (bouton Enregistrer), puis : sélectionner un texte dans NotebookLM
→ "Capturer la sélection", ou déposer un fichier (image/PDF).
Contrat API
| Méthode | Route | Body | Réponse |
|---|---|---|---|
| POST | /api/v1/simulate |
text | image_b64+filename (multipart) |
{job_id, status, result_url?} |
| GET | /api/v1/jobs/{id} |
— | {job_id, status, result_url?, error?} |
| GET | /sim/result/{id}?token=… |
— | HTML résultat (framable, tokenisé) |
Auth : header X-API-Key. Jobs asynchrones (solve 30-120 s) → poll jobs/{id} toutes les 2 s.
Variables d'environnement (gateway)
| Variable | Défaut | Rôle |
|---|---|---|
FENEC_API_KEYS |
dev-key |
clés autorisées (CSV) |
FENEC_MOCK_DELAY |
2.0 |
délai du mock (0 = synchrone) |
FENEC_BACKEND |
mock |
mock | homelab |
FENEC_SOLVE_URL |
— | endpoint solve homelab (requis si homelab) |
FENEC_OCR_URL |
— | endpoint OCR (requis si images) |
Intégration homelab (M6)
HomelabBackend appelle :
- OCR si image :
POST {FENEC_OCR_URL}/process{image_b64}→{text}(ex.ocr-runner.fenec.svc.cluster.local). - Solve :
POST {FENEC_SOLVE_URL}/api/v1/solve{text, filename}→ réponse JSON{html?: string, figures?: [url]}.htmlest servi tel quel dans la page résultat.
Le réseau homelab restreint l'accès à ocr-runner (NetworkPolicy → n8n uniquement) :
à ouvrir vers le gateway au déploiement. Les services internes sont en ClusterIP — le
gateway est déployé dans le cluster (ArgoCD) pour y accéder via service DNS.
Rendu — gates à valider (M5)
- La page
/sim/result/{id}?token=…se charge dans l'iframe du side panel (pas deX-Frame-Options, CSPframe-ancestorsOK) - URL tokenisée : sans
token→ 403 - Chargement < 2 s, lisible à 320-400 px
- Dédoublonnage recettes : un même énoncé déjà résolu → résultat instantané
Sécurité
- Aucun secret dans l'extension (clés API côté serveur uniquement ; la clé utilisateur
vit dans
chrome.storage.local). - Gateway : clé API, rate-limit à poser en production, cap fichier 10 Mo, URL résultats tokenisées.
- OCR/solve = 100 % dans la stack FEneC ; seul l'énoncé/text sélectionné quitte la page.