Naahbi commited on
Commit
d0ea483
·
verified ·
1 Parent(s): 337bea6

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +374 -0
  2. requirements.txt +4 -0
app.py ADDED
@@ -0,0 +1,374 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import ViTForImageClassification, ViTFeatureExtractor
2
+ from PIL import Image
3
+ import torch
4
+
5
+ # Loading in Model
6
+ device = "cuda" if torch.cuda.is_available() else "cpu"
7
+ model = ViTForImageClassification.from_pretrained("imjeffhi/pokemon_classifier").to(device)
8
+ feature_extractor = ViTFeatureExtractor.from_pretrained('imjeffhi/pokemon_classifier')
9
+
10
+
11
+ def predicted_pokemon(img):
12
+ extracted = feature_extractor(images=img, return_tensors='pt').to(device)
13
+ predicted_id = model(**extracted).logits.argmax(-1).item()
14
+ predicted_pokemon = model.config.id2label[predicted_id]
15
+ return predicted_id, predicted_pokemon
16
+
17
+
18
+ """## Platform code
19
+
20
+ """
21
+
22
+ import os
23
+ import gradio as gr
24
+ import json
25
+
26
+ BASE_DIR = 'my_project'
27
+ os.makedirs(BASE_DIR, exist_ok=True)
28
+
29
+ IMG_DIR = os.path.join(BASE_DIR, 'images')
30
+ os.makedirs(IMG_DIR, exist_ok=True)
31
+
32
+ JSON_DATA_DIR = os.path.join(BASE_DIR, 'results')
33
+ os.makedirs(JSON_DATA_DIR, exist_ok=True)
34
+ JSON_USERS_PATH = os.path.join(BASE_DIR, 'users.json')
35
+
36
+ """### main codes"""
37
+
38
+
39
+ def show_page(page_name, username):
40
+ if page_name == 'classifier':
41
+ return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)
42
+ elif page_name == 'archive':
43
+ archive_msg, archive_df = show_archive(username)
44
+ return gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), archive_msg, archive_df
45
+ elif page_name == 'login':
46
+ return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)
47
+
48
+
49
+ def save_result(img: Image.Image, predicted_id, predicted_pokemon, username):
50
+ # controlli di sicurezza
51
+ if img is None:
52
+ return "Error: no image uploaded!"
53
+ if predicted_id is None or predicted_id == "":
54
+ return "Error: classify first!"
55
+ if predicted_pokemon is None or predicted_pokemon == "":
56
+ return "Error: classify first!"
57
+ if username == 'user' or username == '':
58
+ return "Error: sign-in first"
59
+
60
+ now = datetime.now()
61
+ timestamp_file = now.strftime('%Y-%m-%d-%H-%M-%S')
62
+ timestamp_json = now.isoformat()
63
+
64
+ # Salva l'immagine
65
+ img_path = os.path.join(IMG_DIR, username, f'{timestamp_file}.jpg')
66
+ os.makedirs(os.path.dirname(img_path), exist_ok=True)
67
+ img.save(img_path)
68
+
69
+ json_path = os.path.join(JSON_DATA_DIR, f'{username}.json')
70
+ # Leggi JSON esistente
71
+ try:
72
+ with open(json_path, "r") as f:
73
+ results = json.load(f)
74
+ except FileNotFoundError:
75
+ results = []
76
+
77
+ results.append({
78
+ 'timestamp': timestamp_json,
79
+ 'image_path': os.path.relpath(img_path, BASE_DIR),
80
+ 'predicted_id': int(predicted_id),
81
+ 'predicted_pokemon': predicted_pokemon
82
+ })
83
+
84
+ with open(json_path, "w") as f:
85
+ json.dump(results, f, indent=2)
86
+
87
+ return gr.update(value="Results saved successfully!", visible=True)
88
+
89
+
90
+ # laod dell'archivio
91
+ def show_archive(username):
92
+ json_path = os.path.join(JSON_DATA_DIR, f'{username}.json')
93
+ if not os.path.exists(json_path):
94
+ return gr.update(value="Nessun record salvato.", visible=True), gr.update(visible=False)
95
+
96
+ with open(json_path, "r") as f:
97
+ archive_data = json.load(f)
98
+
99
+ if not archive_data:
100
+ return gr.update(value="Nessun record salvato.", visible=True), gr.update(visible=False)
101
+
102
+ rows = []
103
+ for row in archive_data:
104
+ rows.append([row["timestamp"],
105
+ row["predicted_id"],
106
+ row["predicted_pokemon"],
107
+ row["image_path"]])
108
+
109
+ return gr.update(value="", visible=False), gr.update(value=rows, visible=True)
110
+
111
+
112
+ def show_image(evt: gr.SelectData):
113
+ img_path = evt.row_value[3]
114
+ return gr.update(value=os.path.join(BASE_DIR, img_path), visible=True), gr.update(value=img_path), gr.update(
115
+ visible=True)
116
+
117
+
118
+ def delete_record(table_data, img_path, username):
119
+ if img_path is None:
120
+ return gr.update(value=table_data)
121
+
122
+ if os.path.exists(os.path.join(BASE_DIR, img_path)):
123
+ os.remove(os.path.join(BASE_DIR, img_path))
124
+
125
+ json_path = os.path.join(JSON_DATA_DIR, f'{username}.json')
126
+ if os.path.exists(json_path):
127
+ with open(json_path, "r") as f:
128
+ results = json.load(f)
129
+ results = [r for r in results if r["image_path"] != img_path]
130
+ with open(json_path, "w") as f:
131
+ json.dump(results, f, indent=2)
132
+
133
+ rows = []
134
+ for row in results:
135
+ rows.append([row["timestamp"],
136
+ row["predicted_id"],
137
+ row["predicted_pokemon"],
138
+ row["image_path"]])
139
+
140
+ return gr.update(value=rows, visible=True), gr.update(value=None, visible=False), gr.update(visible=False)
141
+
142
+
143
+ def signin(user, psw):
144
+ if not os.path.exists(JSON_USERS_PATH):
145
+ return (
146
+ gr.update(value='Password e/o Nome utente errato', visible=True), # login_msg
147
+ gr.update(value='user', visible=False), # username_sb
148
+ gr.update(visible=True), # login_pg
149
+ gr.update(visible=False), # archive_sb_btn
150
+ gr.update(visible=True), # sign_sb_btn
151
+ gr.update(visible=False), # delete_sb_btn
152
+ gr.update(visible=False), # save_btn
153
+ gr.update(visible=False) # classifier_pg
154
+ )
155
+ else:
156
+ path = JSON_USERS_PATH
157
+ with open(path, 'r') as f:
158
+ users = json.load(f)
159
+ for u in users:
160
+ if u['username'].lower() == user.lower() and u['password'] == psw:
161
+ return (
162
+ gr.update(value='Login effettuato', visible=True), # login_msg
163
+ gr.update(value=f"**{user.upper()}**", visible=True), # username_sb
164
+ gr.update(visible=False), # login_pg
165
+ gr.update(visible=True), # archive_sb_btn
166
+ gr.update(visible=False), # sign_sb_btn
167
+ gr.update(visible=True), # delete_sb_btn
168
+ gr.update(visible=True), # save_btn
169
+ gr.update(visible=True) # classifier_pg
170
+ )
171
+ return (
172
+ gr.update(value='Password e/o Nome utente errato', visible=True), # login_msg
173
+ gr.update(value='user', visible=False), # username_sb
174
+ gr.update(visible=True), # login_pg
175
+ gr.update(visible=False), # archive_sb_btn
176
+ gr.update(visible=True), # sign_sb_btn
177
+ gr.update(visible=False), # delete_sb_btn
178
+ gr.update(visible=False), # save_btn
179
+ gr.update(visible=False) # classifier_pg
180
+ )
181
+
182
+
183
+ def signup(user, psw):
184
+ try:
185
+ with open(JSON_USERS_PATH, "r") as f:
186
+ results = json.load(f)
187
+ except FileNotFoundError:
188
+ results = []
189
+
190
+ for u in results:
191
+ if u['username'].lower() == user.lower():
192
+ return (
193
+ gr.update(value='Utente già esistente', visible=True), # login_msg
194
+ gr.update(value='user', visible=False), # username_sb
195
+ gr.update(visible=True), # login_pg
196
+ gr.update(visible=False), # archive_sb_btn
197
+ gr.update(visible=True), # sign_sb_btn
198
+ gr.update(visible=False), # delete_sb_btn
199
+ gr.update(visible=False), # save_btn
200
+ gr.update(visible=False) # classifier_pg
201
+ )
202
+ if user == '' or psw == '':
203
+ return (
204
+ gr.update(value='Nome utente e/o password non validi', visible=True), # login_msg
205
+ gr.update(value='user', visible=False), # username_sb
206
+ gr.update(visible=True), # login_pg
207
+ gr.update(visible=False), # archive_sb_btn
208
+ gr.update(visible=True), # sign_sb_btn
209
+ gr.update(visible=False), # delete_sb_btn
210
+ gr.update(visible=False), # save_btn
211
+ gr.update(visible=False) # classifier_pg
212
+ )
213
+ results.append({
214
+ 'username': user,
215
+ 'password': psw
216
+ })
217
+
218
+ with open(JSON_USERS_PATH, "w") as f:
219
+ json.dump(results, f, indent=2)
220
+
221
+ return (
222
+ gr.update(value='Login effettuato', visible=True), # login_msg
223
+ gr.update(value=f"**{user.upper()}**", visible=True), # username_sb
224
+ gr.update(visible=False), # login_pg
225
+ gr.update(visible=True), # archive_sb_btn
226
+ gr.update(visible=False), # sign_sb_btn
227
+ gr.update(visible=True), # delete_sb_btn
228
+ gr.update(visible=True), # save_btn
229
+ gr.update(visible=True) # classifier_pg
230
+ )
231
+
232
+
233
+ from PIL import Image
234
+ import gradio as gr
235
+ from datetime import datetime
236
+ import json
237
+
238
+ css = """
239
+ #container {min-height: 100vh;}
240
+ .sidebar {
241
+ background-color: #f0f0f0;
242
+ padding: 10px;
243
+ height: 100vh;
244
+ overflow-y: auto;
245
+ }
246
+ .content {padding: 20px; padding-bottom: 60px; overflow-y:auto}
247
+ .fixed_image img{
248
+ max-width: 224px;
249
+ height: 224px; /* altezza massima */
250
+ object-fit: contain; /* mantiene proporzioni */
251
+ }
252
+ """
253
+
254
+ # UI
255
+ with gr.Blocks(css=css) as demo:
256
+ with gr.Row(elem_id='container'):
257
+ # sidebar
258
+ with gr.Column(scale=1, min_width=200, elem_classes='sidebar'):
259
+ username_sb = gr.Markdown('user', visible=False)
260
+
261
+ cls_sb_bt = gr.Button('Classifier', visible=True)
262
+ archive_sb_btn = gr.Button('Archive', visible=False)
263
+
264
+ sign_sb_btn = gr.Button('Sign-in/Sign-up', visible=True)
265
+ delete_sb_btn = gr.Button('Delete Account', visible=False)
266
+
267
+ # content
268
+ with gr.Column(scale=4):
269
+ with gr.Column(scale=4, min_width=400, elem_classes="content"):
270
+ # Pagina classificatore
271
+ with gr.Group(visible=True) as classifier:
272
+ gr.Markdown('### Classifier')
273
+
274
+ with gr.Row():
275
+ uploader = gr.Image(label='Upload image', sources=['upload', 'webcam'], type='pil',
276
+ elem_classes='fixed_image')
277
+ with gr.Row():
278
+ output_id = gr.Number(value=0, label="ID", interactive=False)
279
+ output_name = gr.Textbox(value="", label="Pokémon", interactive=False)
280
+ with gr.Row():
281
+ # pulsanti
282
+ cls_btn = gr.Button("Classify", visible=True)
283
+ save_btn = gr.Button('Save Results', visible=False)
284
+ save_status = gr.Textbox(label='Status', interactive=False, visible=False)
285
+
286
+ # eventi
287
+ cls_btn.click(
288
+ fn=predicted_pokemon,
289
+ inputs=uploader,
290
+ outputs=[output_id, output_name]
291
+ )
292
+
293
+ save_btn.click(
294
+ fn=save_result,
295
+ inputs=[uploader, output_id, output_name, username_sb],
296
+ outputs=save_status
297
+ )
298
+
299
+ # Pagina archivio
300
+ with gr.Group(visible=False) as archive:
301
+ gr.Markdown('### Archive')
302
+
303
+ with gr.Row():
304
+ archive_msg = gr.Markdown()
305
+ archive_df = gr.Dataframe(
306
+ headers=['Timestamp', 'ID', 'Pokémon', 'Image Path'],
307
+ datatype=['str', 'number', 'str', 'str'],
308
+ interactive=False,
309
+ visible=False
310
+ )
311
+ selected_image = gr.Image(label='Immagine selezionata.', visible=False, type='filepath',
312
+ interactive=False, elem_classes='fixed_image')
313
+ image_path = gr.Textbox(visible=False)
314
+
315
+ with gr.Row():
316
+ # pulsanti
317
+ load_btn = gr.Button('Refresh Archive')
318
+ delete_btn = gr.Button('Delete Record', visible=False)
319
+
320
+ # Eventi
321
+ load_btn.click(fn=show_archive, inputs=[username_sb], outputs=[archive_msg, archive_df])
322
+
323
+ archive_df.select(
324
+ fn=show_image,
325
+ inputs=[],
326
+ outputs=[selected_image, image_path, delete_btn]
327
+ )
328
+
329
+ delete_btn.click(
330
+ fn=delete_record,
331
+ inputs=[archive_df, image_path, username_sb],
332
+ outputs=[archive_df, selected_image, delete_btn]
333
+ )
334
+
335
+ with gr.Group(visible=False) as login:
336
+ gr.Markdown('### Login')
337
+
338
+ with gr.Row():
339
+ username_tbox = gr.Textbox(label='Username')
340
+ password_tbox = gr.Textbox(label='Password', type='password')
341
+
342
+ with gr.Row():
343
+ login_msg = gr.Textbox(label='Status', interactive=False, visible=False)
344
+
345
+ with gr.Row():
346
+ # pulsanti
347
+ signin_btn = gr.Button('Sign-in')
348
+ signup_btn = gr.Button('Sign-up')
349
+
350
+ # logica eventi
351
+ signin_btn.click(
352
+ fn=signin,
353
+ inputs=[username_tbox, password_tbox],
354
+ outputs=[login_msg, username_sb, login, archive_sb_btn, sign_sb_btn, delete_sb_btn, save_btn,
355
+ classifier]
356
+ )
357
+
358
+ signup_btn.click(
359
+ fn=signup,
360
+ inputs=[username_tbox, password_tbox],
361
+ outputs=[login_msg, username_sb, login, archive_sb_btn, sign_sb_btn, delete_sb_btn, save_btn,
362
+ classifier]
363
+ )
364
+
365
+ cls_sb_bt.click(fn=lambda username: show_page('classifier', username), inputs=[username_sb],
366
+ outputs=[classifier, archive, login])
367
+ archive_sb_btn.click(fn=lambda username: show_page('archive', username), inputs=[username_sb],
368
+ outputs=[classifier, archive, login, archive_msg, archive_df])
369
+ sign_sb_btn.click(fn=lambda username: show_page('login', username), inputs=[username_sb],
370
+ outputs=[classifier, archive, login])
371
+ delete_sb_btn.click()
372
+
373
+ if __name__ == '__main__':
374
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ torch~=2.8.0
2
+ gradio~=5.43.1
3
+ transformers~=4.55.4
4
+ pillow~=11.3.0