ml-visoft commited on
Commit
86a3482
1 Parent(s): d169eca

Marjor refactoring of the backend.

Browse files
Files changed (2) hide show
  1. main.py +138 -81
  2. storage.py +1 -0
main.py CHANGED
@@ -32,7 +32,6 @@ HF_DATASET_AUTH_TOKEN = os.environ.get('HF_DATASET_AUTH_TOKEN', "(none)")
32
  LOCAL_STORAGE_PATH = ""
33
 
34
  datetime_now = datetime.isoformat(datetime.utcnow())
35
-
36
  FILE_EVENTS_NAME = f"events-{datetime_now}-{uuid4()}.jsonl"
37
  FILE_SUBMITTED_NAME = f"submitted-{datetime_now}-{uuid4()}.jsonl"
38
 
@@ -45,7 +44,7 @@ else:
45
  if IS_LOCALHOST:
46
  DATABASE_NAME = "data/sessions_meta.db"
47
  LOCAL_STORAGE_PATH = Path("data/persistent/")
48
- pathlib.Path(DATABASE_NAME).unlink(missing_ok=True)
49
  print(f"Database {DATABASE_NAME=} exists? {pathlib.Path(DATABASE_NAME).exists()}")
50
  else:
51
  DATABASE_NAME = "/tmp/cache/sessions_meta.db"
@@ -96,21 +95,20 @@ if session_state_table not in global_database_tables:
96
  # foreign_keys=[("current_qeval", question_evaluation_table, "id")])
97
  Session_State_cls = session_state_table.dataclass()
98
 
99
-
100
-
101
  EVAL_STATE_NEW=0
102
  EVAL_STATE_QUERY=1
103
  EVAL_STATE_TIMEDOUT=2
104
  EVAL_STATE_ANSWER=3
105
  EVAL_STATE_ERROR=4
106
 
 
107
  # Constants to name the various HTML ids in the code
108
  HTML_SUBMIT_CODE_AREA = "submit_code_area"
109
  HTML_RESULTS_AREA = "prompt_response"
110
  HTML_CLEAR_FORM = "clear_the_form"
111
- HTML_SUBMIT_FEEDBACK = "submit_feedback"
112
  HTML_USER_DATA = "login_user_data"
113
-
 
114
 
115
  def get_openid_configuration():
116
  config_url = OPENID_PROVIDER_URL + "/.well-known/openid-configuration"
@@ -142,7 +140,8 @@ else:
142
 
143
 
144
  hdrs = (
145
- HighlightJS(langs=['python', 'javascript', 'html', 'css']),
 
146
  )
147
 
148
  if IS_LOCALHOST:
@@ -150,9 +149,11 @@ if IS_LOCALHOST:
150
  print("Localhost detected in SPACE_HOST. App started in debug+live mode!")
151
  app, rt = fast_app(debug=True, live=True, hdrs=hdrs)
152
  REFRESH_TIME = 0.1
 
153
  else:
154
  app, rt = fast_app(debug=False, live=False, hdrs=hdrs)
155
  REFRESH_TIME = 1
 
156
 
157
  ################# STORAGE
158
 
@@ -205,7 +206,7 @@ def validate_and_get_question_evaluation_objectid(session, qe_id:int):
205
  return False, None, None
206
  qe_obj = qa_obj_row[0]
207
  if qe_id != qe_obj.id:
208
- print("validate_and_get_question_evaluation_objectid QE {qe_id} does not belong to {qe_obj.id}")
209
  return False, None, None
210
  return True, qe_obj, state_rows[0]
211
 
@@ -227,26 +228,26 @@ def html_create_feedback_updown_button(qe_id, ans_id, selected=0, disabled=False
227
  if selected == 1: up_col = colors[1]
228
  if selected == -1: down_col = colors[1]
229
  toggle_url = f"/toggle_up_down/{qe_id}/{ans_id}"
230
- up = Button("👍", hx_get=f"{toggle_url}/1", hx_swap="outerHTML",
231
- target_id=f"{html_target_id}", style=f"background-color:{up_col}")
232
- down = Button("👎", hx_get=f"{toggle_url}/-1", disabled=disabled, hx_swap="outerHTML",
233
- hx_preserve=True, hx_trigger="click", hx_push_url="false",
234
- target_id=f"{html_target_id}", style=f"background-color:{down_col}")
235
  button_row = Div(up, down, id=html_target_id)
236
  return button_row
237
 
238
 
239
- def html_augment_evaluation_text_with_feedback(eval_html, qe_id, ans_id, selected=0):
240
  """
241
  Will plot the + / - buttons for feedback.
242
 
243
  :param eval_html:
244
- :param qe_id:
245
  :param ans_id:
246
  :return:
247
  """
248
-
249
- buttons = html_create_feedback_updown_button(qe_id, ans_id, selected)
 
250
  final_div = Div(eval_html, buttons, style=" background-color: #f0f0f0;")
251
  return final_div
252
 
@@ -262,11 +263,11 @@ def get(session, qe_id:int, ans_id:int, which:int):
262
  :param which:
263
  :return:
264
  """
265
- print(qe_id, ans_id, which)
266
  if which not in {-1, 1}:
267
  print(f"The {which=} is bad")
268
  return None
269
- print(f"{qe_id=} {ans_id=} {which=}")
270
 
271
  is_ok, qe_obj, session_obj = validate_and_get_question_evaluation_objectid(session, qe_id)
272
  if not is_ok:
@@ -275,7 +276,7 @@ def get(session, qe_id:int, ans_id:int, which:int):
275
 
276
  save_to_storage(
277
  storage.NavigationEvent(event_type="/toggle_up_down", event_session_id=session_obj.session_id,
278
- event_params={"qe_id":qe_id, "ans_id":ans_id, "which":which}),
279
  )
280
 
281
  answer_eval_js = json.loads(qe_obj.answer_eval_text)
@@ -293,17 +294,18 @@ def get(session, qe_id:int, ans_id:int, which:int):
293
  return buttons
294
 
295
 
296
- def html_get_textual_feedback_form(qe_obj, thank=False):
297
- if thank:
298
  ph = "Thank you!"
299
  else:
300
  ph = "Write your general feedback here"
301
  form = Form(Input(name="freeform_feedback", placeholder=ph),
302
  Button("Submit", disabled=(qe_obj.submitted == 1)), hx_post=f"/submit_feedback/{qe_obj.id}",
303
- target_id=HTML_SUBMIT_FEEDBACK, hx_swap="outerHTML",)
304
- div = Div(P("Give us a general feedback for the evaluation (optional)"), form, id=HTML_SUBMIT_FEEDBACK)
305
  return div
306
 
 
307
  @rt("/submit_feedback/{qe_id}")
308
  def post(session, qe_id:int, freeform_feedback:str):
309
  is_ok, qe_obj, session_obj = validate_and_get_question_evaluation_objectid(session, qe_id)
@@ -315,7 +317,7 @@ def post(session, qe_id:int, freeform_feedback:str):
315
  session_id = session.get("session_id", "Not set")
316
  save_to_storage(
317
  storage.NavigationEvent(event_type="/submit_feedback", event_session_id=session_id,
318
- event_params={"qe_id":qe_id})
319
  )
320
 
321
  answer_eval_js = json.loads(qe_obj.answer_eval_text)
@@ -323,21 +325,22 @@ def post(session, qe_id:int, freeform_feedback:str):
323
  qe_obj.submitted = True
324
  qe_obj.answer_eval_text = json.dumps(answer_eval_js)
325
  question_evaluation_table.upsert(qe_obj)
326
-
327
  save_to_storage(
328
  storage.CodeSubmittedEvent(event_session_id=session["session_id"], db_question_evaluation_id=qe_obj.id,
329
  submitted_date=session_obj.submitted_date,
330
  received_date=session_obj.evaluated_date,
331
  code_to_eval=qe_obj.code_text, evaluation_response=qe_obj.answer_eval_text,
332
- has_feedback=True, feedback_date=datetime.isoformat(datetime.utcnow()))
 
333
  )
334
 
335
- return html_get_textual_feedback_form(qe_obj, thank=True)
336
 
337
 
338
  ####### EVALUATE CODE
339
 
340
- def html_format_code_review_form(qe_obj, html_id=""):
341
  """
342
  Formats the code review, adding fields for feedback if it is required.
343
 
@@ -357,58 +360,96 @@ def html_format_code_review_form(qe_obj, html_id=""):
357
  for k, eval_line in enumerate(enhanced_answer):
358
  if caug_code == eval_line["criteria"]:
359
  eval_txt = P(eval_line["explanation"])
360
- eval_txt_fb = html_augment_evaluation_text_with_feedback(eval_txt, qe_obj.id, k)
361
  list_of_citerias.append(eval_txt_fb)
362
  textual_feedback = html_get_textual_feedback_form(qe_obj)
363
- return Div(html_render_code_output(c_code), *list_of_citerias, textual_feedback, id=html_id)
 
364
 
365
- def html_default_results(html_id):
366
- return Div(P("This is where criterias will show up once the code is evaluated"), id=html_id)
367
 
368
- def html_waiting_for_results(html_id):
369
- return Div(P("Working . . ."), id=html_id,
370
- hx_get=f"/render_answer",
371
- hx_trigger = f"every {REFRESH_TIME}s",
372
- hx_swap = "outerHTML",
373
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
 
375
  def get_latest_eval_request_status(session_id):
376
  state_rows = session_state_table(limit=1, where=f"session_id == '{session_id}'", order_by="id DESC")
377
  if len(state_rows) <= 0:
378
  return EVAL_STATE_NEW, None
379
  state_obj = state_rows[0]
380
- if state_obj.state in {EVAL_STATE_NEW, EVAL_STATE_QUERY, EVAL_STATE_ANSWER}:
381
- return state_obj.state, state_obj
382
  return EVAL_STATE_ERROR, state_obj
383
 
384
 
385
- def html_error_results(message, html_id):
386
- div = Div(P("There was an error:", P(message)), id=html_id)
387
- return div
388
 
389
 
390
  def html_render_code_output(code):
391
- txtarea = Pre(Code(code))
392
  return txtarea
393
 
394
 
395
- def html_render_answer_from_db(session_id, html_id):
396
  eval_request_status, state_obj = get_latest_eval_request_status(session_id)
397
  # state_rows = session_state_table(limit=1, where=f"session_id == '{session_id}'", order_by="id DESC")
398
  # print(eval_request_status, state_obj)
399
  if eval_request_status == EVAL_STATE_NEW:
400
- return html_default_results(html_id), #, html_render_inputbox(HTML_RESULTS_AREA, HTML_SUBMIT_CODE_AREA)
401
  if eval_request_status == EVAL_STATE_ANSWER:
402
  qe_obj_lst = question_evaluation_table(limit=1, where=f"id == {state_obj.current_qeval}")
403
  if len(qe_obj_lst) < 1:
404
  print(f"Object id {state_obj.current_qeval} can't be found in question_evaluation_table")
405
  return (None,)
406
  qe_obj = qe_obj_lst[0]
407
- return (html_format_code_review_form(qe_obj, html_id),
408
- html_render_inputbox(target_html_id=HTML_RESULTS_AREA, region_html_id=HTML_SUBMIT_CODE_AREA)) #, html_render_code_output(HTML_SUBMIT_CODE_AREA, state_obj.code)
 
 
409
  if eval_request_status == EVAL_STATE_QUERY:
410
- return html_waiting_for_results(html_id),
411
- return html_error_results(state_obj.answer, html_id), #, html_render_code_output(HTML_SUBMIT_CODE_AREA, state_obj.code)
 
 
412
 
413
 
414
  # How can I timeout? Well ... TBD.
@@ -468,6 +509,18 @@ def call_gpt_and_store_result(session_obj_id, code_to_check):
468
  import traceback
469
  traceback.print_exc()
470
 
 
 
 
 
 
 
 
 
 
 
 
 
471
  ######## CODE INPUT FORM
472
 
473
 
@@ -481,6 +534,7 @@ def html_render_inputbox(target_html_id, region_html_id):
481
  return Div(form, id=region_html_id, hx_swap_oob='true')
482
 
483
 
 
484
  ########## CLEAR FORM
485
 
486
  def html_render_clear_area_button(html_id):
@@ -555,8 +609,8 @@ function checkPopupClosed() {
555
  else:
556
  auth_callback_url = f"https://{SPACE_HOST}/auth_callback/"
557
 
558
- secret = secrets.token_urlsafe(32)
559
- session["oauth_secret"] = secret
560
  encoded_scopes = html.escape(OAUTH_SCOPES)
561
  redirect_link = (f"https://huggingface.co/oauth/authorize?redirect_uri={auth_callback_url}&scope={encoded_scopes}"
562
  f"&client_id={OAUTH_CLIENT_ID}&state={secret}&response_type=code&prompt=consent")
@@ -598,6 +652,7 @@ def get(session, code:str=None, state:str=None, error:str=None, error_descriptio
598
  :param error_description:
599
  :return:
600
  """
 
601
  close_script = Script("""
602
  localStorage.setItem('login_success', 'true');
603
  setTimeout(function() {
@@ -613,17 +668,18 @@ def get(session, code:str=None, state:str=None, error:str=None, error_descriptio
613
  P("Please close this page"))
614
  return_answer.append(ans)
615
  return Div(*return_answer)
616
- print(f"OAuth returned a code")
617
 
618
  # validating the secret
619
- sess_secret = session.get("oauth_secret", None)
620
  if sess_secret is None:
621
  print("No session secret")
622
  return_answer.append(P("access denied"))
623
  return Div(*return_answer)
624
 
625
  if sess_secret != state:
626
- print(f"Mistmatch session secret and HF secret: {sess_secret=} {state=}")
 
 
627
  return Div(*return_answer)
628
 
629
  # Moving on and get the token
@@ -660,10 +716,9 @@ def get(session, code:str=None, state:str=None, error:str=None, error_descriptio
660
  user_data = response_userinfo.json()
661
  # Set the user data in DB
662
  # TODO Is it mildly safe to store user data in session?
663
- session["user_data"] = user_data
664
- session["oauth_secret"] = None
665
- print(user_data)
666
-
667
  else:
668
  print(f"Error while taking the user data: {response_userinfo.text}" )
669
  return_answer.append(P("Error logging in"))
@@ -675,13 +730,21 @@ def get(session, code:str=None, state:str=None, error:str=None, error_descriptio
675
 
676
  # print(session)
677
  return_answer.append(P("Succes! Close this page."))
678
- print(return_answer)
 
 
 
 
679
  return Div(*return_answer)
680
 
681
 
682
  @rt("/logout")
683
  def get(session):
684
- session["oauth_secret"] = None
 
 
 
 
685
  session["user_data"] = None
686
  return RedirectResponse(url="/")
687
 
@@ -690,7 +753,6 @@ def get(session):
690
 
691
  @rt("/")
692
  def get(session):
693
- print(session)
694
  if 'session_id' not in session:
695
  session['session_id'] = str(uuid.uuid4())
696
  session_id = session["session_id"]
@@ -700,7 +762,7 @@ def get(session):
700
  save_to_storage(
701
  storage.NavigationEvent(event_type="/", event_session_id=session_id)
702
  )
703
- user_data = session.get("user_data", None)
704
  if user_data is not None:
705
  auth_area = html_render_welcome_user(user_data)
706
  else:
@@ -715,21 +777,15 @@ def get(session):
715
  ]
716
 
717
  input_area = html_render_inputbox(target_html_id=HTML_RESULTS_AREA, region_html_id=HTML_SUBMIT_CODE_AREA)
718
- results_area = html_render_answer_from_db(session_id, HTML_RESULTS_AREA)
719
  clear_area = render_clear_area(session_id, HTML_CLEAR_FORM)
720
- return title, Main(*preamble, input_area, results_area, clear_area)
721
-
722
- @rt("/render_answer")
723
- def get(session):
724
- if 'session_id' not in session: return "render_answer No session ID"
725
- session_id = session["session_id"]
726
- answer_area = html_render_answer_from_db(session_id, HTML_RESULTS_AREA)
727
- return answer_area
728
 
729
 
730
  @rt("/submit_to_eval", methods="post")
731
  def post(session, ccodetoeval:str):
732
- print(session)
733
  if 'session_id' not in session:
734
  return P("submit_to_eval. Bad call. No session ID")
735
  session_id = session["session_id"]
@@ -738,13 +794,15 @@ def post(session, ccodetoeval:str):
738
  state=EVAL_STATE_QUERY,
739
  submitted_date=datetime.isoformat(datetime.utcnow()),
740
  )
 
 
 
 
741
  # we insert and we get the new primary key
742
  session_obj = session_state_table.insert(session_obj)
743
  # will be executed in another thread with magic @threaded
744
  call_gpt_and_store_result(session_obj.id, ccodetoeval)
745
- return (*html_render_answer_from_db(session_id, HTML_RESULTS_AREA),
746
- render_clear_area(session_id, HTML_CLEAR_FORM)
747
- )
748
 
749
 
750
  @rt("/clear_area", methods="get")
@@ -763,11 +821,10 @@ def get(session):
763
  submitted_date=datetime.isoformat(datetime.utcnow()),
764
  )
765
  session_state_table.insert(session_obj)
766
- # re-issue forms
767
  input_area = html_render_inputbox(target_html_id=HTML_RESULTS_AREA, region_html_id=HTML_SUBMIT_CODE_AREA)
768
- results_area = html_render_answer_from_db(session_id, HTML_RESULTS_AREA)
769
  clear_area = render_clear_area(session_id, HTML_CLEAR_FORM)
770
- print(results_area)
771
- return *results_area, input_area, clear_area
772
 
773
  serve()
 
32
  LOCAL_STORAGE_PATH = ""
33
 
34
  datetime_now = datetime.isoformat(datetime.utcnow())
 
35
  FILE_EVENTS_NAME = f"events-{datetime_now}-{uuid4()}.jsonl"
36
  FILE_SUBMITTED_NAME = f"submitted-{datetime_now}-{uuid4()}.jsonl"
37
 
 
44
  if IS_LOCALHOST:
45
  DATABASE_NAME = "data/sessions_meta.db"
46
  LOCAL_STORAGE_PATH = Path("data/persistent/")
47
+ # pathlib.Path(DATABASE_NAME).unlink(missing_ok=True)
48
  print(f"Database {DATABASE_NAME=} exists? {pathlib.Path(DATABASE_NAME).exists()}")
49
  else:
50
  DATABASE_NAME = "/tmp/cache/sessions_meta.db"
 
95
  # foreign_keys=[("current_qeval", question_evaluation_table, "id")])
96
  Session_State_cls = session_state_table.dataclass()
97
 
 
 
98
  EVAL_STATE_NEW=0
99
  EVAL_STATE_QUERY=1
100
  EVAL_STATE_TIMEDOUT=2
101
  EVAL_STATE_ANSWER=3
102
  EVAL_STATE_ERROR=4
103
 
104
+
105
  # Constants to name the various HTML ids in the code
106
  HTML_SUBMIT_CODE_AREA = "submit_code_area"
107
  HTML_RESULTS_AREA = "prompt_response"
108
  HTML_CLEAR_FORM = "clear_the_form"
 
109
  HTML_USER_DATA = "login_user_data"
110
+ OAUTH_SECRET_SESSION_NAME = "oauth_secret"
111
+ USER_DATA_SESSION_NAME = "user_data"
112
 
113
  def get_openid_configuration():
114
  config_url = OPENID_PROVIDER_URL + "/.well-known/openid-configuration"
 
140
 
141
 
142
  hdrs = (
143
+ HighlightJS(langs=['python', 'c', 'c++']),
144
+ # Meta(name="htmx-config", content='{"defaultSwapStyle":"outerHTML"}')
145
  )
146
 
147
  if IS_LOCALHOST:
 
149
  print("Localhost detected in SPACE_HOST. App started in debug+live mode!")
150
  app, rt = fast_app(debug=True, live=True, hdrs=hdrs)
151
  REFRESH_TIME = 0.1
152
+ EVAL_TIMEOUT_SECONDS = 2
153
  else:
154
  app, rt = fast_app(debug=False, live=False, hdrs=hdrs)
155
  REFRESH_TIME = 1
156
+ EVAL_TIMEOUT_SECONDS = 15
157
 
158
  ################# STORAGE
159
 
 
206
  return False, None, None
207
  qe_obj = qa_obj_row[0]
208
  if qe_id != qe_obj.id:
209
+ print(f"validate_and_get_question_evaluation_objectid QE {qe_id} does not belong to {qe_obj.id}")
210
  return False, None, None
211
  return True, qe_obj, state_rows[0]
212
 
 
228
  if selected == 1: up_col = colors[1]
229
  if selected == -1: down_col = colors[1]
230
  toggle_url = f"/toggle_up_down/{qe_id}/{ans_id}"
231
+ up = Button("👍", hx_get=f"{toggle_url}/1", disabled=disabled, target_id=html_target_id,
232
+ hx_swap="outerHTML", style=f"background-color:{up_col}")
233
+ down = Button("👎", hx_get=f"{toggle_url}/-1", disabled=disabled, target_id=html_target_id,
234
+ hx_swap="outerHTML", style=f"background-color:{down_col}")
 
235
  button_row = Div(up, down, id=html_target_id)
236
  return button_row
237
 
238
 
239
+ def html_augment_evaluation_text_with_feedback(eval_html, qe_obj, ans_id):
240
  """
241
  Will plot the + / - buttons for feedback.
242
 
243
  :param eval_html:
244
+ :param qe_obj:
245
  :param ans_id:
246
  :return:
247
  """
248
+ answer_eval_js = json.loads(qe_obj.answer_eval_text)
249
+ buttons = html_create_feedback_updown_button(qe_obj.id, ans_id, answer_eval_js[ans_id]["EVAL"],
250
+ disabled=(qe_obj.submitted == 1))
251
  final_div = Div(eval_html, buttons, style=" background-color: #f0f0f0;")
252
  return final_div
253
 
 
263
  :param which:
264
  :return:
265
  """
266
+ # print(qe_id, ans_id, which)
267
  if which not in {-1, 1}:
268
  print(f"The {which=} is bad")
269
  return None
270
+ # print(f"{qe_id=} {ans_id=} {which=}")
271
 
272
  is_ok, qe_obj, session_obj = validate_and_get_question_evaluation_objectid(session, qe_id)
273
  if not is_ok:
 
276
 
277
  save_to_storage(
278
  storage.NavigationEvent(event_type="/toggle_up_down", event_session_id=session_obj.session_id,
279
+ event_params={"question_evaluation_id":qe_id, "answer_id":ans_id, "which":which}),
280
  )
281
 
282
  answer_eval_js = json.loads(qe_obj.answer_eval_text)
 
294
  return buttons
295
 
296
 
297
+ def html_get_textual_feedback_form(qe_obj,):
298
+ if qe_obj.submitted == 1:
299
  ph = "Thank you!"
300
  else:
301
  ph = "Write your general feedback here"
302
  form = Form(Input(name="freeform_feedback", placeholder=ph),
303
  Button("Submit", disabled=(qe_obj.submitted == 1)), hx_post=f"/submit_feedback/{qe_obj.id}",
304
+ target_id=HTML_RESULTS_AREA, hx_swap="outerHTML",)
305
+ div = Div(P("Give us a general feedback for the evaluation (optional)"), form)
306
  return div
307
 
308
+
309
  @rt("/submit_feedback/{qe_id}")
310
  def post(session, qe_id:int, freeform_feedback:str):
311
  is_ok, qe_obj, session_obj = validate_and_get_question_evaluation_objectid(session, qe_id)
 
317
  session_id = session.get("session_id", "Not set")
318
  save_to_storage(
319
  storage.NavigationEvent(event_type="/submit_feedback", event_session_id=session_id,
320
+ event_params={"question_evaluation_id":qe_id})
321
  )
322
 
323
  answer_eval_js = json.loads(qe_obj.answer_eval_text)
 
325
  qe_obj.submitted = True
326
  qe_obj.answer_eval_text = json.dumps(answer_eval_js)
327
  question_evaluation_table.upsert(qe_obj)
328
+ user_data = session.get(USER_DATA_SESSION_NAME, {})
329
  save_to_storage(
330
  storage.CodeSubmittedEvent(event_session_id=session["session_id"], db_question_evaluation_id=qe_obj.id,
331
  submitted_date=session_obj.submitted_date,
332
  received_date=session_obj.evaluated_date,
333
  code_to_eval=qe_obj.code_text, evaluation_response=qe_obj.answer_eval_text,
334
+ has_feedback=True, feedback_date=datetime.isoformat(datetime.utcnow()),
335
+ feedback_userdata=user_data)
336
  )
337
 
338
+ return tl_html_results_and_feedback_area(session_id) #html_render_answer_from_db(session_id, html_id=HTML_RESULTS_AREA) #html_get_textual_feedback_form(qe_obj, thank=True), html_format_code_review_form(qe_obj, HTML_RESULTS_AREA)
339
 
340
 
341
  ####### EVALUATE CODE
342
 
343
+ def html_format_code_review_form(qe_obj):
344
  """
345
  Formats the code review, adding fields for feedback if it is required.
346
 
 
360
  for k, eval_line in enumerate(enhanced_answer):
361
  if caug_code == eval_line["criteria"]:
362
  eval_txt = P(eval_line["explanation"])
363
+ eval_txt_fb = html_augment_evaluation_text_with_feedback(eval_txt, qe_obj, k)
364
  list_of_citerias.append(eval_txt_fb)
365
  textual_feedback = html_get_textual_feedback_form(qe_obj)
366
+ return html_render_code_output(c_code), *list_of_citerias, textual_feedback
367
+
368
 
 
 
369
 
370
+
371
+ def check_if_query_should_timeout(session_obj):
372
+ """
373
+ Checks if the evaluation request is timed out. Will update the database to ERROR
374
+
375
+ :param eval_request_status:
376
+ :return:
377
+ """
378
+ submitted_dt = datetime.fromisoformat(session_obj.submitted_date)
379
+ crt_time = datetime.utcnow()
380
+ time_difference = crt_time - submitted_dt
381
+ difference_in_seconds = time_difference.total_seconds()
382
+ if difference_in_seconds > EVAL_TIMEOUT_SECONDS:
383
+ session_obj.state = EVAL_STATE_TIMEDOUT
384
+ session_state_table.upsert(session_obj)
385
+
386
+
387
+ def html_default_results():
388
+ return P("Submit a piece of C code to get a Clean-Code evaluation.")
389
+
390
+ def html_waiting_for_results():
391
+ return Div(P("Working . . ."), hx_get=f"/render_answer",
392
+ hx_trigger = f"every {REFRESH_TIME}s", hx_swap="outerHTML", target_id=HTML_RESULTS_AREA,)
393
+
394
+ def html_eval_request_timed_out():
395
+ return P("Timed out. Retry in few minutes pls!")
396
+
397
+
398
+ @rt("/render_answer")
399
+ def get(session):
400
+ """
401
+ Endpoint to render the evaluation answer. Pooled by frontend.
402
+
403
+ :param session:
404
+ :return:
405
+ """
406
+ if 'session_id' not in session: return "render_answer No session ID"
407
+ session_id = session["session_id"]
408
+ answer_area = tl_html_results_and_feedback_area(session_id)
409
+ return answer_area
410
+
411
 
412
  def get_latest_eval_request_status(session_id):
413
  state_rows = session_state_table(limit=1, where=f"session_id == '{session_id}'", order_by="id DESC")
414
  if len(state_rows) <= 0:
415
  return EVAL_STATE_NEW, None
416
  state_obj = state_rows[0]
417
+ if state_obj.state in {EVAL_STATE_NEW, EVAL_STATE_QUERY, EVAL_STATE_TIMEDOUT, EVAL_STATE_ANSWER}:
418
+ return state_obj.state, state_obj
419
  return EVAL_STATE_ERROR, state_obj
420
 
421
 
422
+ def html_error_results(message):
423
+ ans = P("There was an error:", P(message))
424
+ return ans
425
 
426
 
427
  def html_render_code_output(code):
428
+ txtarea = Pre(Code(code, _class="language-c"))
429
  return txtarea
430
 
431
 
432
+ def html_render_answer_from_db(session_id):
433
  eval_request_status, state_obj = get_latest_eval_request_status(session_id)
434
  # state_rows = session_state_table(limit=1, where=f"session_id == '{session_id}'", order_by="id DESC")
435
  # print(eval_request_status, state_obj)
436
  if eval_request_status == EVAL_STATE_NEW:
437
+ return html_default_results(),
438
  if eval_request_status == EVAL_STATE_ANSWER:
439
  qe_obj_lst = question_evaluation_table(limit=1, where=f"id == {state_obj.current_qeval}")
440
  if len(qe_obj_lst) < 1:
441
  print(f"Object id {state_obj.current_qeval} can't be found in question_evaluation_table")
442
  return (None,)
443
  qe_obj = qe_obj_lst[0]
444
+ return (html_format_code_review_form(qe_obj),
445
+ html_render_inputbox(target_html_id=HTML_RESULTS_AREA, region_html_id=HTML_SUBMIT_CODE_AREA))
446
+ if eval_request_status == EVAL_STATE_TIMEDOUT:
447
+ return html_eval_request_timed_out(),
448
  if eval_request_status == EVAL_STATE_QUERY:
449
+ check_if_query_should_timeout(state_obj)
450
+ return html_waiting_for_results(),
451
+ print(f"Unknown state of the code evalation request {state_obj.state}:")
452
+ return html_error_results("Some error occured."),
453
 
454
 
455
  # How can I timeout? Well ... TBD.
 
509
  import traceback
510
  traceback.print_exc()
511
 
512
+
513
+ def tl_html_results_and_feedback_area(session_id):
514
+ """
515
+ Top level component that will render the code evaluation overlapped with feedback submission form.
516
+
517
+ :param session_id:
518
+ :return:
519
+ """
520
+ results_feedback_area = html_render_answer_from_db(session_id)
521
+ return Div(*results_feedback_area, id=HTML_RESULTS_AREA)
522
+
523
+
524
  ######## CODE INPUT FORM
525
 
526
 
 
534
  return Div(form, id=region_html_id, hx_swap_oob='true')
535
 
536
 
537
+
538
  ########## CLEAR FORM
539
 
540
  def html_render_clear_area_button(html_id):
 
609
  else:
610
  auth_callback_url = f"https://{SPACE_HOST}/auth_callback/"
611
 
612
+ secret = datetime.isoformat(datetime.utcnow()) + "-" + secrets.token_urlsafe(32)
613
+ session[OAUTH_SECRET_SESSION_NAME] = secret
614
  encoded_scopes = html.escape(OAUTH_SCOPES)
615
  redirect_link = (f"https://huggingface.co/oauth/authorize?redirect_uri={auth_callback_url}&scope={encoded_scopes}"
616
  f"&client_id={OAUTH_CLIENT_ID}&state={secret}&response_type=code&prompt=consent")
 
652
  :param error_description:
653
  :return:
654
  """
655
+ # print(session)
656
  close_script = Script("""
657
  localStorage.setItem('login_success', 'true');
658
  setTimeout(function() {
 
668
  P("Please close this page"))
669
  return_answer.append(ans)
670
  return Div(*return_answer)
 
671
 
672
  # validating the secret
673
+ sess_secret = session.get(OAUTH_SECRET_SESSION_NAME, None)
674
  if sess_secret is None:
675
  print("No session secret")
676
  return_answer.append(P("access denied"))
677
  return Div(*return_answer)
678
 
679
  if sess_secret != state:
680
+ msg = f"Mismatch session secret and HF secret: {sess_secret=} {state=}"
681
+ print(msg)
682
+ return_answer.append(P("Mismatch session secret and HF secret"))
683
  return Div(*return_answer)
684
 
685
  # Moving on and get the token
 
716
  user_data = response_userinfo.json()
717
  # Set the user data in DB
718
  # TODO Is it mildly safe to store user data in session?
719
+ session[USER_DATA_SESSION_NAME] = user_data
720
+ session[OAUTH_SECRET_SESSION_NAME] = None
721
+ # print(user_data)
 
722
  else:
723
  print(f"Error while taking the user data: {response_userinfo.text}" )
724
  return_answer.append(P("Error logging in"))
 
730
 
731
  # print(session)
732
  return_answer.append(P("Succes! Close this page."))
733
+ save_to_storage(
734
+ storage.NavigationEvent(event_type="/auth_callback", event_session_id=session["session_id"],
735
+ event_params={"user_data":user_data})
736
+ )
737
+
738
  return Div(*return_answer)
739
 
740
 
741
  @rt("/logout")
742
  def get(session):
743
+ session[OAUTH_SECRET_SESSION_NAME] = None
744
+ save_to_storage(
745
+ storage.NavigationEvent(event_type="/logout", event_session_id=session["session_id"],
746
+ event_params={"user_data":session["user_data"]})
747
+ )
748
  session["user_data"] = None
749
  return RedirectResponse(url="/")
750
 
 
753
 
754
  @rt("/")
755
  def get(session):
 
756
  if 'session_id' not in session:
757
  session['session_id'] = str(uuid.uuid4())
758
  session_id = session["session_id"]
 
762
  save_to_storage(
763
  storage.NavigationEvent(event_type="/", event_session_id=session_id)
764
  )
765
+ user_data = session.get(USER_DATA_SESSION_NAME, None)
766
  if user_data is not None:
767
  auth_area = html_render_welcome_user(user_data)
768
  else:
 
777
  ]
778
 
779
  input_area = html_render_inputbox(target_html_id=HTML_RESULTS_AREA, region_html_id=HTML_SUBMIT_CODE_AREA)
780
+ results_feedback_area = tl_html_results_and_feedback_area(session_id)
781
  clear_area = render_clear_area(session_id, HTML_CLEAR_FORM)
782
+ # print(session)
783
+ return title, Main(*preamble, input_area, results_feedback_area, clear_area)
 
 
 
 
 
 
784
 
785
 
786
  @rt("/submit_to_eval", methods="post")
787
  def post(session, ccodetoeval:str):
788
+ # print(session)
789
  if 'session_id' not in session:
790
  return P("submit_to_eval. Bad call. No session ID")
791
  session_id = session["session_id"]
 
794
  state=EVAL_STATE_QUERY,
795
  submitted_date=datetime.isoformat(datetime.utcnow()),
796
  )
797
+ save_to_storage(
798
+ storage.NavigationEvent(event_type="/submit_to_eval", event_session_id=session_id, event_params={"ccodetoeval":ccodetoeval})
799
+ )
800
+
801
  # we insert and we get the new primary key
802
  session_obj = session_state_table.insert(session_obj)
803
  # will be executed in another thread with magic @threaded
804
  call_gpt_and_store_result(session_obj.id, ccodetoeval)
805
+ return tl_html_results_and_feedback_area(session_id), render_clear_area(session_id, HTML_CLEAR_FORM)
 
 
806
 
807
 
808
  @rt("/clear_area", methods="get")
 
821
  submitted_date=datetime.isoformat(datetime.utcnow()),
822
  )
823
  session_state_table.insert(session_obj)
824
+ # re-issue the page, basically.
825
  input_area = html_render_inputbox(target_html_id=HTML_RESULTS_AREA, region_html_id=HTML_SUBMIT_CODE_AREA)
826
+ results_area = tl_html_results_and_feedback_area(session_id)
827
  clear_area = render_clear_area(session_id, HTML_CLEAR_FORM)
828
+ return results_area, input_area, clear_area
 
829
 
830
  serve()
storage.py CHANGED
@@ -23,6 +23,7 @@ class CodeSubmittedEvent():
23
  evaluation_response:str = ""
24
  has_feedback:bool = False
25
  feedback_date:str = ""
 
26
 
27
 
28
 
 
23
  evaluation_response:str = ""
24
  has_feedback:bool = False
25
  feedback_date:str = ""
26
+ feedback_userdata:dict=dataclasses.field(default_factory=dict)
27
 
28
 
29