yassonee commited on
Commit
c0c6567
·
verified ·
1 Parent(s): aa2e94a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -244
app.py CHANGED
@@ -2,9 +2,7 @@ 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()
@@ -69,12 +67,7 @@ def draw_boxes(image, predictions):
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
 
@@ -84,121 +77,116 @@ def image_to_base64(image):
84
  img_str = base64.b64encode(buffered.getvalue()).decode()
85
  return f"data:image/png;base64,{img_str}"
86
 
87
- # Styles communs pour les deux pages
88
- COMMON_STYLES = """
89
- :root {
90
- color-scheme: light dark;
91
- }
92
-
93
- @media (prefers-color-scheme: dark) {
94
- body {
95
- background: #1a1a1a !important;
96
- color: #ffffff !important;
97
- }
98
- .container {
99
- background: #2d2d2d !important;
100
- }
101
- .result-box, .upload-section {
102
- background: #363636 !important;
103
- border-color: #555 !important;
104
- }
105
- .button {
106
- background: #0066cc !important;
107
- }
108
- input[type="file"]::file-selector-button {
109
- background: #444 !important;
110
- color: #fff !important;
111
- border-color: #555 !important;
112
- }
113
- input[type="range"] {
114
- background: #444 !important;
115
- }
116
- .button-progress {
117
- background: rgba(255, 255, 255, 0.2) !important;
118
- }
119
- }
120
-
121
  body {
122
  font-family: system-ui, -apple-system, sans-serif;
123
- background: #f0f2f5;
124
  margin: 0;
125
  padding: 20px;
126
- color: #1a1a1a;
127
- }
128
-
129
- /* Scrollbar personnalisée */
130
- ::-webkit-scrollbar {
131
- width: 8px;
132
- height: 8px;
133
- }
134
-
135
- ::-webkit-scrollbar-track {
136
- background: transparent;
137
- }
138
-
139
- ::-webkit-scrollbar-thumb {
140
- background-color: rgba(156, 163, 175, 0.5);
141
- border-radius: 4px;
142
- }
143
-
144
- @media (prefers-color-scheme: dark) {
145
- ::-webkit-scrollbar-thumb {
146
- background-color: rgba(75, 85, 99, 0.5);
147
- }
148
  }
149
 
150
  .container {
151
  max-width: 1200px;
152
  margin: 0 auto;
153
- background: white;
154
  padding: 20px;
155
  border-radius: 10px;
156
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  }
158
 
159
  .button {
160
- background: #0066cc;
161
  color: white;
162
  border: none;
163
  padding: 12px 30px;
164
  border-radius: 8px;
165
  cursor: pointer;
166
  font-size: 1.1em;
167
- transition: all 0.3s ease;
168
- position: relative;
169
  }
170
 
171
- .button:hover {
172
- background: #0052a3;
 
 
173
  }
174
 
175
- /* Nouvelle barre de progression */
176
- .button {
177
- position: relative;
 
 
 
 
 
 
 
 
 
 
 
178
  }
179
 
180
- @keyframes progress {
181
- 0% { width: 0; }
182
- 100% { width: 100%; }
183
  }
184
 
185
- .button-progress {
186
- position: absolute;
187
- bottom: 0;
188
- left: 0;
189
- height: 4px;
190
- background: rgba(255, 255, 255, 0.5);
191
- width: 0;
192
  }
193
 
194
- .button:active .button-progress {
195
- animation: progress 2s linear forwards;
 
 
 
 
 
 
196
  }
197
 
198
  img {
199
  max-width: 100%;
200
- height: auto;
201
  border-radius: 8px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  }
203
  """
204
 
@@ -210,86 +198,15 @@ async def main():
210
  <head>
211
  <title>Fraktur Detektion</title>
212
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
213
- <style>
214
- {COMMON_STYLES}
215
-
216
- .upload-section {{
217
- background: #f8f9fa;
218
- padding: 40px;
219
- border-radius: 12px;
220
- margin: 20px 0;
221
- text-align: center;
222
- border: 2px dashed #ccc;
223
- transition: all 0.3s ease;
224
- }}
225
-
226
- .upload-section:hover {{
227
- border-color: #0066cc;
228
- }}
229
-
230
- input[type="file"] {{
231
- font-size: 1.1em;
232
- margin: 20px 0;
233
- }}
234
-
235
- input[type="file"]::file-selector-button {{
236
- font-size: 1em;
237
- padding: 10px 20px;
238
- border-radius: 8px;
239
- border: 1px solid #ccc;
240
- background: #f8f9fa;
241
- transition: all 0.3s ease;
242
- cursor: pointer;
243
- }}
244
-
245
- input[type="file"]::file-selector-button:hover {{
246
- background: #e9ecef;
247
- }}
248
-
249
- .confidence-slider {{
250
- width: 100%;
251
- max-width: 300px;
252
- margin: 20px auto;
253
- }}
254
-
255
- input[type="range"] {{
256
- width: 100%;
257
- height: 8px;
258
- border-radius: 4px;
259
- background: #e9ecef;
260
- outline: none;
261
- transition: all 0.3s ease;
262
- -webkit-appearance: none;
263
- }}
264
-
265
- input[type="range"]::-webkit-slider-thumb {{
266
- -webkit-appearance: none;
267
- width: 20px;
268
- height: 20px;
269
- border-radius: 50%;
270
- background: #0066cc;
271
- cursor: pointer;
272
- border: none;
273
- }}
274
- </style>
275
  </head>
276
  <body>
277
  <div class="container">
278
  <div class="upload-section">
279
  <form action="/analyze" method="post" enctype="multipart/form-data">
280
- <div>
281
- <input type="file" name="file" accept="image/*" required>
282
- </div>
283
- <div class="confidence-slider">
284
- <label for="threshold">Konfidenzschwelle: <span id="thresholdValue">0.60</span></label>
285
- <input type="range" id="threshold" name="threshold"
286
- min="0" max="1" step="0.05" value="0.60"
287
- oninput="document.getElementById('thresholdValue').textContent = parseFloat(this.value).toFixed(2)">
288
- </div>
289
- <button type="submit" class="button">
290
- Analysieren
291
- <div class="button-progress"></div>
292
- </button>
293
  </form>
294
  </div>
295
  </div>
@@ -309,11 +226,7 @@ async def analyze_file(file: UploadFile = File(...)):
309
  predictions_locator = models["KnochenAuge"](image)
310
 
311
  filtered_preds = [p for p in predictions_locator if p['score'] >= 0.6]
312
- if filtered_preds:
313
- result_image = draw_boxes(image, filtered_preds)
314
- else:
315
- result_image = image
316
-
317
  result_image_b64 = image_to_base64(result_image)
318
 
319
  results_html = f"""
@@ -322,57 +235,7 @@ async def analyze_file(file: UploadFile = File(...)):
322
  <head>
323
  <title>Ergebnisse</title>
324
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
325
- <style>
326
- {COMMON_STYLES}
327
-
328
- .results-grid {{
329
- display: grid;
330
- grid-template-columns: 1fr 1fr;
331
- gap: 20px;
332
- margin-top: 20px;
333
- }}
334
-
335
- .result-box {{
336
- background: #f8f9fa;
337
- padding: 20px;
338
- border-radius: 12px;
339
- margin: 10px 0;
340
- border: 1px solid #e9ecef;
341
- }}
342
-
343
- .score-high {{
344
- color: #0066cc;
345
- font-weight: bold;
346
- }}
347
-
348
- .score-medium {{
349
- color: #ffa500;
350
- font-weight: bold;
351
- }}
352
-
353
- .back-button {{
354
- display: inline-block;
355
- text-decoration: none;
356
- margin-top: 20px;
357
- }}
358
-
359
- h3 {{
360
- color: #0066cc;
361
- margin-top: 0;
362
- }}
363
-
364
- @media (prefers-color-scheme: dark) {{
365
- h3 {{
366
- color: #66b3ff;
367
- }}
368
- }}
369
-
370
- @media (max-width: 768px) {{
371
- .results-grid {{
372
- grid-template-columns: 1fr;
373
- }}
374
- }}
375
- </style>
376
  </head>
377
  <body>
378
  <div class="container">
@@ -412,10 +275,7 @@ async def analyze_file(file: UploadFile = File(...)):
412
  </div>
413
  </div>
414
 
415
- <a href="/" class="button back-button">
416
- ← Zurück
417
- <div class="button-progress"></div>
418
- </a>
419
  </div>
420
  </body>
421
  </html>
@@ -430,37 +290,20 @@ async def analyze_file(file: UploadFile = File(...)):
430
  <head>
431
  <title>Fehler</title>
432
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
433
- <style>
434
- {COMMON_STYLES}
435
- .error-box {{
436
- background: #fee2e2;
437
- border: 1px solid #ef4444;
438
- padding: 20px;
439
- border-radius: 8px;
440
- margin: 20px 0;
441
- }}
442
- @media (prefers-color-scheme: dark) {{
443
- .error-box {{
444
- background: #471818;
445
- border-color: #dc2626;
446
- }}
447
- }}
448
- </style>
449
  </head>
450
  <body>
451
  <div class="container">
452
- <div class="error-box">
453
  <h3>Fehler</h3>
454
  <p>{str(e)}</p>
455
  </div>
456
- <a href="/" class="button back-button">
457
- ← Zurück
458
- <div class="button-progress"></div>
459
- </a>
460
  </div>
461
  </body>
462
  </html>
463
  """
464
 
465
  if __name__ == "__main__":
 
466
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
2
  from fastapi.responses import HTMLResponse
3
  from transformers import pipeline
4
  from PIL import Image, ImageDraw
 
5
  import io
 
6
  import base64
7
 
8
  app = FastAPI()
 
67
 
68
  text_bbox = draw.textbbox((box['xmin'], box['ymin']-20), label)
69
  draw.rectangle(text_bbox, fill=(0, 0, 0, 180))
70
+ draw.text((box['xmin'], box['ymin']-20), label, fill=(255, 255, 255, 255))
 
 
 
 
 
71
 
72
  return result_image
73
 
 
77
  img_str = base64.b64encode(buffered.getvalue()).decode()
78
  return f"data:image/png;base64,{img_str}"
79
 
80
+ STYLES = """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  body {
82
  font-family: system-ui, -apple-system, sans-serif;
83
+ background: #2d3748;
84
  margin: 0;
85
  padding: 20px;
86
+ color: #e2e8f0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  }
88
 
89
  .container {
90
  max-width: 1200px;
91
  margin: 0 auto;
92
+ background: #1a202c;
93
  padding: 20px;
94
  border-radius: 10px;
95
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
96
+ }
97
+
98
+ .upload-section {
99
+ background: #2d3748;
100
+ padding: 40px;
101
+ border-radius: 12px;
102
+ margin: 20px 0;
103
+ text-align: center;
104
+ border: 2px dashed #4a5568;
105
+ }
106
+
107
+ /* Animation de chargement */
108
+ @keyframes loading {
109
+ 0% { background-position: 200% 0; }
110
+ 100% { background-position: -200% 0; }
111
  }
112
 
113
  .button {
114
+ background: #4299e1;
115
  color: white;
116
  border: none;
117
  padding: 12px 30px;
118
  border-radius: 8px;
119
  cursor: pointer;
120
  font-size: 1.1em;
121
+ overflow: hidden;
 
122
  }
123
 
124
+ .button:active {
125
+ background: linear-gradient(90deg, #4299e1 0%, #63b3ed 50%, #4299e1 100%);
126
+ background-size: 200% 100%;
127
+ animation: loading 2s infinite linear;
128
  }
129
 
130
+ input[type="file"] {
131
+ font-size: 1.1em;
132
+ margin: 20px 0;
133
+ color: #e2e8f0;
134
+ }
135
+
136
+ input[type="file"]::file-selector-button {
137
+ font-size: 1em;
138
+ padding: 10px 20px;
139
+ border-radius: 8px;
140
+ border: 1px solid #4a5568;
141
+ background: #2d3748;
142
+ color: #e2e8f0;
143
+ cursor: pointer;
144
  }
145
 
146
+ input[type="file"]::file-selector-button:hover {
147
+ background: #4a5568;
 
148
  }
149
 
150
+ .result-box {
151
+ background: #2d3748;
152
+ padding: 20px;
153
+ border-radius: 12px;
154
+ margin: 10px 0;
155
+ border: 1px solid #4a5568;
 
156
  }
157
 
158
+ .score-high {
159
+ color: #48bb78;
160
+ font-weight: bold;
161
+ }
162
+
163
+ .score-medium {
164
+ color: #ed8936;
165
+ font-weight: bold;
166
  }
167
 
168
  img {
169
  max-width: 100%;
 
170
  border-radius: 8px;
171
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
172
+ }
173
+
174
+ h3 {
175
+ color: #63b3ed;
176
+ margin-top: 0;
177
+ }
178
+
179
+ .results-grid {
180
+ display: grid;
181
+ grid-template-columns: 1fr 1fr;
182
+ gap: 20px;
183
+ margin-top: 20px;
184
+ }
185
+
186
+ @media (max-width: 768px) {
187
+ .results-grid {
188
+ grid-template-columns: 1fr;
189
+ }
190
  }
191
  """
192
 
 
198
  <head>
199
  <title>Fraktur Detektion</title>
200
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
201
+ <style>{STYLES}</style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  </head>
203
  <body>
204
  <div class="container">
205
  <div class="upload-section">
206
  <form action="/analyze" method="post" enctype="multipart/form-data">
207
+ <input type="file" name="file" accept="image/*" required>
208
+ <br>
209
+ <button type="submit" class="button">Analysieren</button>
 
 
 
 
 
 
 
 
 
 
210
  </form>
211
  </div>
212
  </div>
 
226
  predictions_locator = models["KnochenAuge"](image)
227
 
228
  filtered_preds = [p for p in predictions_locator if p['score'] >= 0.6]
229
+ result_image = draw_boxes(image, filtered_preds) if filtered_preds else image
 
 
 
 
230
  result_image_b64 = image_to_base64(result_image)
231
 
232
  results_html = f"""
 
235
  <head>
236
  <title>Ergebnisse</title>
237
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
238
+ <style>{STYLES}</style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  </head>
240
  <body>
241
  <div class="container">
 
275
  </div>
276
  </div>
277
 
278
+ <a href="/" class="button">← Zurück</a>
 
 
 
279
  </div>
280
  </body>
281
  </html>
 
290
  <head>
291
  <title>Fehler</title>
292
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
293
+ <style>{STYLES}</style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  </head>
295
  <body>
296
  <div class="container">
297
+ <div class="result-box">
298
  <h3>Fehler</h3>
299
  <p>{str(e)}</p>
300
  </div>
301
+ <a href="/" class="button">← Zurück</a>
 
 
 
302
  </div>
303
  </body>
304
  </html>
305
  """
306
 
307
  if __name__ == "__main__":
308
+ import uvicorn
309
  uvicorn.run(app, host="0.0.0.0", port=7860)