lanna_lalala;- commited on
Commit
a0ad5fe
Β·
1 Parent(s): 2950f9c

init frontend

Browse files
Files changed (2) hide show
  1. app.py +46 -21
  2. utils/api.py +61 -22
app.py CHANGED
@@ -15,6 +15,10 @@ from phase.Student_view.games import profitpuzzle
15
  from utils import db,api
16
  import os
17
 
 
 
 
 
18
 
19
  try:
20
  ok = api.health().get("ok")
@@ -228,28 +232,48 @@ def main():
228
  submit = st.form_submit_button("Login")
229
 
230
  if submit:
231
- conn = db.get_db_connection()
232
- if not conn:
233
- st.error("❌ Unable to connect to the database.")
234
- else:
235
  try:
236
- user = db.check_password(email, password)
237
- if user:
238
- st.session_state.user = {
239
- "user_id": user["user_id"],
240
- "name": user["name"],
241
- "role": user["role"], # "Student" or "Teacher"
242
- "email": user["email"],
243
- }
244
- st.success(f"πŸŽ‰ Logged in as {user['name']} ({user['role']})")
245
- st.session_state.current_page = (
246
- "Student Dashboard" if user["role"] == "Student" else "Teacher Dashboard"
247
- )
248
- st.rerun()
249
- else:
250
- st.error("❌ Incorrect email or password, or account not found.")
251
- finally:
252
- conn.close()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
  # --- STUDENT DASHBOARD ---
255
  elif page == "Student Dashboard":
@@ -308,3 +332,4 @@ def main():
308
 
309
  if __name__ == "__main__":
310
  main()
 
 
15
  from utils import db,api
16
  import os
17
 
18
+ from utils.api import BACKEND
19
+ st.sidebar.caption(f"Backend URL: {BACKEND}")
20
+
21
+ DISABLE_DB = os.getenv("DISABLE_DB", "1") == "1"
22
 
23
  try:
24
  ok = api.health().get("ok")
 
232
  submit = st.form_submit_button("Login")
233
 
234
  if submit:
235
+ if DISABLE_DB:
236
+ # Route login to your Backend Space
 
 
237
  try:
238
+ user = api.login(email, password) # calls POST /auth/login
239
+ # Normalize to the structure your app already uses
240
+ st.session_state.user = {
241
+ "user_id": user["user_id"],
242
+ "name": user["name"],
243
+ "role": user["role"], # "Student" or "Teacher" from backend
244
+ "email": user["email"],
245
+ }
246
+ st.success(f"πŸŽ‰ Logged in as {user['name']} ({user['role']})")
247
+ st.session_state.current_page = (
248
+ "Student Dashboard" if user["role"] == "Student" else "Teacher Dashboard"
249
+ )
250
+ st.rerun()
251
+ except Exception as e:
252
+ st.error(f"Login failed. {e}")
253
+ else:
254
+ # Local fallback: keep your old direct-DB logic
255
+ conn = db.get_db_connection()
256
+ if not conn:
257
+ st.error("❌ Unable to connect to the database.")
258
+ else:
259
+ try:
260
+ user = db.check_password(email, password)
261
+ if user:
262
+ st.session_state.user = {
263
+ "user_id": user["user_id"],
264
+ "name": user["name"],
265
+ "role": user["role"], # "Student" or "Teacher"
266
+ "email": user["email"],
267
+ }
268
+ st.success(f"πŸŽ‰ Logged in as {user['name']} ({user['role']})")
269
+ st.session_state.current_page = (
270
+ "Student Dashboard" if user["role"] == "Student" else "Teacher Dashboard"
271
+ )
272
+ st.rerun()
273
+ else:
274
+ st.error("❌ Incorrect email or password, or account not found.")
275
+ finally:
276
+ conn.close()
277
 
278
  # --- STUDENT DASHBOARD ---
279
  elif page == "Student Dashboard":
 
332
 
333
  if __name__ == "__main__":
334
  main()
335
+
utils/api.py CHANGED
@@ -1,32 +1,71 @@
1
  # utils/api.py
2
- import os, requests
 
3
 
4
- BACKEND = (os.getenv("BACKEND_URL") or "").strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  if not BACKEND:
6
- raise RuntimeError("BACKEND_URL is not set in Space secrets.")
7
- BACKEND = BACKEND.rstrip("/")
8
 
9
- def health():
10
- r = requests.get(f"{BACKEND}/health", timeout=10)
11
  r.raise_for_status()
12
- return r.json()
13
 
14
- def start_agent(student_id:int, lesson_id:int, level_slug:str):
15
- r = requests.post(f"{BACKEND}/agent/start", json={"student_id":student_id,"lesson_id":lesson_id,"level_slug":level_slug})
16
  r.raise_for_status()
17
- return r.json()
18
 
19
- def get_quiz(student_id:int, lesson_id:int, level_slug:str):
20
- r = requests.post(f"{BACKEND}/agent/quiz", json={"student_id":student_id,"lesson_id":lesson_id,"level_slug":level_slug})
21
- r.raise_for_status()
22
- return r.json()["items"]
 
 
 
 
 
 
 
 
 
 
 
23
 
24
- def grade_quiz(student_id:int, lesson_id:int, level_slug:str, answers:list[str], assignment_id:int|None=None):
25
- r = requests.post(f"{BACKEND}/agent/grade", json={"student_id":student_id,"lesson_id":lesson_id,"level_slug":level_slug,"answers":answers,"assignment_id":assignment_id})
26
- r.raise_for_status()
27
- d = r.json(); return d["score"], d["total"]
28
 
29
- def next_step(student_id:int, lesson_id:int, level_slug:str, answers:list[str], assignment_id:int|None=None):
30
- r = requests.post(f"{BACKEND}/agent/coach_or_celebrate", json={"student_id":student_id,"lesson_id":lesson_id,"level_slug":level_slug,"answers":answers,"assignment_id":assignment_id})
31
- r.raise_for_status()
32
- return r.json()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # utils/api.py
2
+ import os
3
+ import requests
4
 
5
+ def _normalize_backend_url(url: str) -> str:
6
+ url = (url or "").strip()
7
+ # fix accidental comma typos
8
+ url = url.replace(",", ".")
9
+ # convert huggingface.co/spaces/<owner>/<space> -> https://<owner>-<space>.hf.space
10
+ if "huggingface.co/spaces/" in url:
11
+ tail = url.split("huggingface.co/spaces/")[-1].strip("/")
12
+ parts = tail.split("/")
13
+ if len(parts) >= 2:
14
+ owner, space = parts[0], parts[1]
15
+ url = f"https://{owner}-{space}.hf.space"
16
+ return url.rstrip("/")
17
+
18
+ BACKEND = _normalize_backend_url(os.getenv("BACKEND_URL"))
19
  if not BACKEND:
20
+ raise RuntimeError("BACKEND_URL is not set")
 
21
 
22
+ def _get(path: str, **kwargs):
23
+ r = requests.get(f"{BACKEND}{path}", timeout=kwargs.pop("timeout", 10), **kwargs)
24
  r.raise_for_status()
25
+ return r
26
 
27
+ def _post(path: str, json: dict, **kwargs):
28
+ r = requests.post(f"{BACKEND}{path}", json=json, timeout=kwargs.pop("timeout", 15), **kwargs)
29
  r.raise_for_status()
30
+ return r
31
 
32
+ def health() -> dict:
33
+ # Try /health, then /
34
+ for path in ("/health", "/"):
35
+ try:
36
+ r = _get(path)
37
+ try:
38
+ data = r.json()
39
+ except Exception:
40
+ return {"ok": True}
41
+ if path == "/health":
42
+ return {"ok": bool(data.get("ok", True))}
43
+ return {"ok": data.get("status") == "ok"}
44
+ except Exception:
45
+ continue
46
+ raise RuntimeError(f"Backend not reachable at {BACKEND}")
47
 
48
+ def start_agent(student_id: int, lesson_id: int, level_slug: str) -> dict:
49
+ return _post("/agent/start", json={
50
+ "student_id": student_id, "lesson_id": lesson_id, "level_slug": level_slug
51
+ }).json()
52
 
53
+ def get_quiz(student_id: int, lesson_id: int, level_slug: str) -> list:
54
+ return _post("/agent/quiz", json={
55
+ "student_id": student_id, "lesson_id": lesson_id, "level_slug": level_slug
56
+ }).json()["items"]
57
+
58
+ def grade_quiz(student_id: int, lesson_id: int, level_slug: str,
59
+ answers: list[str], assignment_id: int | None = None):
60
+ data = _post("/agent/grade", json={
61
+ "student_id": student_id, "lesson_id": lesson_id, "level_slug": level_slug,
62
+ "answers": answers, "assignment_id": assignment_id
63
+ }).json()
64
+ return data["score"], data["total"]
65
+
66
+ def next_step(student_id: int, lesson_id: int, level_slug: str,
67
+ answers: list[str], assignment_id: int | None = None) -> dict:
68
+ return _post("/agent/coach_or_celebrate", json={
69
+ "student_id": student_id, "lesson_id": lesson_id, "level_slug": level_slug,
70
+ "answers": answers, "assignment_id": assignment_id
71
+ }).json()