# đ Meetup Killer â Assistant de Cours IA
đŹđ§ [English version](./README.md)
[](https://github.com/Alithiel31/ParseAndCutV2/actions/workflows/lint.yml)
[](https://github.com/Alithiel31/ParseAndCutV2/actions/workflows/integration.yml)
[](https://www.python.org/)
[](https://fastapi.tiangolo.com/)
[](https://react.dev/)
[](https://www.typescriptlang.org/)
[](https://vite.dev/)
[](https://www.docker.com/)
[](https://nginx.org/)
[](https://www.raspberrypi.com/)
[](https://groq.com/)
[](https://parseandcut.alithiel31.dev)
[](https://www.cloudflare.com/)
[](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)).