GaetanoParente commited on
Commit
f1f081e
·
1 Parent(s): 7332220

update interface

Browse files
Files changed (3) hide show
  1. .gitignore +1 -0
  2. app.py +267 -89
  3. data/icon.png +0 -0
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ __pycache__/
app.py CHANGED
@@ -1,122 +1,300 @@
1
  import gradio as gr
2
- import tensorflow as tf
 
 
3
  from modules.binary_classification import binary_classification as binary
4
  from modules.image_classification import image_classification as image
5
  from modules.multilabel_classification import multi_classification as multi
6
  from modules.retina import predict_diabetic_retinopathy as retina_detector
7
- import cv2
 
8
 
9
  def binary_classification(text):
10
- if(text != ''):
11
  return binary(text)
12
- else:
13
- raise gr.Error('Il testo è obbligatorio!')
14
 
15
  def multi_classification(text):
16
- if(text != ''):
17
  try:
18
  return multi(text)
19
- except:
20
- raise gr.Error('La lingua del testo non corrisponde alla lingua del modello!')
21
- else:
22
- raise gr.Error('Il testo è obbligatorio!')
23
-
24
  def file_change(file):
25
  if isinstance(file, list):
26
  file = file[0]
27
-
28
  if file:
29
- image = cv2.imread(file)
30
- return image
31
  return None
32
 
33
  def image_classification(img):
34
- try:
35
  return image(img)
36
- except:
37
- raise gr.Error('L\'immagine è obbligatoria!')
38
-
39
- def file_change_dr(file):
40
- return file
41
 
42
  def retina_classification(retina):
43
- try:
44
  return retina_detector(retina)
45
- except:
46
- raise gr.Error('L\'immagine è obbligatoria!')
47
-
48
- with gr.Blocks() as demo:
49
- gr.Markdown("# NGT AI Platform")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
- with gr.Tab("Pneumonia/Tuberculosis Detection"):
52
- gr.Markdown("""
53
- Inviata una radiografia del petto, il servizio classifica la stessa come:\n
54
- 'Tubercolosi', 'No_Tubercolosi', 'Pneumonia', 'No_Pneumonia'
55
- """)
56
- with gr.Row(equal_height=True):
57
- file_selected = gr.FileExplorer(
58
- root_dir="data/gallery/xray",
59
- file_count='single',
60
- label='Esplora',
61
- height=400
 
 
62
  )
63
- image_input = gr.Image(show_download_button=False,
64
- show_share_button=False, sources=["upload"], height=400)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  with gr.Column():
66
- image_output = [gr.Label(label="Diagnosi", scale=1)]
67
- image_button = gr.Button("Analizza")
68
- with gr.Tab("Diabetic Retinopathy Detection"):
69
- gr.Markdown("""
70
- Questa interfaccia utilizza un modello di deep learning basato su rete neurale convoluzionale, in modo da predirre la presenza o meno di retinopatia diabetica a partire da un'immagine retinica
71
- """)
72
- with gr.Row(equal_height=True):
 
 
 
 
 
 
73
  with gr.Column(scale=1):
74
- file_selected_dr = gr.FileExplorer(
75
- root_dir="data/gallery/retinopaty",
76
- file_count='single',
77
- label='Esplora',
78
- height=400
79
- )
80
- with gr.Column(scale=2):
81
- with gr.Row():
82
- image_i = gr.Image(
83
- show_download_button=False,
84
- show_share_button=False,
85
- sources=["upload"],
86
- height=400
87
  )
88
- with gr.Column():
89
- image_o = [gr.Label(label="Diagnosi"), gr.Label(label="Probabilità di patologia")]
90
- image_button_dr = gr.Button("Analizza")
91
- with gr.Tab("Review Classification"):
92
- gr.Markdown("""
93
- Inviato un testo, il servizio classifica lo stesso come:\n
94
- 'Economia', 'Politica', 'Scienza_e_tecnica', 'Sport', 'Storia'
95
- """)
96
- with gr.Row(equal_height=True):
97
  with gr.Column():
98
- multi_classification_input = gr.Textbox()
 
 
 
 
 
 
 
 
 
 
 
99
  with gr.Column():
100
- multi_classification_output = gr.Label(num_top_classes=8)
101
- multi_classification_button = gr.Button("Analizza")
102
- with gr.Tab("Sentiment Analysis"):
103
- gr.Markdown("Inviato il testo di una recensione, il servizio classifica lo stesso come Positivo o Negativo")
104
- with gr.Row(equal_height=True):
105
  with gr.Column():
106
- binary_classification_input = gr.Textbox()
107
- with gr.Column(scale=1):
108
- binary_classification_output = gr.Label()
109
- binary_classification_button = gr.Button("Analizza")
110
-
111
-
112
-
113
- image_button.click(image_classification, inputs=image_input, outputs=image_output)
114
- image_button_dr.click(retina_classification, inputs=image_i, outputs=image_o)
115
- multi_classification_button.click(multi_classification, inputs=multi_classification_input, outputs=multi_classification_output)
116
- binary_classification_button.click(binary_classification, inputs=binary_classification_input, outputs=binary_classification_output)
117
-
118
- file_selected.change(file_change, inputs=file_selected, outputs=image_input)
119
- file_selected_dr.change(file_change_dr, inputs=file_selected_dr, outputs=image_i)
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
 
1
  import gradio as gr
2
+ import cv2
3
+ import os
4
+
5
  from modules.binary_classification import binary_classification as binary
6
  from modules.image_classification import image_classification as image
7
  from modules.multilabel_classification import multi_classification as multi
8
  from modules.retina import predict_diabetic_retinopathy as retina_detector
9
+
10
+ # -------------------------------------------------------------
11
 
12
  def binary_classification(text):
13
+ if text.strip():
14
  return binary(text)
15
+ raise gr.Error('Il testo è obbligatorio!')
 
16
 
17
  def multi_classification(text):
18
+ if text.strip():
19
  try:
20
  return multi(text)
21
+ except Exception as e:
22
+ raise gr.Error(f'Errore nel modello: {str(e)}')
23
+ raise gr.Error('Il testo è obbligatorio!')
24
+
 
25
  def file_change(file):
26
  if isinstance(file, list):
27
  file = file[0]
 
28
  if file:
29
+ return cv2.imread(file)
 
30
  return None
31
 
32
  def image_classification(img):
33
+ if img is not None:
34
  return image(img)
35
+ raise gr.Error('L\'immagine è obbligatoria!')
 
 
 
 
36
 
37
  def retina_classification(retina):
38
+ if retina is not None:
39
  return retina_detector(retina)
40
+ raise gr.Error('L\'immagine è obbligatoria!')
41
+
42
+ # --- CONFIGURAZIONE TEMA ---
43
+ theme = gr.themes.Soft(
44
+ primary_hue="purple",
45
+ neutral_hue="slate",
46
+ font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"],
47
+ ).set(
48
+ block_title_text_weight="700",
49
+ block_shadow="*shadow_drop_lg",
50
+ button_shadow="*shadow_drop_lg",
51
+ block_label_background_fill="*primary_100",
52
+ )
53
+
54
+ custom_css = """
55
+ /* --- 1. HEADER & LOGO --- */
56
+ .header-row {
57
+ display: flex !important;
58
+ align-items: flex-end !important;
59
+ gap: 20px !important;
60
+ margin-bottom: 30px !important;
61
+ padding-bottom: 20px;
62
+ border-bottom: 1px solid #e2e8f0;
63
+ }
64
+
65
+ .logo-container img {
66
+ margin-bottom: 4px !important;
67
+ object-fit: contain;
68
+ }
69
+
70
+ .header-text-col h1 {
71
+ font-family: 'Inter', sans-serif !important;
72
+ font-weight: 900 !important;
73
+ font-size: 2.2em !important;
74
+ background: linear-gradient(90deg, #D65DB1 0%, #8B5CF6 50%, #F43F5E 100%);
75
+ -webkit-background-clip: text;
76
+ -webkit-text-fill-color: transparent;
77
+ text-align: left !important;
78
+ margin-bottom: -2px !important;
79
+ padding-bottom: 0 !important;
80
+ line-height: 1.0 !important;
81
+ }
82
+
83
+ .header-text-col .subheader {
84
+ text-align: left !important;
85
+ color: #64748b;
86
+ font-size: 1.1em;
87
+ font-weight: 500;
88
+ margin-top: 0 !important;
89
+ padding-top: 0 !important;
90
+ }
91
+
92
+ /* --- 2. CUSTOM TABS STYLE (DESKTOP) --- */
93
+ .tabs > .tab-nav {
94
+ border-bottom: none !important;
95
+ gap: 8px !important;
96
+ margin-bottom: 15px !important;
97
+ }
98
+
99
+ .tabs > .tab-nav > button {
100
+ border: 1px solid #e5e7eb !important;
101
+ border-radius: 10px !important;
102
+ background-color: white;
103
+ color: #475569 !important;
104
+ font-weight: 600 !important;
105
+ transition: all 0.2s ease-in-out;
106
+ padding: 6px 16px !important;
107
+ }
108
+
109
+ .tabs > .tab-nav > button:hover {
110
+ background-color: #f1f5f9 !important;
111
+ transform: translateY(-1px);
112
+ }
113
+
114
+ .tabs > .tab-nav > button.selected {
115
+ background: linear-gradient(135deg, #8B5CF6 0%, #D65DB1 100%) !important;
116
+ color: white !important;
117
+ border: 1px solid transparent !important;
118
+ box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3) !important;
119
+ }
120
+
121
+ /* --- 3. PULSANTI PRIMARY --- */
122
+ button.primary {
123
+ background: linear-gradient(135deg, #8B5CF6 0%, #D65DB1 100%) !important;
124
+ border: none !important;
125
+ color: white !important;
126
+ transition: filter 0.2s;
127
+ }
128
+ button.primary:hover {
129
+ filter: brightness(1.1);
130
+ box-shadow: 0 4px 15px rgba(139, 92, 246, 0.4);
131
+ }
132
+
133
+ /* --- FIX ALLINEAMENTO ALTEZZA (Desktop) --- */
134
+ .fixed-height {
135
+ height: 380px !important;
136
+ overflow: hidden !important;
137
+ }
138
+ .fixed-height button,
139
+ .fixed-height .image-container,
140
+ .fixed-height .upload-container {
141
+ height: 100% !important;
142
+ max_height: 100% !important;
143
+ min_height: 100% !important;
144
+ }
145
+ .fixed-height img {
146
+ object-fit: contain !important;
147
+ max_height: 100% !important;
148
+ }
149
+
150
+ /* --- 4. MOBILE RESPONSIVE (Aggiornato per i TAB) --- */
151
+ @media (max-width: 768px) {
152
+ /* Header Stack */
153
+ .header-row {
154
+ flex-direction: column !important;
155
+ align-items: center !important;
156
+ text-align: center !important;
157
+ gap: 10px !important;
158
+ }
159
+ .header-text-col h1 {
160
+ text-align: center !important;
161
+ font-size: 1.8em !important;
162
+ }
163
+ .header-text-col .subheader {
164
+ text-align: center !important;
165
+ }
166
+
167
+ /* Layout Moduli Stack */
168
+ .responsive-row {
169
+ flex-direction: column !important;
170
+ display: flex !important;
171
+ }
172
+ .responsive-row > * {
173
+ width: 100% !important;
174
+ min-width: 100% !important;
175
+ margin-bottom: 15px !important;
176
+ }
177
+
178
+ /* --- NUOVA GESTIONE TAB MOBILE --- */
179
+ .tabs > .tab-nav {
180
+ flex-wrap: wrap !important; /* Permette di andare a capo */
181
+ justify-content: center !important; /* Centra i bottoni */
182
+ gap: 6px !important; /* Spazio ridotto tra i bottoni */
183
+ }
184
+
185
+ .tabs > .tab-nav > button {
186
+ flex-grow: 1 !important; /* Si allargano per riempire la riga */
187
+ text-align: center !important;
188
+ font-size: 0.85rem !important; /* Testo leggermente più piccolo */
189
+ padding: 8px 10px !important; /* Padding ottimizzato per il tocco */
190
+ margin: 0 !important;
191
+ width: auto !important; /* Lascia decidere al flex-grow */
192
+ min-width: 45% !important; /* Assicura che al massimo ci siano 2 tab per riga */
193
+ }
194
+ }
195
+
196
+ footer {visibility: hidden}
197
+ """
198
+
199
+ with gr.Blocks(theme=theme, css=custom_css, title="NGT AI Platform") as demo:
200
 
201
+ # --- HEADER ---
202
+ with gr.Row(elem_classes="header-row"):
203
+ with gr.Column(scale=0, min_width=80, elem_classes="logo-container"):
204
+ gr.Image(
205
+ value="data/icon.png",
206
+ show_label=False,
207
+ show_download_button=False,
208
+ show_share_button=False,
209
+ container=False,
210
+ show_fullscreen_button=False,
211
+ interactive=False,
212
+ height=80,
213
+ width=80
214
  )
215
+
216
+ with gr.Column(scale=1, elem_classes="header-text-col"):
217
+ gr.Markdown("""
218
+ <h1>NGT AI Platform</h1>
219
+ <div class='subheader'>Advanced Machine Learning Solutions</div>
220
+ """)
221
+
222
+ # --- TAB 1: Chest X-Ray ---
223
+ with gr.Tab("🩻 Chest Diagnosis"):
224
+ gr.Markdown("### 📥 Diagnostica Polmonare")
225
+ gr.Markdown("Carica una radiografia o selezionane una dalla gallery per rilevare **Polmonite** o **Tubercolosi**.")
226
+
227
+ # Aggiunta classe "responsive-row" e rimosso equal_height=True (lo gestiamo col CSS se serve)
228
+ with gr.Row(elem_classes="responsive-row"):
229
+ with gr.Column(scale=1):
230
+ with gr.Accordion("📂 1. Seleziona da Gallery", open=True):
231
+ file_selected = gr.FileExplorer(
232
+ root_dir="data/gallery/xray",
233
+ file_count='single',
234
+ height=274 # Su desktop usa questo, su mobile il layout stackerà
235
+ )
236
+ with gr.Column(scale=1):
237
+ image_input = gr.Image(type="numpy", height=320, label="2. Visualizzazione / Upload Manuale")
238
+
239
+ with gr.Row():
240
  with gr.Column():
241
+ analyze_btn_chest = gr.Button("🔍 Avvia Diagnosi Clinica", variant="primary", size="lg")
242
+ image_output = gr.Label(num_top_classes=2, label="Risultato Predittivo")
243
+
244
+ file_selected.change(file_change, inputs=file_selected, outputs=image_input)
245
+ analyze_btn_chest.click(image_classification, inputs=image_input, outputs=image_output)
246
+
247
+ # --- TAB 2: Diabetic Retinopathy ---
248
+ with gr.Tab("👁️ Diabetic Retinopathy"):
249
+ gr.Markdown("### 📥 Analisi Retinica")
250
+ gr.Markdown("Deep Learning per la predizione della retinopatia diabetica.")
251
+
252
+ # Aggiunta classe "responsive-row"
253
+ with gr.Row(elem_classes="responsive-row"):
254
  with gr.Column(scale=1):
255
+ with gr.Accordion("📂 1. Seleziona da Gallery", open=True):
256
+ file_selected_dr = gr.FileExplorer(
257
+ root_dir="data/gallery/retinopaty",
258
+ file_count='single',
259
+ height=274
 
 
 
 
 
 
 
 
260
  )
261
+ with gr.Column(scale=1):
262
+ image_input_dr = gr.Image(type="numpy", height=320, label="2. Visualizzazione / Upload Manuale")
263
+
264
+ with gr.Row():
 
 
 
 
 
265
  with gr.Column():
266
+ analyze_btn_dr = gr.Button("🔍 Analizza Retina", variant="primary", size="lg")
267
+ with gr.Group():
268
+ output_dr_label = gr.Label(label="Diagnosi Principale")
269
+ output_dr_prob = gr.Label(label="Probabilità Patologia")
270
+
271
+ file_selected_dr.change(file_change, inputs=file_selected_dr, outputs=image_input_dr)
272
+ analyze_btn_dr.click(retina_classification, inputs=image_input_dr, outputs=[output_dr_label, output_dr_prob])
273
+
274
+ # --- TAB 3: Review Classification ---
275
+ with gr.Tab("📰 Topic Classification"):
276
+ gr.Markdown("### Analisi Argomenti del Testo")
277
+ with gr.Row():
278
  with gr.Column():
279
+ multi_input = gr.Textbox(lines=5, placeholder="Incolla qui il testo...", label="Input")
280
+ analyze_btn_multi = gr.Button("🏷️ Classifica", variant="primary")
 
 
 
281
  with gr.Column():
282
+ multi_output = gr.Label(num_top_classes=5, label="Top Categorie")
 
 
 
 
 
 
 
 
 
 
 
 
 
283
 
284
+ gr.Examples(examples=[["La NASA ha lanciato un nuovo satellite."], ["Il prezzo della GPU è sceso."]], inputs=multi_input)
285
+ analyze_btn_multi.click(multi_classification, inputs=multi_input, outputs=multi_output)
286
+
287
+ # --- TAB 4: Sentiment Analysis ---
288
+ with gr.Tab("😊 Sentiment Analysis"):
289
+ gr.Markdown("### Analisi del Sentiment")
290
+ with gr.Row():
291
+ with gr.Column():
292
+ binary_input = gr.Textbox(lines=3, placeholder="Scrivi una recensione...", label="Input")
293
+ analyze_btn_bin = gr.Button("⚖️ Analizza", variant="primary")
294
+ with gr.Column():
295
+ binary_output = gr.Label(label="Sentiment Score")
296
+
297
+ analyze_btn_bin.click(binary_classification, inputs=binary_input, outputs=binary_output)
298
 
299
+ if __name__ == "__main__":
300
+ demo.launch(server_name="0.0.0.0", server_port=7860, allowed_paths=["data"])
data/icon.png ADDED