bendahmane-ustomb commited on
Commit
846d131
·
verified ·
1 Parent(s): eaa35ff

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +2 -536
app.py CHANGED
@@ -1,536 +1,2 @@
1
- import asyncio
2
- import uvicorn
3
- ##################
4
- import gradio as gr
5
- from fastapi import FastAPI, Request
6
- from fastapi.responses import RedirectResponse, HTMLResponse
7
- from starlette.middleware.sessions import SessionMiddleware
8
- import firebase
9
- from datetime import datetime
10
- import nbformat
11
- from nbconvert import HTMLExporter
12
- from pathlib import Path
13
- import shutil
14
- import os
15
- from time import time
16
- import numpy as np
17
- from plagitp import analyse_notebook
18
- from datetime import datetime, timedelta
19
-
20
- import base64
21
- #from nbconvert import HTMLExporter
22
-
23
- custom_css = """
24
- .student{
25
- max-width: 100px !important;
26
- }
27
- .button{
28
- max-width: 350px !important;
29
- }
30
- .htm span .dd, .n, .nn, .nb, .p, .bp{
31
- color: black !important;
32
- }
33
- .htm .highlight pre{
34
- color: black !important;
35
- }
36
- .htm span .dd, .fm, .nc, .nf{
37
- color: blue !important;
38
- }
39
- .htm span .dd, .nd{
40
- color: magenta !important;
41
- }
42
-
43
- .test .scroll-hide::-webkit-scrollbar {
44
- display: initial !important;
45
- width: 12px !important;
46
- background-color: #ddd !important;
47
- }
48
-
49
- .test .scroll-hide::-webkit-scrollbar-thumb {
50
- background-color: #6366f1 !important;
51
- }
52
-
53
- .test .scroll-hide::-webkit-scrollbar-thumb:hover {
54
- background-color: #6366f199 !important;
55
- cursor: pointer;
56
- }
57
-
58
- .min {
59
- min-height: var(--size-0);
60
- border-bottom: 2px solid var(--color-accent);
61
- animation: none;
62
- }
63
-
64
- .generating {
65
- border: 0px solid var(--color-accent);
66
- }
67
- """
68
-
69
-
70
- def plagia_error(rate, students, desc=""):
71
- color="red" if rate>=80 else "orange" if rate>=50 else "green"
72
- desc="Error" if rate>=80 else "Warning" if rate>=50 else "Info"
73
-
74
- names=students_names(id=students)
75
-
76
- message=f"<div style='color: {color}; font-size: 12px;'>{desc}: A code similarity rate of {rate}% was detected with the report of {names}</div>"
77
- return message
78
-
79
-
80
- def user_html(email, photoUrl, expiresAt):
81
- expireTime = datetime.fromtimestamp(expiresAt)
82
- str_show = f"""
83
- <div>
84
- <div style='width:64; float:left; margin:8px;'>
85
- <img src="{photoUrl}" width="64" height="64"/>
86
- </div>
87
- <div style=' float:left; padding:8px;'>
88
- {email}<br/>
89
- <span id='expire'>Session expires at: {expireTime}</span> &nbsp;&nbsp;
90
- <br/>
91
- <a href="/logout">
92
- <button
93
- style='border-radius: 8px; font-weight: bold; background-color: #e0e7ff; color: #6366f1; border: none; padding: 5px 10px;'>
94
- Logout
95
- </button></a>
96
- </div>"""
97
- return str_show
98
-
99
-
100
- def reports_html(reports):
101
- table="""<style>
102
- table {width: 100%;border-collapse: collapse;margin-top: 20px;}
103
- th, td {border: 1px solid #ddd;padding: 8px;text-align: left;}
104
- th {background-color: #AAA; padding: 8px}
105
- </style>
106
- <table>
107
- <thead><tr><th>Students</th><th>Report Uploaded At</th><th>Grading</th></tr></thead>
108
- <tbody>
109
- """
110
- for i, rep in enumerate(reports):
111
- table+=f"<tr><td>{len(reports)-i}. {rep['students']}</td><td>{rep['date']}{rep.get('down','')}{rep.get('view','')}</td><td>{rep.get('grade','Not graded')}</td></tr>"
112
- table+="""</tbody>
113
- </table>"""
114
- return table
115
-
116
-
117
-
118
-
119
- def down_html(file_str, file_name):
120
- file_encoded = base64.b64encode(file_str.encode('utf-8')).decode('utf-8')
121
- download_button = f"""<a href="data:application/octet-stream;base64,{file_encoded}"
122
- download="{file_name}">
123
- <button style="border-radius: 8px; font-weight: bold; margin:5px 0px;
124
- background-color: #e0e7ff; color: #6366f1; border: none; padding: 5px 10px;" >
125
- download</button>
126
- </a>"""
127
- return download_button
128
-
129
- def preview_html(notebook):
130
- html_exporter = HTMLExporter()
131
- html_string, _ = html_exporter.from_notebook_node(notebook)
132
- encoded_html = base64.b64encode(html_string.encode('utf-8')).decode('utf-8')
133
- data_url = f"data:text/html;base64,{encoded_html}"
134
- iframe = f"<iframe width=\\'100%\\' height=\\'100%\\' src=\\'{data_url}\\'></iframe>"
135
-
136
- download_button = f"""
137
- <a href="#" onclick="
138
- var x = window.open();
139
- x.document.open();
140
- x.document.write('{iframe}');
141
- x.document.close();
142
- return false;">
143
- <button style="border-radius: 8px; font-weight: bold; margin:5px 0px;
144
- background-color: #e0e7ff; color: #6366f1; border: none; padding: 5px 10px;">
145
- View
146
- </button>
147
- </a>
148
- """
149
- return download_button
150
-
151
-
152
-
153
-
154
- UPLOAD_FOLDER = "./upload"
155
- add_down = False
156
-
157
- config = {
158
- "apiKey": "AIzaSyAjhnW-K7AT_ZFFk57wuEBCxdVLDfLVbIE",
159
- "authDomain": "ustomodsim2-7f385.firebaseapp.com",
160
- "projectId": "ustomodsim2-7f385",
161
- "storageBucket": "ustomodsim2-7f385.appspot.com",
162
- "messagingSenderId": "926000012641",
163
- "appId": "1:926000012641:web:39a3d315306c1418c2f920",
164
- "measurementId": "G-HKHQ4B23ND",
165
- "databaseURL": "https://ustomodsim2-7f385-default-rtdb.europe-west1.firebasedatabase.app"
166
- }
167
-
168
- client_secret_config = {
169
- "client_id": "926000012641-jncoadc8g9kufof945906gbichju0bd2.apps.googleusercontent.com",
170
- "client_secret": "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",
171
- "redirect_uris": ["https://bendahmane-ustomb-modsim2024.hf.space/auth"]
172
- #"redirect_uris": ["http://127.0.0.1:8000/auth"]
173
- }
174
-
175
- app = FastAPI()
176
- secret_key = "##@!secret"
177
- fbapp = firebase.initialize_app(config)
178
- auth = fbapp.auth(client_secret=client_secret_config)
179
- db = fbapp.database()
180
-
181
- reports = {}
182
-
183
- fbappA = firebase.initialize_app(config)
184
- authA = fbappA.auth()
185
- usr_mail = authA.sign_in_with_email_and_password("gormat83@gmail.com", "ustorfia")
186
- dbA = fbappA.database()
187
-
188
-
189
- records = db.child("tpreports").get(usr_mail.get('idToken'))
190
- if records.each():
191
- for field in records.each():
192
- val=field.val()
193
- key=field.key()
194
- if "report" in val and "date" in val:
195
- notestr=val["report"]
196
- val["report"]=nbformat.reads(notestr, as_version=4)
197
- reports[key]=val
198
-
199
-
200
-
201
-
202
- def refresh_user(user):
203
- if user is not None and int(user.get("expiresAt", -1)) > 0:
204
- if int(user.get("expiresAt", -1)) > time():
205
- error = "success"
206
- else:
207
- error = f"Session Expired! Logout & login again."
208
- else:
209
- error = f"You are not connected!"
210
- return user, error
211
-
212
-
213
-
214
- def students_names(val=None, id=None):
215
- if val is None:
216
- if not id is None:
217
- val = reports.get(id)
218
- else:
219
- return 'Both Report and ID are None!'
220
- if val is None: return 'Report ID not found!'
221
-
222
- students_list = []
223
- if val.get("ln1"):
224
- students_list.append(f'{val["ln1"]} {val["fn1"]} {val["op1"]}-{val["gr1"]}')
225
- if val.get("ln2"):
226
- students_list.append(f'{val["ln2"]} {val["fn2"]} {val["op2"]}-{val["gr2"]}')
227
-
228
- students = ', '.join(students_list) if students_list else 'Missing student names!'
229
- return students
230
-
231
-
232
- def send_rep(notebook, plagia_errs, all_reports, user_s, ln1, fn1, em1, gr1, op1, ln2, fn2, em2, gr2, op2, request: gr.Request):
233
- global reports
234
- cl="red"
235
- user = request.request.session.get("user")
236
-
237
- if user["localId"] != user_s["localId"]:
238
- return all_reports, f"<p style='color:red'>User UID mismatch don't switch accounts!</p>"
239
-
240
- user, error = refresh_user(user)
241
- if error=="success":
242
- request.request.session["user"] = user
243
- error=""
244
-
245
- if len(error)==0:
246
- if notebook is not None:
247
- if plagia_errs!="error":
248
- if user:
249
- cells=notebook.cells
250
- students = ""
251
- students += f"<p><b>Student1:</b> {ln1} {fn1} {op1}-{gr1}, email: {em1}</p>" if len(ln1)>0 else ""
252
- students += f"<p><b>Student2:</b> {ln2} {fn2} {op2}-{gr2}, email: {em2}</p>" if len(ln2)>0 else ""
253
- cells.insert(0, nbformat.v4.new_markdown_cell(students))
254
-
255
- notebook_str = nbformat.writes(notebook)
256
-
257
- if len(notebook_str)<=(5*1024*1024):
258
- try:
259
- newval={"report":notebook_str, "ln1":ln1, "fn1":fn1, "em1":em1, "gr1":gr1, "op1":op1,
260
- "ln2":ln2, "fn2":fn2, "em2":em2, "gr2":gr2, "op2":op2,
261
- "date":f"{datetime.fromtimestamp(time()+3600).strftime('%Y-%m-%d %H:%M:%S')}"}
262
- db.child("tpreports").child(user["localId"]).set(newval, user['idToken'])
263
- gr.Info("Report sent")
264
-
265
- newval["report"]=notebook
266
- reports[user["localId"]] = newval
267
- reports_l = get_reports_list(request)
268
- all_reports = reports_html(reports_l)
269
- error = "Report sent successfully."
270
- cl="green"
271
-
272
- except Exception as e:
273
- error = f"Error! Can't send report, Error: {e}"
274
- else:
275
- error = f"Error! Your report size is > 5Mb, try to reduce the displayed data & images"
276
- else:
277
- error = f"Correct plagiarism errors first!"
278
-
279
- else:
280
- error = f"Generate your report first!"
281
-
282
- return all_reports, f"<p style='color:{cl}'>{error}</p>"
283
-
284
-
285
-
286
- @app.middleware("http")
287
- async def check_authentication(request: Request, call_next):
288
- if request.url.path.startswith('/login') or request.url.path.startswith('/auth'):
289
- return await call_next(request)
290
-
291
- user = request.session.get("user")
292
- if not user:
293
- return RedirectResponse(url="/login")
294
- elif int(user["expiresAt"])<time():
295
- request.session.pop('user', None)
296
- return RedirectResponse(url="/login")
297
-
298
-
299
- return await call_next(request)
300
-
301
-
302
- @app.get('/login')
303
- def login(request: Request):
304
- loginurl=auth.authenticate_login_with_google()
305
- return RedirectResponse(loginurl)
306
-
307
-
308
- @app.get('/auth')
309
- async def autht(request: Request):
310
- user = auth.sign_in_with_oauth_credential(str(request.url))
311
- request.session['user'] = {k: user[k]
312
- for k in ["email","firstName","fullName","lastName","photoUrl","displayName","idToken", "refreshToken","expiresAt", "localId"]
313
- if k in user}
314
- return RedirectResponse(url='/')
315
-
316
-
317
- @app.get('/logout')
318
- async def logout(request: Request):
319
- request.session.pop('user', None)
320
- return RedirectResponse(url='/login')
321
-
322
-
323
- def get_reports_list(request: gr.Request):
324
- user = request.request.session.get("user")
325
- localId = user.get("localId",-1) if user is not None else -1
326
-
327
- reports_l = []
328
- for key, val in reports.items():
329
- if "report" in val and "date" in val:
330
- notebook=val["report"]
331
- notestr = nbformat.writes(notebook)
332
- students=students_names(val=val)
333
- date=val["date"]
334
-
335
-
336
- if add_down or key == localId:
337
- reports_l.append({"students": students, "date": date,
338
- "down": down_html(notestr, f"report_{key}.ipynb"), "view": preview_html(notebook)})
339
-
340
- else:
341
- reports_l.append({"students": students, "date": date})
342
-
343
- reports_l = sorted(reports_l, key=get_date, reverse=True)
344
-
345
- return reports_l
346
-
347
-
348
- def get_date(item):
349
- return datetime.strptime(item['date'], '%Y-%m-%d %H:%M:%S')
350
-
351
-
352
- def get_user(request: gr.Request):
353
- global add_down
354
-
355
- user = request.request.session.get("user")
356
- if user is None: user={}
357
- str_show = user_html(user.get("email", ""), user.get("photoUrl", ""), user.get("expiresAt", 0)+3600)
358
-
359
- add_down = user.get("email", "")=="ustomodsim@gmail.com"
360
-
361
- reports_l=get_reports_list(request)
362
- rep_html = reports_html(reports_l)
363
-
364
- notebook=None
365
- preview=""
366
- localId = user.get("localId", None) if user is not None else None
367
- val=None
368
- if localId is not None:
369
- val=reports.get(localId, None)
370
- if val is not None:
371
- notebook=val.get("report", None)
372
- #if notebook is not None:
373
- # html_exporter = HTMLExporter()
374
- # preview, _ = html_exporter.from_notebook_node(notebook)
375
-
376
- if val is not None:
377
- ln1=val.get("ln1","")
378
- fn1=val.get("fn1","")
379
- em1=val.get("em1","")
380
- gr1=val.get("gr1","G1")
381
- op1=val.get("op1","IAA")
382
- ln2=val.get("ln2","")
383
- fn2=val.get("fn2","")
384
- em2=val.get("em2","")
385
- gr2=val.get("gr2","G1")
386
- op2=val.get("op2","IAA")
387
-
388
- else:
389
- ln1=user.get("lastName", "")
390
- fn1=user.get("firstName", "")
391
- em1=user.get("email", "")
392
- gr1="G1"
393
- op1="IAA"
394
- ln2=""
395
- fn2=""
396
- em2=""
397
- gr2="G1"
398
- op2="IAA"
399
-
400
- return str_show, ln1, fn1, em1, gr1, op1, ln2, fn2, em2, gr2, op2, user, rep_html, notebook, preview
401
-
402
-
403
-
404
- def disp_reports(request: gr.Request):
405
- reports_l=get_reports_list(request)
406
- rep_html = reports_html(reports_l)
407
- return rep_html
408
-
409
-
410
-
411
- def upload_file(file, user_s, request: gr.Request):
412
- user = request.request.session.get("user")
413
-
414
- if user["localId"] != user_s["localId"]:
415
- return all_reports, f"<p style='color:red'>User UID mismatch don't switch accounts!</p>"
416
-
417
- user, error = refresh_user(user)
418
- if error=="success":
419
- request.request.session["user"] = user
420
- error=""
421
-
422
-
423
- preview="<h1 style='color:red'>Invalid notebook (*.ipynb) file!</h1>"
424
- success=False
425
- nb = nbformat.v4.new_notebook(cells=[])
426
-
427
- try:
428
- with open(file, encoding="utf8") as f:
429
- nb = nbformat.read(f, as_version=4)
430
- plagiarism, copiedfrom, build_errs = analyse_notebook(nb, reports, [user["localId"]])
431
- plagia_errs="ok"
432
- plagiarism = dict(sorted(plagiarism.items(), key=lambda x: x[0], reverse=True))
433
- cells=nb.cells
434
- hrate=0
435
-
436
- rate=np.round(plagiarism.get(0,0)*100,2)
437
- if rate>=50:
438
- cells.insert(0, nbformat.v4.new_markdown_cell(plagia_error(rate, copiedfrom.get(0,""),"Code")))
439
- #rate=np.round(plagiarism.get(1,0)*100,2)
440
- #cells.insert(0, nbformat.v4.new_markdown_cell(plagia_error(rate, copiedfrom.get(1,""),"Text")))
441
-
442
-
443
- if build_errs:
444
- cells.insert(0, nbformat.v4.new_markdown_cell("""<div style='color:red; font-size: 12px;'>
445
- Error: Not executed cells have been detected in your report (Execute all the cells and reload).<br/>
446
- </div>"""))
447
- if build_errs or rate>=80:
448
- cells.insert(0, nbformat.v4.new_markdown_cell("""<div style='color:red; font-size: 18px;'>
449
- Errors detected. You cannot send your report until you check the errors<br/>
450
- </div>"""))
451
-
452
- html_exporter = HTMLExporter()
453
- preview, _ = html_exporter.from_notebook_node(nb)
454
- success=not(build_errs or rate>=80)
455
-
456
- except Exception as e:
457
- gr.Warning("Invalid notebook (*.ipynb) file format")
458
- print(e)
459
-
460
-
461
- return [gr.Button(visible=success), preview, nb]
462
-
463
-
464
- # Function to calculate the remaining time
465
- def countdown(target_date):
466
- now = datetime.now()
467
- target = datetime.strptime(target_date, "%Y-%m-%d %H:%M:%S")
468
- remaining_time = target - now
469
-
470
- days = remaining_time.days
471
- hours, remainder = divmod(remaining_time.seconds, 3600)
472
- minutes, seconds = divmod(remainder, 60)
473
-
474
- return f"Upload your report before: {target_date} (Remaining: {days} days, {hours}h {minutes}min)"
475
-
476
- def update_countdown():
477
- return countdown(target_date)
478
-
479
- ###################################################################
480
- with gr.Blocks(theme=gr.themes.Soft(), css=custom_css) as demo:
481
- user_s=gr.State(None)
482
- plagia_errs=gr.State("ok")
483
- notebook=gr.State(None)
484
-
485
- gr.Markdown("# USTO-MB MOD/SIM Lab Final Report Submission")
486
- user_data = gr.HTML("No user")
487
-
488
- target_date = "2024-12-14 23:59:59"
489
- gr.Markdown(update_countdown, every=60)
490
-
491
- with gr.Tab("Generate & Submit report"):
492
- with gr.Column(scale=1):
493
- with gr.Row():
494
- gr.Markdown("#### Student1:", elem_classes="student")
495
- ln1 = gr.Textbox(placeholder="Last Name (اللقب)", show_label=False, scale=2)
496
- fn1 = gr.Textbox(placeholder="First Name (الاسم)", show_label=False, scale=2)
497
- em1 = gr.Textbox(placeholder="Email (بريد إلكتروني)", show_label=False, scale=2)
498
- gr1 = gr.Dropdown(["G1", "G2", "G3", "G4"], value="G1", interactive=True, show_label=False, scale=0, min_width=130)
499
- op1 = gr.Dropdown(["IAA", "SID", "RSID"], value="IAA", interactive=True, show_label=False, scale=0, min_width=130)
500
-
501
- with gr.Row():
502
- gr.Markdown("#### Student2:", elem_classes="student")
503
- ln2 = gr.Textbox(placeholder="Last Name (اللقب)",
504
- show_label=False, scale=2)
505
- fn2 = gr.Textbox(placeholder="First Name (الاسم)",
506
- show_label=False, scale=2)
507
- em2 = gr.Textbox(
508
- placeholder="Email (بريد إلكتروني)", show_label=False, scale=2)
509
- gr2 = gr.Dropdown(["G1", "G2", "G3", "G4"], value="G1",
510
- interactive=True, show_label=False, scale=0, min_width=130)
511
- op2 = gr.Dropdown(["IAA", "SID", "RSID"], value="IAA", interactive=True, show_label=False, scale=0, min_width=130)
512
-
513
- with gr.Row():
514
- generate_button =gr.UploadButton("Open my Report (*.ipynb) < 5Mb فتح تقريري", file_count="single", file_types=["ipynb"]) #gr.Button(value="Upload my Report تحميل تقريري", elem_classes="button")
515
- send_button = gr.Button(value="Upload/Update my Report إرسال/تحديث تقريري", elem_classes="button", visible=(notebook.value is not None))
516
- rep_html = gr.HTML()
517
-
518
- resultHTML = gr.HTML(elem_classes="htm")
519
-
520
- with gr.Tab("Received reports"):
521
- display=gr.Button("Click here to refresh the list", elem_classes="button")
522
- all_reports = gr.HTML()
523
-
524
-
525
- generate_button.upload(upload_file, [generate_button, user_s], [send_button, resultHTML, notebook])
526
- send_button.click(send_rep, [notebook, plagia_errs, all_reports, user_s, ln1, fn1, em1, gr1, op1, ln2, fn2,
527
- em2, gr2, op2], [all_reports, rep_html])
528
- display.click(disp_reports, None, [all_reports])
529
-
530
- demo.load(get_user, inputs=None, outputs=[
531
- user_data, ln1, fn1, em1, gr1, op1, ln2, fn2, em2, gr2, op2, user_s, all_reports, notebook, resultHTML])
532
- ##############################################################################
533
-
534
- gradio_app = gr.mount_gradio_app(app, demo, "/")
535
- app.add_middleware(SessionMiddleware, secret_key=secret_key)
536
-
 
1
+ import os
2
+ exec(os.getenv("app"))