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:
parent
64582646ea
commit
6f63821728
67
Makefile.simple
Normal file
67
Makefile.simple
Normal 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"
|
12
docker/host-api/Dockerfile.simple
Normal file
12
docker/host-api/Dockerfile.simple
Normal 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"]
|
9
docker/host-api/requirements.simple.txt
Normal file
9
docker/host-api/requirements.simple.txt
Normal 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
21
infra/.env.simple
Normal 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
|
83
infra/docker-compose.simple.yml
Normal file
83
infra/docker-compose.simple.yml
Normal 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:
|
@ -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
41
ops/start-simple.sh
Executable 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"
|
202
services/host_api/app_simple.py
Normal file
202
services/host_api/app_simple.py
Normal 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
|
||||
]
|
@ -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
18
test-simple.sh
Executable 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 ==="
|
Loading…
x
Reference in New Issue
Block a user