yassonee commited on
Commit
2ee10cf
·
verified ·
1 Parent(s): e0e7f99

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -89
app.py CHANGED
@@ -1,47 +1,30 @@
1
  from fastapi import FastAPI, File, UploadFile
2
  from fastapi.responses import HTMLResponse
3
- from transformers import AutoImageProcessor, AutoModelForImageClassification
4
  from PIL import Image
5
  import io
6
- import torch
7
  import uvicorn
8
  import base64
9
 
10
  app = FastAPI()
11
 
12
- # Laden der Modelle und des Processors
13
  def load_models():
14
- processor = AutoImageProcessor.from_pretrained("codewithdark/vit-chest-xray")
15
- model = AutoModelForImageClassification.from_pretrained("codewithdark/vit-chest-xray")
16
  return {
17
- "processor": processor,
18
- "model": model
19
  }
20
 
21
  models = load_models()
22
 
23
- # Definition der Krankheitsbezeichnungen
24
- LABEL_COLUMNS = ['Kardiomegalie', 'Ödem', 'Konsolidierung', 'Lungenentzündung', 'Kein Befund']
25
-
26
- def analyze_image(image):
27
- if image.mode != 'RGB':
28
- image = image.convert('RGB')
29
-
30
- inputs = models["processor"](images=image, return_tensors="pt")
31
-
32
- with torch.no_grad():
33
- outputs = models["model"](**inputs)
34
-
35
- probs = torch.nn.functional.softmax(outputs.logits, dim=-1)[0]
36
- predictions = []
37
-
38
- for idx, (label, prob) in enumerate(zip(LABEL_COLUMNS, probs)):
39
- predictions.append({
40
- 'label': label,
41
- 'score': prob.item()
42
- })
43
-
44
- return sorted(predictions, key=lambda x: x['score'], reverse=True)
45
 
46
  def image_to_base64(image):
47
  buffered = io.BytesIO()
@@ -57,6 +40,20 @@ COMMON_STYLES = """
57
  padding: 20px;
58
  color: #1a1a1a;
59
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  .container {
61
  max-width: 1200px;
62
  margin: 0 auto;
@@ -74,73 +71,42 @@ COMMON_STYLES = """
74
  cursor: pointer;
75
  font-size: 1.1em;
76
  transition: all 0.3s ease;
 
77
  }
78
  .button:hover {
79
  background: #404040;
80
  }
81
- .upload-section {
82
- background: #2d2d2d;
83
- padding: 40px;
84
- border-radius: 12px;
85
- margin: 20px 0;
86
- text-align: center;
87
- border: 2px dashed #404040;
88
- transition: all 0.3s ease;
89
- color: white;
90
  }
91
- .upload-section:hover {
92
- border-color: #555;
 
 
 
 
 
93
  }
94
- #loading {
95
- display: none;
96
- color: white;
97
- margin-top: 10px;
98
- animation: blink 1s infinite;
99
- text-align: center;
 
100
  }
101
  @keyframes blink {
102
  0% { opacity: 1; }
103
  50% { opacity: 0; }
104
  100% { opacity: 1; }
105
  }
106
- .preview-image {
107
- max-width: 300px;
108
- margin: 20px auto;
109
  display: none;
110
- }
111
- .results-grid {
112
- display: grid;
113
- grid-template-columns: 1fr 1fr;
114
- gap: 20px;
115
- margin-top: 20px;
116
- }
117
- .result-box {
118
- background: white;
119
- padding: 20px;
120
- border-radius: 12px;
121
- margin: 10px 0;
122
- border: 1px solid #e9ecef;
123
- }
124
- .analyzed-image {
125
- max-width: 400px;
126
- margin: 0 auto;
127
- }
128
- .score-high {
129
- color: #0066cc;
130
- font-weight: bold;
131
- }
132
- .score-medium {
133
- color: #ffa500;
134
- font-weight: bold;
135
- }
136
- h3 {
137
- color: #0066cc;
138
- margin-top: 0;
139
- }
140
- @media (max-width: 768px) {
141
- .results-grid {
142
- grid-template-columns: 1fr;
143
- }
144
  }
145
  """
146
 
@@ -150,17 +116,52 @@ async def main():
150
  <!DOCTYPE html>
151
  <html>
152
  <head>
153
- <title>Röntgenbild-Analyse</title>
154
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
155
  <style>
156
  {COMMON_STYLES}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  </style>
158
  </head>
159
  <body>
160
  <div class="container">
161
  <div class="upload-section">
162
- <form action="/analyze" method="post" enctype="multipart/form-data"
163
- onsubmit="document.getElementById('loading').style.display = 'block';">
164
  <div>
165
  <label for="file-upload" class="file-upload-label">
166
  Röntgenbild auswählen
@@ -169,6 +170,7 @@ async def main():
169
  </div>
170
  <button type="submit" class="button">
171
  Analysieren
 
172
  </button>
173
  <div id="loading">Wird geladen...</div>
174
  </form>
@@ -185,7 +187,7 @@ async def analyze_file(file: UploadFile = File(...)):
185
  contents = await file.read()
186
  image = Image.open(io.BytesIO(contents))
187
 
188
- predictions = analyze_image(image)
189
  result_image_b64 = image_to_base64(image)
190
 
191
  results_html = f"""
@@ -196,6 +198,42 @@ async def analyze_file(file: UploadFile = File(...)):
196
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
197
  <style>
198
  {COMMON_STYLES}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  </style>
200
  </head>
201
  <body>
@@ -210,7 +248,7 @@ async def analyze_file(file: UploadFile = File(...)):
210
  results_html += f"""
211
  <div>
212
  <span class="{confidence_class}">{pred['score']:.1%}</span> -
213
- {pred['label']}
214
  </div>
215
  """
216
 
@@ -218,12 +256,13 @@ async def analyze_file(file: UploadFile = File(...)):
218
  </div>
219
  <div class="result-box">
220
  <h3>Röntgenbild</h3>
221
- <img src="{result_image_b64}" alt="Analysiertes Röntgenbild" class="analyzed-image">
222
  </div>
223
  </div>
224
 
225
  <a href="/" class="button back-button">
226
  ← Zurück
 
227
  </a>
228
  </div>
229
  </body>
@@ -258,6 +297,7 @@ async def analyze_file(file: UploadFile = File(...)):
258
  </div>
259
  <a href="/" class="button back-button">
260
  ← Zurück
 
261
  </a>
262
  </div>
263
  </body>
 
1
  from fastapi import FastAPI, File, UploadFile
2
  from fastapi.responses import HTMLResponse
3
+ from transformers import pipeline
4
  from PIL import Image
5
  import io
 
6
  import uvicorn
7
  import base64
8
 
9
  app = FastAPI()
10
 
11
+ # Chargement des modèles
12
  def load_models():
 
 
13
  return {
14
+ "chest_classifier": pipeline("image-classification", model="codewithdark/vit-chest-xray")
 
15
  }
16
 
17
  models = load_models()
18
 
19
+ def translate_label(label):
20
+ translations = {
21
+ 'Cardiomegaly': 'Kardiomegalie',
22
+ 'Edema': 'Ödem',
23
+ 'Consolidation': 'Konsolidierung',
24
+ 'Pneumonia': 'Lungenentzündung',
25
+ 'No Finding': 'Kein Befund'
26
+ }
27
+ return translations.get(label, label)
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  def image_to_base64(image):
30
  buffered = io.BytesIO()
 
40
  padding: 20px;
41
  color: #1a1a1a;
42
  }
43
+ ::-webkit-scrollbar {
44
+ width: 8px;
45
+ height: 8px;
46
+ }
47
+
48
+ ::-webkit-scrollbar-track {
49
+ background: transparent;
50
+ }
51
+
52
+ ::-webkit-scrollbar-thumb {
53
+ background-color: rgba(156, 163, 175, 0.5);
54
+ border-radius: 4px;
55
+ }
56
+
57
  .container {
58
  max-width: 1200px;
59
  margin: 0 auto;
 
71
  cursor: pointer;
72
  font-size: 1.1em;
73
  transition: all 0.3s ease;
74
+ position: relative;
75
  }
76
  .button:hover {
77
  background: #404040;
78
  }
79
+ @keyframes progress {
80
+ 0% { width: 0; }
81
+ 100% { width: 100%; }
 
 
 
 
 
 
82
  }
83
+ .button-progress {
84
+ position: absolute;
85
+ bottom: 0;
86
+ left: 0;
87
+ height: 4px;
88
+ background: rgba(255, 255, 255, 0.5);
89
+ width: 0;
90
  }
91
+ .button:active .button-progress {
92
+ animation: progress 2s linear forwards;
93
+ }
94
+ img {
95
+ max-width: 100%;
96
+ height: auto;
97
+ border-radius: 8px;
98
  }
99
  @keyframes blink {
100
  0% { opacity: 1; }
101
  50% { opacity: 0; }
102
  100% { opacity: 1; }
103
  }
104
+ #loading {
 
 
105
  display: none;
106
+ color: white;
107
+ margin-top: 10px;
108
+ animation: blink 1s infinite;
109
+ text-align: center;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  }
111
  """
112
 
 
116
  <!DOCTYPE html>
117
  <html>
118
  <head>
119
+ <title>Thorax-Röntgen Analyse</title>
120
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
121
  <style>
122
  {COMMON_STYLES}
123
+
124
+ .upload-section {{
125
+ background: #2d2d2d;
126
+ padding: 40px;
127
+ border-radius: 12px;
128
+ margin: 20px 0;
129
+ text-align: center;
130
+ border: 2px dashed #404040;
131
+ transition: all 0.3s ease;
132
+ color: white;
133
+ }}
134
+ .upload-section:hover {{
135
+ border-color: #555;
136
+ }}
137
+ input[type="file"] {{
138
+ width: 0.1px;
139
+ height: 0.1px;
140
+ opacity: 0;
141
+ overflow: hidden;
142
+ position: absolute;
143
+ z-index: -1;
144
+ }}
145
+ .file-upload-label {{
146
+ display: inline-block;
147
+ padding: 12px 30px;
148
+ background: #404040;
149
+ color: white;
150
+ border-radius: 8px;
151
+ cursor: pointer;
152
+ font-size: 1.1em;
153
+ transition: all 0.3s ease;
154
+ margin: 20px 0;
155
+ }}
156
+ .file-upload-label:hover {{
157
+ background: #555;
158
+ }}
159
  </style>
160
  </head>
161
  <body>
162
  <div class="container">
163
  <div class="upload-section">
164
+ <form action="/analyze" method="post" enctype="multipart/form-data" onsubmit="document.getElementById('loading').style.display = 'block';">
 
165
  <div>
166
  <label for="file-upload" class="file-upload-label">
167
  Röntgenbild auswählen
 
170
  </div>
171
  <button type="submit" class="button">
172
  Analysieren
173
+ <div class="button-progress"></div>
174
  </button>
175
  <div id="loading">Wird geladen...</div>
176
  </form>
 
187
  contents = await file.read()
188
  image = Image.open(io.BytesIO(contents))
189
 
190
+ predictions = models["chest_classifier"](image)
191
  result_image_b64 = image_to_base64(image)
192
 
193
  results_html = f"""
 
198
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
199
  <style>
200
  {COMMON_STYLES}
201
+
202
+ .results-grid {{
203
+ display: grid;
204
+ grid-template-columns: 1fr 1fr;
205
+ gap: 20px;
206
+ margin-top: 20px;
207
+ }}
208
+ .result-box {{
209
+ background: white;
210
+ padding: 20px;
211
+ border-radius: 12px;
212
+ margin: 10px 0;
213
+ border: 1px solid #e9ecef;
214
+ }}
215
+ .score-high {{
216
+ color: #0066cc;
217
+ font-weight: bold;
218
+ }}
219
+ .score-medium {{
220
+ color: #ffa500;
221
+ font-weight: bold;
222
+ }}
223
+ .back-button {{
224
+ display: inline-block;
225
+ text-decoration: none;
226
+ margin-top: 20px;
227
+ }}
228
+ h3 {{
229
+ color: #0066cc;
230
+ margin-top: 0;
231
+ }}
232
+ @media (max-width: 768px) {{
233
+ .results-grid {{
234
+ grid-template-columns: 1fr;
235
+ }}
236
+ }}
237
  </style>
238
  </head>
239
  <body>
 
248
  results_html += f"""
249
  <div>
250
  <span class="{confidence_class}">{pred['score']:.1%}</span> -
251
+ {translate_label(pred['label'])}
252
  </div>
253
  """
254
 
 
256
  </div>
257
  <div class="result-box">
258
  <h3>Röntgenbild</h3>
259
+ <img src="{result_image_b64}" alt="Analysiertes Röntgenbild">
260
  </div>
261
  </div>
262
 
263
  <a href="/" class="button back-button">
264
  ← Zurück
265
+ <div class="button-progress"></div>
266
  </a>
267
  </div>
268
  </body>
 
297
  </div>
298
  <a href="/" class="button back-button">
299
  ← Zurück
300
+ <div class="button-progress"></div>
301
  </a>
302
  </div>
303
  </body>