Plateforme d'analyse de matchs de ping-pong avec lecture video, navigation par clips, recherche full-text, recherche semantique, visualisation d'embeddings, comparaison de joueurs et chatbot.
Version clean de l'ancien repo realisé par Romain PASCAL, Nathan BARBIER, Edgar LEDOUX et Mamoudou WONE.
- Presentation
- Fonctionnalites
- Architecture
- Structure du projet
- Prérequis
- Lancement en local
- Preparation des donnees
- Variables d'environnement
- Tests
- API principale
- Deploiement OVH
- Exploitation et maintenance
- Depannage
L'application repose sur deux blocs principaux :
- un
backendFastAPI qui sert l'API, les videos, les clips et les recherches - un
frontendNext.js qui expose l'interface utilisateur
Le moteur de recherche s'appuie sur Elasticsearch avec deux usages distincts :
- index classique des points pour les filtres et la recherche structuree
- index vectoriel pour les embeddings, la recherche semantique et la visualisation
Le projet fonctionne :
- en local, avec
frontend,backendetelasticsearch - en production, via Docker Compose et Nginx sur un VPS Ubuntu
- galerie de matchs et page de lecture video
- navigation par clips, sets et points
- streaming video et thumbnails
- recherche par filtres sur les points
- recherche semantique et mode highlights
- recommandations de points similaires
- visualisation 2D/3D des embeddings
- page de comparaison entre joueurs
- page de sketch/recherche par trajectoire
- favoris locaux dans le navigateur
- chatbot avec OpenAI si
OPENAI_API_KEYest configuree
ProjetInfo/
├── backend/
│ ├── data/
│ │ └── points_index.csv
│ ├── embeddings/
│ │ ├── embedder.py
│ │ ├── indexer.py
│ │ └── pipeline.py
│ ├── routers/
│ │ ├── chat.py
│ │ ├── search.py
│ │ ├── semantic.py
│ │ ├── videos.py
│ │ └── visualization.py
│ ├── scripts/
│ │ ├── generate_points_index.py
│ │ ├── generate_thumbnails.py
│ │ └── index_to_elasticsearch.py
│ ├── tests/
│ ├── videos/
│ │ └── videos.json
│ ├── Dockerfile
│ ├── main.py
│ └── requirements.txt
├── deploy/
│ └── nginx/
│ └── default.conf
├── frontend/
│ ├── app/
│ ├── components/
│ ├── lib/
│ ├── Dockerfile
│ └── package.json
├── tests/
│ └── e2e/
├── .env.example
├── DEPLOYMENT_OVH.md
├── docker-compose.yml
├── playwright.config.ts
└── README.md
- Python 3.10 ou plus
- Node.js 20 recommande
- Docker et Docker Compose
- VPS Ubuntu
- Docker
- Docker Compose
Le projet a deja ete deploie avec succes sur un VPS OVH Ubuntu.
Depuis la racine du projet :
docker compose up -d elasticsearchVerification :
curl http://localhost:9200cd backend
python -m venv venvActivation :
# Windows
.\venv\Scripts\activate
# Linux / macOS
source venv/bin/activateInstallation :
pip install -r requirements.txtDemarrage :
uvicorn main:app --reload --host 0.0.0.0 --port 8001Acces :
- API :
http://localhost:8001 - docs Swagger :
http://localhost:8001/docs
Dans un second terminal :
cd frontend
npm install
npm run devAcces :
- frontend :
http://localhost:3000
En local, frontend/lib/api.ts utilise par defaut http://localhost:8001 si NEXT_PUBLIC_API_URL n'est pas defini.
Index classique des points :
cd backend
python scripts/index_to_elasticsearch.pyRecreer l'index si besoin :
python scripts/index_to_elasticsearch.py --deleteCette etape est necessaire pour :
/visualization- les recherches semantiques
- les recommandations de points similaires
Commande :
cd backend
python embeddings/pipeline.py index --csv data/points_index.csv --es-host http://localhost:9200 --recreateTest rapide :
python embeddings/pipeline.py search "long rally topspin winner" -k 5Les videos sont stockees dans :
backend/videos/
Le fichier :
backend/videos/videos.json
decrit les matchs exposes dans la galerie.
Les clips sont ranges par match, set et point. Exemple :
backend/videos/
└── fan-zhendong-vs-moregard/
├── FAN-ZHENDONG_vs_TRULS-MOREGARD.mp4
├── FAN-ZHENDONG_vs_TRULS-MOREGARD.jpg
└── clips/
├── set_1_point_0/
│ ├── set_1_point_0.mp4
│ └── set_1_point_0.jpg
└── ...
Le fichier principal est :
backend/data/points_index.csv
Il alimente :
- la recherche standard
- les comparaisons
- la visualisation
- la recherche semantique apres generation des embeddings
Si le CSV change, il faut reindexer Elasticsearch.
Le projet fournit un exemple :
.env.example
Contenu :
NEXT_PUBLIC_API_URL=
FRONTEND_ORIGINS=http://YOUR_SERVER_IP
OPENAI_API_KEY=
OPENAI_MODEL=gpt-4o-mini
ES_JAVA_OPTS=-Xms1g -Xmx1gNEXT_PUBLIC_API_URL- local : vide ou non definie pour utiliser
http://localhost:8001 - production OVH : mettre
http://IP_DU_SERVEURsi le frontend build en appelle absolu
- local : vide ou non definie pour utiliser
FRONTEND_ORIGINS- origine autorisee par CORS dans le backend
- exemple :
http://51.91.120.62
OPENAI_API_KEY- optionnelle
- active les fonctions de chat basees sur OpenAI
OPENAI_MODEL- modele OpenAI utilise
ES_JAVA_OPTS- memoire allouee a Elasticsearch
Depuis backend/ :
pytest tests -vDemarrer Elasticsearch avant :
docker compose up -d elasticsearch
cd backend
pytest tests/integration -vDepuis la racine :
npm install
npx playwright install
npm run test:e2eAutres commandes utiles :
npm run test:e2e:ui
npm run test:e2e:headed
npm run test:e2e:debugGET /api/videosGET /api/videos/{id}GET /api/videos/{id}/metaGET /api/videos/{id}/clipsGET /api/videos/{id}/clips/{clip_id}GET /api/videos/{id}/clips/{clip_id}/thumbnailGET /api/videos/stream/{file_path}?match_id=...
GET /api/search/statusGET /api/searchGET /api/search/point/{match_id}/{point_id}GET /api/search/match-momentum/{match_id}GET /api/search/player-compare/{match_id}GET /api/search/stats
GET /api/semantic/statusGET /api/semantic/highlightsGET /api/semantic/similar
GET /api/visualization/embeddings
POST /api/chatGET /api/chat/status
Cette section documente le deploiement effectue sur un VPS OVH Ubuntu, avec Docker Compose.
Le choix de deploiement a ete :
- un seul VPS
frontend,backend,elasticsearchetnginxsur la meme machine- videos stockees localement sur le disque du VPS
- Elasticsearch non utilise comme service externe
Pourquoi ce choix :
- c'est le plus simple a maintenir
- les videos existent deja en local et le backend les sert directement
- le projet avait deja une base Docker/Elasticsearch
Le fichier docker-compose.yml lance 4 services :
frontendbackendelasticsearchnginx
Points importants :
backendmonte./backend/videos:/app/backend/videoselasticsearchstocke ses donnees dans le volumeelasticsearch_datanginxexpose le port80- le backend reste aussi joignable en direct sur
8001
deploy/nginx/default.conf route :
/versfrontend:3000/api/versbackend:8000
Cela permet d'utiliser une seule adresse publique pour toute l'application.
Le deploiement a ete prepare pour un VPS Ubuntu OVH.
Configuration cible recommandee :
- Ubuntu
- au moins 8 Go de RAM si possible
- acces SSH
Depuis Windows PowerShell :
ssh ubuntu@IP_DU_SERVEURSur le VPS :
sudo apt update
sudo apt install -y docker.io docker-compose-v2 git
sudo usermod -aG docker $USER
newgrp docker
docker --version
docker compose versionSi le groupe Docker ne prend pas effet tout de suite, utiliser sudo docker ....
git clone https://github.com/<user>/<repo>.git
cd ProjetInfo
git checkout backNathancp .env.example .envExemple de contenu pour le VPS :
NEXT_PUBLIC_API_URL=http://IP_DU_SERVEUR
FRONTEND_ORIGINS=http://IP_DU_SERVEUR
OPENAI_API_KEY=
OPENAI_MODEL=gpt-4o-mini
ES_JAVA_OPTS=-Xms1g -Xmx1gRemarques :
NEXT_PUBLIC_API_URLdoit etre coherent avec la facon dont le frontend est buildFRONTEND_ORIGINSdoit contenir l'IP ou le domaine public autorise en CORS- si tu ajoutes un domaine plus tard, pense a mettre a jour cette valeur
Les videos ne sont pas stockees dans Git. Il faut les copier depuis la machine locale.
Depuis PowerShell sous Windows :
scp -r "C:\Users\natha\PycharmProjects\ProjetInfo\backend\videos" ubuntu@IP_DU_SERVEUR:/home/ubuntu/ProjetInfo/backend/Verification sur le serveur :
cd ~/ProjetInfo
ls backend/videosVerifier en particulier :
- la presence de
videos.json - la presence des fichiers
.mp4 - la presence des dossiers
clips
Depuis ~/ProjetInfo :
sudo docker compose up -d --buildVerification :
sudo docker compose psAcces attendus :
- application :
http://IP_DU_SERVEUR - API :
http://IP_DU_SERVEUR/api/videos - backend direct :
http://IP_DU_SERVEUR:8001
sudo docker compose exec backend python scripts/index_to_elasticsearch.pySi tu veux recreer l'index :
sudo docker compose exec backend python scripts/index_to_elasticsearch.py --deletesudo docker compose exec backend python embeddings/pipeline.py index --csv data/points_index.csv --es-host http://elasticsearch:9200 --recreateCette commande est necessaire pour :
- la page
visualization - les recherches semantiques
- les recommendations
Sur le VPS :
cd ~/ProjetInfo
git pull origin backNathan
sudo docker compose up -d --buildSi le VPS a des modifications locales :
git stash -u
git pull origin backNathan
sudo docker compose up -d --buildPour ne rebuild qu'un service :
sudo docker compose up -d --build backend
sudo docker compose up -d --build frontendLe projet peut etre branche facilement sur un domaine OVH.
Principe :
- creer un enregistrement
Avers l'IP du VPS - remplacer
server_name _;dansdeploy/nginx/default.conf - rebuild ou recharger Nginx
- ajouter ensuite HTTPS avec Let's Encrypt si besoin
Exemples DNS :
@ -> IP_DU_SERVEURwww -> IP_DU_SERVEUR
Si le serveur est pris pour un mois seulement, penser a desactiver le renouvellement automatique dans l'espace client OVH.
Commandes utiles sur le serveur :
sudo docker compose ps
sudo docker compose logs -f backend
sudo docker compose logs -f frontend
sudo docker compose logs -f nginx
sudo docker compose logs -f elasticsearch
sudo docker compose restart
sudo docker compose downVerifier l'etat Elasticsearch :
curl http://127.0.0.1/api/search/statusVerifier l'API videos :
curl http://127.0.0.1/api/videosVerifier :
NEXT_PUBLIC_API_URLFRONTEND_ORIGINSdocker compose psdocker compose logs nginxdocker compose logs backend
Recreer l'index standard :
sudo docker compose exec backend python scripts/index_to_elasticsearch.py --deleteRecreer les embeddings :
sudo docker compose exec backend python embeddings/pipeline.py index --csv data/points_index.csv --es-host http://elasticsearch:9200 --recreateCause classique :
- l'index classique existe
- mais les embeddings n'ont pas ete generes
Solution :
sudo docker compose exec backend python embeddings/pipeline.py index --csv data/points_index.csv --es-host http://elasticsearch:9200 --recreateVerifier :
- la presence des fichiers dans
backend/videos - la coherence de
backend/videos/videos.json - les chemins des clips
- les logs du backend
Certaines vues reconstruisent des informations a partir des points indexes. Si le CSV a change :
- recreer l'index standard
- recreer les embeddings
- rebuild le backend si le code a change
- Le deploiement OVH actuel a ete fait avec Docker Compose, sans Kubernetes et sans stockage objet externe.
- Les videos sont volontairement stockees localement sur le serveur pour limiter la complexite.
DEPLOYMENT_OVH.mdreste disponible comme memo court, mais ce README est maintenant la reference principale.