yassonee commited on
Commit
2005bb3
·
verified ·
1 Parent(s): 74282cb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +148 -188
app.py CHANGED
@@ -2,10 +2,9 @@ from fastapi import FastAPI, File, UploadFile
2
  from fastapi.responses import HTMLResponse
3
  from transformers import pipeline
4
  from PIL import Image, ImageDraw
5
- import numpy as np
6
  import io
7
- import uvicorn
8
  import base64
 
9
 
10
  app = FastAPI()
11
 
@@ -20,6 +19,7 @@ def load_models():
20
 
21
  models = load_models()
22
 
 
23
  def translate_label(label):
24
  translations = {
25
  "fracture": "Knochenbruch",
@@ -31,60 +31,20 @@ def translate_label(label):
31
  }
32
  return translations.get(label.lower(), label)
33
 
 
34
  def create_heatmap_overlay(image, box, score):
35
- overlay = Image.new('RGBA', image.size, (0, 0, 0, 0))
36
- draw = ImageDraw.Draw(overlay)
37
-
38
- x1, y1 = box['xmin'], box['ymin']
39
- x2, y2 = box['xmax'], box['ymax']
40
-
41
- if score > 0.8:
42
- fill_color = (255, 0, 0, 100)
43
- border_color = (255, 0, 0, 255)
44
- elif score > 0.6:
45
- fill_color = (255, 165, 0, 100)
46
- border_color = (255, 165, 0, 255)
47
- else:
48
- fill_color = (255, 255, 0, 100)
49
- border_color = (255, 255, 0, 255)
50
-
51
- draw.rectangle([x1, y1, x2, y2], fill=fill_color)
52
- draw.rectangle([x1, y1, x2, y2], outline=border_color, width=2)
53
-
54
- return overlay
55
 
56
  def draw_boxes(image, predictions):
57
- result_image = image.copy().convert('RGBA')
58
-
59
- for pred in predictions:
60
- box = pred['box']
61
- score = pred['score']
62
-
63
- overlay = create_heatmap_overlay(image, box, score)
64
- result_image = Image.alpha_composite(result_image, overlay)
65
-
66
- draw = ImageDraw.Draw(result_image)
67
- temp = 36.5 + (score * 2.5)
68
- label = f"{translate_label(pred['label'])} ({score:.1%} • {temp:.1f}°C)"
69
-
70
- text_bbox = draw.textbbox((box['xmin'], box['ymin']-20), label)
71
- draw.rectangle(text_bbox, fill=(0, 0, 0, 180))
72
-
73
- draw.text(
74
- (box['xmin'], box['ymin']-20),
75
- label,
76
- fill=(255, 255, 255, 255)
77
- )
78
-
79
- return result_image
80
 
81
  def image_to_base64(image):
82
- buffered = io.BytesIO()
83
- image.save(buffered, format="PNG")
84
- img_str = base64.b64encode(buffered.getvalue()).decode()
85
- return f"data:image/png;base64,{img_str}"
86
 
87
- # Page d'accueil avec interface améliorée
88
  @app.get("/", response_class=HTMLResponse)
89
  async def main():
90
  content = """
@@ -93,230 +53,218 @@ async def main():
93
  <head>
94
  <title>Fraktur Detektion</title>
95
  <style>
 
 
96
  body {
97
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
98
- background: #f0f2f5;
99
  margin: 0;
100
- padding: 20px;
101
- color: #1a1a1a;
 
102
  }
 
 
 
 
 
 
 
 
 
 
103
  .container {
104
- max-width: 1200px;
105
- margin: 0 auto;
106
- background: white;
107
- padding: 20px;
108
- border-radius: 10px;
109
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
110
  }
 
111
  .upload-section {
112
- background: #f8f9fa;
113
- padding: 20px;
114
- border-radius: 8px;
115
- margin: 20px 0;
116
  text-align: center;
117
  }
118
- .result-box {
119
- background: #f8f9fa;
120
- padding: 15px;
121
- border-radius: 8px;
122
- margin: 10px 0;
123
- border: 1px solid #e9ecef;
124
- }
125
  .button {
126
  background: #0066cc;
127
  color: white;
128
  border: none;
129
- padding: 10px 20px;
130
- border-radius: 5px;
131
  cursor: pointer;
132
- transition: all 0.3s ease;
133
- font-size: 16px;
134
- }
135
- .button:hover {
136
- background: #0052a3;
137
- transform: translateY(-1px);
138
  }
139
- .results-grid {
 
140
  display: grid;
141
- grid-template-columns: 1fr 1fr;
142
- gap: 20px;
143
- margin-top: 20px;
144
- }
145
- .confidence-slider {
146
- width: 100%;
147
- max-width: 300px;
148
- margin: 20px auto;
149
  }
 
150
  img {
151
  max-width: 100%;
152
- border-radius: 8px;
153
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
154
  }
155
- .loading {
156
- display: none;
157
- text-align: center;
158
- padding: 20px;
159
- font-weight: bold;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  }
161
- .score-high { color: #0066cc; }
162
- .score-medium { color: #ffa500; }
163
- .score-low { color: #dc3545; }
164
  </style>
165
  </head>
166
  <body>
167
  <div class="container">
168
- <h1>📤 Fraktur Detektion</h1>
169
 
170
  <div class="upload-section">
171
  <form action="/analyze" method="post" enctype="multipart/form-data">
172
- <div>
173
- <input type="file" name="file" accept="image/*" required>
174
- </div>
175
- <div class="confidence-slider">
176
- <label for="threshold">Konfidenzschwelle: <span id="thresholdValue">0.60</span></label>
177
- <input type="range" id="threshold" name="threshold"
178
- min="0" max="1" step="0.05" value="0.60"
179
- oninput="updateThreshold(this.value)">
180
- </div>
181
  <button type="submit" class="button">Analysieren</button>
182
  </form>
183
  </div>
184
-
185
- <div id="loading" class="loading">
186
- Bild wird analysiert... ⏳
187
- </div>
188
-
189
- <script>
190
- function updateThreshold(value) {
191
- document.getElementById('thresholdValue').textContent = parseFloat(value).toFixed(2);
192
- }
193
-
194
- document.querySelector('form').onsubmit = function() {
195
- document.getElementById('loading').style.display = 'block';
196
- }
197
- </script>
198
  </div>
199
  </body>
200
  </html>
201
  """
202
  return content
203
 
 
204
  @app.post("/analyze", response_class=HTMLResponse)
205
  async def analyze_file(file: UploadFile = File(...)):
206
  try:
207
- # Lecture de l'image
208
  contents = await file.read()
209
  image = Image.open(io.BytesIO(contents))
210
 
211
- # Analyse avec tous les modèles
212
  predictions_watcher = models["KnochenWächter"](image)
213
  predictions_master = models["RöntgenMeister"](image)
214
  predictions_locator = models["KnochenAuge"](image)
215
 
216
- # Création de l'image annotée
217
  filtered_preds = [p for p in predictions_locator if p['score'] >= 0.6]
218
- if filtered_preds:
219
- result_image = draw_boxes(image, filtered_preds)
220
- else:
221
- result_image = image
222
-
223
- # Conversion des images en base64
224
  result_image_b64 = image_to_base64(result_image)
225
 
226
- # Construction du HTML pour les résultats
227
  results_html = """
228
  <!DOCTYPE html>
229
  <html>
230
  <head>
231
- <title>Analyse Ergebnisse</title>
232
  <style>
 
 
233
  body {
234
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
235
- background: #f0f2f5;
236
  margin: 0;
237
- padding: 20px;
238
- color: #1a1a1a;
 
 
 
 
 
 
 
 
239
  }
 
240
  .container {
241
- max-width: 1200px;
242
- margin: 0 auto;
243
- background: white;
244
- padding: 20px;
245
- border-radius: 10px;
246
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
247
  }
 
248
  .results-grid {
249
  display: grid;
250
- grid-template-columns: 1fr 1fr;
251
- gap: 20px;
252
- margin-top: 20px;
253
  }
 
254
  .result-box {
255
- background: #f8f9fa;
256
- padding: 15px;
257
- border-radius: 8px;
258
- margin: 10px 0;
259
- border: 1px solid #e9ecef;
260
  }
261
- .score-high { color: #0066cc; font-weight: bold; }
262
- .score-medium { color: #ffa500; font-weight: bold; }
263
  .back-button {
264
  display: inline-block;
265
  background: #0066cc;
266
  color: white;
267
- padding: 10px 20px;
268
- border-radius: 5px;
269
  text-decoration: none;
270
- margin-top: 20px;
271
- transition: all 0.3s ease;
272
- }
273
- .back-button:hover {
274
- background: #0052a3;
275
- transform: translateY(-1px);
276
  }
 
277
  img {
278
  max-width: 100%;
279
- border-radius: 8px;
280
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  }
282
  </style>
283
  </head>
284
  <body>
285
  <div class="container">
286
- <h1>🔍 Analyse Ergebnisse</h1>
287
 
288
  <div class="results-grid">
289
- <div>
290
- <h2>🤖 KI-Diagnose</h2>
291
  """
292
 
293
  # KnochenWächter results
294
- results_html += "<h3>🛡️ KnochenWächter</h3>"
295
  for pred in predictions_watcher:
296
- confidence_class = "score-high" if pred['score'] > 0.7 else "score-medium"
297
- results_html += f"""
298
- <div class="result-box">
299
- <span class="{confidence_class}">{pred['score']:.1%}</span> -
300
- {translate_label(pred['label'])}
301
- </div>
302
- """
303
 
304
  # RöntgenMeister results
305
- results_html += "<h3>🎓 RöntgenMeister</h3>"
306
  for pred in predictions_master:
307
- confidence_class = "score-high" if pred['score'] > 0.7 else "score-medium"
308
- results_html += f"""
309
- <div class="result-box">
310
- <span class="{confidence_class}">{pred['score']:.1%}</span> -
311
- {translate_label(pred['label'])}
312
- </div>
313
- """
314
 
315
- # Add image and close HTML
316
  results_html += f"""
317
- </div>
318
- <div>
319
- <h2>🎯 Fraktur Lokalisation</h2>
320
  <img src="{result_image_b64}" alt="Analyzed image">
321
  </div>
322
  </div>
@@ -331,12 +279,24 @@ async def analyze_file(file: UploadFile = File(...)):
331
 
332
  except Exception as e:
333
  return f"""
334
- <body style="font-family: Arial; max-width: 800px; margin: 0 auto; padding: 20px;">
335
- <h1>Fehler</h1>
336
- <p>Ein Fehler ist aufgetreten: {str(e)}</p>
337
- <br>
 
 
 
 
 
 
 
 
 
 
 
338
  <a href="/" class="back-button">← Zurück</a>
339
  </body>
 
340
  """
341
 
342
  if __name__ == "__main__":
 
2
  from fastapi.responses import HTMLResponse
3
  from transformers import pipeline
4
  from PIL import Image, ImageDraw
 
5
  import io
 
6
  import base64
7
+ import uvicorn
8
 
9
  app = FastAPI()
10
 
 
19
 
20
  models = load_models()
21
 
22
+ # Fonctions d'analyse existantes restent identiques
23
  def translate_label(label):
24
  translations = {
25
  "fracture": "Knochenbruch",
 
31
  }
32
  return translations.get(label.lower(), label)
33
 
34
+ # Autres fonctions helper restent identiques
35
  def create_heatmap_overlay(image, box, score):
36
+ # Votre code existant reste le même
37
+ [...]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
  def draw_boxes(image, predictions):
40
+ # Votre code existant reste le même
41
+ [...]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
  def image_to_base64(image):
44
+ # Votre code existant reste le même
45
+ [...]
 
 
46
 
47
+ # Page d'accueil simplifiée
48
  @app.get("/", response_class=HTMLResponse)
49
  async def main():
50
  content = """
 
53
  <head>
54
  <title>Fraktur Detektion</title>
55
  <style>
56
+ :root { color-scheme: light dark; }
57
+
58
  body {
59
+ font-family: system-ui, -apple-system, sans-serif;
 
60
  margin: 0;
61
+ padding: 1rem;
62
+ max-width: 100%;
63
+ overflow-x: hidden;
64
  }
65
+
66
+ @media (prefers-color-scheme: dark) {
67
+ body {
68
+ background: #1a1a1a;
69
+ color: #fff;
70
+ }
71
+ .container { background: #2d2d2d; }
72
+ .upload-section { background: #3d3d3d; }
73
+ }
74
+
75
  .container {
76
+ background: #ffffff;
77
+ padding: 1.5rem;
78
+ border-radius: 0.5rem;
 
 
79
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
80
  }
81
+
82
  .upload-section {
83
+ background: #f5f5f5;
84
+ padding: 1.5rem;
85
+ border-radius: 0.5rem;
86
+ margin: 1rem 0;
87
  text-align: center;
88
  }
89
+
 
 
 
 
 
 
90
  .button {
91
  background: #0066cc;
92
  color: white;
93
  border: none;
94
+ padding: 0.5rem 1rem;
95
+ border-radius: 0.25rem;
96
  cursor: pointer;
97
+ margin-top: 1rem;
 
 
 
 
 
98
  }
99
+
100
+ .results-container {
101
  display: grid;
102
+ gap: 1rem;
103
+ margin-top: 1rem;
 
 
 
 
 
 
104
  }
105
+
106
  img {
107
  max-width: 100%;
108
+ height: auto;
109
+ border-radius: 0.5rem;
110
  }
111
+
112
+ ::-webkit-scrollbar {
113
+ width: 8px;
114
+ height: 8px;
115
+ }
116
+
117
+ ::-webkit-scrollbar-track {
118
+ background: transparent;
119
+ }
120
+
121
+ ::-webkit-scrollbar-thumb {
122
+ background-color: rgba(0, 0, 0, 0.2);
123
+ border-radius: 4px;
124
+ }
125
+
126
+ @media (prefers-color-scheme: dark) {
127
+ ::-webkit-scrollbar-thumb {
128
+ background-color: rgba(255, 255, 255, 0.2);
129
+ }
130
  }
 
 
 
131
  </style>
132
  </head>
133
  <body>
134
  <div class="container">
135
+ <h2>Fraktur Detektion</h2>
136
 
137
  <div class="upload-section">
138
  <form action="/analyze" method="post" enctype="multipart/form-data">
139
+ <input type="file" name="file" accept="image/*" required>
140
+ <br>
 
 
 
 
 
 
 
141
  <button type="submit" class="button">Analysieren</button>
142
  </form>
143
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  </div>
145
  </body>
146
  </html>
147
  """
148
  return content
149
 
150
+ # Page de résultats simplifiée
151
  @app.post("/analyze", response_class=HTMLResponse)
152
  async def analyze_file(file: UploadFile = File(...)):
153
  try:
154
+ # Votre logique d'analyse existante
155
  contents = await file.read()
156
  image = Image.open(io.BytesIO(contents))
157
 
 
158
  predictions_watcher = models["KnochenWächter"](image)
159
  predictions_master = models["RöntgenMeister"](image)
160
  predictions_locator = models["KnochenAuge"](image)
161
 
 
162
  filtered_preds = [p for p in predictions_locator if p['score'] >= 0.6]
163
+ result_image = draw_boxes(image, filtered_preds) if filtered_preds else image
 
 
 
 
 
164
  result_image_b64 = image_to_base64(result_image)
165
 
 
166
  results_html = """
167
  <!DOCTYPE html>
168
  <html>
169
  <head>
170
+ <title>Ergebnisse</title>
171
  <style>
172
+ :root { color-scheme: light dark; }
173
+
174
  body {
175
+ font-family: system-ui, -apple-system, sans-serif;
 
176
  margin: 0;
177
+ padding: 1rem;
178
+ }
179
+
180
+ @media (prefers-color-scheme: dark) {
181
+ body {
182
+ background: #1a1a1a;
183
+ color: #fff;
184
+ }
185
+ .container { background: #2d2d2d; }
186
+ .result-box { background: #3d3d3d; }
187
  }
188
+
189
  .container {
190
+ background: #ffffff;
191
+ padding: 1.5rem;
192
+ border-radius: 0.5rem;
 
 
193
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
194
  }
195
+
196
  .results-grid {
197
  display: grid;
198
+ gap: 1rem;
199
+ margin-top: 1rem;
 
200
  }
201
+
202
  .result-box {
203
+ background: #f5f5f5;
204
+ padding: 1rem;
205
+ border-radius: 0.5rem;
 
 
206
  }
207
+
 
208
  .back-button {
209
  display: inline-block;
210
  background: #0066cc;
211
  color: white;
212
+ padding: 0.5rem 1rem;
213
+ border-radius: 0.25rem;
214
  text-decoration: none;
215
+ margin-top: 1rem;
 
 
 
 
 
216
  }
217
+
218
  img {
219
  max-width: 100%;
220
+ height: auto;
221
+ border-radius: 0.5rem;
222
+ }
223
+
224
+ ::-webkit-scrollbar {
225
+ width: 8px;
226
+ height: 8px;
227
+ }
228
+
229
+ ::-webkit-scrollbar-track {
230
+ background: transparent;
231
+ }
232
+
233
+ ::-webkit-scrollbar-thumb {
234
+ background-color: rgba(0, 0, 0, 0.2);
235
+ border-radius: 4px;
236
+ }
237
+
238
+ @media (prefers-color-scheme: dark) {
239
+ ::-webkit-scrollbar-thumb {
240
+ background-color: rgba(255, 255, 255, 0.2);
241
+ }
242
  }
243
  </style>
244
  </head>
245
  <body>
246
  <div class="container">
247
+ <h2>Analyse Ergebnisse</h2>
248
 
249
  <div class="results-grid">
 
 
250
  """
251
 
252
  # KnochenWächter results
253
+ results_html += "<div class='result-box'><h3>KnochenWächter</h3>"
254
  for pred in predictions_watcher:
255
+ results_html += f"<p>{pred['score']:.1%} - {translate_label(pred['label'])}</p>"
256
+ results_html += "</div>"
 
 
 
 
 
257
 
258
  # RöntgenMeister results
259
+ results_html += "<div class='result-box'><h3>RöntgenMeister</h3>"
260
  for pred in predictions_master:
261
+ results_html += f"<p>{pred['score']:.1%} - {translate_label(pred['label'])}</p>"
262
+ results_html += "</div>"
 
 
 
 
 
263
 
264
+ # Image result
265
  results_html += f"""
266
+ <div class='result-box'>
267
+ <h3>Fraktur Lokalisation</h3>
 
268
  <img src="{result_image_b64}" alt="Analyzed image">
269
  </div>
270
  </div>
 
279
 
280
  except Exception as e:
281
  return f"""
282
+ <!DOCTYPE html>
283
+ <html>
284
+ <head>
285
+ <title>Fehler</title>
286
+ <style>
287
+ :root { color-scheme: light dark; }
288
+ body {{
289
+ font-family: system-ui, -apple-system, sans-serif;
290
+ margin: 1rem;
291
+ }}
292
+ </style>
293
+ </head>
294
+ <body>
295
+ <h2>Fehler</h2>
296
+ <p>{str(e)}</p>
297
  <a href="/" class="back-button">← Zurück</a>
298
  </body>
299
+ </html>
300
  """
301
 
302
  if __name__ == "__main__":