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

Fix HF Space: switch from llama-cpp-python to transformers for better compatibility

Browse files
Files changed (2) hide show
  1. inference.py +70 -49
  2. requirements.txt +4 -3
inference.py CHANGED
@@ -1,16 +1,15 @@
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:
@@ -25,54 +24,72 @@ except ModuleNotFoundError:
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")
@@ -82,18 +99,9 @@ def generate_text(model_name: str, prompt: str, max_new_tokens: int = 512) -> st
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")
@@ -102,7 +110,20 @@ def generate_with_image(prompt: str, image_base64: str, max_new_tokens: int = 51
102
 
103
  @spaces.GPU(duration=60)
104
  def health_check() -> dict:
105
- return {
106
- "status": "ok",
107
- "model_loaded": _llm is not None,
108
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  """
2
  KnowLedge Inference β€” inference.py
3
 
4
+ Runs on CPU using transformers library for better HF Spaces compatibility.
5
 
6
  Model backends
7
  --------------
8
+ E4B : unsloth/gemma-4-4b-it loaded via transformers (CPU).
9
  """
10
 
11
  import logging
12
+ from typing import Optional
 
13
 
14
  # ── spaces stub β€” GPU decorator is a no-op on the free CPU tier ───────────────
15
  try:
 
24
 
25
  spaces = _SpacesStub()
26
 
27
+ # ── transformers ──────────────────────────────────────────────────────────────
28
  try:
29
+ from transformers import AutoTokenizer, AutoModelForCausalLM
30
+ import torch
31
  except ModuleNotFoundError:
32
+ AutoTokenizer = None
33
+ AutoModelForCausalLM = None
34
+ torch = None
35
 
36
 
37
+ MODEL_REPO = "unsloth/gemma-4-4b-it"
 
38
 
39
+ _tokenizer = None
40
+ _model = None
41
  logger = logging.getLogger(__name__)
42
 
43
 
44
  def load_model():
45
+ global _tokenizer, _model
46
+ if _model is None:
47
+ if AutoTokenizer is None or AutoModelForCausalLM is None:
48
  raise RuntimeError(
49
+ "transformers is not installed. "
50
  "Add it to hf_space/requirements.txt."
51
  )
52
+
53
+ logger.info(f"Loading model {MODEL_REPO}...")
54
+ _tokenizer = AutoTokenizer.from_pretrained(MODEL_REPO)
55
+ _model = AutoModelForCausalLM.from_pretrained(
56
+ MODEL_REPO,
57
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
58
+ device_map="auto" if torch.cuda.is_available() else "cpu",
59
+ trust_remote_code=True
 
60
  )
61
+ logger.info("Model loaded successfully")
62
+
63
+ return _tokenizer, _model
64
 
65
 
66
  @spaces.GPU(duration=90)
67
  def generate_text(model_name: str, prompt: str, max_new_tokens: int = 512) -> str:
68
  try:
69
+ tokenizer, model = load_model()
70
+
71
+ # Format prompt for Gemma
72
+ formatted_prompt = f"<bos><start_of_turn>user\n{prompt}<end_of_turn>\n<start_of_turn>model\n"
73
+
74
+ inputs = tokenizer(formatted_prompt, return_tensors="pt")
75
+
76
+ with torch.no_grad():
77
+ outputs = model.generate(
78
+ **inputs,
79
+ max_new_tokens=max_new_tokens,
80
+ temperature=0.7,
81
+ top_p=0.95,
82
+ do_sample=True,
83
+ pad_token_id=tokenizer.eos_token_id
84
+ )
85
+
86
+ # Decode only the new tokens
87
+ response = tokenizer.decode(
88
+ outputs[0][inputs.input_ids.shape[1]:],
89
+ skip_special_tokens=True
90
  )
91
+
92
+ return response.strip()
93
 
94
  except Exception:
95
  logger.exception("Text generation failed")
 
99
  @spaces.GPU(duration=120)
100
  def generate_with_image(prompt: str, image_base64: str, max_new_tokens: int = 512) -> str:
101
  try:
102
+ # For now, treat as text-only since Gemma 4 vision support varies
103
+ text_prompt = f"{prompt}\n\n[Image provided - analyzing as text prompt]"
104
+ return generate_text("e4b", text_prompt, max_new_tokens)
 
 
 
 
 
 
 
 
 
105
 
106
  except Exception:
107
  logger.exception("Vision generation failed")
 
110
 
111
  @spaces.GPU(duration=60)
112
  def health_check() -> dict:
113
+ try:
114
+ tokenizer, model = load_model()
115
+ return {
116
+ "status": "ok",
117
+ "model_loaded": True,
118
+ "backend": "transformers",
119
+ "model_repo": MODEL_REPO,
120
+ "device": str(next(model.parameters()).device) if model else "unknown"
121
+ }
122
+ except Exception as e:
123
+ return {
124
+ "status": "error",
125
+ "model_loaded": False,
126
+ "backend": "transformers",
127
+ "model_repo": MODEL_REPO,
128
+ "error": str(e)
129
+ }
requirements.txt CHANGED
@@ -2,9 +2,10 @@ 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
 
2
  uvicorn==0.30.6
3
  gradio==4.44.1
4
 
5
+ # Use transformers instead of llama-cpp for better HF Spaces compatibility
6
+ transformers==4.45.2
7
+ torch==2.1.0
8
+ accelerate==0.25.0
9
 
10
  # Utilities
11
  Pillow