charan-ml commited on
Commit
e1b76ea
Β·
1 Parent(s): 4c42b27

Switch to HF Space as default backend, make Ollama optional

Browse files
Files changed (6) hide show
  1. README.md +44 -0
  2. app.py +62 -0
  3. deploy.sh +72 -0
  4. inference.py +108 -0
  5. requirements.txt +11 -0
  6. runtime.txt +1 -0
README.md ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: KnowLedge Inference API
3
+ emoji: πŸ“–
4
+ colorFrom: yellow
5
+ colorTo: green
6
+ sdk: gradio
7
+ python_version: 3.10.16
8
+ sdk_version: 4.44.1
9
+ app_file: app.py
10
+ pinned: true
11
+ license: apache-2.0
12
+ tags:
13
+ - gemma
14
+ - gemma-4
15
+ - education
16
+ - inference-api
17
+ - knowledge
18
+ - hackathon
19
+ ---
20
+
21
+ # KnowLedge Inference API
22
+
23
+ Gemma 4 E2B + E4B inference backend for the
24
+ [KnowLedge](https://github.com/Charan-suresh/KnowLedge) learning ledger.
25
+
26
+ Part of the Kaggle Gemma 4 Good Hackathon submission.
27
+
28
+ ## Endpoints
29
+
30
+ | Endpoint | Model | Used by |
31
+ |---|---|---|
32
+ | `/api/generate` | E2B or E4B | Scout (concept tagging), Sage (Socratic dialogue) |
33
+ | `/api/generate_vision` | E4B vision | Lens (handwriting verification) |
34
+ | `/api/health` | - | FastAPI health check |
35
+
36
+ ## Not for direct use
37
+
38
+ This Space is called programmatically by the KnowLedge FastAPI backend
39
+ deployed on Render. It is not a chat interface.
40
+
41
+ ## Deployment note
42
+
43
+ Deploy these files to a separate Hugging Face Space repository.
44
+ Do not import from the `knowledge/` package inside the Space app.
app.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from pydantic import BaseModel
3
+ import uvicorn
4
+
5
+ try:
6
+ from inference import generate_text, generate_with_image, health_check
7
+ except ModuleNotFoundError:
8
+ from .inference import generate_text, generate_with_image, health_check
9
+
10
+ app = FastAPI()
11
+
12
+
13
+ class GenerateRequest(BaseModel):
14
+ prompt: str
15
+ model: str = "e2b"
16
+ max_tokens: int = 512
17
+
18
+
19
+ class VisionRequest(BaseModel):
20
+ prompt: str
21
+ image_base64: str
22
+ max_tokens: int = 512
23
+
24
+
25
+ @app.get("/")
26
+ def root():
27
+ return {"message": "KnowLedge Inference API is running"}
28
+
29
+
30
+ @app.get("/api/health")
31
+ def health():
32
+ try:
33
+ return health_check()
34
+ except Exception as exc:
35
+ return {"status": "error", "error": str(exc)}
36
+
37
+
38
+ @app.post("/api/generate")
39
+ def generate(req: GenerateRequest):
40
+ try:
41
+ model_name = "e2b" if "e2b" in req.model.lower() else "e4b"
42
+ response = generate_text(model_name, req.prompt, req.max_tokens)
43
+ return {"response": response}
44
+ except Exception as exc:
45
+ return {"error": str(exc)}
46
+
47
+
48
+ @app.post("/api/generate_vision")
49
+ def generate_vision(req: VisionRequest):
50
+ try:
51
+ response = generate_with_image(
52
+ req.prompt,
53
+ req.image_base64,
54
+ req.max_tokens,
55
+ )
56
+ return {"response": response}
57
+ except Exception as exc:
58
+ return {"error": str(exc)}
59
+
60
+
61
+ if __name__ == "__main__":
62
+ uvicorn.run(app, host="0.0.0.0", port=7860)
deploy.sh ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # KnowLedge - Hugging Face Space deployment guide
3
+ # Run each block manually in sequence.
4
+ # Prerequisites: huggingface_hub installed, HF account created
5
+
6
+ # -- Step 1: Install HF CLI -------------------------------------------------
7
+ pip install huggingface_hub
8
+
9
+ # -- Step 2: Login to Hugging Face ------------------------------------------
10
+ huggingface-cli login
11
+ # Paste your HF token when prompted
12
+ # Get token at: https://huggingface.co/settings/tokens
13
+ # Token needs "write" permission
14
+
15
+ # -- Step 3: Create the Space ------------------------------------------------
16
+ python3 - << 'EOF'
17
+ from huggingface_hub import HfApi
18
+ api = HfApi()
19
+ api.create_repo(
20
+ repo_id="knowledge-inference", # becomes: your-username/knowledge-inference
21
+ repo_type="space",
22
+ space_sdk="gradio",
23
+ private=False, # must be public for free ZeroGPU
24
+ exist_ok=True,
25
+ )
26
+ print("Space created successfully")
27
+ EOF
28
+
29
+ # -- Step 4: Upload Space files ----------------------------------------------
30
+ python3 - << 'EOF'
31
+ from huggingface_hub import HfApi
32
+ import os
33
+
34
+ api = HfApi()
35
+ space_id = f"{api.whoami()['name']}/knowledge-inference"
36
+ base_dir = os.getcwd()
37
+
38
+ files = ["app.py", "inference.py", "requirements.txt", "README.md"]
39
+ for f in files:
40
+ path = os.path.join(base_dir, f)
41
+ api.upload_file(
42
+ path_or_fileobj=path,
43
+ path_in_repo=f,
44
+ repo_id=space_id,
45
+ repo_type="space",
46
+ )
47
+ print(f"Uploaded: {f}")
48
+
49
+ print(f"\nSpace URL: https://huggingface.co/spaces/{space_id}")
50
+ print(f"API URL: https://{space_id.replace('/', '-')}.hf.space")
51
+ EOF
52
+
53
+ # -- Step 5: Enable ZeroGPU --------------------------------------------------
54
+ # Go to: https://huggingface.co/spaces/YOUR-USERNAME/knowledge-inference/settings
55
+ # Under "Space Hardware" -> select "ZeroGPU (NVIDIA H200)"
56
+ # This cannot be done via API - must be done in the HF web UI
57
+ echo "-> Manually enable ZeroGPU in Space settings:"
58
+ echo " https://huggingface.co/spaces/$(huggingface-cli whoami)/knowledge-inference/settings"
59
+
60
+ # -- Step 6: Get your Space API URL ------------------------------------------
61
+ # After deployment (~3-5 minutes for build), your endpoints are:
62
+ # Text: POST https://your-username-knowledge-inference.hf.space/api/generate
63
+ # Vision: POST https://your-username-knowledge-inference.hf.space/api/generate_vision
64
+ # Health: GET https://your-username-knowledge-inference.hf.space/api/health
65
+
66
+ # -- Step 7: Set Render env vars ---------------------------------------------
67
+ # In Render dashboard -> your service -> Environment:
68
+ # INFERENCE_BACKEND = hf_space
69
+ # HF_SPACE_URL = your-username/knowledge-inference
70
+ # Then trigger a manual redeploy on Render.
71
+
72
+ echo "Deployment complete. Set HF_SPACE_URL in Render and redeploy."
inference.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ KnowLedge Inference β€” inference.py
3
+
4
+ Runs entirely on CPU on the standard free HF Spaces tier (no ZeroGPU).
5
+
6
+ Model backends
7
+ --------------
8
+ E4B : unsloth/gemma-4-4b-it-GGUF loaded via llama-cpp-python (CPU, n_gpu_layers=0).
9
+ """
10
+
11
+ import logging
12
+
13
+ from huggingface_hub import hf_hub_download
14
+
15
+ # ── spaces stub β€” GPU decorator is a no-op on the free CPU tier ───────────────
16
+ try:
17
+ import spaces
18
+ except ModuleNotFoundError:
19
+ class _SpacesStub:
20
+ @staticmethod
21
+ def GPU(duration: int = 0):
22
+ def decorator(fn):
23
+ return fn
24
+ return decorator
25
+
26
+ spaces = _SpacesStub()
27
+
28
+ # ── llama-cpp-python ──────────────────────────────────────────────────────────
29
+ try:
30
+ from llama_cpp import Llama
31
+ except ModuleNotFoundError:
32
+ Llama = None
33
+
34
+
35
+ MODEL_REPO = "unsloth/gemma-4-4b-it-GGUF"
36
+ MODEL_FILE = "gemma-4-4b-it-Q4_K_M.gguf"
37
+
38
+ _llm = None
39
+ logger = logging.getLogger(__name__)
40
+
41
+
42
+ def load_model():
43
+ global _llm
44
+ if _llm is None:
45
+ if Llama is None:
46
+ raise RuntimeError(
47
+ "llama-cpp-python is not installed. "
48
+ "Add it to hf_space/requirements.txt."
49
+ )
50
+ model_path = str(hf_hub_download(
51
+ repo_id=MODEL_REPO,
52
+ filename=MODEL_FILE
53
+ ))
54
+
55
+ _llm = Llama(
56
+ model_path=model_path,
57
+ n_ctx=4096,
58
+ n_threads=4
59
+ )
60
+ return _llm
61
+
62
+
63
+ @spaces.GPU(duration=90)
64
+ def generate_text(model_name: str, prompt: str, max_new_tokens: int = 512) -> str:
65
+ try:
66
+ llm = load_model()
67
+
68
+ output = llm(
69
+ str(prompt),
70
+ max_tokens=max_new_tokens,
71
+ temperature=0.7,
72
+ top_p=0.95
73
+ )
74
+
75
+ return output["choices"][0]["text"]
76
+
77
+ except Exception:
78
+ logger.exception("Text generation failed")
79
+ raise
80
+
81
+
82
+ @spaces.GPU(duration=120)
83
+ def generate_with_image(prompt: str, image_base64: str, max_new_tokens: int = 512) -> str:
84
+ try:
85
+ llm = load_model()
86
+
87
+ text_prompt = f"{prompt}\n\n[Image provided]"
88
+
89
+ output = llm(
90
+ str(text_prompt),
91
+ max_tokens=max_new_tokens,
92
+ temperature=0.7,
93
+ top_p=0.95
94
+ )
95
+
96
+ return output["choices"][0]["text"]
97
+
98
+ except Exception:
99
+ logger.exception("Vision generation failed")
100
+ raise
101
+
102
+
103
+ @spaces.GPU(duration=60)
104
+ def health_check() -> dict:
105
+ return {
106
+ "status": "ok",
107
+ "model_loaded": _llm is not None,
108
+ }
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fastapi==0.112.2
2
+ uvicorn==0.30.6
3
+ gradio==4.44.1
4
+
5
+ # Inference - E4B via llama-cpp-python (GGUF, CPU-only, no ZeroGPU needed)
6
+ --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cpu
7
+ llama-cpp-python==0.2.90
8
+
9
+ # Utilities
10
+ Pillow
11
+ huggingface_hub==0.25.2
runtime.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ python-3.10.16