dhammawatthumpra commited on
Commit
fc33cde
·
1 Parent(s): ed478b7

เตรียมความพร้อมสำหรับการ Deploy บน HF Spaces: เพิ่ม ONNX Reranker, แก้ไข Static Path และปรับปรุง Asset Downloader

Browse files
webapp/tipitaka-api/app/main.py CHANGED
@@ -83,7 +83,7 @@ async def health():
83
  # ── Serve built frontend in production (Docker/HF Space) ──
84
  if settings.SERVE_STATIC:
85
  static_dir = settings.STATIC_DIR or os.path.join(
86
- os.path.dirname(__file__), "..", "..", "web", "dist"
87
  )
88
  if os.path.isdir(static_dir):
89
  from fastapi.responses import FileResponse, HTMLResponse
 
83
  # ── Serve built frontend in production (Docker/HF Space) ──
84
  if settings.SERVE_STATIC:
85
  static_dir = settings.STATIC_DIR or os.path.join(
86
+ os.path.dirname(__file__), "..", "..", "tipitaka-web", "dist"
87
  )
88
  if os.path.isdir(static_dir):
89
  from fastapi.responses import FileResponse, HTMLResponse
webapp/tipitaka-api/download_assets.py CHANGED
@@ -19,84 +19,100 @@ settings = get_settings()
19
  DB_PATH = Path(settings.DATABASE_PATH)
20
  QDRANT_DIR = Path(settings.QDRANT_PATH)
21
  SNAPSHOT_DIR = Path(settings.SNAPSHOT_DIR)
 
22
 
23
  # User's local snapshot path fallback (for verification in verify_assets)
24
  USER_LOCAL_SNAPSHOT_DIR = Path(r"F:\_Ai\Tipitaka-AI-Expert\Tipitaka-Data\data\snapshots")
25
 
26
  BUCKET_ID = "dhammawatthumpra/tipitaka-storage"
 
27
 
28
  # Files to check/download
29
  BUCKET_FILES = [
30
  ("tipitaka_mcu.db", str(DB_PATH)),
31
- ("qdrant/tipitaka_chunks.snapshot", "tipitaka_chunks.snapshot"),
32
- ("qdrant/tipitaka_scripture.snapshot", "tipitaka_scripture.snapshot"),
33
  ]
34
 
 
 
 
 
 
 
 
35
 
36
- def check_file_exists(local_path_name: str) -> bool:
37
- """Check if a file exists either in project SNAPSHOT_DIR or USER_LOCAL_SNAPSHOT_DIR."""
38
- # If it's the DB, check DB_PATH
39
- if local_path_name == str(DB_PATH):
40
- return DB_PATH.exists()
41
-
42
- # If it's a snapshot, check both locations
43
- in_project = SNAPSHOT_DIR / local_path_name
44
- in_user_local = USER_LOCAL_SNAPSHOT_DIR / local_path_name
45
 
46
- return in_project.exists() or in_user_local.exists()
 
 
 
 
 
 
47
 
48
 
49
  def download_files() -> None:
50
  """Download missing files from HF bucket."""
51
  hf_token = os.getenv("HF_TOKEN", "")
 
52
 
53
- # Filter to files that don't exist yet in any location
54
- pending = []
55
- for remote, local_name in BUCKET_FILES:
56
- if not check_file_exists(local_name if "snapshot" in local_name else str(DB_PATH)):
57
- # Determine destination: if it's the DB, use DB_PATH, else use project SNAPSHOT_DIR
58
- dest = DB_PATH if "db" in local_name else (SNAPSHOT_DIR / local_name)
59
- pending.append((remote, str(dest)))
60
-
61
- if not pending:
62
- print("Success: All assets already exist in project or local storage - skipping download.")
63
- return
64
-
65
- if not hf_token:
66
- print("WARNING: HF_TOKEN not set — skipping asset download.")
67
- return
68
-
69
- print(f"Downloading {len(pending)} files from bucket '{BUCKET_ID}'...")
70
-
71
- try:
72
- from huggingface_hub import hf_hub_download
73
-
74
- for remote, dest_str in pending:
75
- dest_path = Path(dest_str)
76
- print(f"Downloading {remote} -> {dest_path}")
77
-
78
- dest_path.parent.mkdir(parents=True, exist_ok=True)
79
-
80
- # Note: hf_hub_download with local_dir will create subfolders if remote has slashes
81
- # So if remote is "qdrant/foo.snapshot" and local_dir is DATA_DIR,
82
- # it becomes DATA_DIR/qdrant/foo.snapshot.
83
- # But we want it in DATA_DIR/snapshots/foo.snapshot.
84
- # So we use local_dir_use_symlinks=False and manually move if needed,
85
- # or just download to a temp and move.
 
86
 
87
- downloaded_path = hf_hub_download(
88
- repo_id=BUCKET_ID,
89
- filename=remote,
90
- repo_type="dataset",
91
- token=hf_token
92
- )
93
-
94
- import shutil
95
- shutil.copy(downloaded_path, dest_path)
96
-
97
- print("All files processed successfully.")
98
- except Exception as e:
99
- print(f"ERROR downloading files: {e}")
 
 
 
100
 
101
 
102
  def verify_assets() -> bool:
@@ -108,27 +124,27 @@ def verify_assets() -> bool:
108
  chunks_exists = (SNAPSHOT_DIR / "tipitaka_chunks.snapshot").exists() or \
109
  (USER_LOCAL_SNAPSHOT_DIR / "tipitaka_chunks.snapshot").exists()
110
 
111
- scripture_exists = (SNAPSHOT_DIR / "tipitaka_scripture.snapshot").exists() or \
112
- (USER_LOCAL_SNAPSHOT_DIR / "tipitaka_scripture.snapshot").exists()
113
-
114
  if not chunks_exists:
115
  missing.append("tipitaka_chunks.snapshot")
116
- if not scripture_exists:
117
- missing.append("tipitaka_scripture.snapshot")
 
 
118
 
119
  if missing:
120
- print(f"WARNING: Missing critical assets in any location: {missing}")
121
  return False
122
 
123
- print("Success: All critical assets verified (either in project or local storage).")
124
  return True
125
 
126
 
127
  if __name__ == "__main__":
128
- # Ensure directories exist
129
  QDRANT_DIR.mkdir(parents=True, exist_ok=True)
130
  SNAPSHOT_DIR.mkdir(parents=True, exist_ok=True)
 
131
 
132
  download_files()
133
  verify_assets()
134
  print("Asset management complete.")
 
 
19
  DB_PATH = Path(settings.DATABASE_PATH)
20
  QDRANT_DIR = Path(settings.QDRANT_PATH)
21
  SNAPSHOT_DIR = Path(settings.SNAPSHOT_DIR)
22
+ MODELS_DIR = Path(__file__).resolve().parent / "models"
23
 
24
  # User's local snapshot path fallback (for verification in verify_assets)
25
  USER_LOCAL_SNAPSHOT_DIR = Path(r"F:\_Ai\Tipitaka-AI-Expert\Tipitaka-Data\data\snapshots")
26
 
27
  BUCKET_ID = "dhammawatthumpra/tipitaka-storage"
28
+ RERANK_REPO_ID = "jinaai/jina-reranker-v2-base-multilingual"
29
 
30
  # Files to check/download
31
  BUCKET_FILES = [
32
  ("tipitaka_mcu.db", str(DB_PATH)),
33
+ ("qdrant/tipitaka_chunks.snapshot", str(SNAPSHOT_DIR / "tipitaka_chunks.snapshot")),
34
+ ("qdrant/tipitaka_scripture.snapshot", str(SNAPSHOT_DIR / "tipitaka_scripture.snapshot")),
35
  ]
36
 
37
+ # Essential Reranker files (ONNX)
38
+ RERANK_FILES = [
39
+ "config.json",
40
+ "tokenizer.json",
41
+ "tokenizer_config.json",
42
+ "onnx/model_int8.onnx",
43
+ ]
44
 
45
+
46
+ def check_file_exists(path: Path) -> bool:
47
+ """Check if a file exists locally or in user fallback."""
48
+ if path.exists():
49
+ return True
 
 
 
 
50
 
51
+ # Check fallback for snapshots
52
+ if "snapshot" in path.name:
53
+ fallback = USER_LOCAL_SNAPSHOT_DIR / path.name
54
+ if fallback.exists():
55
+ return True
56
+
57
+ return False
58
 
59
 
60
  def download_files() -> None:
61
  """Download missing files from HF bucket."""
62
  hf_token = os.getenv("HF_TOKEN", "")
63
+ from huggingface_hub import hf_hub_download
64
 
65
+ # 1. Download Core Assets (DB & Snapshots)
66
+ pending_core = []
67
+ for remote, local_path_str in BUCKET_FILES:
68
+ local_path = Path(local_path_str)
69
+ if not check_file_exists(local_path):
70
+ pending_core.append((remote, local_path))
71
+
72
+ if pending_core:
73
+ if not hf_token:
74
+ print("WARNING: HF_TOKEN not set — cannot download core assets.")
75
+ else:
76
+ print(f"Downloading {len(pending_core)} core assets from '{BUCKET_ID}'...")
77
+ for remote, dest_path in pending_core:
78
+ try:
79
+ print(f"Downloading {remote} -> {dest_path}")
80
+ dest_path.parent.mkdir(parents=True, exist_ok=True)
81
+ downloaded = hf_hub_download(
82
+ repo_id=BUCKET_ID,
83
+ filename=remote,
84
+ repo_type="dataset",
85
+ token=hf_token
86
+ )
87
+ import shutil
88
+ shutil.copy(downloaded, dest_path)
89
+ except Exception as e:
90
+ print(f"FAILED to download {remote}: {e}")
91
+
92
+ # 2. Download Reranker Assets (if missing)
93
+ rerank_dir = MODELS_DIR / "jina-v2-onnx"
94
+ pending_rerank = []
95
+ for filename in RERANK_FILES:
96
+ local_path = rerank_dir / filename
97
+ if not local_path.exists():
98
+ pending_rerank.append(filename)
99
 
100
+ if pending_rerank:
101
+ print(f"Downloading {len(pending_rerank)} reranker assets from '{RERANK_REPO_ID}'...")
102
+ for filename in pending_rerank:
103
+ try:
104
+ dest_path = rerank_dir / filename
105
+ print(f"Downloading {filename} -> {dest_path}")
106
+ dest_path.parent.mkdir(parents=True, exist_ok=True)
107
+ downloaded = hf_hub_download(
108
+ repo_id=RERANK_REPO_ID,
109
+ filename=filename,
110
+ token=hf_token if hf_token else None
111
+ )
112
+ import shutil
113
+ shutil.copy(downloaded, dest_path)
114
+ except Exception as e:
115
+ print(f"FAILED to download reranker file {filename}: {e}")
116
 
117
 
118
  def verify_assets() -> bool:
 
124
  chunks_exists = (SNAPSHOT_DIR / "tipitaka_chunks.snapshot").exists() or \
125
  (USER_LOCAL_SNAPSHOT_DIR / "tipitaka_chunks.snapshot").exists()
126
 
 
 
 
127
  if not chunks_exists:
128
  missing.append("tipitaka_chunks.snapshot")
129
+
130
+ rerank_model = MODELS_DIR / "jina-v2-onnx" / "onnx" / "model_int8.onnx"
131
+ if not rerank_model.exists():
132
+ missing.append("reranker_model (model_int8.onnx)")
133
 
134
  if missing:
135
+ print(f"WARNING: Missing assets: {missing}")
136
  return False
137
 
138
+ print("Success: All critical assets verified.")
139
  return True
140
 
141
 
142
  if __name__ == "__main__":
 
143
  QDRANT_DIR.mkdir(parents=True, exist_ok=True)
144
  SNAPSHOT_DIR.mkdir(parents=True, exist_ok=True)
145
+ MODELS_DIR.mkdir(parents=True, exist_ok=True)
146
 
147
  download_files()
148
  verify_assets()
149
  print("Asset management complete.")
150
+
webapp/tipitaka-api/requirements.txt CHANGED
@@ -9,3 +9,8 @@ sentence-transformers>=3.0
9
  huggingface_hub>=0.20
10
  torch>=2.0
11
  pythainlp>=5.0
 
 
 
 
 
 
9
  huggingface_hub>=0.20
10
  torch>=2.0
11
  pythainlp>=5.0
12
+ onnxruntime>=1.17.0
13
+ transformers>=4.40.0
14
+ numpy>=1.24.0
15
+ httpx>=0.27.0
16
+ anyio>=4.0.0