Dellboy commited on
Commit
5be713f
·
verified ·
1 Parent(s): 26cc93e

chatPDB API: FastAPI + llama-cpp-python ZeroGPU backend, Q4_K_M GGUF

Browse files
Files changed (4) hide show
  1. Dockerfile +18 -0
  2. README.md +10 -5
  3. app.py +97 -0
  4. requirements.txt +5 -0
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM nvidia/cuda:12.1.0-cudnn8-devel-ubuntu22.04
2
+
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+ RUN apt-get update && apt-get install -y python3 python3-pip git && rm -rf /var/lib/apt/lists/*
5
+
6
+ WORKDIR /app
7
+ COPY requirements.txt .
8
+
9
+ # Build llama-cpp-python with CUDA support
10
+ ENV CMAKE_ARGS="-DGGML_CUDA=on"
11
+ RUN pip3 install --no-cache-dir llama-cpp-python --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cu121
12
+
13
+ RUN pip3 install --no-cache-dir fastapi uvicorn huggingface_hub spaces
14
+
15
+ COPY app.py .
16
+
17
+ EXPOSE 7860
18
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -1,10 +1,15 @@
1
  ---
2
- title: Chatpdb Api
3
- emoji: 🐠
4
- colorFrom: purple
5
- colorTo: purple
6
  sdk: docker
 
7
  pinned: false
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
1
  ---
2
+ title: chatPDB API
3
+ emoji: 🧬
4
+ colorFrom: green
5
+ colorTo: blue
6
  sdk: docker
7
+ app_port: 7860
8
  pinned: false
9
  ---
10
 
11
+ # chatPDB Inference API
12
+
13
+ ZeroGPU-backed streaming inference endpoint for chatPDB 32B v1 (Q4_K_M GGUF).
14
+
15
+ Endpoint: `POST /generate` — returns `text/event-stream` of token chunks.
app.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ chatPDB inference API — HuggingFace Space (ZeroGPU)
3
+
4
+ Serves a streaming /generate endpoint backed by llama-cpp-python.
5
+ The GGUF is pulled from the Hub on first request and cached for the session.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import os
11
+ from pathlib import Path
12
+ from typing import Generator
13
+
14
+ import spaces
15
+ from fastapi import FastAPI
16
+ from fastapi.responses import StreamingResponse
17
+ from huggingface_hub import hf_hub_download
18
+
19
+ # ---------------------------------------------------------------------------
20
+ # Model config
21
+ # ---------------------------------------------------------------------------
22
+
23
+ REPO_ID = "Dellboy/chatpdb_32b_v1-GGUF"
24
+ FILENAME = "chatpdb_32b_v1_q4km.gguf"
25
+ MODEL_PATH: Path | None = None # set after first download
26
+
27
+ N_CTX = 1536 # matches chatPDB's real training max_seq_length (config/train_config.yaml)
28
+ N_GPU_LAYERS = -1 # offload all layers to GPU
29
+
30
+ # ---------------------------------------------------------------------------
31
+ # App
32
+ # ---------------------------------------------------------------------------
33
+
34
+ app = FastAPI(title="chatPDB API")
35
+
36
+
37
+ def _get_model():
38
+ """Download GGUF on first call, return cached Llama instance."""
39
+ global MODEL_PATH
40
+ from llama_cpp import Llama
41
+
42
+ if MODEL_PATH is None:
43
+ MODEL_PATH = Path(hf_hub_download(repo_id=REPO_ID, filename=FILENAME))
44
+
45
+ return Llama(
46
+ model_path=str(MODEL_PATH),
47
+ n_ctx=N_CTX,
48
+ n_gpu_layers=N_GPU_LAYERS,
49
+ verbose=False,
50
+ )
51
+
52
+
53
+ @spaces.GPU
54
+ def _generate_tokens(
55
+ prompt: str,
56
+ max_tokens: int,
57
+ temperature: float,
58
+ repeat_penalty: float,
59
+ ) -> Generator[str, None, None]:
60
+ """Run inference inside the ZeroGPU lease."""
61
+ llm = _get_model()
62
+ stream = llm(
63
+ prompt,
64
+ max_tokens=max_tokens,
65
+ temperature=temperature,
66
+ repeat_penalty=repeat_penalty,
67
+ stream=True,
68
+ )
69
+ for chunk in stream:
70
+ token = chunk["choices"][0]["text"]
71
+ if token:
72
+ yield token
73
+
74
+
75
+ @app.post("/generate")
76
+ async def generate(request: dict):
77
+ """
78
+ POST /generate
79
+ Body: { "prompt": "...", "max_tokens": 512, "temperature": 0.15, "repeat_penalty": 1.15 }
80
+ Returns: text/event-stream of token strings
81
+ """
82
+ prompt = request.get("prompt", "")
83
+ max_tokens = int(request.get("max_tokens", 512))
84
+ temperature = float(request.get("temperature", 0.15))
85
+ repeat_penalty = float(request.get("repeat_penalty", 1.15))
86
+
87
+ def event_stream():
88
+ for token in _generate_tokens(prompt, max_tokens, temperature, repeat_penalty):
89
+ yield f"data: {json.dumps({'token': token})}\n\n"
90
+ yield "data: [DONE]\n\n"
91
+
92
+ return StreamingResponse(event_stream(), media_type="text/event-stream")
93
+
94
+
95
+ @app.get("/health")
96
+ def health():
97
+ return {"status": "ok"}
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ llama-cpp-python[cuda]
4
+ huggingface_hub
5
+ spaces