Mohd-Shujath commited on
Commit
2c0a1bd
·
1 Parent(s): 5ec38d4

Add spaces.GPU decorator for ZeroGPU support

Browse files
Files changed (1) hide show
  1. app.py +43 -74
app.py CHANGED
@@ -4,50 +4,35 @@ import subprocess
4
  import re
5
 
6
  # =============================================================
7
- # 1. Bootstrap: Install latest prebuilt CPU-only llama-cpp-python
8
  # =============================================================
9
  def bootstrap_llama_cpp():
10
- print("Bootstrapping llama-cpp-python (CPU-only, manylinux)...")
11
  from huggingface_hub import HfApi, hf_hub_download
12
 
13
  api = HfApi()
14
  files = api.list_repo_files("AIencoder/llama-cpp-wheels", repo_type="dataset")
15
-
16
  py_tag = f"cp{sys.version_info.major}{sys.version_info.minor}"
17
 
18
- # Collect all CPU wheels for linux x86_64, version 0.3.x
19
  candidates = []
20
  for p in files:
21
- if not p.endswith(".whl"):
22
- continue
23
- if "linux/x86_64/cpu/" not in p:
24
- continue
25
- if "cuda" in p.lower():
26
  continue
27
  if py_tag not in p and "py3-none" not in p:
28
  continue
29
- # Extract version number
30
  m = re.search(r"/0\.3\.(\d+)/", p)
31
- if not m:
32
- continue
33
- minor = int(m.group(1))
34
- if minor < 20: # Need >= 0.3.20 for Qwen3.5 support
35
  continue
36
- candidates.append((minor, p))
37
 
38
- # Sort by version number descending → pick latest
39
  candidates.sort(key=lambda x: x[0], reverse=True)
40
-
41
- if not candidates:
42
- raise RuntimeError("No compatible CPU wheel found for >= 0.3.20!")
43
-
44
  chosen = candidates[0][1]
45
  print(f"Selected wheel: {chosen}")
46
  whl_path = hf_hub_download("AIencoder/llama-cpp-wheels", chosen, repo_type="dataset")
47
  subprocess.check_call([
48
  sys.executable, "-m", "pip", "install", "--force-reinstall", whl_path
49
  ])
50
- print("llama-cpp-python installed successfully!")
51
 
52
  try:
53
  from llama_cpp import Llama
@@ -56,33 +41,18 @@ except (ImportError, RuntimeError, OSError):
56
  bootstrap_llama_cpp()
57
  from llama_cpp import Llama
58
 
 
59
  from typing import List, Literal, Optional
60
  from pydantic import BaseModel, Field
61
- from fastapi import FastAPI, HTTPException, Header
62
  import gradio as gr
63
 
64
  # =============================================================
65
- # 2. Verify & Load GGUF Model
66
  # =============================================================
67
  MODEL_PATH = "Qwen3.5-0.8B.Q4_K_M.gguf"
68
  API_KEY = os.getenv("API_KEY", "commitcon-secret-2026")
69
 
70
- # Diagnostic: check if file exists and is real (not LFS pointer)
71
- if not os.path.exists(MODEL_PATH):
72
- raise FileNotFoundError(f"Model file {MODEL_PATH} not found in /app/")
73
-
74
- file_size = os.path.getsize(MODEL_PATH)
75
- print(f"Model file size: {file_size / 1e6:.1f} MB")
76
-
77
- if file_size < 1_000_000: # < 1MB means it's an LFS pointer, not the real file
78
- with open(MODEL_PATH, "r", errors="ignore") as f:
79
- content = f.read(200)
80
- raise RuntimeError(
81
- f"Model file is only {file_size} bytes — likely a Git LFS pointer, not the real weights.\n"
82
- f"File content: {content}\n"
83
- f"Fix: Re-upload the .gguf file using the Hugging Face web UI (Files tab → Add file → Upload)."
84
- )
85
-
86
  print(f"Loading {MODEL_PATH} via llama-cpp-python ...")
87
  llm = Llama(
88
  model_path=MODEL_PATH,
@@ -92,21 +62,6 @@ llm = Llama(
92
  )
93
  print("Model loaded successfully!")
94
 
95
- # =============================================================
96
- # 3. FastAPI Endpoints
97
- # =============================================================
98
- app = FastAPI(title="CommitCon Sherpa AI Copilot")
99
-
100
- class HistoryMessage(BaseModel):
101
- role: Literal["user", "assistant"]
102
- content: str = Field(min_length=1, max_length=4000)
103
-
104
- class ChatRequest(BaseModel):
105
- driver_id: Optional[str] = "DRV_DEFAULT"
106
- driver_prompt: str = Field(min_length=1, max_length=2000)
107
- current_zone_id: Optional[str] = None
108
- history: List[HistoryMessage] = Field(default_factory=list)
109
-
110
  SYSTEM_PROMPT = (
111
  "You are Sherpa, an AI driving assistant for the CommitCon ride-hailing "
112
  "repositioning platform in Bengaluru. Provide concise, direct, helpful "
@@ -114,6 +69,8 @@ SYSTEM_PROMPT = (
114
  "earnings, and low traffic delays."
115
  )
116
 
 
 
117
  def run_inference(prompt: str, history: List[dict] = None) -> str:
118
  messages = [{"role": "system", "content": SYSTEM_PROMPT}]
119
  if history:
@@ -125,23 +82,8 @@ def run_inference(prompt: str, history: List[dict] = None) -> str:
125
  )
126
  return response["choices"][0]["message"]["content"]
127
 
128
- @app.get("/")
129
- def root():
130
- return {"status": "ok", "service": "CommitCon HF Driver AI Inference Service"}
131
-
132
- @app.post("/chat")
133
- def chat_endpoint(payload: ChatRequest, x_api_key: Optional[str] = Header(None)):
134
- if API_KEY and x_api_key != API_KEY:
135
- raise HTTPException(status_code=401, detail="Unauthorized: Invalid API Key")
136
- formatted_history = [{"role": m.role, "content": m.content} for m in payload.history]
137
- answer = run_inference(payload.driver_prompt, formatted_history)
138
- return {
139
- "status": "success", "answer": answer,
140
- "model": "project-driver-qwen-gguf", "zone_context": payload.current_zone_id
141
- }
142
-
143
  # =============================================================
144
- # 4. Gradio Chat UI
145
  # =============================================================
146
  def gradio_chat(user_message, history):
147
  hist_formatted = []
@@ -155,10 +97,37 @@ def gradio_chat(user_message, history):
155
  demo = gr.ChatInterface(
156
  fn=gradio_chat,
157
  title="🧭 CommitCon Sherpa Driver Copilot",
158
- description="Fine-tuned Qwen 0.8B Q4_K_M — llama-cpp-python CPU inference"
159
  )
160
- app = gr.mount_gradio_app(app, demo, path="/")
161
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  if __name__ == "__main__":
163
- import uvicorn
164
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
4
  import re
5
 
6
  # =============================================================
7
+ # 1. Bootstrap: Install prebuilt CPU/ZeroGPU llama-cpp-python
8
  # =============================================================
9
  def bootstrap_llama_cpp():
10
+ print("Bootstrapping llama-cpp-python...")
11
  from huggingface_hub import HfApi, hf_hub_download
12
 
13
  api = HfApi()
14
  files = api.list_repo_files("AIencoder/llama-cpp-wheels", repo_type="dataset")
 
15
  py_tag = f"cp{sys.version_info.major}{sys.version_info.minor}"
16
 
 
17
  candidates = []
18
  for p in files:
19
+ if not p.endswith(".whl") or "linux/x86_64/cpu/" not in p or "cuda" in p.lower():
 
 
 
 
20
  continue
21
  if py_tag not in p and "py3-none" not in p:
22
  continue
 
23
  m = re.search(r"/0\.3\.(\d+)/", p)
24
+ if not m or int(m.group(1)) < 20:
 
 
 
25
  continue
26
+ candidates.append((int(m.group(1)), p))
27
 
 
28
  candidates.sort(key=lambda x: x[0], reverse=True)
 
 
 
 
29
  chosen = candidates[0][1]
30
  print(f"Selected wheel: {chosen}")
31
  whl_path = hf_hub_download("AIencoder/llama-cpp-wheels", chosen, repo_type="dataset")
32
  subprocess.check_call([
33
  sys.executable, "-m", "pip", "install", "--force-reinstall", whl_path
34
  ])
35
+ print("llama-cpp-python ready!")
36
 
37
  try:
38
  from llama_cpp import Llama
 
41
  bootstrap_llama_cpp()
42
  from llama_cpp import Llama
43
 
44
+ import spaces
45
  from typing import List, Literal, Optional
46
  from pydantic import BaseModel, Field
47
+ from fastapi import HTTPException, Header
48
  import gradio as gr
49
 
50
  # =============================================================
51
+ # 2. Load GGUF Model
52
  # =============================================================
53
  MODEL_PATH = "Qwen3.5-0.8B.Q4_K_M.gguf"
54
  API_KEY = os.getenv("API_KEY", "commitcon-secret-2026")
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  print(f"Loading {MODEL_PATH} via llama-cpp-python ...")
57
  llm = Llama(
58
  model_path=MODEL_PATH,
 
62
  )
63
  print("Model loaded successfully!")
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  SYSTEM_PROMPT = (
66
  "You are Sherpa, an AI driving assistant for the CommitCon ride-hailing "
67
  "repositioning platform in Bengaluru. Provide concise, direct, helpful "
 
69
  "earnings, and low traffic delays."
70
  )
71
 
72
+ # ZeroGPU decorator satisfies HF's startup check
73
+ @spaces.GPU
74
  def run_inference(prompt: str, history: List[dict] = None) -> str:
75
  messages = [{"role": "system", "content": SYSTEM_PROMPT}]
76
  if history:
 
82
  )
83
  return response["choices"][0]["message"]["content"]
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  # =============================================================
86
+ # 3. Gradio UI
87
  # =============================================================
88
  def gradio_chat(user_message, history):
89
  hist_formatted = []
 
97
  demo = gr.ChatInterface(
98
  fn=gradio_chat,
99
  title="🧭 CommitCon Sherpa Driver Copilot",
100
+ description="Fine-tuned Qwen 0.8B Q4_K_M — llama-cpp-python inference"
101
  )
 
102
 
103
+ # =============================================================
104
+ # 4. Attach FastAPI Endpoints to demo.app
105
+ # =============================================================
106
+ class HistoryMessage(BaseModel):
107
+ role: Literal["user", "assistant"]
108
+ content: str = Field(min_length=1, max_length=4000)
109
+
110
+ class ChatRequest(BaseModel):
111
+ driver_id: Optional[str] = "DRV_DEFAULT"
112
+ driver_prompt: str = Field(min_length=1, max_length=2000)
113
+ current_zone_id: Optional[str] = None
114
+ history: List[HistoryMessage] = Field(default_factory=list)
115
+
116
+ @demo.app.post("/chat")
117
+ def chat_endpoint(payload: ChatRequest, x_api_key: Optional[str] = Header(None)):
118
+ if API_KEY and x_api_key != API_KEY:
119
+ raise HTTPException(status_code=401, detail="Unauthorized: Invalid API Key")
120
+ formatted_history = [{"role": m.role, "content": m.content} for m in payload.history]
121
+ answer = run_inference(payload.driver_prompt, formatted_history)
122
+ return {
123
+ "status": "success",
124
+ "answer": answer,
125
+ "model": "project-driver-qwen-gguf",
126
+ "zone_context": payload.current_zone_id
127
+ }
128
+
129
+ # =============================================================
130
+ # 5. Launch
131
+ # =============================================================
132
  if __name__ == "__main__":
133
+ demo.launch()