# 📋 Tâches d'implémentation - API Diagramme PH ## Vue d'ensemble Implémentation progressive et testable de l'API, étape par étape. --- ## 🎯 Phase 1 : Configuration initiale (MAINTENANT) ### ✅ Tâche 1.1 : Structure de base du projet **Durée estimée** : 30 minutes **Actions** : ```bash # Créer structure mkdir -p app/api/v1/endpoints mkdir -p app/core mkdir -p app/models mkdir -p app/services mkdir -p app/utils mkdir -p libs/so mkdir -p tests/test_api mkdir -p tests/test_core mkdir -p docker mkdir -p deployment/scripts ``` **Fichiers à créer** : - [ ] `app/__init__.py` - [ ] `app/config.py` - [ ] `app/main.py` - [ ] `requirements.txt` - [ ] `.env.example` - [ ] `.gitignore` **Test** : Structure des dossiers existe --- ### ✅ Tâche 1.2 : Configuration requirements.txt **Durée estimée** : 10 minutes **Créer** : `requirements.txt` ```txt fastapi==0.109.0 uvicorn[standard]==0.27.0 pydantic==2.5.0 pydantic-settings==2.1.0 numpy==1.26.3 pandas==2.2.0 matplotlib==3.8.2 plotly==5.18.0 python-multipart==0.0.6 cachetools==5.3.2 python-json-logger==2.0.7 ``` **Test** : `pip install -r requirements.txt` fonctionne --- ### ✅ Tâche 1.3 : Configuration de base **Durée estimée** : 15 minutes **Créer** : `app/config.py` ```python from pydantic_settings import BaseSettings class Settings(BaseSettings): APP_NAME: str = "Diagram PH API" VERSION: str = "1.0.0" ENV: str = "development" LOG_LEVEL: str = "DEBUG" class Config: env_file = ".env" settings = Settings() ``` **Créer** : `.env.example` ```env ENV=development LOG_LEVEL=DEBUG ``` **Test** : Importer settings fonctionne --- ### ✅ Tâche 1.4 : Application FastAPI minimale **Durée estimée** : 20 minutes **Créer** : `app/main.py` ```python from fastapi import FastAPI from app.config import settings app = FastAPI( title=settings.APP_NAME, version=settings.VERSION ) @app.get("/") def root(): return { "message": "Diagram PH API", "version": settings.VERSION, "status": "running" } @app.get("/api/v1/health") def health(): return { "status": "healthy", "version": settings.VERSION } ``` **Test** : ```bash uvicorn app.main:app --reload # Visiter http://localhost:8000 # Visiter http://localhost:8000/api/v1/health ``` **Résultat attendu** : API démarre, endpoints répondent --- ## 🎯 Phase 2 : Intégration bibliothèques .so (ENSUITE) ### ✅ Tâche 2.1 : Copier bibliothèques .so **Durée estimée** : 5 minutes **Actions** : ```bash # Copier les fichiers .so cp IPM_SO/*.so libs/so/ ``` **Test** : Fichiers existent dans `libs/so/` --- ### ✅ Tâche 2.2 : Wrapper bibliothèque de base **Durée estimée** : 45 minutes **Créer** : `app/core/refrigerant_loader.py` ```python import ctypes import platform from pathlib import Path from typing import Optional class RefrigerantLoader: """Gestionnaire de chargement des bibliothèques .so""" BASE_DIR = Path(__file__).parent.parent.parent / "libs" @classmethod def get_library_path(cls, refrigerant: str) -> Path: """Retourne le chemin de la bibliothèque""" system = platform.system() if system == "Windows": return cls.BASE_DIR / "dll" / f"{refrigerant}.dll" elif system == "Linux": return cls.BASE_DIR / "so" / f"lib{refrigerant}.so" else: raise OSError(f"Unsupported OS: {system}") @classmethod def load(cls, refrigerant: str): """Charge la bibliothèque""" lib_path = cls.get_library_path(refrigerant) if not lib_path.exists(): raise FileNotFoundError(f"Library not found: {lib_path}") try: return ctypes.CDLL(str(lib_path)) except OSError as e: raise RuntimeError(f"Failed to load {lib_path}: {e}") @classmethod def list_available(cls) -> list: """Liste les réfrigérants disponibles""" system = platform.system() if system == "Windows": dir_path = cls.BASE_DIR / "dll" pattern = "R*.dll" else: dir_path = cls.BASE_DIR / "so" pattern = "libR*.so" if not dir_path.exists(): return [] files = list(dir_path.glob(pattern)) refrigerants = [] for f in files: if system == "Windows": name = f.stem else: name = f.stem[3:] # Remove 'lib' prefix refrigerants.append(name) return sorted(refrigerants) ``` **Test** : ```python # test_loader.py from app.core.refrigerant_loader import RefrigerantLoader # Lister disponibles refrigerants = RefrigerantLoader.list_available() print(f"Disponibles: {refrigerants}") # Charger R134a lib = RefrigerantLoader.load("R134a") print(f"✅ R134a chargé: {lib}") ``` **Résultat attendu** : Liste des réfrigérants + chargement réussi --- ### ✅ Tâche 2.3 : Endpoint liste réfrigérants **Durée estimée** : 20 minutes **Créer** : `app/api/v1/endpoints/refrigerants.py` ```python from fastapi import APIRouter from app.core.refrigerant_loader import RefrigerantLoader router = APIRouter() @router.get("/refrigerants") def list_refrigerants(): """Liste des réfrigérants disponibles""" refrigerants = RefrigerantLoader.list_available() return { "success": True, "count": len(refrigerants), "refrigerants": refrigerants } ``` **Modifier** : `app/main.py` ```python from app.api.v1.endpoints import refrigerants app.include_router( refrigerants.router, prefix="/api/v1", tags=["refrigerants"] ) ``` **Test** : ```bash curl http://localhost:8000/api/v1/refrigerants ``` **Résultat attendu** : JSON avec liste des réfrigérants --- ## 🎯 Phase 3 : Calculs thermodynamiques (APRÈS) ### ✅ Tâche 3.1 : Interface simple_refrig_api.py **Durée estimée** : 30 minutes **Copier et adapter** : `IPM_DLL/simple_refrig_api.py` → `app/core/refrig_api.py` **Modifications** : - Adapter paths pour `libs/so/` - Simplifier pour besoins API - Ajouter gestion erreurs **Test** : ```python from app.core.refrig_api import Refifc # Test R134a refrig = Refifc("R134a") props = refrig.get_properties_PT(500000, 278.15) print(f"✅ Propriétés calculées: {props}") ``` --- ### ✅ Tâche 3.2 : Endpoint propriétés basiques **Durée estimée** : 40 minutes **Créer** : `app/models/requests.py` ```python from pydantic import BaseModel, Field from typing import Optional class PropertyRequest(BaseModel): refrigerant: str = Field(..., description="Nom du réfrigérant") pressure: float = Field(..., gt=0, description="Pression [Pa]") temperature: float = Field(..., description="Température [K]") ``` **Créer** : `app/api/v1/endpoints/properties.py` ```python from fastapi import APIRouter, HTTPException from app.models.requests import PropertyRequest from app.core.refrig_api import Refifc router = APIRouter() @router.post("/properties/calculate") def calculate_properties(request: PropertyRequest): """Calcule les propriétés thermodynamiques""" try: refrig = Refifc(request.refrigerant) # TODO: Appeler méthodes DLL return { "success": True, "refrigerant": request.refrigerant, "properties": { "pressure": request.pressure, "temperature": request.temperature, # TODO: Ajouter propriétés calculées } } except FileNotFoundError: raise HTTPException(404, "Refrigerant not found") except Exception as e: raise HTTPException(500, str(e)) ``` **Test** : ```bash curl -X POST http://localhost:8000/api/v1/properties/calculate \ -H "Content-Type: application/json" \ -d '{ "refrigerant": "R134a", "pressure": 500000, "temperature": 278.15 }' ``` --- ## 🎯 Phase 4 : Génération diagrammes (PLUS TARD) ### ✅ Tâche 4.1 : Courbe de saturation basique **Durée estimée** : 1 heure **Créer** : `app/core/diagram_generator.py` - Générer courbe saturation - Format JSON simple --- ### ✅ Tâche 4.2 : Export Plotly JSON **Durée estimée** : 1 heure - Créer figure Plotly - Exporter en JSON - Endpoint `/diagram/generate` --- ### ✅ Tâche 4.3 : Export Matplotlib PNG **Durée estimée** : 45 minutes - Générer image PNG - Encoder en base64 - Option dans endpoint --- ## 🎯 Phase 5 : Calculs cycle (ENCORE PLUS TARD) ### ✅ Tâche 5.1 : Calculs COP basiques **Durée estimée** : 1.5 heures --- ### ✅ Tâche 5.2 : Endpoint cycle complet **Durée estimée** : 1 heure --- ## 🎯 Checklist de progression ### Maintenant (Session actuelle) - [ ] Tâche 1.1 : Structure projet - [ ] Tâche 1.2 : Requirements - [ ] Tâche 1.3 : Configuration - [ ] Tâche 1.4 : FastAPI minimal - [ ] **TEST** : API démarre et répond ### Session suivante - [ ] Tâche 2.1 : Copier .so - [ ] Tâche 2.2 : Loader bibliothèques - [ ] Tâche 2.3 : Endpoint réfrigérants - [ ] **TEST** : Liste réfrigérants fonctionne ### Après - [ ] Phase 3 : Calculs propriétés - [ ] Phase 4 : Diagrammes - [ ] Phase 5 : Cycles --- ## 🧪 Tests à chaque étape ### Test 1 : Structure ```bash ls -la app/ ls -la libs/so/ ``` ### Test 2 : API démarre ```bash uvicorn app.main:app --reload curl http://localhost:8000/api/v1/health ``` ### Test 3 : Bibliothèques ```python python -c "from app.core.refrigerant_loader import RefrigerantLoader; print(RefrigerantLoader.list_available())" ``` ### Test 4 : Endpoint complet ```bash curl http://localhost:8000/api/v1/refrigerants ``` --- ## ✅ Critères de succès Après Phase 1 (aujourd'hui) : - ✅ API FastAPI fonctionne - ✅ Endpoint /health répond - ✅ Documentation auto (/docs) Après Phase 2 : - ✅ Bibliothèques .so chargées - ✅ Liste réfrigérants disponible - ✅ Aucune erreur au démarrage --- ## 🚀 On commence maintenant ! **Prochaine action** : Basculer en mode Code et créer la structure (Tâche 1.1) Êtes-vous prêt ?