Skip to content

Commit d7c7b3a

Browse files
committed
fix: resolve merge conflicts, keep local versions
2 parents 8c6e132 + 1c6599a commit d7c7b3a

53 files changed

Lines changed: 9540 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci-cd.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: CI/CD Crime Predictor
2+
on:
3+
push:
4+
branches: [ main, develop ]
5+
paths: [ 'models/crime_predictor/**' ]
6+
pull_request:
7+
paths: [ 'models/crime_predictor/**' ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Setup Python
16+
uses: actions/setup-python@v4
17+
with:
18+
python-version: '3.11'
19+
20+
- name: Install dependencies
21+
run: |
22+
cd models/crime_predictor
23+
pip install -r requirements.txt pytest
24+
25+
- name: Run tests
26+
run: |
27+
cd models/crime_predictor
28+
pytest tests/ -v
29+
30+
- name: Build Docker
31+
run: |
32+
cd models/crime_predictor
33+
docker build -t crime-predictor:test .
34+
35+
deploy-model:
36+
needs: test
37+
runs-on: ubuntu-latest
38+
if: github.ref == 'refs/heads/main'
39+
40+
steps:
41+
- uses: actions/checkout@v4
42+
43+
- name: Train & Deploy Model
44+
env:
45+
MLFLOW_TRACKING_URI: ${{ secrets.MLFLOW_URI }}
46+
run: |
47+
cd models/crime_predictor
48+
pip install -r requirements.txt mlflow
49+
mlflow server --backend-store-uri ./mlruns --default-artifact-root ./mlruns --host 0.0.0.0 --port 5000 &
50+
sleep 10
51+
python train.py --data-url "https://static.data.gouv.fr/.../delinquance.csv"
52+
53+
- name: Push Docker Image
54+
uses: docker/login-action@v3
55+
with:
56+
registry: ghcr.io
57+
username: ${{ github.actor }}
58+
password: ${{ secrets.GITHUB_TOKEN }}
59+
60+
- name: Build & Push
61+
run: |
62+
cd models/crime_predictor
63+
docker build -t ghcr.io/${{ github.repository }}/crime-predictor:latest .
64+
docker push ghcr.io/${{ github.repository }}/crime-predictor:latest

.github/workflows/deploy-gh-pages.yml

Whitespace-only changes.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Data Science Designer and Developer
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

app.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import streamlit as st
2+
import pandas as pd
3+
import plotly.express as px
4+
# Importez vos modules du projet
5+
# from your_analysis import load_data, analyze_security
6+
7+
st.set_page_config(page_title="Oasis Security", layout="wide")
8+
9+
st.title("🛡️ Oasis Security Analysis")
10+
st.markdown("Analyse de sécurité pour la certification CDSD")
11+
12+
# Sidebar pour navigation
13+
page = st.sidebar.selectbox("Choisir une analyse",
14+
["Vue d'ensemble", "Analyse des menaces", "Visualisations"])
15+
16+
if page == "Vue d'ensemble":
17+
st.header("📊 Résumé exécutif")
18+
col1, col2 = st.columns(2)
19+
with col1:
20+
st.metric("Menaces critiques", "12") # Remplacez par vos vraies métriques
21+
with col2:
22+
st.metric("Score de sécurité", "87%")
23+
24+
# Chargez vos données
25+
# df = load_data()
26+
# st.dataframe(df)
27+
28+
if page == "Visualisations":
29+
st.header("📈 Dashboards interactifs")
30+
# fig = px.bar(...) # Vos graphiques
31+
# st.plotly_chart(fig)

data/ predict.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# predict.py (version MLflow-aware)
2+
from fastapi import FastAPI, HTTPException
3+
from pydantic import BaseModel
4+
import mlflow
5+
import mlflow.lightgbm
6+
import pandas as pd
7+
import numpy as np
8+
from model import CrimeRatePredictor
9+
import os
10+
from typing import Dict
11+
import uvicorn
12+
from contextlib import asynccontextmanager
13+
14+
# Config MLflow
15+
mlflow.set_tracking_uri(os.getenv("MLFLOW_TRACKING_URI", "http://localhost:5000"))
16+
mlflow.set_experiment("crime_predictor_prod")
17+
18+
app = FastAPI(title="Crime Predictor API v2", version="2.0.0")
19+
20+
# Modèle global (lazy loaded)
21+
predictor = None
22+
23+
@asynccontextmanager
24+
async def lifespan(app: FastAPI):
25+
"""Lifecycle: load model on startup"""
26+
global predictor
27+
print("🚀 Chargement modèle MLflow...")
28+
29+
# Charger depuis MLflow Model Registry (prod)
30+
model_uri = "models:/crime_predictor_prod/Production"
31+
predictor = mlflow.lightgbm.load_model(model_uri)
32+
33+
# Ou fallback local si pas de registry
34+
if predictor is None:
35+
predictor = CrimeRatePredictor()
36+
predictor.load("models/crime_predictor.pkl")
37+
38+
yield
39+
print("🛑 API shutdown")
40+
41+
app.router.lifespan_context = lifespan
42+
43+
class PredictionRequest(BaseModel):
44+
year: int = 2030
45+
indicateur: str
46+
region: str
47+
lag1: float = None
48+
lag2: float = None
49+
50+
@app.post("/predict", response_model=Dict)
51+
async def predict(request: PredictionRequest):
52+
"""Prédiction taux délinquance 2030"""
53+
global predictor
54+
55+
with mlflow.start_run(nested=True) as run:
56+
try:
57+
# Feature engineering dynamique
58+
features = pd.DataFrame([{
59+
'year_sin': np.sin(2 * np.pi * request.year / 10),
60+
'year_cos': np.cos(2 * np.pi * request.year / 10),
61+
'year_trend': (request.year - 2016) / 9,
62+
'lag1': request.lag1 or 250.0,
63+
'lag2': request.lag2 or 245.0,
64+
'roll_mean_3': (request.lag1 or 250 + request.lag2 or 245 + 240) / 3,
65+
'region_mean': 250.0,
66+
'ind_code': hash(request.indicateur) % 100,
67+
'reg_code': int(request.region.replace("R", ""))
68+
}])
69+
70+
# Prédiction
71+
pred = float(predictor.predict(features)[0])
72+
73+
# Log MLflow (observability)
74+
mlflow.log_param("indicateur", request.indicateur)
75+
mlflow.log_param("region", request.region)
76+
mlflow.log_param("year", request.year)
77+
mlflow.log_metric("prediction", pred)
78+
79+
return {
80+
"prediction": pred,
81+
"unit": "taux / 100k habitants",
82+
"confidence": 0.87,
83+
"mlflow_run_id": run.info.run_id,
84+
"interpretation": "🚨" if pred > 400 else "⚠️" if pred > 300 else "✅"
85+
}
86+
87+
except Exception as e:
88+
mlflow.log_metric("error", 1)
89+
raise HTTPException(status_code=500, detail=str(e))
90+
91+
@app.get("/leaderboard")
92+
async def leaderboard():
93+
"""Top 5 régions + indicateurs risque"""
94+
client = mlflow.MlflowClient()
95+
runs = client.search_runs(experiment_ids=["0"], order_by=["metrics.prediction DESC"], max_results=50)
96+
97+
summary = {
98+
"top_risks": [
99+
{"indicateur": r.data.params.get("indicateur", "N/A"),
100+
"region": r.data.params.get("region", "N/A"),
101+
"pred_2030": r.data.metrics.get("prediction", 0)}
102+
for r in runs
103+
][:5]
104+
}
105+
return summary
106+
107+
@app.get("/health")
108+
async def health():
109+
return {"status": "healthy", "model_version": "v2.0"}
110+
111+
if __name__ == "__main__":
112+
uvicorn.run(app, host="0.0.0.0", port=8000)
Binary file not shown.

data/crimes-et-délits-PN-GN.xlsx

3.97 MB
Binary file not shown.

0 commit comments

Comments
 (0)