Update main.py
Browse files
main.py
CHANGED
|
@@ -204,22 +204,46 @@ def _resolve_uid_by_email(email: str):
|
|
| 204 |
return None
|
| 205 |
|
| 206 |
def fetch_syllabus_structure(remote_id: str):
|
|
|
|
| 207 |
try:
|
| 208 |
-
|
| 209 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
except Exception as e:
|
| 211 |
-
logger.error(f"
|
| 212 |
return None
|
| 213 |
|
| 214 |
def search_syllabus_context(query: str, remote_id: str = None):
|
|
|
|
| 215 |
try:
|
| 216 |
payload = {"query": query}
|
| 217 |
if remote_id:
|
| 218 |
payload["filter_subject_id"] = remote_id
|
| 219 |
-
|
| 220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
except Exception as e:
|
| 222 |
-
logger.error(f"
|
| 223 |
return []
|
| 224 |
|
| 225 |
# -----------------------------------------------------------------------------
|
|
@@ -1720,6 +1744,65 @@ def submit_path_node():
|
|
| 1720 |
return jsonify({"success": True, "passed": False, "message": "Score too low. Review the lesson and try again."})
|
| 1721 |
|
| 1722 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1723 |
# -----------------------------------------------------------------------------
|
| 1724 |
# 17. MAIN
|
| 1725 |
# -----------------------------------------------------------------------------
|
|
|
|
| 204 |
return None
|
| 205 |
|
| 206 |
def fetch_syllabus_structure(remote_id: str):
|
| 207 |
+
url = f"{DATA_API_BASE_URL}/structure/{remote_id}"
|
| 208 |
try:
|
| 209 |
+
logger.info(f"Fetching syllabus: {url}")
|
| 210 |
+
resp = requests.get(url, timeout=15)
|
| 211 |
+
logger.info(f"Syllabus fetch {remote_id}: HTTP {resp.status_code}")
|
| 212 |
+
if resp.status_code == 200:
|
| 213 |
+
return resp.json()
|
| 214 |
+
logger.error(f"Syllabus fetch failed {remote_id}: HTTP {resp.status_code} — {resp.text[:200]}")
|
| 215 |
+
return None
|
| 216 |
+
except requests.exceptions.Timeout:
|
| 217 |
+
logger.error(f"Syllabus fetch TIMEOUT after 15s: {url}")
|
| 218 |
+
return None
|
| 219 |
+
except requests.exceptions.ConnectionError as e:
|
| 220 |
+
logger.error(f"Syllabus fetch CONNECTION ERROR: {url} — {e}")
|
| 221 |
+
return None
|
| 222 |
except Exception as e:
|
| 223 |
+
logger.error(f"Syllabus fetch unexpected error {remote_id}: {type(e).__name__}: {e}")
|
| 224 |
return None
|
| 225 |
|
| 226 |
def search_syllabus_context(query: str, remote_id: str = None):
|
| 227 |
+
url = f"{DATA_API_BASE_URL}/search"
|
| 228 |
try:
|
| 229 |
payload = {"query": query}
|
| 230 |
if remote_id:
|
| 231 |
payload["filter_subject_id"] = remote_id
|
| 232 |
+
logger.info(f"Searching syllabus: query='{query[:50]}' subject={remote_id}")
|
| 233 |
+
resp = requests.post(url, json=payload, timeout=15)
|
| 234 |
+
logger.info(f"Syllabus search: HTTP {resp.status_code}")
|
| 235 |
+
if resp.status_code == 200:
|
| 236 |
+
return resp.json().get("results", [])
|
| 237 |
+
logger.error(f"Syllabus search failed: HTTP {resp.status_code} — {resp.text[:200]}")
|
| 238 |
+
return []
|
| 239 |
+
except requests.exceptions.Timeout:
|
| 240 |
+
logger.error(f"Syllabus search TIMEOUT after 15s: {url}")
|
| 241 |
+
return []
|
| 242 |
+
except requests.exceptions.ConnectionError as e:
|
| 243 |
+
logger.error(f"Syllabus search CONNECTION ERROR: {url} — {e}")
|
| 244 |
+
return []
|
| 245 |
except Exception as e:
|
| 246 |
+
logger.error(f"Syllabus search unexpected error: {type(e).__name__}: {e}")
|
| 247 |
return []
|
| 248 |
|
| 249 |
# -----------------------------------------------------------------------------
|
|
|
|
| 1744 |
return jsonify({"success": True, "passed": False, "message": "Score too low. Review the lesson and try again."})
|
| 1745 |
|
| 1746 |
|
| 1747 |
+
|
| 1748 |
+
@app.route("/api/debug/data-api", methods=["GET"])
|
| 1749 |
+
def debug_data_api():
|
| 1750 |
+
"""
|
| 1751 |
+
Diagnostic endpoint — tests connectivity from app server to infra server.
|
| 1752 |
+
Call this from the browser to see exactly what the app server gets back.
|
| 1753 |
+
Admin only.
|
| 1754 |
+
"""
|
| 1755 |
+
uid = verify_token(request.headers.get("Authorization"))
|
| 1756 |
+
if not uid:
|
| 1757 |
+
return jsonify({"error": "Unauthorized"}), 401
|
| 1758 |
+
try:
|
| 1759 |
+
require_role(uid, ["admin"])
|
| 1760 |
+
except PermissionError as e:
|
| 1761 |
+
return jsonify({"error": str(e)}), 403
|
| 1762 |
+
|
| 1763 |
+
results = {"data_api_base_url": DATA_API_BASE_URL, "tests": []}
|
| 1764 |
+
|
| 1765 |
+
# Test 1: root/health
|
| 1766 |
+
for test_path in ["/", "/health", "/v1/subjects"]:
|
| 1767 |
+
url = DATA_API_BASE_URL.rstrip("/v1").rstrip("/") + test_path
|
| 1768 |
+
try:
|
| 1769 |
+
r = requests.get(url, timeout=10)
|
| 1770 |
+
results["tests"].append({
|
| 1771 |
+
"url": url, "status": r.status_code,
|
| 1772 |
+
"ok": r.status_code == 200,
|
| 1773 |
+
"body_preview": r.text[:300]
|
| 1774 |
+
})
|
| 1775 |
+
except Exception as e:
|
| 1776 |
+
results["tests"].append({"url": url, "status": "ERROR", "ok": False, "error": str(e)})
|
| 1777 |
+
|
| 1778 |
+
# Test 2: specific structure fetch
|
| 1779 |
+
test_remote_id = "A_9702"
|
| 1780 |
+
url = f"{DATA_API_BASE_URL}/structure/{test_remote_id}"
|
| 1781 |
+
try:
|
| 1782 |
+
r = requests.get(url, timeout=10)
|
| 1783 |
+
body = r.json() if r.status_code == 200 else r.text[:300]
|
| 1784 |
+
results["tests"].append({
|
| 1785 |
+
"url": url, "status": r.status_code, "ok": r.status_code == 200,
|
| 1786 |
+
"has_tree": isinstance(body, dict) and "tree" in body,
|
| 1787 |
+
"tree_length": len(body.get("tree", [])) if isinstance(body, dict) else 0
|
| 1788 |
+
})
|
| 1789 |
+
except Exception as e:
|
| 1790 |
+
results["tests"].append({"url": url, "status": "ERROR", "ok": False, "error": str(e)})
|
| 1791 |
+
|
| 1792 |
+
# Test 3: search
|
| 1793 |
+
url = f"{DATA_API_BASE_URL}/search"
|
| 1794 |
+
try:
|
| 1795 |
+
r = requests.post(url, json={"query": "kinematics motion"}, timeout=10)
|
| 1796 |
+
body = r.json() if r.status_code == 200 else r.text[:300]
|
| 1797 |
+
results["tests"].append({
|
| 1798 |
+
"url": url, "status": r.status_code, "ok": r.status_code == 200,
|
| 1799 |
+
"results_count": len(body.get("results", [])) if isinstance(body, dict) else 0
|
| 1800 |
+
})
|
| 1801 |
+
except Exception as e:
|
| 1802 |
+
results["tests"].append({"url": url, "status": "ERROR", "ok": False, "error": str(e)})
|
| 1803 |
+
|
| 1804 |
+
return jsonify(results)
|
| 1805 |
+
|
| 1806 |
# -----------------------------------------------------------------------------
|
| 1807 |
# 17. MAIN
|
| 1808 |
# -----------------------------------------------------------------------------
|