# 🌍 **PandaTree — Système National de Gestion, Cartographie et Reconnaissance des Arbres de Côte d’Ivoire**
> Projet porté par le **CNRA (Centre National de Recherche Agronomique de Côte d’Ivoire)**
> Développé avec Django REST Framework — Architecture modulaire, évolutive et souveraine.
> **Objectif :** Créer une plateforme nationale libre pour la **cartographie, la reconnaissance et la valorisation du patrimoine végétal ivoirien.**
---
## 🧭 1. Vision et objectifs
Le projet **PandaTree** vise à :
* Centraliser les **informations botaniques nationales** (arbres, régions, familles, usages).
* Offrir aux **agents de terrain et chercheurs** un outil fiable de collecte et de reconnaissance d’espèces.
* Déployer une **application mobile Flutter** pour l’enregistrement et la consultation en mobilité.
* Intégrer la **reconnaissance de feuilles locale** via un moteur KNN interne.
* Permettre la **cartographie nationale en temps réel** sur base OpenStreetMap.
> 💡 *« Identifier, cartographier et préserver — la nature connectée au service de la recherche ivoirienne. »*
---
## 🏗️ 2. Architecture logicielle
| Composant | Technologie | Rôle principal |
| ---------------------------- | ------------------------------ | ------------------------------------------------- |
| **Backend API** | Django + Django REST Framework | Cœur du système, logique métier et endpoints REST |
| **Base de données** | PostgreSQL | Données structurées et relations géographiques |
| **Application mobile** | Flutter (Android / iOS) | Collecte, scan, affichage cartographique |
| **Stockage d’images** | Django Storage (Media) | Gestion des photos d’arbres et feuilles |
| **Reconnaissance IA locale** | KNN interne (vectorisation) | Calcul de similarité entre échantillons |
| **Documentation API** | drf-spectacular + Swagger UI | Interface interactive pour les développeurs |
| **Tâches asynchrones** | Celery (optionnel) | Reindexation automatique |
---
## 🧩 3. Modules fonctionnels
### 🌳 **Module Trees — Gestion et Cartographie des arbres**
* Création, édition et suppression d’un arbre.
* Enregistrement des **3 photos obligatoires** : arbre entier, feuille, racine.
* Informations botaniques complètes (nom local, scientifique, famille, région, sol, latitude, longitude).
* Système de **likes**, de **vues**, et d’**export CSV** via l’interface d’administration.
* Visualisation sur **carte Leaflet** (GeoJSON-like API).
* Sécurisation par utilisateur (seuls les propriétaires ou administrateurs peuvent modifier/supprimer).
### 🍃 **Module Recognition — Reconnaissance de feuilles et feedback**
* Téléversement d’une photo de feuille (`/api/recognition/predict/`)
* Calcul de similarité via le **KNN interne**
* Stockage de l’historique (`LeafRecognition`)
* Possibilité de **feedback utilisateur** (confirmation ou correction d’espèce)
* Réindexation automatique des échantillons
---
## 🔄 4. Flux de fonctionnement
### 🔹 1. Enregistrement d’un arbre
1. L’utilisateur envoie un formulaire + 3 images via `POST /api/trees/`
2. Les données sont sauvegardées dans la table `Tree`
3. Un vecteur 544D est calculé automatiquement sur la photo de feuille
### 🔹 2. Prédiction d’une feuille
1. L’utilisateur envoie une image via `POST /api/recognition/predict/`
2. Le système crée une entrée `LeafRecognition`
3. Le moteur KNN retourne l’arbre le plus similaire
4. Le résultat est sauvegardé avec le score de confiance
### 🔹 3. Feedback utilisateur
1. L’utilisateur envoie son feedback via `POST /api/recognition/feedback/`
2. Le système met à jour la prédiction (espèce confirmée ou corrigée)
3. Option : ajout automatique de la photo aux échantillons (`LeafSample`)
---
## ⚙️ 5. Documentation API complète
Toutes les routes sont protégées par authentification (`Authorization: Bearer <token>`).
Les exemples ci-dessous sont adaptés pour **Flutter** ou **Postman**.
---
### 🔐 Authentification
L’authentification repose sur **Django Rest Framework + JWT**.
* **Login :** `POST /api/auth/login/`
* **Register :** `POST /api/auth/register/`
* **Header commun :**
```
Authorization: Bearer <votre_token_jwt>
```
---
### 🌳 Endpoints Trees
| Méthode | Endpoint | Description | Auth |
| -------- | ----------------------- | ------------------------------------------- | ---------------------- |
| `GET` | `/api/trees/` | Liste des arbres (filtres disponibles) | ✅ |
| `GET` | `/api/trees/{id}/` | Détail d’un arbre | ✅ |
| `POST` | `/api/trees/` | Créer un arbre (avec 3 images obligatoires) | ✅ |
| `PATCH` | `/api/trees/{id}/` | Modifier un arbre | ✅ (propriétaire/admin) |
| `DELETE` | `/api/trees/{id}/` | Supprimer un arbre | ✅ (propriétaire/admin) |
| `GET` | `/api/trees/mine/` | Lister mes arbres | ✅ |
| `POST` | `/api/trees/{id}/like/` | Liker un arbre | ✅ |
| `GET` | `/api/trees/map/` | Points carte (GeoJSON-like) | ✅ |
#### 🔹 Exemple : création d’un arbre
**POST** `/api/trees/`
`multipart/form-data` :
| Champ | Type | Obligatoire | Exemple |
| ---------- | ------ | ----------- | ----------- |
| name_local | string | ✅ | Iroko |
| latitude | float | ✅ | 5.345678 |
| longitude | float | ✅ | -4.012345 |
| region | string | ✅ | Abidjan |
| photo_tree | image | ✅ | arbre.jpg |
| photo_leaf | image | ✅ | feuille.jpg |
| photo_root | image | ✅ | racine.jpg |
**Réponse (201)** :
```json
{
"id": 12,
"name_local": "Iroko",
"region": "Abidjan",
"photo_leaf_url": "https://api.pandatree.ci/media/trees/photos/leaf/iroko.jpg"
}
```
---
### 🍃 Endpoints Recognition
| Méthode | Endpoint | Description | Auth |
| ------- | ---------------------------- | ----------------------------------------------------- | ---- |
| `POST` | `/api/recognition/predict/` | Envoyer une photo de feuille et obtenir la prédiction | ✅ |
| `POST` | `/api/recognition/feedback/` | Envoyer un feedback utilisateur | ✅ |
| `POST` | `/api/recognition/samples/` | Ajouter un échantillon labellisé (LeafSample) | ✅ |
| `POST` | `/api/recognition/reindex/` | Reconstruire l’index KNN | ✅ |
| `GET` | `/api/recognition/species/` | Liste ou ajout d’espèces connues | ✅ |
#### 🔹 Exemple : prédiction d’une feuille
**POST** `/api/recognition/predict/`
`multipart/form-data` :
| Champ | Type | Obligatoire | Exemple |
| ----- | ----- | ----------- | ----------- |
| file | image | ✅ | feuille.jpg |
**Réponse (200)** :
```json
{
"id": 8,
"predicted_species": "Ficus exasperata",
"confidence": 0.92,
"suggestions": [
{"tree_id": 23, "confidence": 0.87, "region": "Bouaké"},
{"tree_id": 45, "confidence": 0.81, "region": "Abidjan"}
],
"top_tree": {
"id": 23,
"name_local": "Figuier",
"region": "Bouaké"
}
}
```
---
#### 🔹 Exemple : feedback utilisateur
**POST** `/api/recognition/feedback/`
```json
{
"recognition_id": 8,
"is_correct": true,
"confirmed_species": 5,
"notes": "Bonne correspondance",
"add_to_samples": true
}
```
**Réponse (200)** :
```json
{
"success": true,
"id": 8
}
```
---
### 🧬 Endpoints Espèces et Échantillons
| Méthode | Endpoint | Description |
| ------- | --------------------------- | --------------------------------------- |
| `GET` | `/api/recognition/species/` | Lister toutes les espèces |
| `POST` | `/api/recognition/species/` | Créer une nouvelle espèce |
| `POST` | `/api/recognition/samples/` | Ajouter un nouvel échantillon labellisé |
---
## 🧱 6. Structure de la base de données
### Table `Tree`
| Champ | Type | Description |
| ------------------------------------------ | -------- | -------------------------- |
| `name_local` | str | Nom vernaculaire |
| `name_scientific` | str | Nom scientifique |
| `family` | str | Famille botanique |
| `region` | str | Région géographique |
| `photo_tree` / `photo_leaf` / `photo_root` | image | Photos obligatoires |
| `latitude` / `longitude` | float | Coordonnées GPS |
| `created_by` | FK(User) | Auteur |
| `vector` | JSON | Vecteur de features (544D) |
### Table `LeafRecognition`
| Champ | Type | Description |
| ------------------- | ----------- | ------------------------------- |
| `image` | image | Image envoyée par l’utilisateur |
| `predicted_species` | str | Nom de l’espèce prédite |
| `confidence` | float | Score de confiance |
| `suggestions` | JSON | Liste d’espèces similaires |
| `confirmed_species` | FK(Species) | Espèce confirmée |
| `is_correct` | bool | Statut du feedback |
| `notes` | text | Commentaire utilisateur |
---
## 🧩 7. Architecture du code (DDD)
```
recognition/
├── application/
│ ├── dto/
│ ├── use_cases/
│ └── ...
├── domain/
│ ├── entities/
│ └── enums/
├── infrastructure/
│ ├── db/
│ ├── repositories/
│ └── services/
└── interfaces/
└── rest/
```
> 🧠 **Use Cases** = logique métier
> 💾 **Repositories** = interaction avec la base
> 🌐 **Interfaces REST** = endpoints DRF
---
## ⚙️ 8. Installation et exécution
### 🐍 Environnement
```bash
git clone https://github.com/cnra/pandatree.git
cd pandatree
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```
### 📦 Variables d’environnement (.env)
```bash
DJANGO_DEBUG=True
SECRET_KEY=change-this
DB_NAME=pandatree
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=127.0.0.1
EMAIL_HOST_USER=devs.iipea@gmail.com
EMAIL_HOST_PASSWORD=xxxx
TIME_ZONE=Africa/Abidjan
```
### 🚀 Lancer le serveur
```bash
python manage.py migrate
python manage.py runserver
```
Accès Swagger :
👉 [http://127.0.0.1:8000/api/schema/swagger/](http://127.0.0.1:8000/api/schema/swagger/)
---
## 📱 9. Intégration Flutter — Exemples
### 🔹 Upload d’une feuille pour reconnaissance
```dart
var request = http.MultipartRequest(
'POST',
Uri.parse('https://api.pandatree.ci/api/recognition/predict/'),
);
request.headers['Authorization'] = 'Bearer $token';
request.files.add(await http.MultipartFile.fromPath('file', imagePath));
var response = await request.send();
print(await response.stream.bytesToString());
```
### 🔹 Envoi de feedback
```dart
await http.post(
Uri.parse('https://api.pandatree.ci/api/recognition/feedback/'),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
body: jsonEncode({
'recognition_id': 8,
'is_correct': true,
'confirmed_species': 5,
'notes': 'Bonne correspondance'
}),
);
```
---
## 🧑💻 10. Bonnes pratiques CNRA
* Respecter l’architecture **Clean / DDD** (UseCase ↔ Repository ↔ Interface).
* Toujours écrire des **tests unitaires Django** (`TestCase`).
* Éviter les requêtes N+1 → utiliser `select_related`.
* Centraliser les images dans `/media/`.
* Documenter chaque endpoint avec `@extend_schema`.
* Ne jamais stocker d’informations personnelles non nécessaires.
---
## 🚀 11. Perspectives d’évolution
* Ajout d’un **système de taxonomie complet (familles, genres, espèces)**.
* Déploiement de la **carte publique interactive (Leaflet)**.
* Intégration des **statistiques régionales** (arbres/espèces par région).
* Synchronisation **offline-first** sur l’application Flutter.
* Export complet (CSV, Excel, PDF) des inventaires régionaux.
---
## 🐼 12. Slogan
> **“Planter, Identifier, Préserver — PandaTree, la nature connectée.”**