enzo-09 commited on
Commit
28da7de
·
1 Parent(s): 08e9882

Initial commit with Flask API and Docker setup

Browse files
Files changed (4) hide show
  1. .dockerignore +10 -0
  2. Dockerfile +18 -0
  3. app.py +168 -0
  4. requirements.txt +3 -0
.dockerignore ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__
2
+ *.pyc
3
+ *.pyo
4
+ *.pyd
5
+ .Python
6
+ env/
7
+ venv/
8
+ *.log
9
+ .git
10
+ .gitignore
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Utiliser une image Python officielle comme base
2
+ FROM python:3.9-slim
3
+
4
+ # Définir le répertoire de travail
5
+ WORKDIR /app
6
+
7
+ # Copier les fichiers requirements.txt (à créer) et installer les dépendances
8
+ COPY requirements.txt .
9
+ RUN pip install --no-cache-dir -r requirements.txt
10
+
11
+ # Copier tout le code de l'application dans le conteneur
12
+ COPY . .
13
+
14
+ # Exposer le port sur lequel l'application va tourner (5000 dans votre cas)
15
+ EXPOSE 5000
16
+
17
+ # Commande pour lancer l'application
18
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py (modifié)
2
+ from flask import Flask, request, jsonify
3
+ from flask_cors import CORS
4
+ import numpy as np
5
+ from random import randint, choice
6
+
7
+ app = Flask(__name__)
8
+ CORS(app)
9
+
10
+ class Patient:
11
+ def __init__(self, id, esi_level, needs):
12
+ self.id = id
13
+ self.esi_level = esi_level
14
+ self.needs = needs
15
+
16
+ class CHU:
17
+ def __init__(self, id, resources, distance):
18
+ self.id = id
19
+ self.resources = resources.copy()
20
+ self.assigned_patients = {}
21
+ self.available_resources = resources.copy()
22
+ self.distance = distance # Nouvelle propriété pour la distance
23
+
24
+ def update_resources(chu, patient, action="remove"):
25
+ for r, qty in patient.needs.items():
26
+ if action == "remove":
27
+ chu.available_resources[r] = chu.available_resources.get(r, 0) - qty
28
+ print(f"CHU {chu.id} - {r} décrémenté: {chu.available_resources[r]}")
29
+ elif action == "add":
30
+ chu.available_resources[r] = chu.available_resources.get(r, 0) + qty
31
+ print(f"CHU {chu.id} - {r} incrémenté: {chu.available_resources[r]}")
32
+
33
+ def has_sufficient_resources(chu, needs):
34
+ for r, qty in needs.items():
35
+ available = chu.available_resources.get(r, 0)
36
+ if available < qty:
37
+ print(f"Échec pour {r}: besoin {qty}, disponible {available} dans CHU {chu.id}")
38
+ return False
39
+ print(f"Ressources suffisantes dans CHU {chu.id}")
40
+ return True
41
+
42
+ def assign_to_chu(chu, patient):
43
+ chu.assigned_patients[patient.id] = patient
44
+ update_resources(chu, patient, "remove")
45
+
46
+ def release_from_chu(chu, patient_id):
47
+ if patient_id in chu.assigned_patients:
48
+ patient = chu.assigned_patients[patient_id]
49
+ update_resources(chu, patient, "add")
50
+ del chu.assigned_patients[patient_id]
51
+
52
+ def generate_random_resources(nb_chus):
53
+ chus = []
54
+ for i in range(nb_chus):
55
+ resources = {
56
+ "lit": randint(35, 45),
57
+ "specialiste": randint(15, 25),
58
+ "generaliste": randint(15, 25),
59
+ "defibrillateur": randint(3, 8),
60
+ "scanner": randint(2, 5),
61
+ "respirateur": randint(5, 10),
62
+ "poche_sang": randint(50, 100)
63
+ }
64
+ # Générer une distance fictive entre 1 et 50 km
65
+ distance = randint(1, 50)
66
+ chus.append(CHU(i, resources, distance))
67
+ return chus
68
+
69
+ def generate_patient_needs(esi_level, requested_resources):
70
+ needs = {}
71
+ if esi_level == 1:
72
+ needs = {"lit": 1, "specialiste": 1, "defibrillateur": randint(0, 1), "respirateur": randint(0, 1), "poche_sang": randint(0, 3)}
73
+ elif esi_level == 2:
74
+ needs = {"lit": 1, "specialiste": 1, "scanner": randint(0, 1), "respirateur": randint(0, 1)}
75
+ elif esi_level == 3:
76
+ needs = {"lit": 1, "scanner": randint(0, 1), "specialiste": randint(0, 1), "generaliste": randint(0, 1)}
77
+ elif esi_level == 4:
78
+ needs = {"lit": randint(0, 1), "scanner": randint(0, 1), "generaliste": randint(0, 1)}
79
+ elif esi_level == 5:
80
+ needs = {"lit": randint(0, 1)} if randint(0, 1) else {}
81
+
82
+ resource_mapping = {
83
+ "Lit": "lit",
84
+ "Respirateur": "respirateur",
85
+ "Oxygène": "poche_sang",
86
+ "Sang": "poche_sang",
87
+ "Spécialiste": "specialiste",
88
+ "Généraliste": "generaliste",
89
+ "Défibrillateur": "defibrillateur"
90
+ }
91
+ for res in requested_resources:
92
+ key = resource_mapping.get(res)
93
+ if key:
94
+ needs[key] = needs.get(key, 0) + 1
95
+ else:
96
+ print(f"Ressource non reconnue: {res}")
97
+
98
+ print(f"Besoins générés pour ESI {esi_level}: {needs}")
99
+ return needs
100
+
101
+ def assign_patients_with_reallocation(patients, chus):
102
+ allocation = {p.id: chu.id for chu in chus for p in chu.assigned_patients.values()}
103
+ reallocations = []
104
+
105
+ patients_sorted = sorted(patients, key=lambda p: p.esi_level)
106
+ for patient in patients_sorted:
107
+ # Trouver tous les CHU avec assez de ressources
108
+ eligible_chus = [chu for chu in chus if has_sufficient_resources(chu, patient.needs)]
109
+
110
+ if eligible_chus:
111
+ # Choisir le CHU le plus proche parmi ceux qui ont assez de ressources
112
+ best_chu = min(eligible_chus, key=lambda chu: chu.distance)
113
+ print(f"CHU {best_chu.id} sélectionné pour patient {patient.id} (distance: {best_chu.distance} km)")
114
+ allocation[patient.id] = best_chu.id
115
+ assign_to_chu(best_chu, patient)
116
+ else:
117
+ # Si aucun CHU n'a assez de ressources et ESI <= 3, tenter une réallocation
118
+ if patient.esi_level <= 3:
119
+ for chu in chus:
120
+ to_release = [p for p in chu.assigned_patients.values() if p.esi_level > patient.esi_level]
121
+ if to_release:
122
+ candidate = max(to_release, key=lambda p: p.esi_level)
123
+ release_from_chu(chu, candidate.id)
124
+ reallocations.append((candidate.id, chu.id, patient.id, candidate.needs))
125
+ if has_sufficient_resources(chu, patient.needs):
126
+ allocation[patient.id] = chu.id
127
+ assign_to_chu(chu, patient)
128
+ break
129
+
130
+ unassigned = [p for p in patients if p.id not in allocation]
131
+ return allocation, reallocations, unassigned
132
+
133
+ # Initialiser 10 CHU au lieu de 3
134
+ chus = generate_random_resources(10)
135
+
136
+ @app.route('/assign_patient', methods=['POST'])
137
+ def assign_patient():
138
+ data = request.json
139
+ patient_id = data.get('id', f"PAT-{randint(1000, 9999)}")
140
+ esi_level = int(data['esi'])
141
+ requested_resources = data.get('ressources', [])
142
+
143
+ print(f"Données reçues: id={patient_id}, esi={esi_level}, ressources={requested_resources}")
144
+
145
+ patient_needs = generate_patient_needs(esi_level, requested_resources)
146
+ patient = Patient(patient_id, esi_level, patient_needs)
147
+
148
+ allocation, reallocations, unassigned = assign_patients_with_reallocation([patient], chus)
149
+
150
+ response = {
151
+ "patient_id": patient_id,
152
+ "assigned_chu": allocation.get(patient_id, None),
153
+ "chus": [
154
+ {
155
+ "id": chu.id,
156
+ "available_resources": chu.available_resources,
157
+ "assigned_patients": len(chu.assigned_patients),
158
+ "distance": chu.distance # Ajouter la distance dans la réponse
159
+ }
160
+ for chu in chus
161
+ ],
162
+ "reallocations": reallocations,
163
+ "unassigned": [p.id for p in unassigned]
164
+ }
165
+ return jsonify(response)
166
+
167
+ if __name__ == "__main__":
168
+ app.run(debug=True, port=5000)
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ Flask==2.0.1
2
+ flask-cors==3.0.10
3
+ numpy==1.21.0