SarahXia0405 commited on
Commit
3020750
·
verified ·
1 Parent(s): 33a55b5

Update api/server.py

Browse files
Files changed (1) hide show
  1. api/server.py +76 -25
api/server.py CHANGED
@@ -2,7 +2,7 @@
2
  import os
3
  import time
4
  import threading
5
- from typing import Dict, List, Optional, Any, Tuple
6
 
7
  from fastapi import FastAPI, UploadFile, File, Form, Request
8
  from fastapi.responses import FileResponse, JSONResponse
@@ -37,9 +37,29 @@ API_DIR = os.path.dirname(__file__)
37
  MODULE10_PATH = os.path.join(API_DIR, "module10_responsible_ai.pdf")
38
  MODULE10_DOC_TYPE = "Literature Review / Paper"
39
 
40
- WEB_DIST = os.path.abspath(os.path.join(API_DIR, "..", "web", "build"))
41
- WEB_INDEX = os.path.join(WEB_DIST, "index.html")
42
- WEB_ASSETS = os.path.join(WEB_DIST, "assets")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
  LS_DATASET_NAME = os.getenv("LS_DATASET_NAME", "clare_user_events").strip()
45
  LS_PROJECT = os.getenv("LANGSMITH_PROJECT", os.getenv("LANGCHAIN_PROJECT", "")).strip()
@@ -75,25 +95,58 @@ app.add_middleware(
75
  )
76
 
77
  # ----------------------------
78
- # Static hosting (Vite build)
79
  # ----------------------------
80
- if os.path.isdir(WEB_ASSETS):
81
- app.mount("/assets", StaticFiles(directory=WEB_ASSETS), name="assets")
 
 
 
 
 
82
 
83
- if os.path.isdir(WEB_DIST):
84
- app.mount("/static", StaticFiles(directory=WEB_DIST), name="static")
 
85
 
86
 
87
  @app.get("/")
88
  def index():
 
 
 
 
 
 
 
89
  if os.path.exists(WEB_INDEX):
90
  return FileResponse(WEB_INDEX)
91
  return JSONResponse(
92
- {"detail": "web/build not found. Build frontend first (web/build/index.html)."},
93
  status_code=500,
94
  )
95
 
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  # ----------------------------
98
  # In-memory session store (MVP)
99
  # ----------------------------
@@ -373,10 +426,7 @@ def chat(req: ChatReq):
373
 
374
  sess["history"] = new_history
375
 
376
- refs = [
377
- {"source_file": c.get("source_file"), "section": c.get("section")}
378
- for c in (rag_used_chunks or [])
379
- ]
380
 
381
  rag_context_chars = len(rag_context_text or "")
382
  rag_used_chunks_count = len(rag_used_chunks or [])
@@ -487,7 +537,6 @@ def api_feedback(req: FeedbackReq):
487
  if rating not in ("helpful", "not_helpful"):
488
  return JSONResponse({"ok": False, "error": "Invalid rating"}, status_code=400)
489
 
490
- # normalize fields
491
  assistant_text = (req.assistant_text or "").strip()
492
  user_text = (req.user_text or "").strip()
493
  comment = (req.comment or "").strip()
@@ -505,12 +554,8 @@ def api_feedback(req: FeedbackReq):
505
  "timestamp_ms": timestamp_ms,
506
  "rating": rating,
507
  "assistant_message_id": req.assistant_message_id,
508
-
509
- # Keep the Example readable:
510
- "question": user_text, # what user asked (optional)
511
- "answer": assistant_text, # the assistant response being rated
512
-
513
- # metadata
514
  "comment": comment,
515
  "tags": tags,
516
  "refs": refs,
@@ -568,17 +613,23 @@ def memoryline(user_id: str):
568
  # ----------------------------
569
  @app.get("/{full_path:path}")
570
  def spa_fallback(full_path: str, request: Request):
 
571
  if (
572
  full_path.startswith("api/")
573
  or full_path.startswith("assets/")
574
  or full_path.startswith("static/")
 
 
575
  ):
576
  return JSONResponse({"detail": "Not Found"}, status_code=404)
577
 
578
- if os.path.exists(WEB_INDEX):
579
- return FileResponse(WEB_INDEX)
 
 
 
580
 
581
  return JSONResponse(
582
- {"detail": "web/build not found. Build frontend first (web/build/index.html)."},
583
  status_code=500,
584
- )
 
2
  import os
3
  import time
4
  import threading
5
+ from typing import Dict, List, Optional, Any
6
 
7
  from fastapi import FastAPI, UploadFile, File, Form, Request
8
  from fastapi.responses import FileResponse, JSONResponse
 
37
  MODULE10_PATH = os.path.join(API_DIR, "module10_responsible_ai.pdf")
38
  MODULE10_DOC_TYPE = "Literature Review / Paper"
39
 
40
+ # ----------------------------
41
+ # Static hosting (SPA build)
42
+ # Prefer CRA web/build then Vite web/dist
43
+ # ----------------------------
44
+ WEB_BUILD = os.path.abspath(os.path.join(API_DIR, "..", "web", "build"))
45
+ WEB_DIST2 = os.path.abspath(os.path.join(API_DIR, "..", "web", "dist"))
46
+
47
+ def _pick_web_root() -> str:
48
+ build_index = os.path.join(WEB_BUILD, "index.html")
49
+ dist_index = os.path.join(WEB_DIST2, "index.html")
50
+ if os.path.exists(build_index):
51
+ return WEB_BUILD
52
+ if os.path.exists(dist_index):
53
+ return WEB_DIST2
54
+ # fallback: prefer build path, but may not exist yet
55
+ return WEB_BUILD
56
+
57
+ WEB_ROOT = _pick_web_root()
58
+ WEB_INDEX = os.path.join(WEB_ROOT, "index.html")
59
+
60
+ WEB_ASSETS_DIR = os.path.join(WEB_ROOT, "assets") # Vite
61
+ WEB_STATIC_DIR = os.path.join(WEB_ROOT, "static") # CRA
62
+ # Some builds also place misc files at root (favicon, manifest, etc.)
63
 
64
  LS_DATASET_NAME = os.getenv("LS_DATASET_NAME", "clare_user_events").strip()
65
  LS_PROJECT = os.getenv("LANGSMITH_PROJECT", os.getenv("LANGCHAIN_PROJECT", "")).strip()
 
95
  )
96
 
97
  # ----------------------------
98
+ # Static hosting mounts
99
  # ----------------------------
100
+ # If Vite build: /assets exists
101
+ if os.path.isdir(WEB_ASSETS_DIR):
102
+ app.mount("/assets", StaticFiles(directory=WEB_ASSETS_DIR), name="assets")
103
+
104
+ # If CRA build: /static exists
105
+ if os.path.isdir(WEB_STATIC_DIR):
106
+ app.mount("/static", StaticFiles(directory=WEB_STATIC_DIR), name="static")
107
 
108
+ # Mount the full root to serve favicon/manifest/robots.txt, etc.
109
+ if os.path.isdir(WEB_ROOT):
110
+ app.mount("/_app", StaticFiles(directory=WEB_ROOT), name="app_root")
111
 
112
 
113
  @app.get("/")
114
  def index():
115
+ # Re-pick on each request in case build output changed after container start
116
+ global WEB_ROOT, WEB_INDEX, WEB_ASSETS_DIR, WEB_STATIC_DIR
117
+ WEB_ROOT = _pick_web_root()
118
+ WEB_INDEX = os.path.join(WEB_ROOT, "index.html")
119
+ WEB_ASSETS_DIR = os.path.join(WEB_ROOT, "assets")
120
+ WEB_STATIC_DIR = os.path.join(WEB_ROOT, "static")
121
+
122
  if os.path.exists(WEB_INDEX):
123
  return FileResponse(WEB_INDEX)
124
  return JSONResponse(
125
+ {"detail": "web build not found. Expected web/build/index.html or web/dist/index.html."},
126
  status_code=500,
127
  )
128
 
129
 
130
+ # ----------------------------
131
+ # Debug endpoint (verify deployment / static root)
132
+ # ----------------------------
133
+ @app.get("/__debug__")
134
+ def __debug__():
135
+ root = _pick_web_root()
136
+ return {
137
+ "ok": True,
138
+ "ts": int(time.time()),
139
+ "web_build": WEB_BUILD,
140
+ "web_dist": WEB_DIST2,
141
+ "web_root_selected": root,
142
+ "index_path": os.path.join(root, "index.html"),
143
+ "has_index": os.path.exists(os.path.join(root, "index.html")),
144
+ "has_assets_dir": os.path.isdir(os.path.join(root, "assets")),
145
+ "has_static_dir": os.path.isdir(os.path.join(root, "static")),
146
+ "uptime_s": round(time.time() - APP_START_TS, 3),
147
+ }
148
+
149
+
150
  # ----------------------------
151
  # In-memory session store (MVP)
152
  # ----------------------------
 
426
 
427
  sess["history"] = new_history
428
 
429
+ refs = [{"source_file": c.get("source_file"), "section": c.get("section")} for c in (rag_used_chunks or [])]
 
 
 
430
 
431
  rag_context_chars = len(rag_context_text or "")
432
  rag_used_chunks_count = len(rag_used_chunks or [])
 
537
  if rating not in ("helpful", "not_helpful"):
538
  return JSONResponse({"ok": False, "error": "Invalid rating"}, status_code=400)
539
 
 
540
  assistant_text = (req.assistant_text or "").strip()
541
  user_text = (req.user_text or "").strip()
542
  comment = (req.comment or "").strip()
 
554
  "timestamp_ms": timestamp_ms,
555
  "rating": rating,
556
  "assistant_message_id": req.assistant_message_id,
557
+ "question": user_text,
558
+ "answer": assistant_text,
 
 
 
 
559
  "comment": comment,
560
  "tags": tags,
561
  "refs": refs,
 
613
  # ----------------------------
614
  @app.get("/{full_path:path}")
615
  def spa_fallback(full_path: str, request: Request):
616
+ # allow API and static mounts to 404 normally
617
  if (
618
  full_path.startswith("api/")
619
  or full_path.startswith("assets/")
620
  or full_path.startswith("static/")
621
+ or full_path.startswith("_app/")
622
+ or full_path in ("__debug__", "health", "ready")
623
  ):
624
  return JSONResponse({"detail": "Not Found"}, status_code=404)
625
 
626
+ root = _pick_web_root()
627
+ idx = os.path.join(root, "index.html")
628
+
629
+ if os.path.exists(idx):
630
+ return FileResponse(idx)
631
 
632
  return JSONResponse(
633
+ {"detail": "web build not found. Expected web/build/index.html or web/dist/index.html."},
634
  status_code=500,
635
+ )