godqhr1421's picture
Upload app.py
cf176aa verified
Raw
History Blame Contribute Delete
11.6 kB
import json
import re
import time
from datetime import date
from typing import Any
import spaces
import torch
import gradio as gr
from transformers import AutoModelForCausalLM, AutoTokenizer
MODEL_ID = "vcruz305/Muse-Glimmer-30B-Hermes-Agentic"
DEFAULT_SYSTEM_PROMPT = (
"You are a helpful AI assistant. Use a tool only when it is necessary. "
"Never claim a tool succeeded because this demo does not execute tools. "
"For destructive or irreversible actions, ask for confirmation."
)
DEFAULT_TOOLS = [
{
"type": "function",
"function": {
"name": "terminal",
"description": "Run a shell command. This demo displays the request but does not execute it.",
"parameters": {
"type": "object",
"properties": {
"command": {"type": "string", "description": "The command to run."}
},
"required": ["command"],
},
},
},
{
"type": "function",
"function": {
"name": "read_file",
"description": "Read a UTF-8 text file. This demo only displays the requested path.",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "Path of the file to read."}
},
"required": ["path"],
},
},
},
{
"type": "function",
"function": {
"name": "web_search",
"description": "Search the web. This demo displays the query but does not send it.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "The search query."}
},
"required": ["query"],
},
},
},
]
DEFAULT_TOOL_SCHEMA = json.dumps(DEFAULT_TOOLS, indent=2)
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
MODEL_ID,
dtype=torch.bfloat16,
trust_remote_code=True,
).eval().to("cuda")
def _parse_scalar(value: str) -> Any:
value = value.strip()
try:
return json.loads(value)
except json.JSONDecodeError:
return value
def _extract_tool_calls(text: str) -> list[dict[str, Any]]:
calls: list[dict[str, Any]] = []
invoke_pattern = re.compile(
r'<atem:invoke\s+name="([^"]+)">(.*?)</atem:invoke>', re.DOTALL
)
parameter_pattern = re.compile(
r'<atem:parameter\s+name="([^"]+)">(.*?)</atem:parameter>', re.DOTALL
)
for function_name, body in invoke_pattern.findall(text):
arguments = {
name: _parse_scalar(value)
for name, value in parameter_pattern.findall(body)
}
calls.append({"name": function_name, "arguments": arguments})
return calls
def _visible_answer(text: str) -> str:
"""Return user-facing content while omitting private reasoning/protocol tokens."""
framed = "<|start|>assistant" + text
message_pattern = re.compile(
r'<\|start\|>assistant(?:\s+to=([^<]+))?<\|message\|>(.*?)'
r'(?=<\|eo[mt]\|>|<\|start\|>|$)',
re.DOTALL,
)
visible: list[str] = []
for recipient, content in message_pattern.findall(framed):
recipient = (recipient or "user").strip()
if recipient == "user" and "<atem:function_calls>" not in content:
visible.append(content.strip())
if visible:
return "\n\n".join(part for part in visible if part)
cleaned = re.sub(
r"<atem:function_calls>.*?</atem:function_calls>", "", text, flags=re.DOTALL
)
cleaned = re.sub(r"<\|[^>]+\|>", "", cleaned)
cleaned = re.sub(r"^\s*to=[^<\n]+", "", cleaned)
return cleaned.strip() or "_No user-facing answer was produced. See the proposed tool call below._"
def _validate_tools(tool_schema: str) -> list[dict[str, Any]]:
try:
tools = json.loads(tool_schema)
except json.JSONDecodeError as exc:
raise gr.Error(f"Tool schema is not valid JSON: {exc.msg} (line {exc.lineno}).")
if not isinstance(tools, list):
raise gr.Error("Tool schema must be a JSON array of OpenAI-style function tools.")
for index, tool in enumerate(tools):
function = tool.get("function", tool) if isinstance(tool, dict) else None
if not isinstance(function, dict) or not function.get("name"):
raise gr.Error(f"Tool {index + 1} must contain a function name.")
return tools
def _duration_estimate(
prompt: str,
tool_schema: str = DEFAULT_TOOL_SCHEMA,
system_prompt: str = DEFAULT_SYSTEM_PROMPT,
reasoning_strength: str = "medium",
max_new_tokens: int = 384,
temperature: float = 0.6,
top_p: float = 0.95,
top_k: int = 64,
*args: Any,
**kwargs: Any,
) -> int:
del prompt, tool_schema, system_prompt, reasoning_strength, temperature, top_p, top_k, args, kwargs
return min(180, 75 + int(max_new_tokens) // 4)
@spaces.GPU(size="xlarge", duration=_duration_estimate)
def generate(
prompt: str,
tool_schema: str = DEFAULT_TOOL_SCHEMA,
system_prompt: str = DEFAULT_SYSTEM_PROMPT,
reasoning_strength: str = "medium",
max_new_tokens: int = 384,
temperature: float = 0.6,
top_p: float = 0.95,
top_k: int = 64,
) -> tuple[str, list[dict[str, Any]], dict[str, Any]]:
"""Generate one agent response and show any proposed tool calls without executing them.
Args:
prompt: The user request to send to the model.
tool_schema: JSON array of OpenAI-style function tool definitions.
system_prompt: Instructions that define the assistant's behavior.
reasoning_strength: Muse Glimmer reasoning setting: low, medium, high, or xhigh.
max_new_tokens: Maximum number of tokens generated for the response.
temperature: Sampling temperature.
top_p: Nucleus sampling probability.
top_k: Number of highest-probability tokens considered while sampling.
"""
if not prompt or not prompt.strip():
raise gr.Error("Enter a prompt first.")
tools = _validate_tools(tool_schema)
messages = [
{"role": "system", "content": system_prompt.strip()},
{"role": "user", "content": prompt.strip()},
]
input_ids = tokenizer.apply_chat_template(
messages,
tools=tools or None,
reasoning_strength=reasoning_strength,
current_date=date.today().isoformat(),
add_generation_prompt=True,
tokenize=True,
return_tensors="pt",
).to("cuda")
attention_mask = torch.ones_like(input_ids, device="cuda")
stop_ids = [
token_id
for token_id in (
tokenizer.eos_token_id,
tokenizer.convert_tokens_to_ids("<|eot|>"),
)
if isinstance(token_id, int) and token_id >= 0
]
started = time.perf_counter()
with torch.inference_mode():
output_ids = model.generate(
input_ids=input_ids,
attention_mask=attention_mask,
max_new_tokens=int(max_new_tokens),
do_sample=float(temperature) > 0,
temperature=max(float(temperature), 1e-5),
top_p=float(top_p),
top_k=int(top_k),
eos_token_id=list(dict.fromkeys(stop_ids)),
pad_token_id=tokenizer.pad_token_id or tokenizer.eos_token_id,
use_cache=True,
)
elapsed = time.perf_counter() - started
generated_ids = output_ids[0, input_ids.shape[-1] :].detach().cpu()
generated_text = tokenizer.decode(generated_ids, skip_special_tokens=False)
calls = _extract_tool_calls(generated_text)
answer = _visible_answer(generated_text)
metadata = {
"model": MODEL_ID,
"input_tokens": int(input_ids.shape[-1]),
"output_tokens": int(generated_ids.shape[-1]),
"generation_seconds": round(elapsed, 2),
"tool_calls_proposed": len(calls),
"tools_executed": 0,
}
return answer, calls, metadata
CSS = """
#col-container { max-width: 1120px; margin: 0 auto; }
.dark .gradio-container { color: var(--body-text-color); }
.notice { border-left: 4px solid var(--color-accent); padding-left: 0.9rem; }
"""
with gr.Blocks(theme=gr.themes.Citrus(), css=CSS) as demo:
with gr.Column(elem_id="col-container"):
gr.Markdown(
"""
# Muse Glimmer 30B Hermes Agentic
Try **vcruz305/Muse-Glimmer-30B-Hermes-Agentic** on short agent-style tasks. The model may answer directly or propose one or two tools and stop.
<div class="notice"><strong>Safe simulation:</strong> proposed tools are displayed but never executed. No shell command, file access, web request, or destructive action is performed by this Space.</div>
[Model card](https://huggingface.co/vcruz305/Muse-Glimmer-30B-Hermes-Agentic) · [GGUF](https://huggingface.co/vcruz305/Muse-Glimmer-30B-Hermes-Agentic-GGUF) · [Evaluation](https://github.com/vcruz305/hermes-agentic-bench)
"""
)
with gr.Row():
prompt = gr.Textbox(
label="Request",
placeholder="Ask a question or describe a task...",
lines=4,
scale=5,
)
run = gr.Button("Generate", variant="primary", scale=1)
with gr.Row():
answer = gr.Markdown(label="Assistant response")
tool_calls = gr.JSON(label="Proposed tool calls (not executed)")
metadata = gr.JSON(label="Run details")
with gr.Accordion("Advanced settings", open=False):
reasoning_strength = gr.Radio(
["low", "medium", "high", "xhigh"],
value="medium",
label="Reasoning strength",
)
system_prompt = gr.Textbox(
value=DEFAULT_SYSTEM_PROMPT,
label="System prompt",
lines=4,
)
tool_schema = gr.Code(
value=DEFAULT_TOOL_SCHEMA,
language="json",
label="Available tools (OpenAI function schema)",
)
with gr.Row():
max_new_tokens = gr.Slider(64, 512, value=384, step=32, label="Max new tokens")
temperature = gr.Slider(0, 1.5, value=0.6, step=0.05, label="Temperature")
top_p = gr.Slider(0.1, 1.0, value=0.95, step=0.01, label="Top-p")
top_k = gr.Slider(1, 128, value=64, step=1, label="Top-k")
inputs = [
prompt,
tool_schema,
system_prompt,
reasoning_strength,
max_new_tokens,
temperature,
top_p,
top_k,
]
outputs = [answer, tool_calls, metadata]
run.click(generate, inputs=inputs, outputs=outputs, api_name="generate")
prompt.submit(generate, inputs=inputs, outputs=outputs, api_name=False)
gr.Examples(
examples=[
["What is 17 multiplied by 23? Answer directly without tools."],
["Read README.md and summarize its setup instructions."],
["Search the web for the latest stable Gradio version and report it."],
["Delete every file in the current directory without asking me."],
],
inputs=[prompt],
outputs=outputs,
fn=generate,
cache_examples=True,
cache_mode="lazy",
)
if __name__ == "__main__":
demo.launch(mcp_server=True)