Spaces:
Running on Zero
Running on Zero
File size: 5,106 Bytes
f60d986 5138afe a0f99e4 d99de7e 5138afe d217db3 d99de7e 66bf9b9 d217db3 d99de7e 5138afe 66bf9b9 5138afe d99de7e 5138afe d99de7e 5138afe d99de7e 66bf9b9 d99de7e 66bf9b9 d99de7e 66bf9b9 d99de7e 66bf9b9 d99de7e 5138afe d217db3 5138afe 418cd34 aa348d3 418cd34 aa348d3 418cd34 aa348d3 d217db3 5138afe d217db3 10834f9 5d39c7c d217db3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | import io
import os
import shutil
import subprocess
import urllib.request
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path
# ---- 自动拉取 Xet 指针文件 ----
def _is_valid_image(fpath):
try:
with open(fpath, "rb") as f:
head = f.read(16)
if len(head) < 4:
return False
if head[:8] == b"\x89PNG\r\n\x1a\n":
return True
if head[:3] == b"\xff\xd8\xff":
return True
if head[:6] in (b"GIF87a", b"GIF89a"):
return True
if head[:4] == b"RIFF" and head[8:12] == b"WEBP":
return True
if head[:2] == b"BM":
return True
return False
except Exception:
return False
def _is_valid_image_bytes(data):
if len(data) < 4:
return False
if data[:8] == b"\x89PNG\r\n\x1a\n":
return True
if data[:3] == b"\xff\xd8\xff":
return True
if data[:6] in (b"GIF87a", b"GIF89a"):
return True
if data[:4] == b"RIFF" and data[8:12] == b"WEBP":
return True
if data[:2] == b"BM":
return True
return False
def _download_one(urls, fpath):
"""尝试从多个源下载,成功一个即返回。"""
if isinstance(urls, str):
urls = [urls]
for url in urls:
for attempt in range(3):
try:
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=120) as resp:
data = resp.read()
if data and _is_valid_image_bytes(data):
with open(fpath, "wb") as f:
f.write(data)
return True
except Exception:
if attempt < 2:
import time
time.sleep(1)
return False
def _materialize_xet():
repo_id = "donotthink/meme"
hf_base = f"https://huggingface.co/spaces/{repo_id}/resolve/main"
gh_base = "https://raw.githubusercontent.com/Memes02/meme-generator/main"
exts = (".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp")
need_download = []
total = 0
for root, _dirs, files in os.walk("meme_generator"):
for fname in files:
if not fname.lower().endswith(exts):
continue
total += 1
fpath = os.path.join(root, fname)
if not _is_valid_image(fpath):
need_download.append(fpath)
print(f"[xet] scanned {total} images, {len(need_download)} need download", flush=True)
if not need_download:
return
count = 0
failed_files = []
with ThreadPoolExecutor(max_workers=6) as executor:
futures = {}
for fpath in need_download:
rel = os.path.relpath(fpath, ".").replace(os.sep, "/")
# 先试 HF,失败再试 GitHub
urls = [f"{hf_base}/{rel}", f"{gh_base}/{rel}"]
futures[executor.submit(_download_one, urls, fpath)] = fpath
for fut in as_completed(futures):
fpath = futures[fut]
if fut.result():
count += 1
else:
failed_files.append(fpath)
if (count + len(failed_files)) % 100 == 0:
print(f"[xet] progress {count + len(failed_files)}/{len(need_download)}", flush=True)
print(f"[xet] materialized {count} files, {len(failed_files)} failures", flush=True)
if failed_files:
print(f"[xet] failed files ({len(failed_files)}):", flush=True)
for f in failed_files[:30]:
print(f" - {f}", flush=True)
if len(failed_files) > 30:
print(f" ... and {len(failed_files) - 30} more", flush=True)
_materialize_xet()
# ---- 注册字体 ----
_font_src = Path("resources/fonts")
_font_dst = Path.home() / ".fonts"
if _font_src.exists():
_font_dst.mkdir(parents=True, exist_ok=True)
for _f in _font_src.iterdir():
if _f.is_file():
shutil.copy2(_f, _font_dst / _f.name)
subprocess.run(["fc-cache", "-fv"], capture_output=True)
# ---- ZeroGPU 兼容层:必须有 @spaces.GPU 装饰的函数并实际调用,否则 ZeroGPU 会停止应用 ----
import spaces
import asyncio
@spaces.GPU
def _zero_gpu_warmup():
"""占位函数,让 ZeroGPU 检测到 GPU 函数调用。实际不使用 GPU。"""
return "warmup-ok"
# 启动前实际调用一次,触发 spaces 库的 GPU 初始化
try:
_r = _zero_gpu_warmup()
if asyncio.iscoroutine(_r):
asyncio.run(_r)
print("[zero-gpu] warmup done", flush=True)
except Exception as _e:
print(f"[zero-gpu] warmup skipped: {_e}", flush=True)
# ---- 启动 meme_generator 原生 FastAPI(无 Gradio,无 CSRF)----
import uvicorn
from meme_generator.app import app, register_routers
register_routers()
print("[meme] API server starting on 0.0.0.0:7860", flush=True)
print("[meme] endpoints: /memes/keys, /memes/{key}/, /memes/{key}/info, /docs", flush=True)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7860)
|