fomext commited on
Commit
c4a519f
·
verified ·
1 Parent(s): aae8071

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +5 -6
  2. app.py +207 -0
  3. requirements.txt +6 -0
README.md CHANGED
@@ -1,11 +1,10 @@
1
  ---
2
- title: Intelect Module V3
3
- emoji: 🏆
4
- colorFrom: red
5
- colorTo: yellow
6
  sdk: gradio
7
- sdk_version: 6.19.0
8
- python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
11
  ---
 
1
  ---
2
+ title: Qwen3 14B 4-bit
3
+ emoji: 🧠
4
+ colorFrom: blue
5
+ colorTo: green
6
  sdk: gradio
7
+ sdk_version: 4.41.0
 
8
  app_file: app.py
9
  pinned: false
10
  ---
app.py ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import time
3
+ import uuid
4
+ from typing import Optional
5
+
6
+ import gradio as gr
7
+ import spaces
8
+ import torch
9
+ from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer, BitsAndBytesConfig
10
+
11
+ # ---------------------------------------------------------------------------
12
+ # Configuration
13
+ # ---------------------------------------------------------------------------
14
+
15
+ MODEL_ID = "Qwen/Qwen3-14B"
16
+ MODEL_ALIAS = "qwen3-14b-4bit"
17
+
18
+ print(f"Loading tokenizer for {MODEL_ID} …")
19
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
20
+
21
+ print(f"Loading model {MODEL_ID} in 4-bit …")
22
+ bnb_config = BitsAndBytesConfig(
23
+ load_in_4bit=True,
24
+ bnb_4bit_use_double_quant=True,
25
+ bnb_4bit_quant_type="nf4",
26
+ bnb_4bit_compute_dtype=torch.bfloat16,
27
+ )
28
+ model = AutoModelForCausalLM.from_pretrained(
29
+ MODEL_ID,
30
+ quantization_config=bnb_config,
31
+ device_map="auto",
32
+ )
33
+ model.eval()
34
+ print("Model ready.")
35
+
36
+
37
+ # ---------------------------------------------------------------------------
38
+ # GPU generation functions — ZeroGPU anchors
39
+ # ---------------------------------------------------------------------------
40
+
41
+
42
+ @spaces.GPU
43
+ def gradio_chat(message: str, history: list) -> str:
44
+ hf_messages = [{"role": "user" if i % 2 == 0 else "assistant", "content": m}
45
+ for i, m in enumerate([msg for pair in history for msg in pair] + [message])]
46
+ prompt = tokenizer.apply_chat_template(
47
+ hf_messages, tokenize=False, add_generation_prompt=True
48
+ # NOTE: Qwen3-Coder is non-thinking only; enable_thinking is not supported.
49
+ )
50
+ inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
51
+ with torch.no_grad():
52
+ output_ids = model.generate(
53
+ **inputs,
54
+ max_new_tokens=512,
55
+ do_sample=True,
56
+ temperature=0.7,
57
+ top_p=0.9,
58
+ pad_token_id=tokenizer.eos_token_id,
59
+ )
60
+ new_ids = output_ids[0][inputs["input_ids"].shape[1]:]
61
+ return tokenizer.decode(new_ids, skip_special_tokens=True)
62
+
63
+
64
+ @spaces.GPU
65
+ def _generate_response(prompt: str, gen_kwargs: dict) -> str:
66
+ inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
67
+ with torch.no_grad():
68
+ output_ids = model.generate(**inputs, **gen_kwargs)
69
+ new_ids = output_ids[0][inputs["input_ids"].shape[1]:]
70
+ return tokenizer.decode(new_ids, skip_special_tokens=True)
71
+
72
+
73
+ # ---------------------------------------------------------------------------
74
+ # API functions
75
+ # ---------------------------------------------------------------------------
76
+
77
+
78
+ def list_models() -> str:
79
+ """Returns a JSON string listing available models."""
80
+ result = {
81
+ "object": "list",
82
+ "data": [{"id": MODEL_ALIAS, "object": "model", "created": int(time.time()), "owned_by": "qwen"}],
83
+ }
84
+ return json.dumps(result)
85
+
86
+
87
+ def chat_completions(
88
+ messages_json: str,
89
+ max_tokens: int = 512,
90
+ temperature: float = 0.7,
91
+ top_p: float = 0.9,
92
+ ) -> str:
93
+ """
94
+ Non-streaming chat completions. Returns an OpenAI-compatible JSON string.
95
+
96
+ messages_json: JSON array of {role, content} objects,
97
+ e.g. '[{"role":"user","content":"Hello"}]'
98
+
99
+ NOTE: Qwen3-14B supports thinking mode. Set enable_thinking=True in the
100
+ chat template call if you want chain-of-thought reasoning.
101
+ """
102
+ try:
103
+ messages = json.loads(messages_json)
104
+ except json.JSONDecodeError as e:
105
+ return json.dumps({"error": f"Invalid messages_json: {e}"})
106
+
107
+ try:
108
+ hf_messages = [{"role": m["role"], "content": m["content"]} for m in messages]
109
+ prompt = tokenizer.apply_chat_template(
110
+ hf_messages,
111
+ tokenize=False,
112
+ add_generation_prompt=True,
113
+ )
114
+ except Exception as e:
115
+ return json.dumps({"error": f"Prompt build failed: {e}"})
116
+
117
+ gen_kwargs = dict(
118
+ max_new_tokens=max_tokens,
119
+ temperature=temperature,
120
+ top_p=top_p,
121
+ do_sample=True,
122
+ pad_token_id=tokenizer.eos_token_id,
123
+ )
124
+
125
+ try:
126
+ content = _generate_response(prompt, gen_kwargs)
127
+ except Exception as e:
128
+ return json.dumps({"error": f"Generation failed: {e}"})
129
+
130
+ cid = f"chatcmpl-{uuid.uuid4().hex}"
131
+ result = {
132
+ "id": cid,
133
+ "object": "chat.completion",
134
+ "created": int(time.time()),
135
+ "model": MODEL_ALIAS,
136
+ "choices": [{"index": 0, "message": {"role": "assistant", "content": content}, "finish_reason": "stop"}],
137
+ "usage": {"prompt_tokens": -1, "completion_tokens": -1, "total_tokens": -1},
138
+ }
139
+ return json.dumps(result)
140
+
141
+
142
+ def health() -> str:
143
+ """Returns a JSON health-check string."""
144
+ return json.dumps({"status": "ok", "model": MODEL_ID})
145
+
146
+
147
+ # ---------------------------------------------------------------------------
148
+ # Gradio UI + API
149
+ # ---------------------------------------------------------------------------
150
+
151
+ with gr.Blocks(title=f"{MODEL_ALIAS} API") as demo:
152
+ gr.Markdown(f"""
153
+ # {MODEL_ALIAS} — Gradio API
154
+
155
+ Endpoints (via Gradio built-in API):
156
+
157
+ | api_name | Description |
158
+ |----------|-------------|
159
+ | `list_models` | List available models → JSON string |
160
+ | `chat_completions` | Chat completions → JSON string |
161
+ | `health` | Health check → JSON string |
162
+
163
+ Call them at `/gradio_api/call/<api_name>` (POST with `{{"data": [...]}}`)
164
+ or use the Gradio Python client.
165
+
166
+ You can also chat directly below.
167
+ """)
168
+
169
+ gr.ChatInterface(fn=gradio_chat)
170
+
171
+ with gr.Row(visible=False):
172
+ # -- health ------------------------------------------------------
173
+ _health_btn = gr.Button("health")
174
+ _health_out = gr.Textbox()
175
+ _health_btn.click(fn=health, inputs=[], outputs=[_health_out], api_name="health")
176
+
177
+ # -- list_models -------------------------------------------------
178
+ _models_btn = gr.Button("list_models")
179
+ _models_out = gr.Textbox()
180
+ _models_btn.click(fn=list_models, inputs=[], outputs=[_models_out], api_name="list_models")
181
+
182
+ with gr.Row(visible=False):
183
+ # -- chat_completions --------------------------------------------
184
+ _cc_messages = gr.Textbox(label="messages_json")
185
+ _cc_max_tokens = gr.Number(label="max_tokens", value=512)
186
+ _cc_temp = gr.Number(label="temperature", value=0.7)
187
+ _cc_top_p = gr.Number(label="top_p", value=0.9)
188
+ _cc_out = gr.Textbox(label="result")
189
+ _cc_btn = gr.Button("chat_completions")
190
+ _cc_btn.click(
191
+ fn=chat_completions,
192
+ inputs=[_cc_messages, _cc_max_tokens, _cc_temp, _cc_top_p],
193
+ outputs=[_cc_out],
194
+ api_name="chat_completions",
195
+ )
196
+
197
+
198
+ # ---------------------------------------------------------------------------
199
+ # Entry-point
200
+ # ---------------------------------------------------------------------------
201
+
202
+ if __name__ == "__main__":
203
+ demo.queue()
204
+ demo.launch(
205
+ server_name="0.0.0.0",
206
+ server_port=7860,
207
+ )
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ huggingface_hub==0.30
2
+ transformers>=4.51.0
3
+ tokenizers>=0.21.0
4
+ accelerate>=0.34.0
5
+ bitsandbytes>=0.43.0
6
+ fastapi>=0.110.0