github-actions[bot] commited on
Commit
4297382
ยท
1 Parent(s): e57a1e6

chore: sync HF Space from main

Browse files
Files changed (5) hide show
  1. .gitattributes +0 -35
  2. .gitignore +4 -0
  3. Dockerfile +76 -9
  4. README.md +10 -5
  5. start.sh +88 -50
.gitattributes DELETED
@@ -1,35 +0,0 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ ๆž„ๅปบๆ—ฅๅฟ—.MD
2
+ ้‡ๅฏๆ—ฅๅฟ—.MD
3
+ Dockerfileไพ‹ๅญ
4
+ entrypointไพ‹ๅญ.sh
Dockerfile CHANGED
@@ -1,18 +1,85 @@
1
- FROM ghcr.io/chenyme/grok2api:latest
2
 
3
- ENV TZ=Asia/Shanghai \
4
- LOG_LEVEL=INFO \
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  SERVER_PORT=7860 \
6
- SERVER_WORKERS=1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
- # ๅŸบ็ก€้•œๅƒ python ๅœจ /opt/venv/bin/python3๏ผŒไฝ†ๆ—  pip๏ผŒ็”จ ensurepip ๅฎ‰่ฃ…ๅŽๅ†่ฃ…ไพ่ต–
9
- RUN python3 -m ensurepip --upgrade && \
10
- python3 -m pip install --no-cache-dir "huggingface_hub>=0.23.0" "watchdog>=4.0.0"
 
 
 
11
 
12
- RUN mkdir -p /app/data /app/logs && chmod -R 777 /app/data /app/logs
 
 
 
13
 
14
  COPY start.sh /app/start.sh
15
- RUN sed -i 's/\r$//' /app/start.sh && chmod +x /app/start.sh
 
16
 
17
  EXPOSE 7860
18
 
 
1
+ FROM python:3.13-alpine AS builder
2
 
3
+ ENV PYTHONDONTWRITEBYTECODE=1 \
4
+ PYTHONUNBUFFERED=1 \
5
+ TZ=Asia/Shanghai \
6
+ UV_PROJECT_ENVIRONMENT=/opt/venv
7
+
8
+ ENV PATH="$UV_PROJECT_ENVIRONMENT/bin:$PATH"
9
+
10
+ RUN apk add --no-cache \
11
+ git \
12
+ tzdata \
13
+ ca-certificates \
14
+ build-base \
15
+ linux-headers \
16
+ libffi-dev \
17
+ openssl-dev \
18
+ curl-dev \
19
+ cargo \
20
+ rust
21
+
22
+ WORKDIR /src
23
+
24
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
25
+
26
+ ARG GROK2API_REPO=https://github.com/chenyme/grok2api.git
27
+ ARG GROK2API_REF=main
28
+
29
+ RUN git clone --depth 1 --branch "$GROK2API_REF" "$GROK2API_REPO" /src/grok2api
30
+
31
+ WORKDIR /src/grok2api
32
+
33
+ RUN uv sync --frozen --no-dev --no-install-project \
34
+ && find /opt/venv -type d -name "__pycache__" -prune -exec rm -rf {} + \
35
+ && find /opt/venv -type f -name "*.pyc" -delete \
36
+ && find /opt/venv -type d -name "tests" -prune -exec rm -rf {} + \
37
+ && find /opt/venv -type d -name "test" -prune -exec rm -rf {} + \
38
+ && find /opt/venv -type d -name "testing" -prune -exec rm -rf {} + \
39
+ && find /opt/venv -type f -name "*.so" -exec strip --strip-unneeded {} + || true \
40
+ && rm -rf /root/.cache /tmp/uv-cache
41
+
42
+ FROM python:3.13-alpine
43
+
44
+ ENV PYTHONDONTWRITEBYTECODE=1 \
45
+ PYTHONUNBUFFERED=1 \
46
+ TZ=Asia/Shanghai \
47
+ VIRTUAL_ENV=/opt/venv \
48
+ DATA_DIR=/app/data \
49
+ SERVER_HOST=0.0.0.0 \
50
  SERVER_PORT=7860 \
51
+ SERVER_WORKERS=1 \
52
+ LOG_LEVEL=INFO
53
+
54
+ ENV PATH="$VIRTUAL_ENV/bin:$PATH"
55
+
56
+ RUN apk add --no-cache \
57
+ tzdata \
58
+ ca-certificates \
59
+ git \
60
+ libffi \
61
+ openssl \
62
+ libgcc \
63
+ libstdc++ \
64
+ libcurl
65
+
66
+ WORKDIR /app
67
 
68
+ COPY --from=builder /opt/venv /opt/venv
69
+ COPY --from=builder /src/grok2api/config.defaults.toml ./
70
+ COPY --from=builder /src/grok2api/app ./app
71
+ COPY --from=builder /src/grok2api/_public ./_public
72
+ COPY --from=builder /src/grok2api/main.py ./
73
+ COPY --from=builder /src/grok2api/scripts ./scripts
74
 
75
+ RUN python3 -m ensurepip --upgrade \
76
+ && python3 -m pip install --no-cache-dir "huggingface_hub>=0.23.0" "watchdog>=4.0.0" \
77
+ && mkdir -p /app/data /app/logs \
78
+ && chmod +x /app/scripts/entrypoint.sh
79
 
80
  COPY start.sh /app/start.sh
81
+ RUN sed -i 's/\r$//' /app/start.sh \
82
+ && chmod +x /app/start.sh
83
 
84
  EXPOSE 7860
85
 
README.md CHANGED
@@ -1,10 +1,15 @@
1
  ---
2
- title: Grok2api
3
- emoji: ๐Ÿจ
4
- colorFrom: yellow
5
- colorTo: purple
6
  sdk: docker
 
7
  pinned: false
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
1
  ---
2
+ title: grok2api
3
+ emoji: ๐Ÿš€
4
+ colorFrom: gray
5
+ colorTo: indigo
6
  sdk: docker
7
+ app_port: 7860
8
  pinned: false
9
  ---
10
 
11
+ # grok2api
12
+
13
+ This Hugging Face Space is synced from the `huggingface-HFGROK2API-A` directory in the source repository.
14
+
15
+ It uses Docker mode and builds the latest `chenyme/grok2api` source during Space build.
start.sh CHANGED
@@ -1,16 +1,22 @@
1
  #!/bin/sh
2
- set -e
3
 
4
  PYTHON=/opt/venv/bin/python3
 
 
 
5
  echo "[start] using python: $PYTHON"
 
6
 
7
- # โ”€โ”€ 1. ไปŽ HF Bucket ๆขๅค data/ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
8
  $PYTHON - <<'PYEOF'
9
- import os, sys
 
10
  from huggingface_hub import HfFileSystem
11
 
12
  token = os.environ.get("HF_TOKEN", "")
13
- repo = os.environ.get("HF_BUCKET_REPO", "")
 
14
 
15
  if not token or not repo:
16
  print("[bucket_pull] skipped: HF_TOKEN or HF_BUCKET_REPO not set")
@@ -18,111 +24,143 @@ if not token or not repo:
18
 
19
  fs = HfFileSystem(token=token)
20
  bucket_root = f"hf://buckets/{repo}"
21
- local_data = "/app/data"
22
  os.makedirs(local_data, exist_ok=True)
23
 
24
  try:
25
  if not fs.exists(bucket_root):
26
  print(f"[bucket_pull] bucket {bucket_root} not found, skipping")
27
  sys.exit(0)
28
-
29
  files = fs.glob(f"{bucket_root}/**/*")
30
  pulled = 0
 
31
  for remote_file in files:
32
  if fs.isfile(remote_file):
33
- rel_path = remote_file.replace(f"hf://buckets/{repo}/", "")
34
  local_file = os.path.join(local_data, rel_path)
35
  os.makedirs(os.path.dirname(local_file), exist_ok=True)
36
  fs.get(remote_file, local_file)
37
  print(f"[bucket_pull] restored: {rel_path}")
38
  pulled += 1
39
  print(f"[bucket_pull] done, {pulled} file(s) restored.")
40
- except Exception as e:
41
- print(f"[bucket_pull] error: {e}")
42
  PYEOF
43
 
44
- # โ”€โ”€ 2. ๅˆๅง‹ๅŒ–ๅญ˜ๅ‚จ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
45
  if [ -f /app/scripts/init_storage.sh ]; then
46
  /app/scripts/init_storage.sh
47
  fi
48
 
49
- # โ”€โ”€ 3. ๆณจๅ…ฅ Secrets ๅˆฐ config.toml โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
50
- CONFIG="/app/data/config.toml"
51
- if [ -n "$APP_KEY" ] && [ -f "$CONFIG" ]; then
52
  sed -i "s|^app_key = .*|app_key = \"$APP_KEY\"|" "$CONFIG"
53
  fi
54
- if [ -n "$API_KEY" ] && [ -f "$CONFIG" ]; then
55
  sed -i "s|^api_key = .*|api_key = \"$API_KEY\"|" "$CONFIG"
56
  fi
57
 
58
  export SERVER_STORAGE_TYPE="${SERVER_STORAGE_TYPE:-local}"
59
  export SERVER_STORAGE_URL="${SERVER_STORAGE_URL:-}"
60
 
61
- # โ”€โ”€ 4. ๅŽๅฐ๏ผšๆ–‡ไปถ็›‘ๅฌ๏ผˆ็ซ‹ๅณๆŽจ้€๏ผ‰+ ๅ…œๅบ•ๅฎšๆ—ถๅŒๆญฅ๏ผˆๆฏ5ๅˆ†้’Ÿ๏ผ‰โ”€โ”€
62
  $PYTHON - <<'PYEOF' &
63
- import os, sys, time, threading, glob
64
- from watchdog.observers import Observer
65
- from watchdog.events import FileSystemEventHandler
 
66
  from huggingface_hub import HfFileSystem
 
 
67
 
68
  token = os.environ.get("HF_TOKEN", "")
69
- repo = os.environ.get("HF_BUCKET_REPO", "")
 
 
 
70
 
71
  def push():
72
  if not token or not repo:
73
  return
 
74
  fs = HfFileSystem(token=token)
75
- data_dir = "/app/data"
76
- bucket_root = f"hf://buckets/{repo}"
77
-
78
- files = [f for f in glob.glob(os.path.join(data_dir, "**", "*"), recursive=True) if os.path.isfile(f)]
 
79
  if not files:
80
  return
 
81
  try:
82
  for local_path in files:
83
- rel_path = os.path.relpath(local_path, data_dir)
84
  remote_path = f"{bucket_root}/{rel_path}"
85
  fs.put(local_path, remote_path)
86
  print(f"[bucket_push] pushed {len(files)} file(s)", flush=True)
87
- except Exception as e:
88
- print(f"[bucket_push] error: {e}", flush=True)
 
89
 
90
  class Handler(FileSystemEventHandler):
91
  def __init__(self):
92
  self._timer = None
93
  self._lock = threading.Lock()
 
94
  def _schedule(self):
95
  with self._lock:
96
  if self._timer:
97
  self._timer.cancel()
98
  self._timer = threading.Timer(5, push)
99
  self._timer.start()
100
- def on_modified(self, e):
101
- if not e.is_directory: self._schedule()
102
- def on_created(self, e):
103
- if not e.is_directory: self._schedule()
104
-
105
- # ๆ–‡ไปถๅ˜ๅŒ–็›‘ๅฌ
106
- observer = Observer()
107
- observer.schedule(Handler(), path="/app/data", recursive=True)
108
- observer.start()
109
- print("[bucket_watch] watching /app/data...", flush=True)
110
-
111
- # ๅ…œๅบ•ๅฎšๆ—ถๅŒๆญฅ
112
- def periodic():
113
- while True:
114
- time.sleep(300)
115
- push()
116
- threading.Thread(target=periodic, daemon=True).start()
117
 
118
- try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  while True:
120
- time.sleep(1)
121
- except KeyboardInterrupt:
122
- observer.stop()
123
- observer.join()
124
  PYEOF
125
 
126
- # โ”€โ”€ 5. ๅฏๅŠจๅบ”็”จ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
127
  echo "[start] starting grok2api..."
128
- exec /opt/venv/bin/granian --interface asgi --host 0.0.0.0 --port 7860 --workers 1 main:app
 
 
 
 
 
1
  #!/bin/sh
2
+ set -eu
3
 
4
  PYTHON=/opt/venv/bin/python3
5
+ DATA_DIR="${DATA_DIR:-/app/data}"
6
+ CONFIG="$DATA_DIR/config.toml"
7
+
8
  echo "[start] using python: $PYTHON"
9
+ echo "[start] data dir: $DATA_DIR"
10
 
11
+ # 1. ไปŽ HF Bucket ๆขๅค data/
12
  $PYTHON - <<'PYEOF'
13
+ import os
14
+ import sys
15
  from huggingface_hub import HfFileSystem
16
 
17
  token = os.environ.get("HF_TOKEN", "")
18
+ repo = os.environ.get("HF_BUCKET_REPO", "")
19
+ local_data = os.environ.get("DATA_DIR", "/app/data")
20
 
21
  if not token or not repo:
22
  print("[bucket_pull] skipped: HF_TOKEN or HF_BUCKET_REPO not set")
 
24
 
25
  fs = HfFileSystem(token=token)
26
  bucket_root = f"hf://buckets/{repo}"
 
27
  os.makedirs(local_data, exist_ok=True)
28
 
29
  try:
30
  if not fs.exists(bucket_root):
31
  print(f"[bucket_pull] bucket {bucket_root} not found, skipping")
32
  sys.exit(0)
33
+
34
  files = fs.glob(f"{bucket_root}/**/*")
35
  pulled = 0
36
+ prefix = f"hf://buckets/{repo}/"
37
  for remote_file in files:
38
  if fs.isfile(remote_file):
39
+ rel_path = remote_file.replace(prefix, "", 1)
40
  local_file = os.path.join(local_data, rel_path)
41
  os.makedirs(os.path.dirname(local_file), exist_ok=True)
42
  fs.get(remote_file, local_file)
43
  print(f"[bucket_pull] restored: {rel_path}")
44
  pulled += 1
45
  print(f"[bucket_pull] done, {pulled} file(s) restored.")
46
+ except Exception as exc:
47
+ print(f"[bucket_pull] error: {exc}")
48
  PYEOF
49
 
50
+ # 2. ๅˆๅง‹ๅŒ–ๅญ˜ๅ‚จ
51
  if [ -f /app/scripts/init_storage.sh ]; then
52
  /app/scripts/init_storage.sh
53
  fi
54
 
55
+ # 3. ๆณจๅ…ฅ Secrets ๅˆฐ config.toml
56
+ if [ -n "${APP_KEY:-}" ] && [ -f "$CONFIG" ]; then
 
57
  sed -i "s|^app_key = .*|app_key = \"$APP_KEY\"|" "$CONFIG"
58
  fi
59
+ if [ -n "${API_KEY:-}" ] && [ -f "$CONFIG" ]; then
60
  sed -i "s|^api_key = .*|api_key = \"$API_KEY\"|" "$CONFIG"
61
  fi
62
 
63
  export SERVER_STORAGE_TYPE="${SERVER_STORAGE_TYPE:-local}"
64
  export SERVER_STORAGE_URL="${SERVER_STORAGE_URL:-}"
65
 
66
+ # 4. ๅŽๅฐ๏ผšๆ–‡ไปถ็›‘ๅฌ๏ผˆ้˜ฒๆŠ–ๆŽจ้€๏ผ‰+ ๅ…œๅบ•ๅฎšๆ—ถๅŒๆญฅ
67
  $PYTHON - <<'PYEOF' &
68
+ import glob
69
+ import os
70
+ import threading
71
+ import time
72
  from huggingface_hub import HfFileSystem
73
+ from watchdog.events import FileSystemEventHandler
74
+ from watchdog.observers import Observer
75
 
76
  token = os.environ.get("HF_TOKEN", "")
77
+ repo = os.environ.get("HF_BUCKET_REPO", "")
78
+ data_dir = os.environ.get("DATA_DIR", "/app/data")
79
+ bucket_root = f"hf://buckets/{repo}"
80
+
81
 
82
  def push():
83
  if not token or not repo:
84
  return
85
+
86
  fs = HfFileSystem(token=token)
87
+ files = [
88
+ path
89
+ for path in glob.glob(os.path.join(data_dir, "**", "*"), recursive=True)
90
+ if os.path.isfile(path)
91
+ ]
92
  if not files:
93
  return
94
+
95
  try:
96
  for local_path in files:
97
+ rel_path = os.path.relpath(local_path, data_dir).replace("\\", "/")
98
  remote_path = f"{bucket_root}/{rel_path}"
99
  fs.put(local_path, remote_path)
100
  print(f"[bucket_push] pushed {len(files)} file(s)", flush=True)
101
+ except Exception as exc:
102
+ print(f"[bucket_push] error: {exc}", flush=True)
103
+
104
 
105
  class Handler(FileSystemEventHandler):
106
  def __init__(self):
107
  self._timer = None
108
  self._lock = threading.Lock()
109
+
110
  def _schedule(self):
111
  with self._lock:
112
  if self._timer:
113
  self._timer.cancel()
114
  self._timer = threading.Timer(5, push)
115
  self._timer.start()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
+ def on_modified(self, event):
118
+ if not event.is_directory:
119
+ self._schedule()
120
+
121
+ def on_created(self, event):
122
+ if not event.is_directory:
123
+ self._schedule()
124
+
125
+ def on_deleted(self, event):
126
+ if not event.is_directory:
127
+ self._schedule()
128
+
129
+ def on_moved(self, event):
130
+ if not event.is_directory:
131
+ self._schedule()
132
+
133
+
134
+ if token and repo:
135
+ os.makedirs(data_dir, exist_ok=True)
136
+ observer = Observer()
137
+ observer.schedule(Handler(), path=data_dir, recursive=True)
138
+ observer.start()
139
+ print(f"[bucket_watch] watching {data_dir}...", flush=True)
140
+
141
+ def periodic():
142
+ while True:
143
+ time.sleep(300)
144
+ push()
145
+
146
+ threading.Thread(target=periodic, daemon=True).start()
147
+
148
+ try:
149
+ while True:
150
+ time.sleep(1)
151
+ except KeyboardInterrupt:
152
+ observer.stop()
153
+ observer.join()
154
+ else:
155
+ print("[bucket_watch] skipped: HF_TOKEN or HF_BUCKET_REPO not set", flush=True)
156
  while True:
157
+ time.sleep(3600)
 
 
 
158
  PYEOF
159
 
160
+ # 5. ๅฏๅŠจๅบ”็”จ
161
  echo "[start] starting grok2api..."
162
+ exec /opt/venv/bin/granian --interface asgi \
163
+ --host "${SERVER_HOST:-0.0.0.0}" \
164
+ --port "${SERVER_PORT:-7860}" \
165
+ --workers "${SERVER_WORKERS:-1}" \
166
+ main:app