463 lines
10 KiB
Markdown
463 lines
10 KiB
Markdown
# 📋 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 ? |