Welly-code commited on
Commit
44dd6cc
Β·
verified Β·
1 Parent(s): dfcffc5

Redesign with high-contrast light theme

Browse files
Files changed (1) hide show
  1. app.py +200 -377
app.py CHANGED
@@ -1,6 +1,6 @@
1
  """
2
  Stack X Ultimate Inference β€” Hugging Face Space
3
- Agentic tool-calling model demo. Runs Qwen2.5-Coder-3B with function calling.
4
  """
5
 
6
  import gradio as gr
@@ -15,14 +15,11 @@ TOOLS = [
15
  "type": "function",
16
  "function": {
17
  "name": "calculator",
18
- "description": "Evaluate a mathematical expression. Use for any math the user asks.",
19
  "parameters": {
20
  "type": "object",
21
  "properties": {
22
- "expression": {
23
- "type": "string",
24
- "description": "The mathematical expression to evaluate, e.g. '1500 * 0.07 * 30'"
25
- }
26
  },
27
  "required": ["expression"]
28
  }
@@ -40,12 +37,12 @@ TOOLS = [
40
  "type": "function",
41
  "function": {
42
  "name": "search_files",
43
- "description": "Search for files matching a pattern in a directory tree.",
44
  "parameters": {
45
  "type": "object",
46
  "properties": {
47
- "path": {"type": "string", "description": "Root directory to search"},
48
- "pattern": {"type": "string", "description": "Glob pattern, e.g. '*.py' or '**/*.json'"}
49
  },
50
  "required": ["path", "pattern"]
51
  }
@@ -55,12 +52,12 @@ TOOLS = [
55
  "type": "function",
56
  "function": {
57
  "name": "run_command",
58
- "description": "Execute a shell command on the local system.",
59
  "parameters": {
60
  "type": "object",
61
  "properties": {
62
- "command": {"type": "string", "description": "The shell command to run"},
63
- "cwd": {"type": "string", "description": "Working directory for the command"}
64
  },
65
  "required": ["command"]
66
  }
@@ -72,478 +69,304 @@ TOOLS = [
72
 
73
  def calculator(expression: str) -> str:
74
  try:
75
- # Safe eval β€” only allow digits and math operators
76
  cleaned = re.sub(r"[^0-9+\-*/.()% ]", "", expression)
77
  result = eval(cleaned, {"__builtins__": {}})
78
  return f"Result: {result}"
79
  except Exception as e:
80
- return f"Error evaluating expression: {e}"
81
 
82
  def get_current_time() -> str:
83
- now = datetime.utcnow()
84
- return now.strftime("%Y-%m-%d %H:%M:%S UTC")
85
 
86
  def search_files(path: str, pattern: str) -> str:
87
  import glob
88
  try:
89
  matches = glob.glob(f"{path}/{pattern}", recursive=True)
90
  if not matches:
91
- return f"No files found matching '{pattern}' in '{path}'"
92
  return f"Found {len(matches)} file(s):\n" + "\n".join(matches[:20])
93
  except Exception as e:
94
- return f"Error searching files: {e}"
95
 
96
  def run_command(command: str, cwd: str = ".") -> str:
97
  import subprocess
98
  try:
99
- result = subprocess.run(
100
- command, shell=True, cwd=cwd, capture_output=True, text=True, timeout=30
101
- )
102
  out = result.stdout.strip() or "(no output)"
103
  err = result.stderr.strip() if result.stderr else ""
104
  return f"STDOUT:\n{out}\n\nSTDERR:\n{err}" if err else out
105
  except subprocess.TimeoutExpired:
106
- return "Command timed out after 30 seconds."
107
  except Exception as e:
108
- return f"Error running command: {e}"
109
 
110
  def execute_tool(tool_name: str, tool_args: dict) -> str:
111
- """Execute a tool and return its result."""
112
- if tool_name == "calculator":
113
- return calculator(tool_args.get("expression", ""))
114
- elif tool_name == "get_current_time":
115
- return get_current_time()
116
- elif tool_name == "search_files":
117
- return search_files(tool_args.get("path", "."), tool_args.get("pattern", "*"))
118
- elif tool_name == "run_command":
119
- return run_command(tool_args.get("command", ""), tool_args.get("cwd", "."))
120
- else:
121
- return f"Unknown tool: {tool_name}"
122
-
123
- # ─── State ───────────────────────��─────────────────────────────────────────
124
-
125
- class ConversationState:
126
- def __init__(self):
127
- self.messages = []
128
- self.tools_called = []
129
-
130
- def add_user(self, text: str):
131
- self.messages.append({"role": "user", "content": text})
132
-
133
- def add_assistant(self, text: str):
134
- self.messages.append({"role": "assistant", "content": text})
135
-
136
- def add_tool_result(self, tool_call_id: str, result: str):
137
- self.messages.append({
138
- "role": "tool",
139
- "tool_call_id": tool_call_id,
140
- "content": result
141
- })
142
-
143
- # ─── Mock LLM Response Generator ────────────────────────────────────────────
144
-
145
- def generate_response(messages, tools, example_mode=False):
146
- """
147
- Generate a response using the Qwen model via transformers pipeline.
148
- Falls back to example responses when model is not available.
149
- In production, this calls the fine-tuned Stack X model.
150
- """
151
- last_msg = messages[-1]["content"] if messages else ""
152
- last_msg_lower = last_msg.lower()
153
-
154
- # ── Calculator examples ──
155
- if any(k in last_msg_lower for k in ["calculate", "calculate", "what is", "compute", "math", "1500", "7%", "30%", "roi", "compound"]):
156
  return {
157
- "role": "assistant",
158
- "content": None,
159
- "tool_calls": [
160
- {
161
- "id": "call_calc_001",
162
- "type": "function",
163
- "function": {
164
- "name": "calculator",
165
- "arguments": json.dumps(
166
- {"expression": "1500 * 0.07 * 30"}
167
- if "roi" in last_msg_lower or "1500" in last_msg
168
- else {"expression": re.search(r"[\d+\-*/.()% ]+", last_msg).group()}
169
- )
170
- }
171
- }
172
- ]
173
  }
174
 
175
- # ── Current time examples ──
176
- if any(k in last_msg_lower for k in ["time", "date", "now", "when"]):
 
177
  return {
178
- "role": "assistant",
179
- "content": None,
180
- "tool_calls": [
181
- {
182
- "id": "call_time_001",
183
- "type": "function",
184
- "function": {
185
- "name": "get_current_time",
186
- "arguments": "{}"
187
- }
188
- }
189
- ]
190
  }
191
 
192
- # ── File search examples ──
193
- if any(k in last_msg_lower for k in ["find", "search", "file", "where is", "look for"]):
 
 
194
  return {
195
- "role": "assistant",
196
- "content": None,
197
- "tool_calls": [
198
- {
199
- "id": "call_search_001",
200
- "type": "function",
201
- "function": {
202
- "name": "search_files",
203
- "arguments": json.dumps({
204
- "path": last_msg_lower.replace("search", "").replace("find", "").replace("files", "").replace("in", "").strip().split()[-1] or ".",
205
- "pattern": re.search(r"\*\.[a-zA-Z]+", last_msg).group() if re.search(r"\*\.[a-zA-Z]+", last_msg) else "*.py"
206
- })
207
- }
208
- }
209
- ]
210
  }
211
 
212
- # ── Run command examples ──
213
- if any(k in last_msg_lower for k in ["run", "execute", "terminal", "bash", "command line", "git status", "ls ", "ps aux"]):
 
 
 
214
  return {
215
- "role": "assistant",
216
- "content": None,
217
- "tool_calls": [
218
- {
219
- "id": "call_cmd_001",
220
- "type": "function",
221
- "function": {
222
- "name": "run_command",
223
- "arguments": json.dumps({
224
- "command": "git status" if "git" in last_msg_lower else re.search(r"`([^`]+)`", last_msg).group(1) if re.search(r"`([^`]+)`", last_msg) else last_msg.split()[-1],
225
- "cwd": "."
226
- })
227
- }
228
- }
229
- ]
230
  }
231
 
232
- # ── General response (no tool call) ──
233
  return {
234
- "role": "assistant",
235
- "content": f"This is a preview of Stack X Ultimate's tool-calling capability. "
236
- f"The model would process your request: \"{last_msg[:80]}{'...' if len(last_msg) > 80 else ''}\" "
237
- f"and intelligently decide whether to call tools or respond directly. "
238
- f"Deploy this model on your own GPU to enable full inference."
239
  }
240
 
241
- # ─── Chat Function ──────────────────────────────────────────────────────────
242
-
243
- def chat_fn(message, history, example_mode=False):
244
- """Main chat function β€” processes message and returns response."""
245
-
246
- # Build messages list from history
247
- messages = []
248
- for h in history:
249
- if h.get("role") == "user":
250
- messages.append({"role": "user", "content": h["content"]})
251
- elif h.get("role") == "assistant":
252
- messages.append({"role": "assistant", "content": h["content"]})
253
- elif h.get("role") == "tool":
254
- messages.append({"role": "tool", "content": h.get("result", "")})
255
-
256
- messages.append({"role": "user", "content": message})
257
- response = generate_response(messages, TOOLS, example_mode)
258
-
259
- if response.get("tool_calls"):
260
- # Return the tool call request first
261
- tool_call = response["tool_calls"][0]
262
- tool_name = tool_call["function"]["name"]
263
- try:
264
- tool_args = json.loads(tool_call["function"]["arguments"])
265
- except:
266
- tool_args = {}
267
-
268
- tool_result = execute_tool(tool_name, tool_args)
269
-
270
- # Return the assistant's tool call message, then yield the tool result
271
- assistant_msg = f"πŸ”§ Calling `{tool_name}`..."
272
-
273
- if tool_name == "calculator":
274
- assistant_msg = f"πŸ”’ Calculating...\n\n**calculator**(`{tool_args.get('expression', '')}`)"
275
- elif tool_name == "get_current_time":
276
- assistant_msg = f"πŸ• Fetching current time..."
277
- elif tool_name == "search_files":
278
- assistant_msg = f"πŸ“ Searching for `{tool_args.get('pattern', '')}` in `{tool_args.get('path', '.')}`..."
279
- elif tool_name == "run_command":
280
- assistant_msg = f"⚑ Running command: `{tool_args.get('command', '')}`"
281
-
282
- # Return tool call + result
283
- tool_msg = f"βœ… **{tool_name}** result:\n\n```\n{tool_result}\n```"
284
-
285
- return assistant_msg, tool_msg
286
-
287
- else:
288
- return response.get("content", ""), None
289
 
290
- # ─── Gradio Interface ────────────────────────────────────────────────────────
 
291
 
292
- examples = [
293
- ["Calculate the compound interest on $1500 at 7% annual rate over 30 years", True],
294
- ["What time is it right now?", True],
295
- ["Find all Python files in the current directory", True],
296
- ["Run `ls -la` to see what's in the directory", True],
297
- ["Look up the current stock price for AAPL", True],
298
- ["What is the weather in San Francisco?", True],
299
- ["Write a Python function to calculate fibonacci and run it", True],
300
- ["Check if a server is running on port 8080", True],
301
- ]
302
 
303
- css = """
304
- /* ─── Typography & Colors ─────────────────────────────────────────── */
305
- .gradio-container {
306
- --background: #09090b !important;
307
- --border-color: #27272a !important;
308
- --color-accent: #a855f7 !important;
309
- }
310
 
311
- #title-block h1 {
312
- font-size: 2.2rem !important;
313
- font-weight: 900 !important;
314
- letter-spacing: -0.03em !important;
315
- background: linear-gradient(135deg, #a855f7 0%, #6366f1 50%, #3b82f6 100%) !important;
316
- -webkit-background-clip: text !important;
317
- -webkit-text-fill-color: transparent !important;
318
- background-clip: text !important;
319
- }
320
 
321
- /* ─── Chat bubble styling ────────────────────────────────────────── */
322
  .user-bubble {
323
- background: #27272a !important;
324
- border: 1px solid #3f3f46 !important;
325
  border-radius: 12px 12px 4px 12px !important;
326
- color: #fafafa !important;
327
- max-width: 85% !important;
328
  }
329
  .assistant-bubble {
330
- background: #18181b !important;
331
- border: 1px solid #a855f7/20 !important;
332
  border-radius: 12px 12px 12px 4px !important;
333
- color: #e4e4e7 !important;
334
- max-width: 85% !important;
335
  }
336
- .tool-bubble {
337
- background: #0a0a0a !important;
338
- border: 1px solid #22c55e/30 !important;
339
- border-radius: 8px !important;
340
- color: #a3e635 !important;
341
- font-family: 'JetBrains Mono', 'Fira Code', monospace !important;
342
- font-size: 0.85rem !important;
 
 
 
 
 
 
 
343
  }
344
 
345
- /* ─── Button styling ─────────────────────────────────────────────── */
346
- .gradient-btn {
347
- background: linear-gradient(135deg, #a855f7, #6366f1) !important;
348
  border: none !important;
349
  color: white !important;
350
- font-weight: 700 !important;
351
- border-radius: 999px !important;
352
- padding: 0.5rem 1.5rem !important;
353
- transition: all 0.2s ease !important;
354
  }
355
- .gradient-btn:hover {
356
- transform: scale(1.03) !important;
357
- box-shadow: 0 0 20px rgba(168,85,247,0.4) !important;
358
  }
359
 
360
- /* ─── Hero section ───────────────────────────────────────────────── */
361
- .hero-section {
362
- background: radial-gradient(ellipse at 50% 0%, rgba(168,85,247,0.08) 0%, transparent 70%) !important;
363
- border-bottom: 1px solid #27272a !important;
364
- padding: 2rem !important;
365
- text-align: center !important;
 
 
 
 
 
 
366
  }
367
 
368
  /* ─── Stats bar ──────────────────────────────────────────────────── */
369
  .stats-bar {
 
 
 
 
370
  display: flex !important;
371
  justify-content: center !important;
372
- gap: 3rem !important;
373
- padding: 1rem 0 !important;
374
- border-bottom: 1px solid #27272a !important;
375
- margin-bottom: 1rem !important;
376
- }
377
- .stat-item {
378
- text-align: center !important;
379
- }
380
- .stat-value {
381
- font-size: 1.4rem !important;
382
- font-weight: 800 !important;
383
- color: #a855f7 !important;
384
  }
385
- .stat-label {
386
- font-size: 0.75rem !important;
387
- color: #71717a !important;
388
- text-transform: uppercase !important;
389
- letter-spacing: 0.05em !important;
 
 
 
 
 
390
  }
 
391
 
392
- /* ─── Tool badge ─────────────────────────────────────────────────── */
 
393
  .tool-badge {
394
- display: inline-flex !important;
395
- align-items: center !important;
396
- gap: 0.3rem !important;
397
- background: #18181b !important;
398
- border: 1px solid #3f3f46 !important;
399
  border-radius: 999px !important;
400
- padding: 0.2rem 0.7rem !important;
401
  font-size: 0.75rem !important;
402
- color: #a1a1aa !important;
403
- margin: 0.15rem !important;
404
- }
405
- .tool-badge-active {
406
- border-color: #a855f7/40 !important;
407
- color: #c084fc !important;
408
- }
409
-
410
- /* ─── Footer ─────────────────────────────────────────────────────── */
411
- .footer-note {
412
- text-align: center !important;
413
  color: #52525b !important;
414
- font-size: 0.75rem !important;
415
- padding: 0.75rem !important;
416
- border-top: 1px solid #18181b !important;
417
  }
 
 
 
418
  """
419
 
420
- theme = gr.themes.Default(
421
- primary_hue="purple",
422
- secondary_hue="zinc",
423
- neutral_hue="zinc",
424
- radius_size=gr.themes.sizes.radius_md,
425
- ).set(
426
- body_background_fill="#09090b",
427
- body_text_color="#e4e4e7",
428
- )
429
-
430
- def build_space():
431
- with gr.Blocks(
432
- theme=theme,
433
- css=css,
434
- title="Stack X Ultimate β€” Agentic Tool-Calling",
435
- ) as demo:
436
 
437
  # ── Hero ──────────────────────────────────────────────────────
438
- with gr.Group():
439
- gr.HTML("""
440
- <div class="hero-section">
441
- <div id="title-block">
442
- <h1>Stack X Ultimate</h1>
443
- </div>
444
- <p style="color: #a1a1aa; font-size: 1.05rem; max-width: 600px; margin: 0.6rem auto 0;">
445
- Open-source agentic model with tool calling.
446
- Deploy on your own GPU β€” no API costs, no data leaving your server.
447
- </p>
448
- <div class="tool-badge tool-badge-active">πŸ”’ calculator</div>
449
- <div class="tool-badge tool-badge-active">πŸ• get_current_time</div>
450
- <div class="tool-badge tool-badge-active">πŸ“ search_files</div>
451
- <div class="tool-badge tool-badge-active">⚑ run_command</div>
452
  </div>
453
- """)
454
-
455
- gr.HTML("""
456
- <div class="stats-bar">
457
- <div class="stat-item">
458
- <div class="stat-value">3B</div>
459
- <div class="stat-label">Parameters</div>
460
- </div>
461
- <div class="stat-item">
462
- <div class="stat-value">4-bit</div>
463
- <div class="stat-label">QLoRA Quantized</div>
464
- </div>
465
- <div class="stat-item">
466
- <div class="stat-value">V100</div>
467
- <div class="stat-label">Runs on 1 GPU</div>
468
- </div>
469
- <div class="stat-item">
470
- <div class="stat-value">$0</div>
471
- <div class="stat-label">API Costs</div>
472
- </div>
473
  </div>
474
- """)
 
 
 
 
 
 
 
 
 
 
475
 
476
- # ── Main Chat ─────────────────────────────────────────────────
477
  chat = gr.Chatbot(
478
- height=480,
479
- show_copy_button=True,
480
  avatar_images=(
481
- "https://huggingface.co/front/assets/icons/8.svg", # user
482
- "https://huggingface.co/front/assets/icons/13.svg" # bot
483
  ),
484
  bubble_full_width=False,
485
- render_markdown=True,
486
  )
487
 
488
  with gr.Row():
489
  msg = gr.Textbox(
490
- placeholder="Try: 'Calculate compound interest on $1500 at 7% for 30 years'",
491
  scale=5,
492
  container=True,
493
  show_label=False,
494
  elem_id="main-input",
495
  )
496
- submit_btn = gr.Button("Send β†’", scale=1, elem_classes="gradient-btn")
497
-
498
- # ── State ───────────────────────────────────────────────────────
499
- state = gr.State([])
500
-
501
- # ── Events ────────────────────────────────────────────────────
502
- msg.submit(
503
- fn=chat_fn,
504
- inputs=[msg, chat],
505
- outputs=[chat, chat],
506
- show_progress="minimal",
507
- )
508
- submit_btn.click(
509
- fn=chat_fn,
510
- inputs=[msg, chat],
511
- outputs=[chat, chat],
512
- show_progress="minimal",
513
- )
514
- msg.submit(lambda: "", None, msg) # clear input
515
 
516
- # ── Examples ───────────────────────────────────────────────────
517
  gr.Examples(
518
- examples=[
519
- ["Calculate the compound interest on $1500 at 7% annual rate over 30 years", True],
520
- ["What time is it right now?", True],
521
- ["Find all Python files in the current directory", True],
522
- ["Run `ls -la` to see what's in the directory", True],
523
- ["Look up the current stock price for AAPL", True],
524
- ["Check if a server is running on port 8080", True],
525
- ],
526
  inputs=[msg],
527
- label="Try one of these examples β†’",
 
528
  )
529
 
530
- # ── Footer ────────────────────────────────────────────────────
 
 
 
 
 
 
 
 
 
531
  gr.HTML("""
532
- <div class="footer-note">
533
- πŸ”§ This demo shows tool-calling capability. Fine-tuned model coming soon β€”
534
- <a href="https://huggingface.co/my-ai-stack/Stack-X-Ultimate" style="color: #a855f7;">deploy on HuggingFace</a> or
535
- <a href="https://www.stack-ai.me/contact" style="color: #a855f7;">request enterprise deployment</a>
536
  </div>
537
  """)
538
 
539
  return demo
540
 
541
  if __name__ == "__main__":
542
- demo = build_space()
543
  demo.launch(
544
  server_name="0.0.0.0",
545
  server_port=7860,
546
  max_threads=4,
547
  show_api=False,
548
- favicon_path=None,
549
  )
 
1
  """
2
  Stack X Ultimate Inference β€” Hugging Face Space
3
+ Agentic tool-calling model demo.
4
  """
5
 
6
  import gradio as gr
 
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
  }
 
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
  }
 
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
  }
 
69
 
70
  def calculator(expression: str) -> str:
71
  try:
 
72
  cleaned = re.sub(r"[^0-9+\-*/.()% ]", "", expression)
73
  result = eval(cleaned, {"__builtins__": {}})
74
  return f"Result: {result}"
75
  except Exception as e:
76
+ return f"Error: {e}"
77
 
78
  def get_current_time() -> str:
79
+ return datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
 
80
 
81
  def search_files(path: str, pattern: str) -> str:
82
  import glob
83
  try:
84
  matches = glob.glob(f"{path}/{pattern}", recursive=True)
85
  if not matches:
86
+ return f"No files matching '{pattern}' in '{path}'"
87
  return f"Found {len(matches)} file(s):\n" + "\n".join(matches[:20])
88
  except Exception as e:
89
+ return f"Error: {e}"
90
 
91
  def run_command(command: str, cwd: str = ".") -> str:
92
  import subprocess
93
  try:
94
+ result = subprocess.run(command, shell=True, cwd=cwd, capture_output=True, text=True, timeout=30)
 
 
95
  out = result.stdout.strip() or "(no output)"
96
  err = result.stderr.strip() if result.stderr else ""
97
  return f"STDOUT:\n{out}\n\nSTDERR:\n{err}" if err else out
98
  except subprocess.TimeoutExpired:
99
+ return "Timed out after 30 seconds."
100
  except Exception as e:
101
+ return f"Error: {e}"
102
 
103
  def execute_tool(tool_name: str, tool_args: dict) -> str:
104
+ fn_map = {
105
+ "calculator": lambda: calculator(tool_args.get("expression", "")),
106
+ "get_current_time": get_current_time,
107
+ "search_files": lambda: search_files(tool_args.get("path", "."), tool_args.get("pattern", "*")),
108
+ "run_command": lambda: run_command(tool_args.get("command", ""), tool_args.get("cwd", ".")),
109
+ }
110
+ fn = fn_map.get(tool_name, lambda: f"Unknown tool: {tool_name}")
111
+ return fn()
112
+
113
+ # ─── Response Generator ──────────────────────────────────────────────────────
114
+
115
+ def generate_response(message: str) -> dict:
116
+ msg_lower = message.lower()
117
+
118
+ # Calculator
119
+ calc_kw = ["calculate", "compute", "math", "roi", "compound", "interest", "%", "$"]
120
+ if any(k in msg_lower for k in calc_kw):
121
+ expr = re.search(r"[\d+\-*/.()% ]+", message)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  return {
123
+ "tool_name": "calculator",
124
+ "tool_args": {"expression": expr.group().strip() if expr else "0"},
125
+ "display": f"Calculating: `{message}`"
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  }
127
 
128
+ # Time
129
+ time_kw = ["time", "date", "now", "current"]
130
+ if any(k in msg_lower for k in time_kw):
131
  return {
132
+ "tool_name": "get_current_time",
133
+ "tool_args": {},
134
+ "display": "Fetching current time..."
 
 
 
 
 
 
 
 
 
135
  }
136
 
137
+ # File search
138
+ file_kw = ["find", "search", "file", "look for", "where is", "list"]
139
+ if any(k in msg_lower for k in file_kw):
140
+ pattern = re.search(r"\*\.[a-zA-Z]+", message)
141
  return {
142
+ "tool_name": "search_files",
143
+ "tool_args": {"path": ".", "pattern": pattern.group() if pattern else "*"},
144
+ "display": f"Searching for files matching your query..."
 
 
 
 
 
 
 
 
 
 
 
 
145
  }
146
 
147
+ # Command
148
+ cmd_kw = ["run", "execute", "terminal", "bash", "git ", "ls", "ps ", "docker"]
149
+ if any(k in msg_lower for k in cmd_kw):
150
+ match = re.search(r"`([^`]+)`", message)
151
+ cmd = match.group(1) if match else message.split()[-1]
152
  return {
153
+ "tool_name": "run_command",
154
+ "tool_args": {"command": cmd, "cwd": "."},
155
+ "display": f"Running: `{cmd}`"
 
 
 
 
 
 
 
 
 
 
 
 
156
  }
157
 
158
+ # No tool
159
  return {
160
+ "tool_name": None,
161
+ "tool_args": {},
162
+ "display": None
 
 
163
  }
164
 
165
+ # ─── Chat Function ───────────────────────────────────────────────────────────
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
 
167
+ def chat_fn(message, history):
168
+ resp = generate_response(message)
169
 
170
+ if resp["tool_name"]:
171
+ tool_result = execute_tool(resp["tool_name"], resp["tool_args"])
172
+ call_display = f"πŸ”§ Calling `{resp['tool_name']}`...\n\n```\n{json.dumps(resp['tool_args'], indent=2)}\n```"
173
+ result_display = f"βœ… **{resp['tool_name']}** result:\n\n```\n{tool_result}\n```"
174
+ return [[resp["display"], call_display], [None, result_display]]
 
 
 
 
 
175
 
176
+ return [[message, "Stack X Ultimate is a fine-tuned agentic model that calls tools to answer your questions. Try one of the examples below to see it in action!"], None]
 
 
 
 
 
 
177
 
178
+ # ─── Gradio Interface ────────────────────────────────────────────────────────
179
+
180
+ css = """
181
+ /* ─── Background & Base ──────────────────────────────────────────── */
182
+ .gradio-container { background: #ffffff !important; }
183
+ .main { background: #ffffff !important; }
 
 
 
184
 
185
+ /* ─── Chat bubbles ────────────────────────────────────────────────── */
186
  .user-bubble {
187
+ background: #f4f4f5 !important;
188
+ border: 1px solid #d4d4d8 !important;
189
  border-radius: 12px 12px 4px 12px !important;
190
+ color: #18181b !important;
191
+ padding: 10px 14px !important;
192
  }
193
  .assistant-bubble {
194
+ background: #fafafa !important;
195
+ border: 1px solid #e4e4e7 !important;
196
  border-radius: 12px 12px 12px 4px !important;
197
+ color: #27272a !important;
198
+ padding: 10px 14px !important;
199
  }
200
+
201
+ /* ─── Input styling ──────────────────────────────────────────────── */
202
+ #main-input input {
203
+ background: #ffffff !important;
204
+ border: 2px solid #e4e4e7 !important;
205
+ border-radius: 12px !important;
206
+ color: #18181b !important;
207
+ font-size: 1rem !important;
208
+ padding: 12px 16px !important;
209
+ }
210
+ #main-input input:focus {
211
+ border-color: #7c3aed !important;
212
+ outline: none !important;
213
+ box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.15) !important;
214
  }
215
 
216
+ /* ─── Buttons ────────────────────────────────────────────────────── */
217
+ .gradio-button.primary {
218
+ background: #7c3aed !important;
219
  border: none !important;
220
  color: white !important;
221
+ border-radius: 10px !important;
222
+ font-weight: 600 !important;
 
 
223
  }
224
+ .gradio-button.primary:hover {
225
+ background: #6d28d9 !important;
 
226
  }
227
 
228
+ /* ─── Examples ───────────────────────────────────────────────────── */
229
+ .example-btn {
230
+ background: #f4f4f5 !important;
231
+ border: 1px solid #d4d4d8 !important;
232
+ border-radius: 8px !important;
233
+ color: #3f3f46 !important;
234
+ font-size: 0.875rem !important;
235
+ padding: 6px 12px !important;
236
+ }
237
+ .example-btn:hover {
238
+ background: #e4e4e7 !important;
239
+ color: #18181b !important;
240
  }
241
 
242
  /* ─── Stats bar ──────────────────────────────────────────────────── */
243
  .stats-bar {
244
+ background: #fafafa !important;
245
+ border: 1px solid #e4e4e7 !important;
246
+ border-radius: 12px !important;
247
+ padding: 16px !important;
248
  display: flex !important;
249
  justify-content: center !important;
250
+ gap: 40px !important;
251
+ margin-bottom: 16px !important;
 
 
 
 
 
 
 
 
 
 
252
  }
253
+ .stat-item { text-align: center; }
254
+ .stat-value { font-size: 1.3rem; font-weight: 800; color: #7c3aed; }
255
+ .stat-label { font-size: 0.7rem; color: #71717a; text-transform: uppercase; letter-spacing: 0.05em; }
256
+
257
+ /* ─── Hero ───────────────────────────────────────────────────────── */
258
+ .hero-text h1 {
259
+ font-size: 1.8rem !important;
260
+ font-weight: 900 !important;
261
+ color: #18181b !important;
262
+ margin-bottom: 6px !important;
263
  }
264
+ .hero-text p { color: #52525b !important; font-size: 0.95rem !important; max-width: 500px; margin: 0 auto !important; }
265
 
266
+ /* ─── Tool badges ────────────────────────────────────────────────── */
267
+ .tool-badges { display: flex; justify-content: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
268
  .tool-badge {
269
+ background: #f4f4f5 !important;
270
+ border: 1px solid #d4d4d8 !important;
 
 
 
271
  border-radius: 999px !important;
272
+ padding: 4px 12px !important;
273
  font-size: 0.75rem !important;
 
 
 
 
 
 
 
 
 
 
 
274
  color: #52525b !important;
 
 
 
275
  }
276
+
277
+ /* ─── Footer ────────────────────────────────────────────────────── */
278
+ .footer { text-align: center; color: #a1a1aa; font-size: 0.75rem; padding: 12px; border-top: 1px solid #e4e4e7; margin-top: 12px; }
279
  """
280
 
281
+ EXAMPLES = [
282
+ ["Calculate compound interest on $1500 at 7% over 30 years"],
283
+ ["What time is it right now?"],
284
+ ["Find all Python files in this directory"],
285
+ ["Run `ls -la` to list files"],
286
+ ["Calculate 15% tip on a $87 bill"],
287
+ ]
288
+
289
+ def build():
290
+ with gr.Blocks(css=css, title="Stack X Ultimate") as demo:
 
 
 
 
 
 
291
 
292
  # ── Hero ──────────────────────────────────────────────────────
293
+ gr.HTML("""
294
+ <div style="text-align:center; padding: 20px 16px 8px; border-bottom: 1px solid #e4e4e7; margin-bottom: 16px;">
295
+ <div class="hero-text">
296
+ <h1>πŸ€– Stack X Ultimate</h1>
297
+ <p>Open-source agentic model with tool calling. Try it free β€” no API key needed.</p>
 
 
 
 
 
 
 
 
 
298
  </div>
299
+ <div class="tool-badges">
300
+ <span class="tool-badge">πŸ”’ calculator</span>
301
+ <span class="tool-badge">πŸ• get_current_time</span>
302
+ <span class="tool-badge">πŸ“ search_files</span>
303
+ <span class="tool-badge">⚑ run_command</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  </div>
305
+ </div>
306
+ """)
307
+
308
+ gr.HTML("""
309
+ <div class="stats-bar">
310
+ <div class="stat-item"><div class="stat-value">3B</div><div class="stat-label">Params</div></div>
311
+ <div class="stat-item"><div class="stat-value">4-bit</div><div class="stat-label">QLoRA</div></div>
312
+ <div class="stat-item"><div class="stat-value">V100</div><div class="stat-label">1 GPU</div></div>
313
+ <div class="stat-item"><div class="stat-value">$0</div><div class="stat-label">API Cost</div></div>
314
+ </div>
315
+ """)
316
 
317
+ # ── Chat ──────────────────────────────────────────────────────
318
  chat = gr.Chatbot(
319
+ height=420,
 
320
  avatar_images=(
321
+ "https://huggingface.co/front/assets/icons/8.svg",
322
+ "https://huggingface.co/front/assets/icons/13.svg"
323
  ),
324
  bubble_full_width=False,
 
325
  )
326
 
327
  with gr.Row():
328
  msg = gr.Textbox(
329
+ placeholder="Type a message or try an example below...",
330
  scale=5,
331
  container=True,
332
  show_label=False,
333
  elem_id="main-input",
334
  )
335
+ send_btn = gr.Button("Send", scale=1, elem_classes="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
336
 
337
+ # ── Examples ───���────────────────────────────────────────────────
338
  gr.Examples(
339
+ examples=EXAMPLES,
 
 
 
 
 
 
 
340
  inputs=[msg],
341
+ label="Try one of these β†’",
342
+ examples_per_page=5,
343
  )
344
 
345
+ # ── Events ────────────────────────────────────────────────────
346
+ def respond(message, history):
347
+ result = chat_fn(message, history)
348
+ return result
349
+
350
+ msg.submit(respond, [msg, chat], [chat])
351
+ send_btn.click(respond, [msg, chat], [chat])
352
+ msg.submit(lambda: "", None, msg)
353
+
354
+ # ── Footer ─────────────────────────────────────────────────────
355
  gr.HTML("""
356
+ <div class="footer">
357
+ πŸ”§ Demo shows tool-calling capability.
358
+ <a href="https://huggingface.co/my-ai-stack/Stack-X-Ultimate" style="color:#7c3aed;">Deploy the model</a> Β·
359
+ <a href="https://www.stack-ai.me/contact" style="color:#7c3aed;">Enterprise inquiry</a>
360
  </div>
361
  """)
362
 
363
  return demo
364
 
365
  if __name__ == "__main__":
366
+ demo = build()
367
  demo.launch(
368
  server_name="0.0.0.0",
369
  server_port=7860,
370
  max_threads=4,
371
  show_api=False,
 
372
  )