yassonee commited on
Commit
2c3deb2
·
verified ·
1 Parent(s): 5879dd0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -286
app.py CHANGED
@@ -1,301 +1,96 @@
1
- from fastapi import FastAPI, File, UploadFile
2
- from fastapi.responses import HTMLResponse
3
- from transformers import AutoImageProcessor, AutoModelForImageClassification, 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 image_to_base64(image):
20
- buffered = io.BytesIO()
21
- image.save(buffered, format="PNG")
22
- img_str = base64.b64encode(buffered.getvalue()).decode()
23
- return f"data:image/png;base64,{img_str}"
24
-
25
- COMMON_STYLES = """
26
- body {
27
- font-family: system-ui, -apple-system, sans-serif;
28
- background: #f0f2f5;
29
- margin: 0;
30
- padding: 20px;
31
- color: #1a1a1a;
32
- }
33
- ::-webkit-scrollbar {
34
- width: 8px;
35
- height: 8px;
36
- }
37
 
38
- ::-webkit-scrollbar-track {
39
- background: transparent;
40
- }
41
 
42
- ::-webkit-scrollbar-thumb {
43
- background-color: rgba(156, 163, 175, 0.5);
44
- border-radius: 4px;
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
- .container {
48
- max-width: 1200px;
49
- margin: 0 auto;
50
- background: white;
51
- padding: 20px;
52
- border-radius: 10px;
53
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
54
- }
55
- .button {
56
- background: #2d2d2d;
57
- color: white;
58
- border: none;
59
- padding: 12px 30px;
60
- border-radius: 8px;
61
- cursor: pointer;
62
- font-size: 1.1em;
63
- transition: all 0.3s ease;
64
- position: relative;
65
- }
66
- .button:hover {
67
- background: #404040;
68
- }
69
- @keyframes progress {
70
- 0% { width: 0; }
71
- 100% { width: 100%; }
72
- }
73
- @keyframes blink {
74
- 0% { opacity: 1; }
75
- 50% { opacity: 0; }
76
- 100% { opacity: 1; }
77
- }
78
- #loading {
79
- display: none;
80
- color: white;
81
- margin-top: 10px;
82
- animation: blink 1s infinite;
83
- text-align: center;
84
- }
85
- .button-progress {
86
- position: absolute;
87
- bottom: 0;
88
- left: 0;
89
- height: 4px;
90
- background: rgba(255, 255, 255, 0.5);
91
- width: 0;
92
- }
93
- .button:active .button-progress {
94
- animation: progress 2s linear forwards;
95
- }
96
- img {
97
- max-width: 100%;
98
- height: auto;
99
- border-radius: 8px;
100
- }
101
- """
102
-
103
- @app.get("/", response_class=HTMLResponse)
104
- async def main():
105
- content = f"""
106
- <!DOCTYPE html>
107
- <html>
108
- <head>
109
- <title>Chest X-Ray Analysis</title>
110
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
111
- <style>
112
- {COMMON_STYLES}
113
-
114
- .upload-section {{
115
- background: #2d2d2d;
116
- padding: 40px;
117
- border-radius: 12px;
118
- margin: 20px 0;
119
- text-align: center;
120
- border: 2px dashed #404040;
121
- transition: all 0.3s ease;
122
- color: white;
123
- }}
124
- .upload-section:hover {{
125
- border-color: #555;
126
- }}
127
- input[type="file"] {{
128
- font-size: 1.1em;
129
- margin: 20px 0;
130
- color: white;
131
- }}
132
- input[type="file"]::file-selector-button {{
133
- font-size: 1em;
134
- padding: 10px 20px;
135
- border-radius: 8px;
136
- border: 1px solid #404040;
137
- background: #2d2d2d;
138
- color: white;
139
- transition: all 0.3s ease;
140
- cursor: pointer;
141
- }}
142
- input[type="file"]::file-selector-button:hover {{
143
- background: #404040;
144
- }}
145
- .preview-image {{
146
- max-width: 300px;
147
- margin: 20px auto;
148
- display: none;
149
- }}
150
- </style>
151
- </head>
152
- <body>
153
- <div class="container">
154
- <div class="upload-section">
155
- <form action="/analyze" method="post" enctype="multipart/form-data" onsubmit="document.getElementById('loading').style.display = 'block';">
156
- <div>
157
- <input type="file" name="file" accept="image/*" required
158
- onchange="document.getElementById('preview').src = window.URL.createObjectURL(this.files[0]);
159
- document.getElementById('preview').style.display = 'block';">
160
- </div>
161
- <img id="preview" class="preview-image" src="" alt="Preview">
162
- <button type="submit" class="button">
163
- Analyze X-Ray
164
- <div class="button-progress"></div>
165
- </button>
166
- <div id="loading">Loading...</div>
167
- </form>
168
- </div>
169
- </div>
170
- </body>
171
- </html>
172
- """
173
- return content
174
 
175
- @app.post("/analyze", response_class=HTMLResponse)
176
- async def analyze_file(file: UploadFile = File(...)):
177
  try:
178
- contents = await file.read()
179
- image = Image.open(io.BytesIO(contents))
180
 
181
- # Get predictions from the model
182
- predictions = models["chest_classifier"](image)
183
 
184
- result_image_b64 = image_to_base64(image)
 
185
 
186
- results_html = f"""
187
- <!DOCTYPE html>
188
- <html>
189
- <head>
190
- <title>Results</title>
191
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
192
- <style>
193
- {COMMON_STYLES}
194
-
195
- .results-grid {{
196
- display: grid;
197
- grid-template-columns: 1fr 1fr;
198
- gap: 20px;
199
- margin-top: 20px;
200
- }}
201
- .result-box {{
202
- background: white;
203
- padding: 20px;
204
- border-radius: 12px;
205
- margin: 10px 0;
206
- border: 1px solid #e9ecef;
207
- }}
208
- .score-high {{
209
- color: #0066cc;
210
- font-weight: bold;
211
- }}
212
- .score-medium {{
213
- color: #ffa500;
214
- font-weight: bold;
215
- }}
216
- .back-button {{
217
- display: inline-block;
218
- text-decoration: none;
219
- margin-top: 20px;
220
- }}
221
- h3 {{
222
- color: #0066cc;
223
- margin-top: 0;
224
- }}
225
- @media (max-width: 768px) {{
226
- .results-grid {{
227
- grid-template-columns: 1fr;
228
- }}
229
- }}
230
- </style>
231
- </head>
232
- <body>
233
- <div class="container">
234
- <div class="results-grid">
235
- <div class="result-box">
236
- <h3>Analysis Results</h3>
237
- """
238
 
239
- for pred in predictions:
240
- confidence_class = "score-high" if pred['score'] > 0.7 else "score-medium"
241
- results_html += f"""
242
- <div>
243
- <span class="{confidence_class}">{pred['score']:.1%}</span> -
244
- {pred['label']}
245
- </div>
246
- """
247
-
248
- results_html += f"""
249
- </div>
250
- <div class='result-box'>
251
- <h3>X-Ray Image</h3>
252
- <img src="{result_image_b64}" alt="Analyzed X-Ray">
253
- </div>
254
- </div>
255
-
256
- <a href="/" class="button back-button">
257
- ← Back
258
- <div class="button-progress"></div>
259
- </a>
260
- </div>
261
- </body>
262
- </html>
263
- """
264
-
265
- return results_html
266
 
 
267
  except Exception as e:
268
- return f"""
269
- <!DOCTYPE html>
270
- <html>
271
- <head>
272
- <title>Error</title>
273
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
274
- <style>
275
- {COMMON_STYLES}
276
- .error-box {{
277
- background: #fee2e2;
278
- border: 1px solid #ef4444;
279
- padding: 20px;
280
- border-radius: 8px;
281
- margin: 20px 0;
282
- }}
283
- </style>
284
- </head>
285
- <body>
286
- <div class="container">
287
- <div class="error-box">
288
- <h3>Error</h3>
289
- <p>{str(e)}</p>
290
- </div>
291
- <a href="/" class="button back-button">
292
- ← Back
293
- <div class="button-progress"></div>
294
- </a>
295
- </div>
296
- </body>
297
- </html>
298
- """
 
299
 
300
- if __name__ == "__main__":
301
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
1
+ import gradio as gr
2
+ from transformers import pipeline
3
+ import torch
4
+ from PIL import Image, ImageDraw
5
+ import numpy as np
 
 
 
 
6
 
7
  # Chargement des modèles
8
+ classifier = pipeline("image-classification", model="abhishek/chest-xray-classification")
9
+ detector = pipeline("object-detection", model="nickysam/detect-thorax-anomaly-75acc")
 
 
 
 
10
 
11
+ def draw_boxes(image, predictions):
12
+ # Convertir l'image numpy en PIL si nécessaire
13
+ if isinstance(image, np.ndarray):
14
+ image = Image.fromarray(np.uint8(image))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
+ draw = ImageDraw.Draw(image)
 
 
17
 
18
+ # Dessiner les boîtes de détection
19
+ for pred in predictions:
20
+ box = pred['box']
21
+ score = pred['score']
22
+ label = pred['label']
23
+
24
+ # Coordonnées de la boîte
25
+ x1, y1 = box['xmin'], box['ymin']
26
+ x2, y2 = box['xmax'], box['ymax']
27
+
28
+ # Couleur en fonction du score
29
+ color = (255, 0, 0) if score > 0.7 else (255, 165, 0)
30
+
31
+ # Dessiner le rectangle
32
+ draw.rectangle([x1, y1, x2, y2], outline=color, width=2)
33
+
34
+ # Ajouter le label et le score
35
+ label_text = f"{label}: {score:.1%}"
36
+ draw.text((x1, y1-15), label_text, fill=color)
37
 
38
+ return image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
+ def analyze_xray(image):
 
41
  try:
42
+ # Classification générale
43
+ classifications = classifier(image)
44
 
45
+ # Détection des anomalies
46
+ detections = detector(image)
47
 
48
+ # Dessiner les boîtes sur l'image
49
+ annotated_image = draw_boxes(image, detections)
50
 
51
+ # Préparer les résultats
52
+ results = "Classifications:\n"
53
+ for pred in classifications:
54
+ results += f"{pred['label']}: {pred['score']:.1%}\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
+ results += "\nDetected Anomalies:\n"
57
+ for det in detections:
58
+ results += f"{det['label']}: {det['score']:.1%}\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
+ return annotated_image, results
61
  except Exception as e:
62
+ return image, f"Error: {str(e)}"
63
+
64
+ # Interface Gradio
65
+ with gr.Blocks(theme=gr.themes.Soft(
66
+ primary_hue="gray",
67
+ secondary_hue="gray",
68
+ )) as demo:
69
+ gr.Markdown("""
70
+ # Chest X-Ray Analysis
71
+ This application analyzes chest X-rays to:
72
+ 1. Classify general conditions
73
+ 2. Detect and locate specific anomalies
74
+ """)
75
+
76
+ with gr.Row():
77
+ with gr.Column():
78
+ input_image = gr.Image(label="Upload X-Ray Image", type="pil")
79
+ analyze_btn = gr.Button("Analyze", variant="primary")
80
+
81
+ with gr.Column():
82
+ output_image = gr.Image(label="Analyzed Image")
83
+ output_text = gr.Textbox(label="Results", lines=10)
84
+
85
+ analyze_btn.click(
86
+ fn=analyze_xray,
87
+ inputs=[input_image],
88
+ outputs=[output_image, output_text]
89
+ )
90
+
91
+ gr.Markdown("""
92
+ Note: This tool is for demonstration purposes only and should not be used for medical diagnosis.
93
+ """)
94
 
95
+ # Lancement de l'application
96
+ demo.launch()