Nebulixlabs commited on
Commit
d5a2747
·
verified ·
1 Parent(s): c8a62b1

Upload 6 files

Browse files
Files changed (6) hide show
  1. .gitignore +2 -0
  2. DEPLOY_HF_SPACE.md +16 -13
  3. Dockerfile +24 -9
  4. README.md +34 -38
  5. app.py +64 -0
  6. requirements.txt +3 -13
.gitignore CHANGED
@@ -3,3 +3,5 @@
3
  *.db-shm
4
  *.db-wal
5
  .encryption-key
 
 
 
3
  *.db-shm
4
  *.db-wal
5
  .encryption-key
6
+ __pycache__/
7
+ *.py[cod]
DEPLOY_HF_SPACE.md CHANGED
@@ -1,21 +1,24 @@
1
- # Deployment checklist (Hugging Face Spaces)
2
 
3
- 1. Create a **Docker** Space and upload/push this folder.
4
- 2. Add a Space secret `ENCRYPTION_KEY`. Generate locally:
5
- `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"`
6
- 3. Attach a writable Storage Bucket at `/data` if database persistence is needed.
7
- 4. Ensure the Space metadata retains `sdk: docker` and `app_port: 7860` in `README.md`.
8
- 5. Open the Space URL and finish FreeLLMAPI's initial account setup.
9
- 6. In the dashboard, add provider keys and copy the unified FreeLLMAPI API key.
10
- 7. From the computer running Claude Code:
11
  `npx freellmapi setup-claude --url "https://<username>-<space-name>.hf.space" --api-key "<unified-api-key>"`
12
 
13
- ## Expected URLs
14
 
15
  - UI: `https://<username>-<space-name>.hf.space/`
16
- - Claude Code base URL: `https://<username>-<space-name>.hf.space`
17
- - OpenAI-style API base: `https://<username>-<space-name>.hf.space/v1`
18
 
19
  ## Important
20
 
21
- Never commit an actual provider key, unified API key, or `ENCRYPTION_KEY` to the Space repository. FreeLLMAPI is intended as a single-user router; a public Space must not be treated as a community endpoint. Space default storage is ephemeral unless a persistent volume/bucket is attached.
 
 
 
 
1
+ # Deployment checklist
2
 
3
+ 1. Create/select a Hugging Face Space with **Docker** SDK.
4
+ 2. Upload `README.md`, `Dockerfile`, `app.py`, `requirements.txt`, and `.gitignore` to the repository root.
5
+ 3. Add the `ENCRYPTION_KEY` secret in Space Settings → Variables and secrets. Generate it locally with:
6
+ `python -c "import secrets; print(secrets.token_hex(32))"`
7
+ 4. For persistence, attach a writable Storage Bucket volume to `/data`. Without a mounted persistent volume, the database and fallback key may be lost on restart.
8
+ 5. Wait for the build. The runtime should start with `node server/dist/index.js`; the Python launcher ensures this command is passed to the upstream entrypoint.
9
+ 6. Open the Space, complete the dashboard's initial account setup, then configure upstream provider keys.
10
+ 7. Copy the unified API key from the dashboard and configure Claude Code:
11
  `npx freellmapi setup-claude --url "https://<username>-<space-name>.hf.space" --api-key "<unified-api-key>"`
12
 
13
+ ## Endpoints
14
 
15
  - UI: `https://<username>-<space-name>.hf.space/`
16
+ - OpenAI-compatible API: `https://<username>-<space-name>.hf.space/v1`
17
+ - Claude Code / Anthropic API base: `https://<username>-<space-name>.hf.space`
18
 
19
  ## Important
20
 
21
+ - FreeLLMAPI is a Node.js/React application. `app.py` is the Python startup wrapper, not a Python rewrite of the entire product.
22
+ - Never commit provider keys, unified API keys, or encryption secrets to Git.
23
+ - A private Space may require Hugging Face authentication in addition to FreeLLMAPI authentication. Test external CLI access for your visibility settings.
24
+ - Keep the same encryption secret when retaining an existing database.
Dockerfile CHANGED
@@ -1,15 +1,30 @@
1
- # FreeLLMAPI upstream image includes the Node API server and React dashboard.
2
- # Pin to a release rather than tracking :latest for repeatable Space builds.
3
  FROM ghcr.io/tashfeenahmed/freellmapi:v0.16.7
4
 
5
  USER root
6
- COPY hf-entrypoint.sh /usr/local/bin/hf-entrypoint.sh
7
- RUN chmod 755 /usr/local/bin/hf-entrypoint.sh
8
 
9
- ENV NODE_ENV=production
10
- ENV PORT=7860
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  EXPOSE 7860
12
 
13
- # Keep the upstream image's CMD (node server/dist/index.js); our wrapper sets
14
- # the Hugging Face port/data path and then calls the official entrypoint.
15
- ENTRYPOINT ["/usr/local/bin/hf-entrypoint.sh"]
 
 
1
+ # FreeLLMAPI's actual API and dashboard are Node.js/React; use the upstream
2
+ # release image, with a small Python launcher to configure Hugging Face Spaces.
3
  FROM ghcr.io/tashfeenahmed/freellmapi:v0.16.7
4
 
5
  USER root
 
 
6
 
7
+ # Python launcher + pip keep the Space package Python-friendly and install the
8
+ # declared requirements.txt. No third-party Python dependencies are currently
9
+ # needed by app.py.
10
+ RUN apt-get update \
11
+ && apt-get install -y --no-install-recommends python3 python3-pip \
12
+ && rm -rf /var/lib/apt/lists/*
13
+
14
+ WORKDIR /app
15
+ COPY requirements.txt /app/requirements.txt
16
+ RUN if grep -qEv '^[[:space:]]*(#.*)?$' /app/requirements.txt; then \
17
+ python3 -m pip install --break-system-packages --no-cache-dir -r /app/requirements.txt; \
18
+ fi
19
+ COPY app.py /app/app.py
20
+
21
+ ENV NODE_ENV=production \
22
+ PORT=7860 \
23
+ FREELLMAPI_DATA_DIR=/data
24
+
25
  EXPOSE 7860
26
 
27
+ # Explicit CMD is important: without a command, the inherited setpriv-based
28
+ # upstream entrypoint can emit "setpriv: No program specified".
29
+ ENTRYPOINT ["python3", "/app/app.py"]
30
+ CMD ["node", "server/dist/index.js"]
README.md CHANGED
@@ -10,70 +10,66 @@ pinned: false
10
 
11
  # FreeLLMAPI on Hugging Face Spaces
12
 
13
- A Hugging Face Spaces deployment wrapper for [FreeLLMAPI](https://github.com/tashfeenahmed/freellmapi). It uses the official upstream Docker image, including the **web dashboard/UI**, OpenAI-compatible API, and Anthropic Messages API used by Claude Code.
14
 
15
- ## Deploy it
16
 
17
- 1. Create a new **Docker** Space on Hugging Face.
18
- 2. Upload these files (`Dockerfile`, `hf-entrypoint.sh`, `README.md`, `DEPLOY_HF_SPACE.md`) to the Space repository, or push this folder with Git.
19
- 3. In Space **Settings → Variables and secrets**, add a secret named `ENCRYPTION_KEY`. Generate a fresh 64-character hex key on your own computer with:
 
 
20
 
21
  ```bash
22
- node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
23
  ```
24
 
25
- If you skip this secret, the entrypoint generates a fallback key file in `/data`.
26
- 4. For data to survive a Space restart/rebuild, attach a writable Hugging Face Storage Bucket at the mount path `/data`. Without persistent storage, the database and fallback key can be lost on restart.
27
- 5. Wait for the Docker build to complete, then open the Space URL. The upstream app dashboard should load. Complete the app's initial account setup, sign in, and add the API-provider keys you intend to use on the **Keys** page.
28
 
29
- The Space URL looks like `https://<your-username>-<space-name>.hf.space`.
30
 
31
- ## Endpoints after deployment
32
 
33
- Replace the example URL with your actual Space URL.
34
 
35
- - Dashboard/UI: `https://<your-username>-<space-name>.hf.space/`
36
- - OpenAI-compatible API base: `https://<your-username>-<space-name>.hf.space/v1`
37
- - Anthropic Messages API base for Claude Code: `https://<your-username>-<space-name>.hf.space` (the client calls `/v1/messages`)
38
- - Models check: `https://<your-username>-<space-name>.hf.space/v1/models`
39
 
40
- The inference calls need the **unified API key** shown in the FreeLLMAPI dashboard. It is not the same as an upstream provider key or a Hugging Face access token.
41
 
42
  ## Claude Code
43
 
44
  On the computer where Claude Code is installed, run:
45
 
46
  ```bash
47
- npx freellmapi setup-claude --url "https://<your-username>-<space-name>.hf.space" --api-key "<your-freellmapi-unified-api-key>"
 
 
48
  ```
49
 
50
- The setup command reads the available model catalog from your running FreeLLMAPI instance and configures Claude Code. If you'd rather use environment variables manually, set:
51
 
52
  ```bash
53
- export ANTHROPIC_BASE_URL="https://<your-username>-<space-name>.hf.space"
54
  export ANTHROPIC_AUTH_TOKEN="<your-freellmapi-unified-api-key>"
55
  claude
56
  ```
57
 
58
- Keep the key on your own computer or in a local secret manager. **Do not** commit it to this Space, put it in frontend JavaScript, or paste it into public issues/screenshots.
59
-
60
- ## Other clients
61
-
62
- For an OpenAI-compatible client, use:
63
-
64
- ```text
65
- Base URL: https://<your-username>-<space-name>.hf.space/v1
66
- API key: <your-freellmapi-unified-api-key>
67
- ```
68
 
69
- ## Security and persistence notes
70
 
71
- - A publicly reachable Space URL is accessible from the internet. FreeLLMAPI is designed as a single-user router, not as a shared public API service. Use a strong dashboard password and keep the unified API key private; anyone who obtains that key may be able to use your configured provider quota.
72
- - Do not store upstream provider keys in this repository. Enter them through the dashboard after deployment. Keep the same `ENCRYPTION_KEY` when retaining an existing database; changing it without re-encrypting stored keys can make them unreadable.
73
- - A `Private` Space may require Hugging Face authentication in addition to FreeLLMAPI's own key and may not work directly with every external CLI. For a publicly reachable Space, rely on FreeLLMAPI's app/API authentication and keep credentials private.
74
- - A Hugging Face Space's default disk is ephemeral. Attach a writable Storage Bucket to `/data` to persist the SQLite database and generated fallback encryption key across restarts/rebuilds.
75
- - FreeLLMAPI and upstream free-provider quotas/terms remain applicable. See the upstream README and documentation for the current limits and terms.
76
 
77
- ## Upstream project
78
 
79
- This wrapper does not fork or reimplement FreeLLMAPI; it adapts the official container's port and data path for Spaces. See the [upstream GitHub repository](https://github.com/tashfeenahmed/freellmapi) and [Hugging Face Docker Spaces documentation](https://huggingface.co/docs/hub/en/spaces-sdks-docker).
 
 
 
10
 
11
  # FreeLLMAPI on Hugging Face Spaces
12
 
13
+ A Hugging Face Spaces deployment for [FreeLLMAPI](https://github.com/tashfeenahmed/freellmapi). It preserves the upstream web dashboard/UI, OpenAI-compatible API, and Anthropic Messages API used by Claude Code.
14
 
15
+ **Why Docker plus Python?** Hugging Face supports Python Spaces and Docker Spaces. The original FreeLLMAPI project itself is Node.js/React, so `requirements.txt` alone cannot run the whole product. This package includes a small Python launcher (`app.py`) and `requirements.txt`, while Docker runs the official upstream application image so its real UI and API remain intact.
16
 
17
+ ## Deploy
18
+
19
+ 1. Create a new Space with **Docker** as its SDK, or replace the files in the root of your existing Docker Space with this package.
20
+ 2. Upload these files to the Space repository root: `README.md`, `Dockerfile`, `app.py`, `requirements.txt`, and `.gitignore`.
21
+ 3. In **Settings → Variables and secrets**, add a secret named `ENCRYPTION_KEY`. Generate a 64-character hex key on your own computer:
22
 
23
  ```bash
24
+ python -c "import secrets; print(secrets.token_hex(32))"
25
  ```
26
 
27
+ Paste the output as the secret value. The launcher can generate a fallback key at `/data/.encryption-key`, but a stable secret is preferable for production use.
28
+ 4. To retain the database and fallback key after restarts, create/attach a writable Hugging Face Storage Bucket volume mounted at `/data`. Without a persistent mounted volume, Space files may be lost on restarts.
29
+ 5. Wait for the Docker build, then open the Space URL. Finish the initial account setup and add provider keys on the dashboard's **Keys** page.
30
 
31
+ The `setpriv: No program specified` error is addressed by launching the upstream entrypoint with an explicit default command (`node server/dist/index.js`) and a Python fallback when no command is provided.
32
 
33
+ ## URLs
34
 
35
+ Replace the examples with your actual Space URL, usually `https://<username>-<space-name>.hf.space`.
36
 
37
+ - Dashboard/UI: `https://<username>-<space-name>.hf.space/`
38
+ - OpenAI-compatible API: `https://<username>-<space-name>.hf.space/v1`
39
+ - Anthropic Messages API / Claude Code: `https://<username>-<space-name>.hf.space` (the client calls `/v1/messages`)
40
+ - Model list check: `https://<username>-<space-name>.hf.space/v1/models`
41
 
42
+ Use the **unified FreeLLMAPI API key** shown in the dashboard. It is not your provider's key or a Hugging Face token.
43
 
44
  ## Claude Code
45
 
46
  On the computer where Claude Code is installed, run:
47
 
48
  ```bash
49
+ npx freellmapi setup-claude \
50
+ --url "https://<username>-<space-name>.hf.space" \
51
+ --api-key "<your-freellmapi-unified-api-key>"
52
  ```
53
 
54
+ Or configure environment variables manually:
55
 
56
  ```bash
57
+ export ANTHROPIC_BASE_URL="https://<username>-<space-name>.hf.space"
58
  export ANTHROPIC_AUTH_TOKEN="<your-freellmapi-unified-api-key>"
59
  claude
60
  ```
61
 
62
+ Keep the key private: do not commit it to the Space repository or put it in browser/frontend code.
 
 
 
 
 
 
 
 
 
63
 
64
+ ## Notes
65
 
66
+ - A Space configured as **Private** can require Hugging Face authentication as well; external CLI compatibility depends on whether the client can authenticate to the private Space. Make the Space public only if appropriate and protect the app/API credentials.
67
+ - FreeLLMAPI is intended as a single-user router, not a public shared API service. Never share your unified API key.
68
+ - Keep `ENCRYPTION_KEY` stable if keeping an existing database. Changing it can make stored provider keys unreadable.
69
+ - The Python launcher uses only the standard library; `requirements.txt` is present for packaging consistency and currently has no third-party packages.
 
70
 
71
+ ## Upstream
72
 
73
+ - [FreeLLMAPI source and docs](https://github.com/tashfeenahmed/freellmapi)
74
+ - [Hugging Face Docker Spaces documentation](https://huggingface.co/docs/hub/en/spaces-sdks-docker)
75
+ - [Hugging Face Spaces storage documentation](https://huggingface.co/docs/hub/main/spaces-storage)
app.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Hugging Face Spaces launcher for the upstream FreeLLMAPI container.
3
+
4
+ FreeLLMAPI itself is a Node.js/React application. This small Python launcher
5
+ prepares the Space environment and explicitly forwards the server command to
6
+ the upstream privilege-dropping entrypoint.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import os
11
+ import secrets
12
+ import sys
13
+ from pathlib import Path
14
+
15
+
16
+ def prepare_environment() -> None:
17
+ data_dir = Path(os.environ.get("FREELLMAPI_DATA_DIR", "/data"))
18
+ data_dir.mkdir(parents=True, exist_ok=True)
19
+
20
+ os.environ.setdefault("NODE_ENV", "production")
21
+ os.environ.setdefault("PORT", os.environ.get("SPACE_PORT", "7860"))
22
+ os.environ.setdefault("FREEAPI_DB_PATH", str(data_dir / "freeapi.db"))
23
+
24
+ # Keep a stable generated key beside the DB if a Space Secret was not set.
25
+ # For a persistent deployment, mount a writable bucket at /data.
26
+ if not os.environ.get("ENCRYPTION_KEY"):
27
+ key_file = Path(
28
+ os.environ.get("ENCRYPTION_KEY_FILE", str(data_dir / ".encryption-key"))
29
+ )
30
+ if not key_file.is_file() or key_file.stat().st_size == 0:
31
+ key_file.parent.mkdir(parents=True, exist_ok=True)
32
+ try:
33
+ descriptor = os.open(
34
+ key_file,
35
+ os.O_WRONLY | os.O_CREAT | os.O_EXCL,
36
+ 0o600,
37
+ )
38
+ except FileExistsError:
39
+ # Another startup process created it first.
40
+ pass
41
+ else:
42
+ with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
43
+ handle.write(secrets.token_hex(32))
44
+ handle.write("\n")
45
+ os.environ["ENCRYPTION_KEY"] = key_file.read_text(encoding="utf-8").strip()
46
+
47
+
48
+ def main() -> None:
49
+ prepare_environment()
50
+
51
+ # Dockerfile supplies this CMD explicitly. Keep the fallback to avoid ever
52
+ # calling setpriv with an empty command (the error seen in the Space logs).
53
+ command = sys.argv[1:] or ["node", "server/dist/index.js"]
54
+ upstream_entrypoint = "/usr/local/bin/docker-entrypoint.sh"
55
+ if not os.path.isfile(upstream_entrypoint):
56
+ raise FileNotFoundError(
57
+ f"Expected upstream FreeLLMAPI entrypoint at {upstream_entrypoint}"
58
+ )
59
+
60
+ os.execv(upstream_entrypoint, [upstream_entrypoint, *command])
61
+
62
+
63
+ if __name__ == "__main__":
64
+ main()
requirements.txt CHANGED
@@ -1,13 +1,3 @@
1
- fastapi>=0.100.0
2
- uvicorn>=0.23.0
3
- huggingface_hub>=0.16.4
4
- rank_bm25>=0.2.2
5
- torch>=2.0.0
6
- tiktoken
7
- aiohttp>=3.8.5
8
- beautifulsoup4>=4.12.2
9
- transformers>=4.36.0
10
- accelerate>=0.25.0
11
- bitsandbytes>=0.41.0
12
- openai
13
- faiss-cpu
 
1
+ # No third-party Python packages are required.
2
+ # app.py uses only the Python standard library; the actual FreeLLMAPI server/UI
3
+ # and its dependencies are shipped in the upstream container image.