Spaces:
Running
Running
mirror ledger to private dataset
Browse files- app/ledger.py +81 -1
- app/main.py +22 -4
app/ledger.py
CHANGED
|
@@ -34,6 +34,84 @@ ROOT = _root()
|
|
| 34 |
LOCK = threading.Lock()
|
| 35 |
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
def boot_check():
|
| 38 |
"""์์ฅ์ด ์ฌ์์์ ๊ฒฌ๋๋์ง **์ค์ธก**ํ๋ค.
|
| 39 |
|
|
@@ -107,7 +185,8 @@ def register(user_id, strategy, ptype, assets):
|
|
| 107 |
"visits": prev.get("visits", []),
|
| 108 |
}
|
| 109 |
_write(_p("users.json"), u)
|
| 110 |
-
|
|
|
|
| 111 |
|
| 112 |
|
| 113 |
def user_by_key(key):
|
|
@@ -143,6 +222,7 @@ def submit(user_id, asset, position, source="api"):
|
|
| 143 |
with LOCK:
|
| 144 |
with open(_p("positions", "%s.jsonl" % asset), "a", encoding="utf-8") as f:
|
| 145 |
f.write(json.dumps(rec, ensure_ascii=False) + "\n")
|
|
|
|
| 146 |
touch(user_id)
|
| 147 |
return rec
|
| 148 |
|
|
|
|
| 34 |
LOCK = threading.Lock()
|
| 35 |
|
| 36 |
|
| 37 |
+
# โโโโโโโโโโโโโโโโโโโโโโโ ์์ฅ ๋ฏธ๋ฌ โโโโโโโโโโโโโโโโโโโโโโโ
|
| 38 |
+
# ๐ด HF Space์ /data ๋ ์์ ์คํ ๋ฆฌ์ง๋ฅผ ๋ถ์ด์ง ์์ผ๋ฉด ์ฌ์์์ ์ฌ๋ผ์ง๋ค.
|
| 39 |
+
# ์ค์ธกํ๋ค โ ์ฌ์์ ํ ๋ถํ
ํ์์ด ์์ด์ก๋ค(boots 1 -> 1).
|
| 40 |
+
# ์ ๋ฃ ์คํ ๋ฆฌ์ง ๋์ ๋น๊ณต๊ฐ ๋ฐ์ดํฐ์
์ ์ฅ์์ ์์ฅ์ ๋ฏธ๋ฌ๋งํ๋ค.
|
| 41 |
+
# ์์ฆ 4๊ฐ์์น ๊ธฐ๋ก์ด ์ปจํ
์ด๋ ์ฌ์์ ํ ๋ฒ์ ๋ ์๊ฐ๋ฉด ๋ํ๊ฐ ๋๋๋ค.
|
| 42 |
+
MIRROR = os.environ.get("FINCHAL_MIRROR") # ์: FINAL-Bench/finchal-ledger
|
| 43 |
+
_MIR = {"ok": False, "dirty": False, "at": 0.0, "n": 0, "err": None}
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def _api():
|
| 47 |
+
from huggingface_hub import HfApi
|
| 48 |
+
tok = os.environ.get("HF_TOKEN") or os.environ.get("FINCHAL_HF_TOKEN")
|
| 49 |
+
return HfApi(token=tok) if tok else None
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def restore():
|
| 53 |
+
"""๋ถํ
์ ๋ฏธ๋ฌ์์ ์์ฅ์ ๋์ด๋ฆฐ๋ค. ์ด๊ฒ ์คํจํ๋ฉด ๋ฏธ๋ฌ์ ์ฐ์ง ์๋๋ค.
|
| 54 |
+
|
| 55 |
+
๐ ๋ณต์ ์คํจ ํ flush ํ๋ฉด ๋น ์์ฅ์ด ๋ฏธ๋ฌ๋ฅผ ๋ฎ์ด ์์ฆ์ด ํต์งธ๋ก ์ฌ๋ผ์ง๋ค.
|
| 56 |
+
ํ ๋ฒ์ ์๋ชป๋ ๋ฎ์ด์ฐ๊ธฐ๊ฐ 4๊ฐ์์ ์ง์ด๋ค.
|
| 57 |
+
"""
|
| 58 |
+
if not MIRROR:
|
| 59 |
+
return "๋ฏธ๋ฌ ์์"
|
| 60 |
+
try:
|
| 61 |
+
from huggingface_hub import snapshot_download
|
| 62 |
+
a = _api()
|
| 63 |
+
if a is None:
|
| 64 |
+
_MIR["err"] = "HF_TOKEN ์์"
|
| 65 |
+
return _MIR["err"]
|
| 66 |
+
try:
|
| 67 |
+
a.repo_info(MIRROR, repo_type="dataset")
|
| 68 |
+
except Exception:
|
| 69 |
+
a.create_repo(MIRROR, repo_type="dataset", private=True, exist_ok=True)
|
| 70 |
+
d = snapshot_download(MIRROR, repo_type="dataset",
|
| 71 |
+
token=a.token, local_dir=None)
|
| 72 |
+
import shutil, glob
|
| 73 |
+
os.makedirs(os.path.join(ROOT, "positions"), exist_ok=True)
|
| 74 |
+
n = 0
|
| 75 |
+
for src in glob.glob(os.path.join(d, "**", "*"), recursive=True):
|
| 76 |
+
if not os.path.isfile(src) or os.sep + ".cache" in src:
|
| 77 |
+
continue
|
| 78 |
+
rel = os.path.relpath(src, d)
|
| 79 |
+
if rel.startswith(".git"):
|
| 80 |
+
continue
|
| 81 |
+
dst = os.path.join(ROOT, rel)
|
| 82 |
+
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
| 83 |
+
shutil.copyfile(src, dst)
|
| 84 |
+
n += 1
|
| 85 |
+
_MIR["ok"] = True
|
| 86 |
+
_MIR["n"] = n
|
| 87 |
+
return "๋ณต์ %d๊ฐ" % n
|
| 88 |
+
except Exception as e:
|
| 89 |
+
_MIR["err"] = "%s: %s" % (type(e).__name__, e)
|
| 90 |
+
return _MIR["err"]
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def flush(force=False):
|
| 94 |
+
"""์์ฅ์ ๋ฏธ๋ฌ์ ์ฌ๋ฆฐ๋ค. ์ ์ถ๋ง๋ค ์ฌ๋ฆฌ๋ฉด ์ปค๋ฐ์ด ํญ์ฃผํ๋ฏ๋ก ๋ชจ์์ ๋ณด๋ธ๋ค."""
|
| 95 |
+
if not (MIRROR and _MIR["ok"]) or (not _MIR["dirty"] and not force):
|
| 96 |
+
return False
|
| 97 |
+
try:
|
| 98 |
+
a = _api()
|
| 99 |
+
a.upload_folder(repo_id=MIRROR, repo_type="dataset", folder_path=ROOT,
|
| 100 |
+
commit_message="ledger sync",
|
| 101 |
+
ignore_patterns=["*.tmp", ".cache/*"])
|
| 102 |
+
_MIR["dirty"] = False
|
| 103 |
+
_MIR["at"] = time.time()
|
| 104 |
+
return True
|
| 105 |
+
except Exception as e:
|
| 106 |
+
_MIR["err"] = "%s: %s" % (type(e).__name__, e)
|
| 107 |
+
return False
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def mirror_status():
|
| 111 |
+
return {"repo": MIRROR, "restored": _MIR["ok"], "files": _MIR["n"],
|
| 112 |
+
"pending": _MIR["dirty"], "error": _MIR["err"]}
|
| 113 |
+
|
| 114 |
+
|
| 115 |
def boot_check():
|
| 116 |
"""์์ฅ์ด ์ฌ์์์ ๊ฒฌ๋๋์ง **์ค์ธก**ํ๋ค.
|
| 117 |
|
|
|
|
| 185 |
"visits": prev.get("visits", []),
|
| 186 |
}
|
| 187 |
_write(_p("users.json"), u)
|
| 188 |
+
_MIR["dirty"] = True
|
| 189 |
+
return u[user_id]
|
| 190 |
|
| 191 |
|
| 192 |
def user_by_key(key):
|
|
|
|
| 222 |
with LOCK:
|
| 223 |
with open(_p("positions", "%s.jsonl" % asset), "a", encoding="utf-8") as f:
|
| 224 |
f.write(json.dumps(rec, ensure_ascii=False) + "\n")
|
| 225 |
+
_MIR["dirty"] = True
|
| 226 |
touch(user_id)
|
| 227 |
return rec
|
| 228 |
|
app/main.py
CHANGED
|
@@ -336,14 +336,31 @@ def _anchor_loop():
|
|
| 336 |
time.sleep(6 * 3600)
|
| 337 |
|
| 338 |
|
|
|
|
|
|
|
|
|
|
| 339 |
_DUR = L.boot_check()
|
| 340 |
|
| 341 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 342 |
@app.on_event("startup")
|
| 343 |
def _startup():
|
|
|
|
|
|
|
|
|
|
|
|
|
| 344 |
if os.environ.get("FINCHAL_NO_ANCHOR"):
|
| 345 |
return
|
| 346 |
-
import threading
|
| 347 |
threading.Thread(target=_anchor_loop, daemon=True).start()
|
| 348 |
|
| 349 |
|
|
@@ -351,6 +368,7 @@ def _startup():
|
|
| 351 |
def health():
|
| 352 |
return {"ok": True, "season": S1["name"], "assets": list(ASSETS),
|
| 353 |
"ledger": L.ROOT, "durability": _DUR[0], "boots": _DUR[1],
|
| 354 |
-
"
|
| 355 |
-
|
| 356 |
-
|
|
|
|
|
|
| 336 |
time.sleep(6 * 3600)
|
| 337 |
|
| 338 |
|
| 339 |
+
# ๐ ์์ฅ ๋ณต์์ **๋ค๋ฅธ ๋ฌด์๋ณด๋ค ๋จผ์ **๋ค. ๋ณต์ ์ ์ ๋ถํ
ํ์์ ์ฐ๋ฉด
|
| 340 |
+
# ๊ทธ ํ์์ด ๋ฏธ๋ฌ๋ฅผ ๋ฎ์ด ์์ฅ์ ์ง์ด๋ค.
|
| 341 |
+
_RESTORE = L.restore()
|
| 342 |
_DUR = L.boot_check()
|
| 343 |
|
| 344 |
|
| 345 |
+
def _flush_loop():
|
| 346 |
+
"""์์ฅ์ ์ฃผ๊ธฐ์ ์ผ๋ก ๋ฏธ๋ฌ์ ์ฌ๋ฆฐ๋ค. ์ ์ถ๋ง๋ค ์ปค๋ฐํ๋ฉด ์ ์ฅ์๊ฐ ํฐ์ง๋ค."""
|
| 347 |
+
import traceback
|
| 348 |
+
while True:
|
| 349 |
+
time.sleep(90)
|
| 350 |
+
try:
|
| 351 |
+
L.flush()
|
| 352 |
+
except Exception:
|
| 353 |
+
traceback.print_exc()
|
| 354 |
+
|
| 355 |
+
|
| 356 |
@app.on_event("startup")
|
| 357 |
def _startup():
|
| 358 |
+
import threading
|
| 359 |
+
print("[finchal] ์์ฅ %s ยท ๋ฏธ๋ฌ %s" % (L.ROOT, _RESTORE))
|
| 360 |
+
if L.MIRROR:
|
| 361 |
+
threading.Thread(target=_flush_loop, daemon=True).start()
|
| 362 |
if os.environ.get("FINCHAL_NO_ANCHOR"):
|
| 363 |
return
|
|
|
|
| 364 |
threading.Thread(target=_anchor_loop, daemon=True).start()
|
| 365 |
|
| 366 |
|
|
|
|
| 368 |
def health():
|
| 369 |
return {"ok": True, "season": S1["name"], "assets": list(ASSETS),
|
| 370 |
"ledger": L.ROOT, "durability": _DUR[0], "boots": _DUR[1],
|
| 371 |
+
"mirror": L.mirror_status(), "restore": _RESTORE,
|
| 372 |
+
"warn": None if (_DUR[0] == "ํ์ธ๋จ" or L.mirror_status()["restored"])
|
| 373 |
+
else "์์ฅ์ด ์ฌ์์์ ๊ฒฌ๋๋ค๋ ์ฆ๊ฑฐ๊ฐ ์์ต๋๋ค. "
|
| 374 |
+
"๋ฏธ๋ฌ(FINCHAL_MIRROR)๋ ์์ ์คํ ๋ฆฌ์ง๋ฅผ ๋ถ์ด์ญ์์ค."}
|