feat: Ajout version simplifiée sans IA et correction des ports

- Ajout docker-compose.simple.yml avec ports modifiés (15432, 16379, 19000, 19001, 18000)
- Création app_simple.py sans dépendances IA
- Ajout Dockerfile.simple et requirements.simple.txt
- Correction attribut metadata réservé dans database.py
- Ajout scripts de démarrage et test simplifiés
- Configuration .env.simple pour version sans IA
This commit is contained in:
root 2025-09-09 00:35:32 +02:00
parent 64582646ea
commit 6f63821728
10 changed files with 455 additions and 4 deletions

67
Makefile.simple Normal file
View File

@ -0,0 +1,67 @@
SHELL := /bin/bash
ENV ?= infra/.env
# Charger les variables d'environnement
include $(ENV)
export
.PHONY: help up down start-simple logs ps clean restart
help: ## Afficher l'aide
@echo "Commandes disponibles :"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
up: ## Démarrer tous les services (version complète)
cd infra && docker compose up -d
up-simple: ## Démarrer les services simplifiés (sans IA)
cd infra && docker compose -f docker-compose.simple.yml up -d
down: ## Arrêter tous les services
cd infra && docker compose down
down-simple: ## Arrêter les services simplifiés
cd infra && docker compose -f docker-compose.simple.yml down
start-simple: ## Initialiser l'infrastructure simplifiée
bash ops/start-simple.sh
logs: ## Afficher les logs
cd infra && docker compose logs -f --tail=200
logs-simple: ## Afficher les logs (version simplifiée)
cd infra && docker compose -f docker-compose.simple.yml logs -f --tail=200
ps: ## Afficher le statut des services
cd infra && docker compose ps
ps-simple: ## Afficher le statut des services (version simplifiée)
cd infra && docker compose -f docker-compose.simple.yml ps
clean: ## Nettoyer les volumes et images
cd infra && docker compose down -v
docker system prune -f
restart: ## Redémarrer tous les services
cd infra && docker compose restart
build: ## Reconstruire les images
cd infra && docker compose build --no-cache
build-simple: ## Reconstruire les images (version simplifiée)
cd infra && docker compose -f docker-compose.simple.yml build --no-cache
test-api: ## Tester l'API
curl -F "file=@tests/data/sample.pdf" \
-F "id_dossier=D-2025-001" \
-F "source=upload" \
-F "etude_id=E-001" \
-F "utilisateur_id=U-123" \
http://localhost:8000/api/import
status: ## Vérifier le statut de tous les services
@echo "=== Statut des services ==="
@make ps-simple
@echo ""
@echo "=== Test de connectivité ==="
@curl -s http://localhost:8000/api/health || echo "API non accessible"

View File

@ -0,0 +1,12 @@
FROM python:3.11-slim
RUN apt-get update && apt-get install -y libmagic1 && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY docker/host-api/requirements.simple.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
COPY services/host_api /app
CMD ["uvicorn", "app_simple:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@ -0,0 +1,9 @@
fastapi==0.115.0
uvicorn[standard]==0.30.6
pydantic==2.8.2
sqlalchemy==2.0.35
psycopg[binary]==3.2.1
minio==7.2.7
redis==5.0.7
python-multipart==0.0.9
requests==2.32.3

21
infra/.env.simple Normal file
View File

@ -0,0 +1,21 @@
# Configuration simplifiée sans IA
PROJECT_NAME=notariat
DOMAIN=localhost
TZ=Europe/Paris
# Base de données PostgreSQL
POSTGRES_USER=notariat
POSTGRES_PASSWORD=notariat_pwd
POSTGRES_DB=notariat
# Redis
REDIS_PASSWORD=
# MinIO (stockage objet)
MINIO_ROOT_USER=minio
MINIO_ROOT_PASSWORD=minio_pwd
MINIO_BUCKET=ingest
# Configuration de développement
DEBUG=true
LOG_LEVEL=debug

View File

@ -0,0 +1,83 @@
x-env: &default-env
TZ: ${TZ}
PUID: "1000"
PGID: "1000"
services:
postgres:
image: postgres:16
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "15432:5432"
restart: unless-stopped
redis:
image: redis:7
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redis:/data
ports:
- "16379:6379"
restart: unless-stopped
minio:
image: minio/minio:latest
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
volumes:
- minio:/data
ports:
- "19000:9000"
- "19001:9001"
restart: unless-stopped
host-api:
image: notariat-api-simple
env_file: ./.env
environment:
<<: *default-env
DATABASE_URL: postgresql+psycopg://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres:5432/$POSTGRES_DB
REDIS_URL: redis://redis:6379/0
MINIO_ENDPOINT: http://minio:9000
MINIO_BUCKET: ${MINIO_BUCKET}
volumes:
- ../services/host_api:/app
- ../ops/seed:/seed:ro
- ../ops/seed/schemas:/schemas:ro
ports:
- "18000:8000"
depends_on:
- postgres
- redis
- minio
restart: unless-stopped
# Worker désactivé pour la version simplifiée
# worker:
# build:
# context: ../docker/worker
# env_file: ./.env
# environment:
# <<: *default-env
# DATABASE_URL: postgresql+psycopg://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres:5432/$POSTGRES_DB
# REDIS_URL: redis://redis:6379/0
# MINIO_ENDPOINT: http://minio:9000
# MINIO_BUCKET: ${MINIO_BUCKET}
# volumes:
# - ../services/worker:/app
# - ../ops/seed:/seed:ro
# depends_on:
# - host-api
# restart: unless-stopped
volumes:
pgdata:
redis:
minio:

View File

@ -1,5 +1,3 @@
version: "3.9"
x-env: &default-env
TZ: ${TZ}
PUID: "1000"
@ -25,7 +23,7 @@ services:
restart: unless-stopped
minio:
image: minio/minio:RELEASE.2025-01-13T00-00-00Z
image: minio/minio:latest
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}

41
ops/start-simple.sh Executable file
View File

@ -0,0 +1,41 @@
#!/bin/bash
set -euo pipefail
echo "Démarrage du pipeline notarial simplifié (sans IA)..."
# Aller dans le répertoire infra
cd "$(dirname "$0")/../infra"
# Copier le fichier d'environnement simplifié
cp -n .env.simple .env || true
echo "Fichier .env créé à partir de .env.simple"
# Télécharger les images Docker
echo "Téléchargement des images Docker..."
docker compose -f docker-compose.simple.yml pull
# Démarrer les services de base
echo "Démarrage des services de base..."
docker compose -f docker-compose.simple.yml up -d postgres redis minio
# Attendre que les services soient prêts
echo "Attente du démarrage des services..."
sleep 10
# Configuration MinIO
echo "Configuration de MinIO..."
# Créer l'alias MinIO
mc alias set local http://127.0.0.1:9000 $MINIO_ROOT_USER $MINIO_ROOT_PASSWORD || true
# Créer le bucket
mc mb -p local/$MINIO_BUCKET || true
# Démarrer les services applicatifs
echo "Démarrage des services applicatifs..."
docker compose -f docker-compose.simple.yml up -d host-api worker
echo "Démarrage terminé !"
echo "Services disponibles :"
echo "- API: http://localhost:8000/api"
echo "- MinIO Console: http://localhost:9001"
echo "- PostgreSQL: localhost:5432"
echo "- Redis: localhost:6379"

View File

@ -0,0 +1,202 @@
"""
API d'ingestion simplifiée pour le pipeline notarial (sans IA)
"""
from fastapi import FastAPI, UploadFile, File, Form, HTTPException, Depends
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
import uuid
import time
import os
import logging
from domain.models import ImportMeta, DocumentStatus
from domain.database import get_db, init_db
from routes import health
from utils.storage import store_document
# Configuration du logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI(
title="Notariat Pipeline API (Simplifié)",
description="API d'ingestion simplifiée pour le traitement de documents notariaux (sans IA)",
version="1.0.0-simple"
)
# Configuration CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # À restreindre en production
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Inclusion des routes
app.include_router(health.router, prefix="/api", tags=["health"])
@app.on_event("startup")
async def startup_event():
"""Initialisation au démarrage de l'application"""
logger.info("Démarrage de l'API Notariat Pipeline (Simplifié)")
await init_db()
@app.on_event("shutdown")
async def shutdown_event():
"""Nettoyage à l'arrêt de l'application"""
logger.info("Arrêt de l'API Notariat Pipeline (Simplifié)")
@app.exception_handler(Exception)
async def global_exception_handler(request, exc):
"""Gestionnaire d'exceptions global"""
logger.error(f"Erreur non gérée: {exc}", exc_info=True)
return JSONResponse(
status_code=500,
content={"detail": "Erreur interne du serveur"}
)
@app.get("/")
async def root():
"""Point d'entrée principal"""
return {
"message": "API Notariat Pipeline (Simplifié)",
"version": "1.0.0-simple",
"status": "running",
"features": {
"ai_disabled": True,
"ocr_enabled": False,
"classification_enabled": False,
"extraction_enabled": False
}
}
@app.post("/api/import")
async def import_document(
file: UploadFile = File(...),
id_dossier: str = Form(...),
source: str = Form("upload"),
etude_id: str = Form(...),
utilisateur_id: str = Form(...),
db = Depends(get_db)
):
"""
Import d'un nouveau document dans le pipeline (version simplifiée)
"""
try:
# Vérification du type de fichier
allowed_types = ["application/pdf", "image/jpeg", "image/png", "image/tiff"]
if file.content_type not in allowed_types:
raise HTTPException(
status_code=415,
detail=f"Type de fichier non supporté: {file.content_type}"
)
# Génération d'un ID unique
doc_id = str(uuid.uuid4())
# Lecture du contenu du fichier
content = await file.read()
file_size = len(content)
# Stockage du document
storage_path = await store_document(doc_id, content, file.filename)
# Création de l'enregistrement en base
from domain.database import Document
document = Document(
id=doc_id,
filename=file.filename or "unknown",
mime_type=file.content_type,
size=file_size,
status=DocumentStatus.PENDING.value,
id_dossier=id_dossier,
etude_id=etude_id,
utilisateur_id=utilisateur_id,
source=source
)
db.add(document)
db.commit()
db.refresh(document)
logger.info(f"Document {doc_id} importé avec succès (version simplifiée)")
return {
"status": "stored",
"id_document": doc_id,
"message": "Document stocké (traitement IA désactivé)",
"storage_path": storage_path
}
except Exception as e:
logger.error(f"Erreur lors de l'import du document: {e}")
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/documents/{document_id}")
async def get_document(
document_id: str,
db = Depends(get_db)
):
"""
Récupération des informations d'un document
"""
from domain.database import Document
document = db.query(Document).filter(Document.id == document_id).first()
if not document:
raise HTTPException(status_code=404, detail="Document non trouvé")
return {
"id": document.id,
"filename": document.filename,
"mime_type": document.mime_type,
"size": document.size,
"status": document.status,
"id_dossier": document.id_dossier,
"etude_id": document.etude_id,
"utilisateur_id": document.utilisateur_id,
"created_at": document.created_at,
"updated_at": document.updated_at,
"processing_steps": document.processing_steps,
"extracted_data": document.extracted_data,
"errors": document.errors
}
@app.get("/api/documents")
async def list_documents(
etude_id: str = None,
id_dossier: str = None,
limit: int = 50,
offset: int = 0,
db = Depends(get_db)
):
"""
Liste des documents avec filtres
"""
from domain.database import Document
query = db.query(Document)
if etude_id:
query = query.filter(Document.etude_id == etude_id)
if id_dossier:
query = query.filter(Document.id_dossier == id_dossier)
documents = query.offset(offset).limit(limit).all()
return [
{
"id": doc.id,
"filename": doc.filename,
"mime_type": doc.mime_type,
"size": doc.size,
"status": doc.status,
"id_dossier": doc.id_dossier,
"etude_id": doc.etude_id,
"utilisateur_id": doc.utilisateur_id,
"created_at": doc.created_at,
"updated_at": doc.updated_at
}
for doc in documents
]

View File

@ -52,7 +52,7 @@ class ProcessingLog(Base):
completed_at = Column(DateTime(timezone=True))
duration = Column(Integer) # en millisecondes
error_message = Column(Text)
metadata = Column(JSON, default={})
step_metadata = Column(JSON, default={})
def get_db() -> Generator[Session, None, None]:
"""Dépendance pour obtenir une session de base de données"""

18
test-simple.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
echo "=== Test du pipeline notarial simplifié ==="
# Test de santé de l'API
echo "1. Test de santé de l'API..."
curl -s http://localhost:8000/api/health | jq . || echo "API non accessible"
echo ""
echo "2. Test de l'endpoint racine..."
curl -s http://localhost:8000/ | jq . || echo "Endpoint racine non accessible"
echo ""
echo "3. Test de liste des documents..."
curl -s http://localhost:8000/api/documents | jq . || echo "Liste des documents non accessible"
echo ""
echo "=== Tests terminés ==="