Docker correctly configured
This commit is contained in:
parent
eebe89587b
commit
31c2a49304
10 changed files with 118 additions and 31 deletions
32
.github/workflows/workflow.yml
vendored
Normal file
32
.github/workflows/workflow.yml
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
name: Build and Deploy API
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-run:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
uses: docker/build-push-action@v4
|
||||||
|
with:
|
||||||
|
context: ./deployment/api
|
||||||
|
push: false
|
||||||
|
tags: sentiment_api:latest
|
||||||
|
|
||||||
|
- name: Run docker-compose
|
||||||
|
run: docker-compose up -d
|
||||||
14
deployment/api/.dockerignore
Normal file
14
deployment/api/.dockerignore
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Ignorer les caches Python
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Ignorer les artefacts temporaires
|
||||||
|
downloaded_artifacts/
|
||||||
|
mlruns/
|
||||||
|
logs/
|
||||||
|
|
||||||
|
# Ignorer les tests unitaires
|
||||||
|
tests/
|
||||||
|
|
||||||
|
# Ignorer les variables d'environnement. Elles seront plutôt chargées dans la commande docker run `docker run --env-file ./deployment/api/.env -p 8000:8000 sentiment-api` en développement local, et via des variables définies dans le yaml
|
||||||
|
*.env
|
||||||
21
deployment/api/Dockerfile
Normal file
21
deployment/api/Dockerfile
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Utiliser une image légère Python 3.12
|
||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
# Définir le dossier de travail
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copier uniquement requirements.txt d'abord (pour optimiser le cache Docker)
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
# Installer les dépendances
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# Copier le reste du code source
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Exposer les ports 8000 (fastAPI) et 8501 (streamlit)
|
||||||
|
EXPOSE 8000 8501
|
||||||
|
|
||||||
|
RUN chmod +x /app/start.sh
|
||||||
|
|
||||||
|
CMD ["/app/start.sh"]
|
||||||
Binary file not shown.
31
deployment/api/docker-compose.yml
Normal file
31
deployment/api/docker-compose.yml
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
version: "3.9"
|
||||||
|
services:
|
||||||
|
api:
|
||||||
|
build:
|
||||||
|
context: ./deployment/api
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: sentiment_api
|
||||||
|
ports:
|
||||||
|
- "8000:8000" # API FastAPI
|
||||||
|
- "8501:8501" # Streamlit
|
||||||
|
environment:
|
||||||
|
MLFLOW_TRACKING_URI: "${MLFLOW_TRACKING_URI}" # ex: http://mlflow:5000
|
||||||
|
MLFLOW_S3_ENDPOINT_URL: "${MLFLOW_S3_ENDPOINT_URL}" # ex: url MinIO ou S3
|
||||||
|
AWS_ACCESS_KEY_ID: "${AWS_ACCESS_KEY_ID}" # clé ID S3
|
||||||
|
AWS_SECRET_ACCESS_KEY: "${AWS_SECRET_ACCESS_KEY}" # clé secrète S3
|
||||||
|
|
||||||
|
SMTP_SERVER: "${SMTP_SERVER}" # serveur SMTP
|
||||||
|
SMTP_PORT: "${SMTP_PORT}" # port SMTP (ex: 587)
|
||||||
|
SMTP_EMAIL: "${SMTP_EMAIL}" # email expéditeur
|
||||||
|
SMTP_PASSWORD: "${SMTP_PASSWORD}" # mot de passe SMTP
|
||||||
|
SMTP_FROM_ALIAS: "${SMTP_FROM_ALIAS}" # alias (optionnel)
|
||||||
|
ADMIN_EMAIL: "${ADMIN_EMAIL}" # email admin destinataire
|
||||||
|
|
||||||
|
# only if you have a reverse proxy server
|
||||||
|
# networks:
|
||||||
|
# - swag
|
||||||
|
restart: always
|
||||||
|
# only if you have a reverse proxy server
|
||||||
|
# networks:
|
||||||
|
# swag:
|
||||||
|
# external: true
|
||||||
|
|
@ -11,10 +11,10 @@ def send_error_report_email(error_reports):
|
||||||
"""
|
"""
|
||||||
smtp_server = os.getenv("SMTP_SERVER")
|
smtp_server = os.getenv("SMTP_SERVER")
|
||||||
smtp_port = int(os.getenv("SMTP_PORT", 587))
|
smtp_port = int(os.getenv("SMTP_PORT", 587))
|
||||||
smtp_email = os.getenv("SMTP_EMAIL")
|
smtp_email = os.getenv("SMTP_EMAIL") # main email address. If smt_from_alias is not, it will also be the mail sender
|
||||||
smtp_password = os.getenv("SMTP_PASSWORD")
|
smtp_password = os.getenv("SMTP_PASSWORD")
|
||||||
smtp_from_alias = os.getenv("SMTP_FROM_ALIAS", smtp_email)
|
smtp_from_alias = os.getenv("SMTP_FROM_ALIAS", smtp_email) # mail sender if not none (alias)
|
||||||
admin_email = os.getenv("ADMIN_EMAIL")
|
admin_email = os.getenv("ADMIN_EMAIL") # this one will receive the mail
|
||||||
|
|
||||||
if not all([smtp_server, smtp_email, smtp_password, admin_email]):
|
if not all([smtp_server, smtp_email, smtp_password, admin_email]):
|
||||||
print("❌ Configuration email manquante dans .env")
|
print("❌ Configuration email manquante dans .env")
|
||||||
|
|
@ -23,7 +23,11 @@ def send_error_report_email(error_reports):
|
||||||
try:
|
try:
|
||||||
# Créer le message
|
# Créer le message
|
||||||
msg = MIMEMultipart()
|
msg = MIMEMultipart()
|
||||||
msg['From'] = f"Air Paradis Monitor <{smtp_from_alias}>"
|
if smtp_from_alias is not None:
|
||||||
|
smtp_from = smtp_from_alias
|
||||||
|
else:
|
||||||
|
smtp_from = smtp_email
|
||||||
|
msg['From'] = f"Air Paradis Monitor <{smtp_from}>"
|
||||||
msg['To'] = admin_email
|
msg['To'] = admin_email
|
||||||
msg['Subject'] = f"🚨 Rapport d'erreurs - Prédictions sentiments ({datetime.now().strftime('%d/%m/%Y %H:%M')})"
|
msg['Subject'] = f"🚨 Rapport d'erreurs - Prédictions sentiments ({datetime.now().strftime('%d/%m/%Y %H:%M')})"
|
||||||
|
|
||||||
|
|
@ -86,7 +90,7 @@ Un nouveau rapport d'erreurs a été généré pour l'API de prédiction de sent
|
||||||
---
|
---
|
||||||
Cordialement,
|
Cordialement,
|
||||||
🤖 API Air Paradis - Système de monitoring automatique
|
🤖 API Air Paradis - Système de monitoring automatique
|
||||||
📧 Envoyé depuis : """ + smtp_from_alias
|
📧 Envoyé depuis : """ + smtp_from
|
||||||
|
|
||||||
# Ajouter le corps du message
|
# Ajouter le corps du message
|
||||||
msg.attach(MIMEText(body, 'plain', 'utf-8'))
|
msg.attach(MIMEText(body, 'plain', 'utf-8'))
|
||||||
|
|
@ -97,7 +101,7 @@ Cordialement,
|
||||||
server.login(smtp_email, smtp_password)
|
server.login(smtp_email, smtp_password)
|
||||||
server.send_message(msg)
|
server.send_message(msg)
|
||||||
|
|
||||||
print(f"✅ Email de rapport envoyé avec succès depuis {smtp_from_alias}")
|
print(f"✅ Email de rapport envoyé avec succès depuis {smtp_from}")
|
||||||
print(f"📊 JSON intégré dans le corps du message")
|
print(f"📊 JSON intégré dans le corps du message")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ from tensorflow.keras.preprocessing.sequence import pad_sequences
|
||||||
PARENT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))
|
PARENT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))
|
||||||
sys.path.append(PARENT_DIR)
|
sys.path.append(PARENT_DIR)
|
||||||
# 🔐 Charger les variables d'environnement (.env à deux niveaux au-dessus)
|
# 🔐 Charger les variables d'environnement (.env à deux niveaux au-dessus)
|
||||||
load_dotenv(dotenv_path=os.path.join(PARENT_DIR, ".env"))
|
load_dotenv()
|
||||||
|
|
||||||
|
|
||||||
# 🔁 Import de la fonction de prétraitement (LOCAL)
|
# 🔁 Import de la fonction de prétraitement (LOCAL)
|
||||||
|
|
@ -69,6 +69,7 @@ def load_model_and_artifacts(model_name=MODEL_NAME, stage=STAGE):
|
||||||
# Déterminer les chemins des artefacts
|
# Déterminer les chemins des artefacts
|
||||||
local_dir = "./downloaded_artifacts"
|
local_dir = "./downloaded_artifacts"
|
||||||
os.makedirs(local_dir, exist_ok=True)
|
os.makedirs(local_dir, exist_ok=True)
|
||||||
|
print("Contenu de downloaded_artifacts :", os.listdir(local_dir))
|
||||||
base_path = "local_artifacts"
|
base_path = "local_artifacts"
|
||||||
tokenizer_file = "tokenizer.pickle"
|
tokenizer_file = "tokenizer.pickle"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ requests==2.32.4
|
||||||
# === Machine Learning ===
|
# === Machine Learning ===
|
||||||
tensorflow==2.19.0
|
tensorflow==2.19.0
|
||||||
mlflow==3.1.1
|
mlflow==3.1.1
|
||||||
|
boto3==1.39.2
|
||||||
numpy==2.1.3
|
numpy==2.1.3
|
||||||
pandas==2.3.0
|
pandas==2.3.0
|
||||||
# === Traitement de texte ===
|
# === Traitement de texte ===
|
||||||
|
|
|
||||||
7
deployment/api/start.sh
Normal file
7
deployment/api/start.sh
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Lancer Streamlit en arrière-plan
|
||||||
|
streamlit run app.py --server.port 8501 --server.address 0.0.0.0 &
|
||||||
|
|
||||||
|
# Lancer Uvicorn en premier plan (Docker "suit" ce processus)
|
||||||
|
uvicorn main:app --host 0.0.0.0 --port 8000
|
||||||
|
|
@ -6,30 +6,6 @@ Created on Sat Jul 5 15:03:24 2025
|
||||||
@author: madfuckinman
|
@author: madfuckinman
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# # test_alias_email.py
|
|
||||||
# import os
|
|
||||||
# from dotenv import load_dotenv
|
|
||||||
# from email_service import send_error_report_email
|
|
||||||
|
|
||||||
# load_dotenv()
|
|
||||||
|
|
||||||
# print("🔧 Configuration Email:")
|
|
||||||
# print(f"Serveur SMTP: {os.getenv('SMTP_SERVER')}")
|
|
||||||
# print(f"Authentification: {os.getenv('SMTP_EMAIL')}")
|
|
||||||
# print(f"Expéditeur (alias): {os.getenv('SMTP_FROM_ALIAS')}")
|
|
||||||
# print(f"Destinataire: {os.getenv('ADMIN_EMAIL')}")
|
|
||||||
|
|
||||||
# # Test
|
|
||||||
# test_reports = {
|
|
||||||
# "Service client décevant": "positif",
|
|
||||||
# "J'adore cette compagnie": "negatif",
|
|
||||||
# "Vol annulé sans prévenir": "positif"
|
|
||||||
# }
|
|
||||||
|
|
||||||
# print("\n📧 Test d'envoi depuis l'alias...")
|
|
||||||
# result = send_error_report_email(test_reports)
|
|
||||||
# print(f"Résultat : {'✅ Succès' if result else '❌ Échec'}")
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue