YanAdjeNole commited on
Commit
52c1e6d
·
verified ·
1 Parent(s): 7383247

Update server.py

Browse files
Files changed (1) hide show
  1. server.py +38 -16
server.py CHANGED
@@ -1,21 +1,24 @@
 
1
  import os
2
  import io
3
  import json
4
  from typing import Any, Dict, List, Optional
5
  from fastapi import FastAPI, Query, HTTPException
6
  from fastapi.middleware.cors import CORSMiddleware
 
 
7
  from pydantic import BaseModel
8
  from datetime import datetime, timezone
9
  from huggingface_hub import HfApi, upload_file, hf_hub_download, create_repo
10
 
11
- # === Configuration ===
12
  REPO_ID = os.environ.get("STORE_REPO", "your-org/asset-annotator-store")
13
  HF_TOKEN = os.environ.get("HF_TOKEN")
14
-
15
  api = HfApi(token=HF_TOKEN)
 
16
  app = FastAPI()
17
 
18
- # Allow local frontend access
19
  app.add_middleware(
20
  CORSMiddleware,
21
  allow_origins=["*"],
@@ -24,14 +27,13 @@ app.add_middleware(
24
  allow_headers=["*"],
25
  )
26
 
27
-
28
  def ensure_repo():
29
  try:
30
  create_repo(REPO_ID, repo_type="dataset", exist_ok=True, token=HF_TOKEN)
31
  except Exception:
32
  pass
33
 
34
-
35
  def upload_json(path_in_repo: str, obj: Any, message: str):
36
  ensure_repo()
37
  buf = io.BytesIO(json.dumps(obj, ensure_ascii=False, indent=2).encode("utf-8"))
@@ -44,7 +46,6 @@ def upload_json(path_in_repo: str, obj: Any, message: str):
44
  commit_message=message,
45
  )
46
 
47
-
48
  def download_json(path_in_repo: str) -> Optional[Any]:
49
  try:
50
  local = hf_hub_download(repo_id=REPO_ID, repo_type="dataset", filename=path_in_repo, token=HF_TOKEN)
@@ -53,12 +54,7 @@ def download_json(path_in_repo: str) -> Optional[Any]:
53
  except Exception:
54
  return None
55
 
56
-
57
- @app.get("/api/health")
58
- def health():
59
- return {"ok": True, "repo": REPO_ID}
60
-
61
-
62
  class Dataset(BaseModel):
63
  dataset_id: str
64
  name: str
@@ -66,7 +62,6 @@ class Dataset(BaseModel):
66
  assets: List[str]
67
  dates: List[str]
68
 
69
-
70
  class Annotation(BaseModel):
71
  dataset_id: str
72
  user_id: str
@@ -74,6 +69,11 @@ class Annotation(BaseModel):
74
  step: int
75
  window_len: int
76
 
 
 
 
 
 
77
 
78
  @app.post("/api/dataset/upsert")
79
  def upsert_dataset(ds: Dataset):
@@ -82,7 +82,6 @@ def upsert_dataset(ds: Dataset):
82
  upload_json("datasets/latest.json", payload, f"upsert dataset {ds.dataset_id}")
83
  return {"ok": True}
84
 
85
-
86
  @app.get("/api/dataset/latest")
87
  def get_latest():
88
  obj = download_json("datasets/latest.json")
@@ -90,7 +89,6 @@ def get_latest():
90
  raise HTTPException(status_code=404, detail="No dataset yet.")
91
  return obj
92
 
93
-
94
  @app.get("/api/annotation/get")
95
  def get_annotation(dataset_id: str = Query(...), user_id: str = Query(...)):
96
  obj = download_json(f"annotations/{dataset_id}/{user_id}.json")
@@ -98,10 +96,34 @@ def get_annotation(dataset_id: str = Query(...), user_id: str = Query(...)):
98
  return {"user_id": user_id, "dataset_id": dataset_id, "selections": [], "step": 1, "window_len": 7}
99
  return obj
100
 
101
-
102
  @app.post("/api/annotation/upsert")
103
  def upsert_annotation(ann: Annotation):
104
  payload = ann.dict()
105
  payload["updated_at"] = datetime.now(timezone.utc).isoformat()
106
  upload_json(f"annotations/{ann.dataset_id}/{ann.user_id}.json", payload, f"upsert annotation {ann.dataset_id}/{ann.user_id}")
107
  return {"ok": True}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # server.py
2
  import os
3
  import io
4
  import json
5
  from typing import Any, Dict, List, Optional
6
  from fastapi import FastAPI, Query, HTTPException
7
  from fastapi.middleware.cors import CORSMiddleware
8
+ from fastapi.responses import JSONResponse, FileResponse, PlainTextResponse
9
+ from fastapi.staticfiles import StaticFiles
10
  from pydantic import BaseModel
11
  from datetime import datetime, timezone
12
  from huggingface_hub import HfApi, upload_file, hf_hub_download, create_repo
13
 
14
+ # === Config ===
15
  REPO_ID = os.environ.get("STORE_REPO", "your-org/asset-annotator-store")
16
  HF_TOKEN = os.environ.get("HF_TOKEN")
 
17
  api = HfApi(token=HF_TOKEN)
18
+
19
  app = FastAPI()
20
 
21
+ # CORS(同域访问其实不需要,但保留更宽松)
22
  app.add_middleware(
23
  CORSMiddleware,
24
  allow_origins=["*"],
 
27
  allow_headers=["*"],
28
  )
29
 
30
+ # ---------- Hub helpers ----------
31
  def ensure_repo():
32
  try:
33
  create_repo(REPO_ID, repo_type="dataset", exist_ok=True, token=HF_TOKEN)
34
  except Exception:
35
  pass
36
 
 
37
  def upload_json(path_in_repo: str, obj: Any, message: str):
38
  ensure_repo()
39
  buf = io.BytesIO(json.dumps(obj, ensure_ascii=False, indent=2).encode("utf-8"))
 
46
  commit_message=message,
47
  )
48
 
 
49
  def download_json(path_in_repo: str) -> Optional[Any]:
50
  try:
51
  local = hf_hub_download(repo_id=REPO_ID, repo_type="dataset", filename=path_in_repo, token=HF_TOKEN)
 
54
  except Exception:
55
  return None
56
 
57
+ # ---------- API schemas ----------
 
 
 
 
 
58
  class Dataset(BaseModel):
59
  dataset_id: str
60
  name: str
 
62
  assets: List[str]
63
  dates: List[str]
64
 
 
65
  class Annotation(BaseModel):
66
  dataset_id: str
67
  user_id: str
 
69
  step: int
70
  window_len: int
71
 
72
+ # ---------- API routes ----------
73
+ @app.get("/api/health")
74
+ def health():
75
+ dist_exists = os.path.exists("dist/index.html")
76
+ return {"ok": True, "repo": REPO_ID, "dist": dist_exists}
77
 
78
  @app.post("/api/dataset/upsert")
79
  def upsert_dataset(ds: Dataset):
 
82
  upload_json("datasets/latest.json", payload, f"upsert dataset {ds.dataset_id}")
83
  return {"ok": True}
84
 
 
85
  @app.get("/api/dataset/latest")
86
  def get_latest():
87
  obj = download_json("datasets/latest.json")
 
89
  raise HTTPException(status_code=404, detail="No dataset yet.")
90
  return obj
91
 
 
92
  @app.get("/api/annotation/get")
93
  def get_annotation(dataset_id: str = Query(...), user_id: str = Query(...)):
94
  obj = download_json(f"annotations/{dataset_id}/{user_id}.json")
 
96
  return {"user_id": user_id, "dataset_id": dataset_id, "selections": [], "step": 1, "window_len": 7}
97
  return obj
98
 
 
99
  @app.post("/api/annotation/upsert")
100
  def upsert_annotation(ann: Annotation):
101
  payload = ann.dict()
102
  payload["updated_at"] = datetime.now(timezone.utc).isoformat()
103
  upload_json(f"annotations/{ann.dataset_id}/{ann.user_id}.json", payload, f"upsert annotation {ann.dataset_id}/{ann.user_id}")
104
  return {"ok": True}
105
+
106
+ # ---------- Static mount + SPA fallback ----------
107
+ # 1) 如果 dist 存在,挂载静态资源
108
+ if os.path.isdir("dist"):
109
+ app.mount("/assets", StaticFiles(directory="dist/assets", html=False), name="assets")
110
+
111
+ # 2) 根路径:返回 index.html 或错误提示
112
+ @app.get("/")
113
+ def index():
114
+ if os.path.exists("dist/index.html"):
115
+ return FileResponse("dist/index.html")
116
+ return PlainTextResponse(
117
+ "Frontend not built or not found. Missing dist/index.html.\n"
118
+ "Check Dockerfile build stage and ensure '@vitejs/plugin-react' is installed.",
119
+ status_code=500,
120
+ )
121
+
122
+ # 3) 其它所有路径 → SPA fallback 到 index.html(不覆盖 /api/*)
123
+ @app.get("/{full_path:path}")
124
+ def spa(full_path: str):
125
+ if full_path.startswith("api/"):
126
+ raise HTTPException(status_code=404, detail="Not found")
127
+ if os.path.exists("dist/index.html"):
128
+ return FileResponse("dist/index.html")
129
+ return PlainTextResponse("Frontend not built.", status_code=500)