Upload 4 files
Browse files- README.md +22 -38
- bootstrap.py +4 -3
- space_boot.sh +16 -4
README.md
CHANGED
|
@@ -8,49 +8,33 @@ app_port: 2233
|
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
| 11 |
-
#
|
| 12 |
|
| 13 |
-
|
| 14 |
|
| 15 |
-
##
|
| 16 |
|
| 17 |
-
-
|
| 18 |
-
-
|
| 19 |
-
-
|
| 20 |
-
-
|
| 21 |
-
-
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
-
##
|
| 26 |
-
访问应用后,可以通过Web界面选择模板并生成表情包。
|
| 27 |
|
| 28 |
-
|
| 29 |
-
```
|
| 30 |
-
|
| 31 |
-
curl https://your-space-url/memes/keys
|
| 32 |
|
| 33 |
-
#
|
| 34 |
-
curl -X POST https://your-space-url/memes/petpet/ \
|
| 35 |
-
-F "images=@your-image.jpg"
|
| 36 |
-
```
|
| 37 |
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
- **后端**: FastAPI + Python
|
| 41 |
-
- **图像处理**: Pillow + OpenCV
|
| 42 |
-
- **容器化**: Docker
|
| 43 |
-
- **部署**: Hugging Face Spaces
|
| 44 |
-
|
| 45 |
-
## 📚 API文档
|
| 46 |
-
|
| 47 |
-
启动后访问 `/docs` 查看完整的API文档。
|
| 48 |
-
|
| 49 |
-
## 🔗 相关链接
|
| 50 |
-
|
| 51 |
-
- [GitHub仓库](https://github.com/syfantasy/meme-generator-unified)
|
| 52 |
-
- [Docker镜像](https://ghcr.io/syfantasy/meme-generator:latest)
|
| 53 |
-
|
| 54 |
-
## 📄 许可证
|
| 55 |
-
|
| 56 |
-
本项目采用 MIT 许可证。
|
|
|
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
| 11 |
+
# Hugging Face Space for ghcr.io/1111qwq1111/meme-generator:latest
|
| 12 |
|
| 13 |
+
This Space wraps your published image and adapts it for Spaces (listening on `$PORT`, default 2233). It also supports translator env variables via Space Secrets.
|
| 14 |
|
| 15 |
+
## How to use
|
| 16 |
|
| 17 |
+
- Create a new Space and choose “Docker” as the SDK.
|
| 18 |
+
- Push the files from this `hf-space` folder to the Space repo root.
|
| 19 |
+
- In the Space settings, add Secrets:
|
| 20 |
+
- `TRANSLATOR_PROVIDER` = `openai`
|
| 21 |
+
- `OPENAI_BASE_URL` = `https://api.openai.com/v1`
|
| 22 |
+
- `OPENAI_API_KEY` = `sk-***` (do not hardcode)
|
| 23 |
+
- `OPENAI_MODEL` = `gpt-4.1-mini`
|
| 24 |
+
- (Optionally) `MEME_DATA_DIR` if you want a custom data path; default `/app/data`.
|
| 25 |
|
| 26 |
+
The container will:
|
| 27 |
+
- Ensure built-in memes load after the translator monkey‑patch.
|
| 28 |
+
- Use your OpenAI‑compatible translator if envs are present, otherwise fallback to upstream behavior.
|
| 29 |
+
- Bind the server to `$PORT` (2233 by default on Spaces).
|
| 30 |
|
| 31 |
+
## Endpoints
|
|
|
|
| 32 |
|
| 33 |
+
- OpenAPI docs: `/docs`
|
| 34 |
+
- Meme APIs: `/memes/<key>/` (POST), e.g. `/memes/dianzhongdian/`
|
| 35 |
+
- Aggregated metadata (if available): `/memes/static/infos.json`, `/memes/static/keyMap.json`
|
|
|
|
| 36 |
|
| 37 |
+
## Notes
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
+
- This wrapper assumes your base image provides the Python package `meme_generator` and contributions under `/app/meme-generator-contrib` and `/app/meme_emoji`.
|
| 40 |
+
- No secrets are baked into the image; configure them via Space Secrets.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bootstrap.py
CHANGED
|
@@ -20,7 +20,9 @@ from meme_generator.manager import get_meme, get_memes
|
|
| 20 |
from meme_generator.exception import NoSuchMeme, MemeFeedback
|
| 21 |
from meme_generator.utils import MemeProperties, render_meme_list
|
| 22 |
|
| 23 |
-
|
|
|
|
|
|
|
| 24 |
tc = getattr(meme_config, 'translate', None)
|
| 25 |
env_provider = os.getenv('TRANSLATOR_PROVIDER', '').strip().lower()
|
| 26 |
env_base_url = os.getenv('OPENAI_BASE_URL', '').strip()
|
|
@@ -172,7 +174,6 @@ register_routers()
|
|
| 172 |
data_dir = os.environ.get("MEME_DATA_DIR", "/app/data")
|
| 173 |
app.mount("/memes/static", StaticFiles(directory=data_dir), name="static")
|
| 174 |
|
| 175 |
-
port = int(os.environ.get("PORT", "
|
| 176 |
print(f"[bootstrap] Starting uvicorn on 0.0.0.0:{port}", flush=True)
|
| 177 |
uvicorn.run(app, host="0.0.0.0", port=port)
|
| 178 |
-
|
|
|
|
| 20 |
from meme_generator.exception import NoSuchMeme, MemeFeedback
|
| 21 |
from meme_generator.utils import MemeProperties, render_meme_list
|
| 22 |
|
| 23 |
+
cfg_home = os.environ.get('XDG_CONFIG_HOME')
|
| 24 |
+
cfg_dir = (cfg_home + '/meme_generator') if cfg_home else '<unset>'
|
| 25 |
+
print(f"[bootstrap] XDG_CONFIG_HOME={cfg_home} CONFIG_DIR={cfg_dir}", flush=True)
|
| 26 |
tc = getattr(meme_config, 'translate', None)
|
| 27 |
env_provider = os.getenv('TRANSLATOR_PROVIDER', '').strip().lower()
|
| 28 |
env_base_url = os.getenv('OPENAI_BASE_URL', '').strip()
|
|
|
|
| 174 |
data_dir = os.environ.get("MEME_DATA_DIR", "/app/data")
|
| 175 |
app.mount("/memes/static", StaticFiles(directory=data_dir), name="static")
|
| 176 |
|
| 177 |
+
port = int(os.environ.get("PORT", "2233"))
|
| 178 |
print(f"[bootstrap] Starting uvicorn on 0.0.0.0:{port}", flush=True)
|
| 179 |
uvicorn.run(app, host="0.0.0.0", port=port)
|
|
|
space_boot.sh
CHANGED
|
@@ -1,13 +1,14 @@
|
|
| 1 |
#!/usr/bin/env bash
|
| 2 |
set -euo pipefail
|
| 3 |
|
| 4 |
-
# Ensure a predictable config location for meme_generator
|
| 5 |
-
|
|
|
|
| 6 |
CONFIG_DIR="${XDG_CONFIG_HOME}/meme_generator"
|
| 7 |
CONFIG_FILE="${CONFIG_DIR}/config.toml"
|
| 8 |
mkdir -p "${CONFIG_DIR}"
|
| 9 |
|
| 10 |
-
PORT="${PORT:-
|
| 11 |
MEME_DATA_DIR="${MEME_DATA_DIR:-/app/data}"
|
| 12 |
|
| 13 |
# Snapshot translator env for logs (no secrets printed)
|
|
@@ -38,4 +39,15 @@ log_level = "INFO"
|
|
| 38 |
EOF
|
| 39 |
echo "[space] Wrote config to ${CONFIG_FILE}"
|
| 40 |
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
#!/usr/bin/env bash
|
| 2 |
set -euo pipefail
|
| 3 |
|
| 4 |
+
# Ensure a predictable and writable config location for meme_generator
|
| 5 |
+
# Default to /tmp/config (writable). Allow override via XDG_CONFIG_HOME.
|
| 6 |
+
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-/tmp/config}"
|
| 7 |
CONFIG_DIR="${XDG_CONFIG_HOME}/meme_generator"
|
| 8 |
CONFIG_FILE="${CONFIG_DIR}/config.toml"
|
| 9 |
mkdir -p "${CONFIG_DIR}"
|
| 10 |
|
| 11 |
+
PORT="${PORT:-2233}"
|
| 12 |
MEME_DATA_DIR="${MEME_DATA_DIR:-/app/data}"
|
| 13 |
|
| 14 |
# Snapshot translator env for logs (no secrets printed)
|
|
|
|
| 39 |
EOF
|
| 40 |
echo "[space] Wrote config to ${CONFIG_FILE}"
|
| 41 |
|
| 42 |
+
# Choose a Python interpreter (python or python3)
|
| 43 |
+
PY_BIN="python"
|
| 44 |
+
if ! command -v "$PY_BIN" >/dev/null 2>&1; then
|
| 45 |
+
if command -v python3 >/dev/null 2>&1; then
|
| 46 |
+
PY_BIN="python3"
|
| 47 |
+
else
|
| 48 |
+
echo "[space] Error: no python interpreter found (python/python3)" >&2
|
| 49 |
+
exit 1
|
| 50 |
+
fi
|
| 51 |
+
fi
|
| 52 |
+
echo "[space] Using interpreter: $(command -v $PY_BIN)"
|
| 53 |
+
exec "$PY_BIN" -u /workspace/bootstrap.py
|