Welly-code commited on
Commit
28da4fd
·
verified ·
1 Parent(s): 9c578ef

Minimal Gradio 6.0 compatible build — no deprecated params

Browse files
Files changed (1) hide show
  1. app.py +62 -342
app.py CHANGED
@@ -1,6 +1,6 @@
1
  """
2
  Stack X Ultimate — Hugging Face Space
3
- Agentic tool-calling model demo.
4
  """
5
 
6
  import gradio as gr
@@ -10,66 +10,10 @@ from datetime import datetime
10
 
11
  # ─── Tools ─────────────────────────────────────────────────────────────────
12
 
13
- TOOLS = [
14
- {
15
- "type": "function",
16
- "function": {
17
- "name": "calculator",
18
- "description": "Evaluate a mathematical expression.",
19
- "parameters": {
20
- "type": "object",
21
- "properties": {
22
- "expression": {"type": "string", "description": "e.g. '1500 * 0.07 * 30'"}
23
- },
24
- "required": ["expression"]
25
- }
26
- }
27
- },
28
- {
29
- "type": "function",
30
- "function": {
31
- "name": "get_current_time",
32
- "description": "Get the current UTC time.",
33
- "parameters": {"type": "object", "properties": {}}
34
- }
35
- },
36
- {
37
- "type": "function",
38
- "function": {
39
- "name": "search_files",
40
- "description": "Search for files matching a glob pattern.",
41
- "parameters": {
42
- "type": "object",
43
- "properties": {
44
- "path": {"type": "string", "description": "Root directory"},
45
- "pattern": {"type": "string", "description": "Glob pattern, e.g. '*.py'"}
46
- },
47
- "required": ["path", "pattern"]
48
- }
49
- }
50
- },
51
- {
52
- "type": "function",
53
- "function": {
54
- "name": "run_command",
55
- "description": "Execute a shell command.",
56
- "parameters": {
57
- "type": "object",
58
- "properties": {
59
- "command": {"type": "string", "description": "Shell command to run"},
60
- "cwd": {"type": "string", "description": "Working directory"}
61
- },
62
- "required": ["command"]
63
- }
64
- }
65
- },
66
- ]
67
-
68
  def calculator(expression: str) -> str:
69
  try:
70
  cleaned = re.sub(r"[^0-9+\-*/.()% ]", "", expression)
71
- result = eval(cleaned, {"__builtins__": {}})
72
- return f"Result: {result}"
73
  except Exception as e:
74
  return f"Error: {e}"
75
 
@@ -89,315 +33,93 @@ def search_files(path: str, pattern: str) -> str:
89
  def run_command(command: str, cwd: str = ".") -> str:
90
  import subprocess
91
  try:
92
- result = subprocess.run(command, shell=True, cwd=cwd, capture_output=True, text=True, timeout=30)
93
- out = result.stdout.strip() or "(no output)"
94
- err = result.stderr.strip() if result.stderr else ""
95
  return f"STDOUT:\n{out}\n\nSTDERR:\n{err}" if err else out
96
  except subprocess.TimeoutExpired:
97
  return "Timed out after 30 seconds."
98
  except Exception as e:
99
  return f"Error: {e}"
100
 
101
- def execute_tool(tool_name: str, tool_args: dict) -> str:
102
  fns = {
103
- "calculator": lambda: calculator(tool_args.get("expression", "")),
104
  "get_current_time": get_current_time,
105
- "search_files": lambda: search_files(tool_args.get("path", "."), tool_args.get("pattern", "*")),
106
- "run_command": lambda: run_command(tool_args.get("command", ""), tool_args.get("cwd", ".")),
107
  }
108
  return fns.get(tool_name, lambda: f"Unknown: {tool_name}")()
109
 
110
  # ─── Response Logic ──────────────────────────────────────────────────────────
111
 
112
- def generate_response(message: str) -> dict:
113
- msg_lower = message.lower()
114
 
115
- if any(k in msg_lower for k in ["calculate", "compute", "math", "roi", "compound", "interest", "%", "$"]):
116
  expr = re.search(r"[\d+\-*/.()% ]+", message)
117
- return {"tool": "calculator", "args": {"expression": expr.group().strip() if expr else "0"}}
118
-
119
- if any(k in msg_lower for k in ["time", "date", "now", "current"]):
120
- return {"tool": "get_current_time", "args": {}}
121
-
122
- if any(k in msg_lower for k in ["find", "search", "file", "look for", "where is", "list"]):
123
- pattern = re.search(r"\*\.[a-zA-Z]+", message)
124
- return {"tool": "search_files", "args": {"path": ".", "pattern": pattern.group() if pattern else "*"}}
125
-
126
- if any(k in msg_lower for k in ["run", "execute", "terminal", "bash", "git ", "ls ", "ps ", "docker", "command"]):
127
- match = re.search(r"`([^`]+)`", message)
128
- cmd = match.group(1) if match else message.split()[-1]
129
- return {"tool": "run_command", "args": {"command": cmd, "cwd": "."}}
130
-
131
- return {"tool": None, "args": {}}
132
-
133
- # ─── Chat Function ───────────────────────────────────────────────────────────
134
-
135
- def chat_fn(message, history):
136
- resp = generate_response(message)
137
-
138
- if resp["tool"]:
139
- result = execute_tool(resp["tool"], resp["args"])
140
- call_msg = f"🔧 Calling `{resp['tool']}`...\n\n```json\n{json.dumps(resp['args'], indent=2)}\n```"
141
- result_msg = f"✅ **{resp['tool']}** result:\n\n```\n{result}\n```"
142
- return [[call_msg, result_msg]]
143
-
144
- return [[message,
145
- "Stack X Ultimate is a fine-tuned agentic model that calls tools to answer your questions. "
146
- "Try one of the examples below to see it in action!"
147
- ]]
148
-
149
- # ─── Dark Theme CSS ─────────────────────────────────────────────────────────
150
-
151
- DARK_CSS = """
152
- :root {
153
- --background: #0a0a0a;
154
- --surface: #111111;
155
- --border: #1e1e1e;
156
- --text-primary: #ededed;
157
- --text-secondary: #a1a1a1;
158
- --accent: #a855f7;
159
- --accent-hover: #9333ea;
160
- --code-bg: #161616;
161
- }
162
-
163
- body, html {
164
- background: var(--background) !important;
165
- color: var(--text-primary) !important;
166
- }
167
-
168
- .gradio-container {
169
- background: var(--background) !important;
170
- border: none !important;
171
- }
172
-
173
- /* ── Chat area ── */
174
- .chat-container, . chatbot {
175
- background: var(--background) !important;
176
- }
177
-
178
- /* ── User bubble ── */
179
- .user-bubble {
180
- background: #1e1e1e !important;
181
- border: 1px solid #2e2e2e !important;
182
- border-radius: 12px 12px 4px 12px !important;
183
- color: #f0f0f0 !important;
184
- padding: 10px 14px !important;
185
- max-width: 80% !important;
186
- }
187
-
188
- /* ── Assistant bubble ── */
189
- .assistant-bubble {
190
- background: #141414 !important;
191
- border: 1px solid #2a2a2a !important;
192
- border-radius: 12px 12px 12px 4px !important;
193
- color: #e0e0e0 !important;
194
- padding: 10px 14px !important;
195
- max-width: 80% !important;
196
- }
197
-
198
- /* ── Input box ── */
199
- #main-input input {
200
- background: #111111 !important;
201
- border: 1px solid #2a2a2a !important;
202
- border-radius: 10px !important;
203
- color: #ffffff !important;
204
- font-size: 1rem !important;
205
- padding: 12px 16px !important;
206
- }
207
- #main-input input:focus {
208
- border-color: var(--accent) !important;
209
- outline: none !important;
210
- box-shadow: 0 0 0 2px rgba(168, 85, 247, 0.25) !important;
211
- }
212
-
213
- /* ── Send button ── */
214
- .send-btn {
215
- background: var(--accent) !important;
216
- border: none !important;
217
- color: white !important;
218
- border-radius: 10px !important;
219
- font-weight: 600 !important;
220
- transition: background 0.2s ease !important;
221
- }
222
- .send-btn:hover {
223
- background: var(--accent-hover) !important;
224
- }
225
-
226
- /* ── Examples ── */
227
- .examples-container {
228
- background: #0e0e0e !important;
229
- border: 1px solid #1e1e1e !important;
230
- border-radius: 10px !important;
231
- padding: 12px !important;
232
- }
233
- .example-btn {
234
- background: #161616 !important;
235
- border: 1px solid #2a2a2a !important;
236
- border-radius: 8px !important;
237
- color: #b0b0b0 !important;
238
- font-size: 0.85rem !important;
239
- padding: 6px 12px !important;
240
- }
241
- .example-btn:hover {
242
- background: #1e1e1e !important;
243
- color: #ffffff !important;
244
- border-color: var(--accent) !important;
245
- }
246
-
247
- /* ── Hero ── */
248
- .hero {
249
- background: #0e0e0e !important;
250
- border: 1px solid #1e1e1e !important;
251
- border-radius: 12px !important;
252
- padding: 24px !important;
253
- text-align: center !important;
254
- margin-bottom: 16px !important;
255
- }
256
- .hero h1 {
257
- font-size: 2rem !important;
258
- font-weight: 900 !important;
259
- color: #ffffff !important;
260
- margin: 0 0 8px 0 !important;
261
- }
262
- .hero h1 span {
263
- background: linear-gradient(135deg, #a855f7, #6366f1) !important;
264
- -webkit-background-clip: text !important;
265
- -webkit-text-fill-color: transparent !important;
266
- background-clip: text !important;
267
- }
268
- .hero p {
269
- color: #909090 !important;
270
- font-size: 0.95rem !important;
271
- margin: 0 auto !important;
272
- max-width: 460px !important;
273
- }
274
-
275
- /* ── Stats bar ── */
276
- .stats-bar {
277
- display: flex !important;
278
- justify-content: center !important;
279
- gap: 32px !important;
280
- padding: 16px !important;
281
- margin-bottom: 16px !important;
282
- }
283
- .stat { text-align: center; }
284
- .stat-val {
285
- font-size: 1.5rem !important;
286
- font-weight: 800 !important;
287
- color: var(--accent) !important;
288
- }
289
- .stat-lbl {
290
- font-size: 0.65rem !important;
291
- color: #606060 !important;
292
- text-transform: uppercase !important;
293
- letter-spacing: 0.08em !important;
294
- }
295
-
296
- /* ── Tool badges ── */
297
- .tool-badges {
298
- display: flex !important;
299
- justify-content: center !important;
300
- gap: 8px !important;
301
- flex-wrap: wrap !important;
302
- margin-top: 12px !important;
303
- }
304
- .tool-badge {
305
- background: #161616 !important;
306
- border: 1px solid #2a2a2a !important;
307
- border-radius: 999px !important;
308
- padding: 4px 12px !important;
309
- font-size: 0.75rem !important;
310
- color: #888888 !important;
311
- }
312
-
313
- /* ── Footer ── */
314
- .footer {
315
- text-align: center !important;
316
- color: #505050 !important;
317
- font-size: 0.75rem !important;
318
- padding: 14px !important;
319
- border-top: 1px solid #1a1a1a !important;
320
- margin-top: 16px !important;
321
- }
322
- .footer a { color: var(--accent) !important; text-decoration: none !important; }
323
- .footer a:hover { text-decoration: underline !important; }
324
- """
325
-
326
- # ─── Build UI ───────────────────────────────────────────────────────────────
327
 
328
  EXAMPLES = [
329
- ["Calculate compound interest on $1500 at 7% over 30 years"],
330
- ["What time is it right now?"],
331
- ["Find all Python files in this directory"],
332
- ["Run `ls -la` to list files"],
333
- ["Calculate 15% tip on a $87 bill"],
334
  ]
335
 
336
- def build():
337
- with gr.Blocks(title="Stack X Ultimate") as demo:
 
 
 
338
 
339
- # ── Hero ──────────────────────────────────────────────────────
340
- gr.HTML("""
341
- <div class="hero">
342
- <h1>🤖 Stack X <span>Ultimate</span></h1>
343
- <p>Open-source agentic model with tool calling.<br>Deploy on your own GPU — no API key, no data leaving your server.</p>
344
- <div class="tool-badges">
345
- <span class="tool-badge">🔢 calculator</span>
346
- <span class="tool-badge">🕐 get_current_time</span>
347
- <span class="tool-badge">📁 search_files</span>
348
- <span class="tool-badge">⚡ run_command</span>
349
- </div>
350
- </div>
351
- """)
352
 
353
- gr.HTML("""
354
- <div class="stats-bar">
355
- <div class="stat"><div class="stat-val">3B</div><div class="stat-lbl">Params</div></div>
356
- <div class="stat"><div class="stat-val">Q4</div><div class="stat-lbl">GGUF</div></div>
357
- <div class="stat"><div class="stat-val">V100</div><div class="stat-lbl">1 GPU</div></div>
358
- <div class="stat"><div class="stat-val">$0</div><div class="stat-lbl">API Cost</div></div>
359
- <div class="stat"><div class="stat-val">8K</div><div class="stat-lbl">Context</div></div>
360
- </div>
361
- """)
362
 
363
- # ── Chat ──────────────────────────────────────────────────────
364
- chat = gr.Chatbot(
365
- height=420,
366
- avatar_images=(
367
- "https://huggingface.co/front/assets/icons/8.svg",
368
- "https://huggingface.co/front/assets/icons/13.svg"
369
- ),
370
- )
371
 
372
  with gr.Row():
373
- msg = gr.Textbox(
374
- placeholder="Type a message or try an example below...",
375
- scale=5,
376
- elem_id="main-input",
377
- )
378
- send_btn = gr.Button("Send →", scale=1, elem_class="send-btn")
379
 
380
- # ── Events ────────────────────────────────────────────────────
381
- msg.submit(chat_fn, [msg, chat], [chat])
382
- send_btn.click(chat_fn, [msg, chat], [chat])
383
- msg.submit(lambda: "", None, msg)
384
 
385
- # ── Examples ────────────────────────────────────────────────────
386
- gr.Examples(
387
- examples=EXAMPLES,
388
- inputs=[msg],
389
- label="Try one of these →",
390
- examples_per_page=5,
391
- )
392
 
393
- # ── Footer ──────────────────────────────────────────────────────
394
- gr.HTML("""
395
- <div class="footer">
396
- 🔧 This demo shows tool-calling capability. Fine-tuned model coming soon —
397
- <a href="https://huggingface.co/my-ai-stack/Stack-X-Ultimate">Deploy the model</a> ·
398
- <a href="https://www.stack-ai.me/contact">Enterprise inquiry</a>
399
- </div>
400
- """)
401
 
402
  return demo
403
 
@@ -406,8 +128,6 @@ if __name__ == "__main__":
406
  demo.launch(
407
  server_name="0.0.0.0",
408
  server_port=7860,
409
- css=DARK_CSS,
410
- theme=gr.themes.Default(primary_hue="purple"),
411
  max_threads=4,
412
  show_api=False,
413
  )
 
1
  """
2
  Stack X Ultimate — Hugging Face Space
3
+ Gradio 6.0 compatible.
4
  """
5
 
6
  import gradio as gr
 
10
 
11
  # ─── Tools ─────────────────────────────────────────────────────────────────
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  def calculator(expression: str) -> str:
14
  try:
15
  cleaned = re.sub(r"[^0-9+\-*/.()% ]", "", expression)
16
+ return f"Result: {eval(cleaned, {'__builtins__': {}})}"
 
17
  except Exception as e:
18
  return f"Error: {e}"
19
 
 
33
  def run_command(command: str, cwd: str = ".") -> str:
34
  import subprocess
35
  try:
36
+ r = subprocess.run(command, shell=True, cwd=cwd, capture_output=True, text=True, timeout=30)
37
+ out = r.stdout.strip() or "(no output)"
38
+ err = r.stderr.strip() if r.stderr else ""
39
  return f"STDOUT:\n{out}\n\nSTDERR:\n{err}" if err else out
40
  except subprocess.TimeoutExpired:
41
  return "Timed out after 30 seconds."
42
  except Exception as e:
43
  return f"Error: {e}"
44
 
45
+ def execute(tool_name: str, tool_args: dict) -> str:
46
  fns = {
47
+ "calculator": lambda: calculator(tool_args.get("expression", "")),
48
  "get_current_time": get_current_time,
49
+ "search_files": lambda: search_files(tool_args.get("path", "."), tool_args.get("pattern", "*")),
50
+ "run_command": lambda: run_command(tool_args.get("command", ""), tool_args.get("cwd", ".")),
51
  }
52
  return fns.get(tool_name, lambda: f"Unknown: {tool_name}")()
53
 
54
  # ─── Response Logic ──────────────────────────────────────────────────────────
55
 
56
+ def respond(message: str):
57
+ msg = message.lower()
58
 
59
+ if any(k in msg for k in ["calculate", "compute", "math", "roi", "compound", "interest", "%", "$"]):
60
  expr = re.search(r"[\d+\-*/.()% ]+", message)
61
+ tool, args = "calculator", {"expression": expr.group().strip() if expr else "0"}
62
+ elif any(k in msg for k in ["time", "date", "now", "current"]):
63
+ tool, args = "get_current_time", {}
64
+ elif any(k in msg for k in ["find", "search", "file", "look for", "where is", "list"]):
65
+ pat = re.search(r"\*\.[a-zA-Z]+", message)
66
+ tool, args = "search_files", {"path": ".", "pattern": pat.group() if pat else "*"}
67
+ elif any(k in msg for k in ["run", "execute", "terminal", "bash", "git ", "ls ", "ps ", "docker"]):
68
+ m = re.search(r"`([^`]+)`", message)
69
+ cmd = m.group(1) if m else message.split()[-1]
70
+ tool, args = "run_command", {"command": cmd, "cwd": "."}
71
+ else:
72
+ return "This is a demo of Stack X Ultimate's tool-calling capability. The fine-tuned model processes your message and intelligently decides whether to call a tool. Try one of the examples below! 🔧"
73
+
74
+ result = execute(tool, args)
75
+ call = f"🔧 Calling `{tool}`...\n\n```json\n{json.dumps(args, indent=2)}\n```"
76
+ res = f"✅ **{tool}** result:\n\n```\n{result}\n```"
77
+ return [[call, res]]
78
+
79
+ # ─── Gradio UI ──────────────────────────────────────────────────────────────
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
  EXAMPLES = [
82
+ "Calculate compound interest on $1500 at 7% over 30 years",
83
+ "What time is it right now?",
84
+ "Find all Python files in this directory",
85
+ "Run `ls -la` to list files",
86
+ "Calculate 15% tip on a $87 bill",
87
  ]
88
 
89
+ DARK = """
90
+ body { background: #0a0a0a; color: #e0e0e0; font-family: system-ui, sans-serif; }
91
+ .gradio-container { background: #0a0a0a; }
92
+ .chat { background: #0a0a0a; }
93
+ """
94
 
95
+ def build():
96
+ with gr.Blocks(css=DARK, title="Stack X Ultimate") as demo:
97
+ gr.Markdown(
98
+ "## 🤖 Stack X Ultimate\n"
99
+ "**Open-source agentic model with tool calling.** Deploy on your own GPU — no API key, no data leaving your server.\n\n"
100
+ "🔢 `calculator` · 🕐 `get_current_time` · 📁 `search_files` · ⚡ `run_command`",
101
+ elem_classes="md-block"
102
+ )
 
 
 
 
 
103
 
104
+ gr.Markdown("**3B params · Q4 GGUF · V100 1 GPU · $0 API Cost · 8K context**")
 
 
 
 
 
 
 
 
105
 
106
+ chatbot = gr.Chatbot(height=400)
 
 
 
 
 
 
 
107
 
108
  with gr.Row():
109
+ txt = gr.Textbox(placeholder="Type a message or try an example below...", lines=1, scale=5)
110
+ btn = gr.Button("Send →", variant="primary", scale=1)
 
 
 
 
111
 
112
+ gr.Examples(EXAMPLES, inputs=[txt], label="Try one of these →")
 
 
 
113
 
114
+ btn.click(respond, [txt], [chatbot])
115
+ txt.submit(respond, [txt], [chatbot])
116
+ txt.submit(lambda: "", None, txt)
 
 
 
 
117
 
118
+ gr.Markdown(
119
+ "🔧 Demo shows tool-calling capability. "
120
+ "[Deploy the model](https://huggingface.co/my-ai-stack/Stack-X-Ultimate) · "
121
+ "[Enterprise inquiry](https://www.stack-ai.me/contact)"
122
+ )
 
 
 
123
 
124
  return demo
125
 
 
128
  demo.launch(
129
  server_name="0.0.0.0",
130
  server_port=7860,
 
 
131
  max_threads=4,
132
  show_api=False,
133
  )