DeepLearning101 commited on
Commit
d17d584
·
verified ·
1 Parent(s): a3f2a68

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +65 -13
app.py CHANGED
@@ -14,6 +14,7 @@ Jev-style 判別式決策互動 POC(繁體中文)
14
  """
15
  import json
16
  import os
 
17
  import subprocess
18
  import threading
19
  import time
@@ -138,13 +139,13 @@ def _ensure_backend_locked():
138
  _set_phase("ready", "jevos 已在運行")
139
  return
140
  try:
141
- jev_dir = _find_or_prepare_backend()
142
- binary = os.path.join(jev_dir, "jev")
143
  # 保險:確保可執行(git/網頁上傳可能掉執行權限)
144
  try:
145
  os.chmod(binary, 0o755)
146
  except Exception:
147
  pass
 
148
  _set_phase("starting", "啟動 jevos…")
149
  _server = subprocess.Popen([binary, "serve"], cwd=jev_dir,
150
  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
@@ -159,13 +160,52 @@ def _ensure_backend_locked():
159
  raise
160
 
161
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  def _find_or_prepare_backend():
163
- """找後端檔案,順序:repo 內已解壓 → 快取 → repo 內壓縮檔 → 線上下載。回傳 jev_dir。"""
 
164
  # 1. 已解壓好的(手動上傳到 repo 根目錄,或之前快取的)
165
- for cand in [os.path.join(BASE, "jev"), os.path.join(DATA, "jev")]:
166
- if os.path.exists(os.path.join(cand, "jev")) and os.path.isdir(os.path.join(cand, "model")):
167
- print(f"[poc] 使用現成後端:{cand}", flush=True)
168
- return cand
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  # 2. repo 根目錄有壓縮檔(手動上傳)→ 解到 DATA
170
  jev_dir = os.path.join(DATA, "jev")
171
  tgz = os.path.join(BASE, "jev-linux-x64.tar.gz")
@@ -176,9 +216,10 @@ def _find_or_prepare_backend():
176
  os.makedirs(DATA, exist_ok=True)
177
  with tarfile.open(tgz) as tf:
178
  tf.extractall(DATA, filter="data")
179
- with zipfile.ZipFile(zf) as z:
180
- z.extractall(jev_dir) # 內含 model/
181
- return jev_dir
 
182
  # 3. 線上下載(Spaces 執行期可連外網)
183
  os.makedirs(DATA, exist_ok=True)
184
  tgz = _dl(BIN_URL, os.path.join(DATA, "jev-linux-x64.tar.gz"))
@@ -186,10 +227,21 @@ def _find_or_prepare_backend():
186
  with tarfile.open(tgz) as tf:
187
  tf.extractall(DATA, filter="data")
188
  zf = _dl(MODEL_URL, os.path.join(DATA, "jevos-v3-openvino-int8.zip"))
189
- _set_phase("extracting", "解壓縮模型(約 630MB)…")
 
 
 
 
 
 
 
190
  with zipfile.ZipFile(zf) as z:
191
- z.extractall(jev_dir) # 內含 model/
192
- return jev_dir
 
 
 
 
193
 
194
 
195
  def decide(state, mode, question, options_text):
 
14
  """
15
  import json
16
  import os
17
+ import shutil
18
  import subprocess
19
  import threading
20
  import time
 
139
  _set_phase("ready", "jevos 已在運行")
140
  return
141
  try:
142
+ jev_dir, binary = _find_or_prepare_backend()
 
143
  # 保險:確保可執行(git/網頁上傳可能掉執行權限)
144
  try:
145
  os.chmod(binary, 0o755)
146
  except Exception:
147
  pass
148
+ _ensure_model_weights(os.path.join(jev_dir, "model"))
149
  _set_phase("starting", "啟動 jevos…")
150
  _server = subprocess.Popen([binary, "serve"], cwd=jev_dir,
151
  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 
160
  raise
161
 
162
 
163
+ def _ensure_model_weights(model_dir):
164
+ """確保 openvino_model.bin 存在;缺失時從 release 下載 zip 並只解出該檔(支援續傳)。"""
165
+ bin_path = os.path.join(model_dir, "openvino_model.bin")
166
+ if os.path.isfile(bin_path):
167
+ return
168
+ print("[poc] 缺少 openvino_model.bin,從 release 下載模型包並解出該檔…", flush=True)
169
+ _set_phase("downloading", "下載模型包(約 630MB,只取權重檔,支援續傳)…")
170
+ zf = _dl(MODEL_URL, os.path.join(DATA, "jevos-v3-openvino-int8.zip"))
171
+ _set_phase("extracting", "解出 openvino_model.bin…")
172
+ os.makedirs(model_dir, exist_ok=True)
173
+ with zipfile.ZipFile(zf) as z:
174
+ for name in z.namelist():
175
+ if name.endswith("openvino_model.bin"):
176
+ with z.open(name) as src, open(bin_path, "wb") as dst:
177
+ shutil.copyfileobj(src, dst, length=1024 * 1024)
178
+ print("[poc] openvino_model.bin 就緒", flush=True)
179
+ return
180
+ raise RuntimeError("模型包內找不到 openvino_model.bin")
181
+
182
+
183
  def _find_or_prepare_backend():
184
+ """找後端檔案,順序:repo 內已解壓 → 快取 → repo 內壓縮檔 → 線上下載。
185
+ 回傳 (jev_dir, binary)。jev_dir 下保證有執行檔與 model/(巢狀佈局會建連結)。"""
186
  # 1. 已解壓好的(手動上傳到 repo 根目錄,或之前快取的)
187
+ for base in (BASE, DATA):
188
+ # 1a. 標準佈局:<base>/jev/{jev(執行檔), model/, *.so}
189
+ d = os.path.join(base, "jev")
190
+ b = os.path.join(d, "jev")
191
+ if os.path.isfile(b) and os.path.isdir(os.path.join(d, "model")):
192
+ print(f"[poc] 使用現成後端:{b}", flush=True)
193
+ return d, b
194
+ # 1b. 巢狀佈局:<base>/jev/jev/{jev(執行檔), *.so},model/ 在 <base>/jev/model/
195
+ # (tarball 內層目錄被原樣上傳時會長這樣;執行檔在內層,./model 要能被找到)
196
+ inner = os.path.join(d, "jev")
197
+ b2 = os.path.join(inner, "jev")
198
+ outer_model = os.path.join(d, "model")
199
+ if os.path.isfile(b2) and os.path.isdir(outer_model):
200
+ link = os.path.join(inner, "model")
201
+ if not os.path.exists(link):
202
+ try:
203
+ os.symlink(outer_model, link)
204
+ print("[poc] 巢狀佈局:已建立 model 連結", flush=True)
205
+ except Exception as e:
206
+ print(f"[poc] 建 model 連結失敗:{e}", flush=True)
207
+ print(f"[poc] 使用現成後端(巢狀):{b2}", flush=True)
208
+ return inner, b2
209
  # 2. repo 根目錄有壓縮檔(手動上傳)→ 解到 DATA
210
  jev_dir = os.path.join(DATA, "jev")
211
  tgz = os.path.join(BASE, "jev-linux-x64.tar.gz")
 
216
  os.makedirs(DATA, exist_ok=True)
217
  with tarfile.open(tgz) as tf:
218
  tf.extractall(DATA, filter="data")
219
+ print("[poc] 主程式解壓完成,解壓縮模型(約 630MB,需要幾分鐘)…", flush=True)
220
+ _extract_zip_progress(zf, jev_dir)
221
+ print("[poc] 模型解壓完成", flush=True)
222
+ return jev_dir, os.path.join(jev_dir, "jev")
223
  # 3. 線上下載(Spaces 執行期可連外網)
224
  os.makedirs(DATA, exist_ok=True)
225
  tgz = _dl(BIN_URL, os.path.join(DATA, "jev-linux-x64.tar.gz"))
 
227
  with tarfile.open(tgz) as tf:
228
  tf.extractall(DATA, filter="data")
229
  zf = _dl(MODEL_URL, os.path.join(DATA, "jevos-v3-openvino-int8.zip"))
230
+ _set_phase("extracting", "解壓縮模型(約 630MB,需要幾分鐘)…")
231
+ _extract_zip_progress(zf, jev_dir)
232
+ print("[poc] 模型解壓完成", flush=True)
233
+ return jev_dir, os.path.join(jev_dir, "jev")
234
+
235
+
236
+ def _extract_zip_progress(zf, jev_dir):
237
+ """解壓 zip 並印進度(避免長時間無輸出被誤判卡死)。"""
238
  with zipfile.ZipFile(zf) as z:
239
+ members = z.namelist()
240
+ total = len(members)
241
+ for i, m in enumerate(members):
242
+ z.extract(m, jev_dir)
243
+ if (i + 1) % 25 == 0 or (i + 1) == total:
244
+ print(f"[poc] 模型解壓縮 {i + 1}/{total}", flush=True)
245
 
246
 
247
  def decide(state, mode, question, options_text):