# 🎓 Meetup Killer — Assistant de Cours IA 🇬🇧 [English version](./README.md) [![CI Lint](https://github.com/Alithiel31/ParseAndCutV2/actions/workflows/lint.yml/badge.svg)](https://github.com/Alithiel31/ParseAndCutV2/actions/workflows/lint.yml) [![CI Integration](https://github.com/Alithiel31/ParseAndCutV2/actions/workflows/integration.yml/badge.svg)](https://github.com/Alithiel31/ParseAndCutV2/actions/workflows/integration.yml) [![Python](https://img.shields.io/badge/Python-3.10-3776AB?logo=python&logoColor=white)](https://www.python.org/) [![FastAPI](https://img.shields.io/badge/FastAPI-Backend-009688?logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com/) [![React](https://img.shields.io/badge/React-19-61DAFB?logo=react&logoColor=black)](https://react.dev/) [![TypeScript](https://img.shields.io/badge/TypeScript-Frontend-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/) [![Vite](https://img.shields.io/badge/Vite-PWA-646CFF?logo=vite&logoColor=white)](https://vite.dev/) [![Docker](https://img.shields.io/badge/Docker-Enabled-2496ED?logo=docker&logoColor=white)](https://www.docker.com/) [![Nginx](https://img.shields.io/badge/Nginx-reverse%20proxy-009639?logo=nginx&logoColor=white)](https://nginx.org/) [![Raspberry Pi](https://img.shields.io/badge/Raspberry%20Pi-auto--h%C3%A9berg%C3%A9-A22846?logo=raspberrypi&logoColor=white)](https://www.raspberrypi.com/) [![Groq](https://img.shields.io/badge/Powered%20by-Groq-F55036?logo=groq&logoColor=white)](https://groq.com/) [![DĂ©ployĂ©](https://img.shields.io/badge/DĂ©ployĂ©-parseandcut.alithiel31.dev-blue)](https://parseandcut.alithiel31.dev) [![Cloudflare](https://img.shields.io/badge/Tunnel-Cloudflare-F38020?logo=cloudflare&logoColor=white)](https://www.cloudflare.com/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) > 🚀 **Service en ligne** : [parseandcut.alithiel31.dev](https://parseandcut.alithiel31.dev) **Meetup Killer** transforme vos enregistrements audio de cours ou de rĂ©unions en fiches de rĂ©vision structurĂ©es au format Markdown — ou, si vous prĂ©fĂ©rez juste la transcription brute, c'est possible aussi. Conçu pour tourner sur **Raspberry Pi**, dĂ©ployĂ© via **Docker**, exposĂ© publiquement via un **tunnel Cloudflare** — aucun port ouvert sur le routeur. Le traitement lourd est dĂ©lĂ©guĂ© Ă  l'API **Groq** (Whisper Large V3 pour la transcription, GPT-OSS 120B pour la structuration). ## Sommaire - [Stack & compĂ©tences](#stack--compĂ©tences) - [FonctionnalitĂ©s](#fonctionnalitĂ©s) - [Formats audio supportĂ©s](#formats-audio-supportĂ©s) - [Architecture](#architecture) - [Variables d'environnement](#variables-denvironnement) - [Installation locale](#installation-locale) - [DĂ©ploiement (Docker + Raspberry Pi)](#dĂ©ploiement-docker--raspberry-pi) - [Tests & CI](#tests--ci) - [Releases & versioning](#releases--versioning) - [Documentation](#documentation) - [Contribuer](#contribuer) - [Licence](#licence) ## Stack & compĂ©tences Ce projet couvre, de bout en bout : - **Backend** : FastAPI + Uvicorn (Python 3.10), migrĂ© depuis une implĂ©mentation Flask d'origine - **Traitement audio** : FFmpeg (dĂ©coupage des enregistrements longs pour respecter la limite Groq de 25 Mo par fichier) - **IA** : API Groq — Whisper Large V3 (transcription) + GPT-OSS 120B (structuration) - **Frontend** : [`frontend/`](./frontend) — Progressive Web App React + Vite, packagĂ©e en TWA (Trusted Web Activity) pour Android - **Conteneurisation & dĂ©ploiement** : Docker Compose (conteneurs backend + frontend), cible Raspberry Pi via un `docker context`, tunnel Cloudflare pour le HTTPS/l'accĂšs public sans ouverture de port — voir [`docs/DEPLOY_PI.md`](./docs/DEPLOY_PI.md) - **CI/CD** : GitHub Actions — lint (flake8 pour le backend, oxlint pour le frontend), tests unitaires (pytest) et tests d'intĂ©gration (dĂ©marrage de l'app FastAPI, `/health`, cas d'erreur de `/api/transcribe/start`) Ă  chaque push/PR - **Historique opĂ©rationnel** : migration de la plateforme d'hĂ©bergement de Railway vers une infra auto-hĂ©bergĂ©e Docker/Pi — voir [`docs/Troubleshooting.fr.md`](./docs/Troubleshooting.fr.md) - **Documentation** : changelog versionnĂ© ([Keep a Changelog](https://keepachangelog.com/en/1.0.0/)), releases taguĂ©es (SemVer) ## FonctionnalitĂ©s | FonctionnalitĂ© | DĂ©tail | |---|---| | đŸŽ™ïž Transcription longue durĂ©e | DĂ©coupage automatique en chunks de 10 min — **supporte les audios > 1h** | | 🧠 Fiche structurĂ©e | RĂ©sumĂ©, titres hiĂ©rarchiques, mots-clĂ©s en gras, blocs dĂ©finition | | 🔀 Deux modes de sortie | RĂ©sumĂ© IA ou transcription brute au choix, par upload — le mode transcription saute entiĂšrement l'appel LLM, et fournit des horodatages par segment | | 🌐 Interface moderne | Drag & drop, barre de progression par Ă©tape, affichage des stats | | đŸ‡«đŸ‡·đŸ‡ŹđŸ‡§ Interface FR/EN | SĂ©lecteur de langue (en-tĂȘte), traduit tout le parcours et les pages lĂ©gales ; pilote aussi la langue de sortie du prompt de structuration LLM — indĂ©pendant de Whisper, qui auto-dĂ©tecte toujours la langue parlĂ©e | | 🔔 Notifications locales | Case Ă  cocher « me notifier Ă  la fin » — prĂ©vient l'appareil via le service worker une fois la transcription terminĂ©e, utile si l'onglet est en arriĂšre-plan | | ✅ Validation robuste | VĂ©rification type + taille cĂŽtĂ© client ET serveur (100 Mo max — plafond propre au proxy Cloudflare sur Free/Pro, voir [`docs/Troubleshooting.fr.md`](./docs/Troubleshooting.fr.md)) | | 🔁 Retry automatique | Relance Whisper en cas de timeout rĂ©seau (backoff exponentiel) | | 🐳 Docker ready | FFmpeg + Uvicorn prĂ©-configurĂ©s, image lĂ©gĂšre `python:3.10-slim` | | 📊 Endpoint `/health` | Monitoring : Ă©tat Groq, langue de sortie par dĂ©faut, extensions supportĂ©es | | ⚖ Pages lĂ©gales | CGU, politique de confidentialitĂ© et mentions lĂ©gales servies par le PWA (`/cgu`, `/politique-de-confidentialite`, `/mentions-legales`), chacune en français et en anglais | ## Formats audio supportĂ©s `mp3` · `mp4` · `wav` · `m4a` · `ogg` · `webm` · `flac` · `aac` · `opus` ## Architecture ```mermaid flowchart LR U["Utilisateur (navigateur / TWA)"] -->|upload audio| FE subgraph Pi["Raspberry Pi (Docker Compose)"] TRA["Traefik
reverse proxy · :8000"] FE["conteneur frontend
nginx · frontend/
traefik-net"] BE["conteneur backend
FastAPI + Uvicorn
:5000 (interne uniquement)"] TRA -->|"Host: parseandcut.alithiel31.dev"| FE FE -->|reverse-proxy /api/*| BE end BE -->|FFmpeg| CHUNK["chunks de 10 min"] CHUNK -->|Whisper Large V3| TXT["transcription brute"] TXT -->|"mode=summary"
GPT-OSS 120B| MD["Markdown structuré"] TXT -->|"mode=transcript"| RAW["transcription brute renvoyée telle quelle"] TUN["Tunnel Cloudflare
parseandcut.alithiel31.dev"] --> TRA U -.->|accĂšs public| TUN ``` Nginx (conteneur frontend) sert les fichiers statiques du PWA et reverse-proxy `/api/` vers le backend — same-origin, pas de CORS Ă  gĂ©rer en production. Traefik (reverse proxy partagĂ© sur le Pi) route le nom d'hĂŽte public vers le conteneur frontend via `traefik-net`, sans exposer de port dĂ©diĂ© sur l'hĂŽte. Le tunnel Cloudflare gĂšre le HTTPS et le nom de domaine — aucun certificat Ă  gĂ©rer manuellement, aucun port ouvert sur le routeur. ## Variables d'environnement | Variable | Obligatoire | DĂ©faut | Description | |---|---|---|---| | `GROQ_API_KEY` | ✅ | — | ClĂ© API Groq ([console.groq.com](https://console.groq.com/)) | | `LANGUAGE` | ❌ | `fr` | Langue de sortie par dĂ©faut (`fr`/`en`) si une requĂȘte omet `lang` — ne force **pas** la langue attendue par Whisper, qui auto-dĂ©tecte toujours | | `PORT` | ❌ | `5000` | Port d'Ă©coute du backend | | `CHUNK_DURATION_SEC` | ❌ | `600` | DurĂ©e des chunks en secondes | | `FFMPEG_PATH` | ❌ | `ffmpeg` | Chemin vers le binaire FFmpeg | | `CORS_ORIGINS` | ❌ | `https://parseandcut.alithiel31.dev` | Origines autorisĂ©es sĂ©parĂ©es par des virgules — Ă  surcharger en dev local (Vite sur `:5173` qui tape sur Uvicorn sur `:5000`) | | `MAX_UPLOAD_SIZE_MB` | ❌ | `100` | Taille max d'upload vĂ©rifiĂ©e cĂŽtĂ© backend (en plus du `client_max_body_size` de nginx) — alignĂ© sur le plafond du proxy Cloudflare sur les plans Free/Pro | | `RATE_LIMIT_PROCESS` | ❌ | `5/minute` | Limite de requĂȘtes sur `/api/transcribe/start` et sur la crĂ©ation/fin d'un enregistrement par segments (par IP), format `N/period` | | `RATE_LIMIT_SEGMENTS` | ❌ | `60/minute` | Limite d'envois de segments d'un enregistrement par segments (par IP, partagĂ©e entre tous les segments) | | `RECORDING_SEGMENT_SEC` | ❌ | `300` | DurĂ©e d'un segment d'enregistrement, annoncĂ©e au navigateur | | `RECORDING_EARLY_TRANSCRIPTION` | ❌ | `1` | Transcrit chaque segment dĂšs son arrivĂ©e, pendant que la rĂ©union continue (`0` pour tout traiter Ă  la fin) | | `MAX_SEGMENT_SIZE_MB` | ❌ | `50` | Taille max d'un segment envoyĂ© | | `MAX_RECORDING_SIZE_MB` | ❌ | `300` | Taille cumulĂ©e max des segments d'un enregistrement | | `MAX_SEGMENTS` | ❌ | `500` | Nombre max de segments d'un enregistrement | | `FLASK_DEBUG` | ❌ | `false` | Mode debug (dev uniquement) | > **Note production :** sur le dĂ©ploiement Caesura, `GROQ_API_KEY` n'est pas lue depuis `.env` — elle est injectĂ©e au dĂ©ploiement via Infisical (voir `docs/DEPLOY_PI.md`). Pour le dĂ©veloppement local, renseigne-la directement dans ton `.env` comme dĂ©crit ci-dessous. ## Installation locale 1. **Cloner le dĂ©pĂŽt** ```bash git clone https://github.com/Alithiel31/ParseAndCutV2.git cd ParseAndCutV2 ``` 2. **Configurer le `.env`** ```bash cp ".env exemple" .env ``` Renseigner `GROQ_API_KEY` au minimum. 3. **Lancer avec Docker** ```bash docker build -t meetup-killer . docker run -d -p 5000:5000 --name meetup-app --env-file .env meetup-killer ``` Ou sans Docker (Python 3.10 + FFmpeg installĂ©s localement) : ```bash pip install -r requirements.txt python -m app.main ``` 4. **AccĂ©der Ă  l'outil** sur [http://localhost:5000](http://localhost:5000) > Sur Raspberry Pi, remplacer `localhost` par l'IP locale de la machine. ## DĂ©ploiement (Docker + Raspberry Pi) C'est la mĂ©thode utilisĂ©e en production. Le `docker-compose.yml` de ce dĂ©pĂŽt lance le backend (rĂ©seau interne, port **5000**) et le frontend [`frontend/`](./frontend) (nginx, routĂ© via Traefik sur `traefik-net`, aucun port exposĂ© sur l'hĂŽte) — voir [`docs/DEPLOY_PI.md`](./docs/DEPLOY_PI.md) pour la procĂ©dure complĂšte (crĂ©ation du `docker context` vers le Pi, build, configuration des labels Traefik et de l'ingress Cloudflare). ```bash docker context use rpi docker compose build bash deploy.sh ``` L'endpoint [`/health`](https://parseandcut.alithiel31.dev/api/health) permet de vĂ©rifier l'Ă©tat du service Ă  tout moment. ## Tests & CI ```bash # Lint — mĂȘmes vĂ©rifications que le workflow lint.yml npm run lint # flake8 (backend) cd frontend && npm run lint # oxlint (frontend) # Tests unitaires (routes FastAPI, FFmpeg/Groq mockĂ©s) — comme le workflow integration.yml pytest ``` Deux workflows tournent Ă  chaque push/PR sur `main` : - **CI Lint** (`.github/workflows/lint.yml`) : flake8 (backend), oxlint (frontend) - **CI Integration** (`.github/workflows/integration.yml`) : lance la suite pytest, puis dĂ©marre l'app FastAPI et vĂ©rifie `/`, `/health`, ainsi que les cas d'erreur de `/api/transcribe/start` (fichier manquant → 400, format non supportĂ© → 415) ## Releases & versioning Ce projet suit le [Semantic Versioning](https://semver.org/) (`MAJOR.MINOR.PATCH`) et [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). Chaque changement notable est d'abord ajoutĂ© dans [`CHANGELOG.md`](./CHANGELOG.md) sous `[Unreleased]`, puis sous une section de version une fois taguĂ© : ```bash git tag -a vX.Y.Z -m "vX.Y.Z" git push origin vX.Y.Z ``` Une Release GitHub est ensuite créée Ă  partir du tag, avec sa description reprise de la section correspondante du `CHANGELOG.md`. ## Documentation | Guide | Contenu | |---|---| | [`docs/architecture.fr.md`](./docs/architecture.fr.md) | ModĂšle de job asynchrone, pipeline de traitement, enregistrement par segments, couches de sĂ©curitĂ©, structure du dĂ©pĂŽt | | [`docs/environment.fr.md`](./docs/environment.fr.md) | Toutes les variables d'environnement, constantes codĂ©es en dur, secrets de dĂ©ploiement et de CI | | [`docs/development.fr.md`](./docs/development.fr.md) | Lancer le projet en local, routes et codes d'erreur, tests, CI | | [`docs/DEPLOY_PI.md`](./docs/DEPLOY_PI.md) | Docker context, Traefik, ingress Cloudflare, Infisical | | [`docs/handover-guide.fr.md`](./docs/handover-guide.fr.md) | Ce qui tourne oĂč, accĂšs nĂ©cessaires, remise en service Ă  partir de zĂ©ro, risques connus | | [`docs/Troubleshooting.fr.md`](./docs/Troubleshooting.fr.md) | Incidents dĂ©jĂ  rencontrĂ©s, avec la dĂ©marche de diagnostic | | [`docs/CONTRIBUTING.fr.md`](./docs/CONTRIBUTING.fr.md) · [`docs/SECURITY.fr.md`](./docs/SECURITY.fr.md) · [`docs/SUPPORT.fr.md`](./docs/SUPPORT.fr.md) · [`docs/CODE_OF_CONDUCT.fr.md`](./docs/CODE_OF_CONDUCT.fr.md) | Fichiers communautaires | Chaque guide existe aussi en anglais (sans suffixe). ## Contribuer Voir [`docs/CONTRIBUTING.fr.md`](./docs/CONTRIBUTING.fr.md) pour l'environnement de dĂ©veloppement, comment reproduire les vĂ©rifications de la CI en local, et le format des PR/releases. ## SĂ©curitĂ© Voir [`docs/SECURITY.fr.md`](./docs/SECURITY.fr.md) pour signaler une vulnĂ©rabilitĂ©. ## Licence MIT (voir le champ `license` dans [`package.json`](./package.json)).