jtdearmon commited on
Commit
b159bde
·
verified ·
1 Parent(s): 31dc1d4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +44 -16
app.py CHANGED
@@ -723,7 +723,7 @@ def results_equal_or_superset(df_student: pd.DataFrame, df_expected: pd.DataFram
723
  a = _normalize_columns(df_student); b = _normalize_columns(df_expected)
724
  if set(a.columns) == set(b.columns):
725
  a2 = a[sorted(a.columns)].sort_values(sorted(a.columns)).reset_index(drop=True)
726
- b2 = b[sorted(b.columns)].sort_values(sorted(b.columns)).reset_index(drop=True)
727
  return (a2.equals(b2), None)
728
  if set(b.columns).issubset(set(a.columns)):
729
  a_proj = a[b.columns]
@@ -737,6 +737,13 @@ def results_equal_rowcount_only(df_student: pd.DataFrame, df_expected: pd.DataFr
737
  # When projection isn't specified, match on row count only.
738
  return df_student.shape[0] == df_expected.shape[0]
739
 
 
 
 
 
 
 
 
740
  def exec_student_sql(sql_text: str) -> Tuple[Optional[pd.DataFrame], Optional[str], Optional[str], Optional[str]]:
741
  if not sql_text or not sql_text.strip():
742
  return None, "Enter a SQL statement.", None, None
@@ -954,24 +961,47 @@ def _domain_status_md():
954
  err = CURRENT_INFO.get("error",""); err_short = (err[:160] + "…") if len(err) > 160 else err
955
  return f"⚠️ **OpenAI randomization unavailable** → using fallback **{CURRENT_SCHEMA.get('domain','?')}**.\n\n> Reason: {err_short}"
956
 
957
- def regenerate_domain():
 
 
 
 
 
 
 
 
 
 
 
958
  global CURRENT_SCHEMA, CURRENT_QS, CURRENT_INFO
959
  prev = CURRENT_SCHEMA.get("domain") if CURRENT_SCHEMA else None
960
  CURRENT_SCHEMA, CURRENT_QS, CURRENT_INFO = install_schema_and_prepare_questions(prev_domain=prev)
961
  erd = draw_dynamic_erd(CURRENT_SCHEMA)
962
- return gr.update(value=_domain_status_md(), visible=True), erd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
963
 
964
  def preview_table(tbl: str):
965
  try:
 
 
966
  return run_df(CONN, f"SELECT * FROM {tbl} LIMIT 20")
967
  except Exception as e:
968
  return pd.DataFrame([{"error": str(e)}])
969
 
970
- def list_tables_for_preview():
971
- df = run_df(CONN, "SELECT name, type FROM sqlite_master WHERE type in ('table','view') AND name NOT IN ('users','attempts','session_meta') ORDER BY type, name")
972
- if df.empty: return ["(no tables)"]
973
- return df["name"].tolist()
974
-
975
  # -------------------- UI --------------------
976
  with gr.Blocks(title="Adaptive SQL Trainer — Randomized Domains") as demo:
977
  gr.Markdown(
@@ -1060,21 +1090,19 @@ with gr.Blocks(title="Adaptive SQL Trainer — Randomized Domains") as demo:
1060
  inputs=[export_name],
1061
  outputs=[export_file],
1062
  )
 
 
1063
  regen_btn.click(
1064
  regenerate_domain,
1065
- inputs=[],
1066
- outputs=[regen_fb, er_image],
1067
  )
 
1068
  tbl_btn.click(
1069
- lambda name: preview_table(name),
1070
  inputs=[tbl_dd],
1071
  outputs=[preview_df]
1072
  )
1073
- regen_btn.click( # refresh list after regeneration
1074
- lambda: gr.update(choices=list_tables_for_preview()),
1075
- inputs=[],
1076
- outputs=[tbl_dd]
1077
- )
1078
 
1079
  if __name__ == "__main__":
1080
  demo.launch()
 
723
  a = _normalize_columns(df_student); b = _normalize_columns(df_expected)
724
  if set(a.columns) == set(b.columns):
725
  a2 = a[sorted(a.columns)].sort_values(sorted(a.columns)).reset_index(drop=True)
726
+ b2 = b[sorted(a.columns)].sort_values(sorted(a.columns)).reset_index(drop=True)
727
  return (a2.equals(b2), None)
728
  if set(b.columns).issubset(set(a.columns)):
729
  a_proj = a[b.columns]
 
737
  # When projection isn't specified, match on row count only.
738
  return df_student.shape[0] == df_expected.shape[0]
739
 
740
+ def aliases_present(sql: str, required_aliases: List[str]) -> bool:
741
+ low = re.sub(r"\s+", " ", (sql or "").lower())
742
+ for al in (required_aliases or []):
743
+ if f" {al}." not in low and f" as {al} " not in low:
744
+ return False
745
+ return True
746
+
747
  def exec_student_sql(sql_text: str) -> Tuple[Optional[pd.DataFrame], Optional[str], Optional[str], Optional[str]]:
748
  if not sql_text or not sql_text.strip():
749
  return None, "Enter a SQL statement.", None, None
 
961
  err = CURRENT_INFO.get("error",""); err_short = (err[:160] + "…") if len(err) > 160 else err
962
  return f"⚠️ **OpenAI randomization unavailable** → using fallback **{CURRENT_SCHEMA.get('domain','?')}**.\n\n> Reason: {err_short}"
963
 
964
+ # ----- UPDATED: regenerate also refreshes tbl list and, if session active, seeds a new question + shows input
965
+ def list_tables_for_preview():
966
+ df = run_df(CONN, """
967
+ SELECT name FROM sqlite_master
968
+ WHERE type in ('table','view')
969
+ AND name NOT LIKE 'sqlite_%'
970
+ AND name NOT IN ('users','attempts','session_meta')
971
+ ORDER BY type, name
972
+ """)
973
+ return df["name"].tolist() if not df.empty else ["(no tables)"]
974
+
975
+ def regenerate_domain(session: dict):
976
  global CURRENT_SCHEMA, CURRENT_QS, CURRENT_INFO
977
  prev = CURRENT_SCHEMA.get("domain") if CURRENT_SCHEMA else None
978
  CURRENT_SCHEMA, CURRENT_QS, CURRENT_INFO = install_schema_and_prepare_questions(prev_domain=prev)
979
  erd = draw_dynamic_erd(CURRENT_SCHEMA)
980
+ status = _domain_status_md()
981
+
982
+ # Refresh the preview dropdown
983
+ choices = list_tables_for_preview()
984
+ dd_update = gr.update(choices=choices, value=(choices[0] if choices and choices[0]!="(no tables)" else None))
985
+
986
+ # If a session is active, show the first question immediately for the new domain
987
+ prompt_update = gr.update()
988
+ input_update = gr.update()
989
+ if session and session.get("user_id"):
990
+ q = pick_next_question(session["user_id"])
991
+ session["qid"] = q["id"]; session["q"] = q; session["start_ts"] = time.time()
992
+ prompt_update = gr.update(value=f"**Question {q['id']}**\n\n{q['prompt_md']}", visible=True)
993
+ input_update = gr.update(value="", visible=True)
994
+
995
+ return status, erd, prompt_update, input_update, dd_update, session
996
 
997
  def preview_table(tbl: str):
998
  try:
999
+ if not tbl or tbl=="(no tables)":
1000
+ return pd.DataFrame()
1001
  return run_df(CONN, f"SELECT * FROM {tbl} LIMIT 20")
1002
  except Exception as e:
1003
  return pd.DataFrame([{"error": str(e)}])
1004
 
 
 
 
 
 
1005
  # -------------------- UI --------------------
1006
  with gr.Blocks(title="Adaptive SQL Trainer — Randomized Domains") as demo:
1007
  gr.Markdown(
 
1090
  inputs=[export_name],
1091
  outputs=[export_file],
1092
  )
1093
+
1094
+ # UPDATED: one callback handles regeneration, dropdown refresh, and (if session) reseeding the next question
1095
  regen_btn.click(
1096
  regenerate_domain,
1097
+ inputs=[session_state],
1098
+ outputs=[regen_fb, er_image, prompt_md, sql_input, tbl_dd, session_state],
1099
  )
1100
+
1101
  tbl_btn.click(
1102
+ preview_table,
1103
  inputs=[tbl_dd],
1104
  outputs=[preview_df]
1105
  )
 
 
 
 
 
1106
 
1107
  if __name__ == "__main__":
1108
  demo.launch()