Beexly commited on
Commit
6b8a01c
·
verified ·
1 Parent(s): f8b8976

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. README.md +26 -19
  2. app.py +33 -6
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: GSE Labs Chat
3
  emoji: 🧠
4
  colorFrom: indigo
5
  colorTo: purple
@@ -7,34 +7,41 @@ sdk: gradio
7
  sdk_version: 5.9.1
8
  app_file: app.py
9
  pinned: false
10
- license: apache-2.0
 
 
11
  short_description: Chat with an open-weights model on free ZeroGPU
12
  tags:
13
  - zero-gpu
14
  ---
15
 
16
- # GSE Labs Chat (ZeroGPU)
17
 
18
- A personal Gradio chat UI running **Qwen2.5-72B-Instruct** (4-bit) on
19
- Hugging Face's free **ZeroGPU** hardware (time-sliced Nvidia GPU, allocated
20
- per request). Personal-use tool, not part of the GSE product surface.
21
 
22
- No API key, no per-token billing — inference runs on the Space's shared free
23
- GPU quota instead of a paid hosted API. Responses stream token-by-token, GPU
24
- time requested per reply scales with how many tokens you ask for
25
- (`_duration()` in `app.py`), attention uses `sdpa`, sampling uses
26
- `top_p`/`repetition_penalty` for quality, and chat history is capped at the
27
- last 12 turns to keep long sessions from exceeding context/GPU limits.
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  ## Swapping the model
30
 
31
  Change `MODEL_ID` in `app.py` to any other instruct-tuned model on the Hub.
32
  Verified working sizes so far (4-bit, packed footprint): 32B → ~20.7GB,
33
- 72B → 44.5GB, both confirmed loading and generating cleanly. If a bigger
34
- model OOMs or times out, the previous known-good `MODEL_ID` is
35
  `Qwen/Qwen2.5-32B-Instruct`.
36
-
37
- Measured 72B throughput: ~13.4 tokens/sec including overhead (800 tokens in
38
- 59.8s, live test). The "Max new tokens" slider is capped at 1024 so a
39
- full-length request stays inside the 120s ZeroGPU duration ceiling with
40
- margin — raise it only alongside `_duration()`'s cap, and re-test.
 
1
  ---
2
+ title: Beexly Studio Chat
3
  emoji: 🧠
4
  colorFrom: indigo
5
  colorTo: purple
 
7
  sdk_version: 5.9.1
8
  app_file: app.py
9
  pinned: false
10
+ license: other
11
+ license_name: qwen
12
+ license_link: https://huggingface.co/Qwen/Qwen2.5-72B-Instruct/blob/main/LICENSE
13
  short_description: Chat with an open-weights model on free ZeroGPU
14
  tags:
15
  - zero-gpu
16
  ---
17
 
18
+ # Beexly Studio Chat (ZeroGPU)
19
 
20
+ Personal chat tool. **Not connected to any Galaxy Sports Edge product, data,
21
+ or prediction engine — this is Garrett's own tooling, unrelated to GSE.**
 
22
 
23
+ - **Model**: `Qwen/Qwen2.5-72B-Instruct`, loaded 4-bit (nf4, bitsandbytes)
24
+ - **License**: `qwen` (Alibaba's custom Qwen license, confirmed from the
25
+ model card metadata — not Apache-2.0/MIT; read the full terms on the
26
+ [model card](https://huggingface.co/Qwen/Qwen2.5-72B-Instruct) before any
27
+ commercial or redistribution use, this Space is personal-use only)
28
+ - **Measured limits** (live-tested, see the deploy report): packed footprint
29
+ 44.5GB, ~13.4 tokens/sec including overhead, max 1024 output tokens per
30
+ reply (calibrated so a full-length reply stays under ZeroGPU's 120s grant
31
+ with margin — a 1024-token reply measured 84.0s), cold start ~4-5 min
32
+ (full weight re-download; no persistent storage on the free tier)
33
+
34
+ ## Features
35
+
36
+ - System-prompt picker: General / Code / Writing / Structured JSON output
37
+ - Streaming responses
38
+ - Copy button on every reply (hover a message)
39
+ - Chat history capped at the last 12 turns to bound context growth
40
 
41
  ## Swapping the model
42
 
43
  Change `MODEL_ID` in `app.py` to any other instruct-tuned model on the Hub.
44
  Verified working sizes so far (4-bit, packed footprint): 32B → ~20.7GB,
45
+ 72B → 44.5GB, both loading and generating cleanly. If a bigger model OOMs
46
+ or times out, the previous known-good `MODEL_ID` is
47
  `Qwen/Qwen2.5-32B-Instruct`.
 
 
 
 
 
app.py CHANGED
@@ -13,6 +13,24 @@ from transformers import (
13
  MODEL_ID = "Qwen/Qwen2.5-72B-Instruct"
14
  MAX_HISTORY_TURNS = 12
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
17
  model = AutoModelForCausalLM.from_pretrained(
18
  MODEL_ID,
@@ -26,15 +44,16 @@ model = AutoModelForCausalLM.from_pretrained(
26
  )
27
 
28
 
29
- def _duration(message, history, system_prompt, max_new_tokens, temperature):
30
  return min(120, 40 + int(max_new_tokens) // 10)
31
 
32
 
33
  @spaces.GPU(duration=_duration)
34
- def generate(message, history, system_prompt, max_new_tokens, temperature):
35
  history = history[-(MAX_HISTORY_TURNS * 2):]
 
36
 
37
- messages = [{"role": "system", "content": system_prompt}] if system_prompt else []
38
  for turn in history:
39
  messages.append({"role": turn["role"], "content": turn["content"]})
40
  messages.append({"role": "user", "content": message})
@@ -69,16 +88,24 @@ def generate(message, history, system_prompt, max_new_tokens, temperature):
69
  thread.join()
70
 
71
 
 
 
72
  demo = gr.ChatInterface(
73
  fn=generate,
74
  type="messages",
 
75
  additional_inputs=[
76
- gr.Textbox(label="System prompt", value="You are a helpful assistant."),
 
 
77
  gr.Slider(64, 1024, value=512, step=64, label="Max new tokens"),
78
  gr.Slider(0.0, 1.5, value=0.7, step=0.1, label="Temperature"),
79
  ],
80
- title="GSE Labs Chat (ZeroGPU)",
81
- description=f"Personal free-GPU chat — `{MODEL_ID}` (4-bit), streaming, on ZeroGPU.",
 
 
 
82
  )
83
 
84
  if __name__ == "__main__":
 
13
  MODEL_ID = "Qwen/Qwen2.5-72B-Instruct"
14
  MAX_HISTORY_TURNS = 12
15
 
16
+ SYSTEM_PROMPTS = {
17
+ "General": "You are a helpful assistant.",
18
+ "Code": (
19
+ "You are an expert software engineer. Answer with correct, working code. "
20
+ "Prefer minimal, direct solutions. Explain tricky parts briefly, in comments "
21
+ "only where the reasoning isn't obvious from the code itself."
22
+ ),
23
+ "Writing": (
24
+ "You are a skilled editor and writer. Write clearly and concisely. "
25
+ "Match the requested tone and length exactly. Avoid filler and cliches."
26
+ ),
27
+ "Structured JSON output": (
28
+ "You output ONLY valid JSON matching what the user asks for — no prose, "
29
+ "no markdown code fences, no explanation before or after. If the request "
30
+ "is ambiguous, make a reasonable schema choice and stay consistent."
31
+ ),
32
+ }
33
+
34
  tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
35
  model = AutoModelForCausalLM.from_pretrained(
36
  MODEL_ID,
 
44
  )
45
 
46
 
47
+ def _duration(message, history, system_prompt_name, max_new_tokens, temperature):
48
  return min(120, 40 + int(max_new_tokens) // 10)
49
 
50
 
51
  @spaces.GPU(duration=_duration)
52
+ def generate(message, history, system_prompt_name, max_new_tokens, temperature):
53
  history = history[-(MAX_HISTORY_TURNS * 2):]
54
+ system_prompt = SYSTEM_PROMPTS.get(system_prompt_name, SYSTEM_PROMPTS["General"])
55
 
56
+ messages = [{"role": "system", "content": system_prompt}]
57
  for turn in history:
58
  messages.append({"role": turn["role"], "content": turn["content"]})
59
  messages.append({"role": "user", "content": message})
 
88
  thread.join()
89
 
90
 
91
+ chatbot = gr.Chatbot(type="messages", show_copy_button=True, label="Chat")
92
+
93
  demo = gr.ChatInterface(
94
  fn=generate,
95
  type="messages",
96
+ chatbot=chatbot,
97
  additional_inputs=[
98
+ gr.Dropdown(
99
+ list(SYSTEM_PROMPTS.keys()), value="General", label="System prompt"
100
+ ),
101
  gr.Slider(64, 1024, value=512, step=64, label="Max new tokens"),
102
  gr.Slider(0.0, 1.5, value=0.7, step=0.1, label="Temperature"),
103
  ],
104
+ title="Beexly Studio Chat (ZeroGPU)",
105
+ description=(
106
+ f"Personal free-GPU chat — `{MODEL_ID}` (4-bit), streaming, on ZeroGPU. "
107
+ "Hover any reply for a copy button. Not part of any Galaxy Sports Edge product."
108
+ ),
109
  )
110
 
111
  if __name__ == "__main__":