godqhr1421 commited on
Commit
45e12ae
·
verified ·
1 Parent(s): 4a60d9c

Upload app.js

Browse files
Files changed (1) hide show
  1. app.js +140 -0
app.js ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const tools = [
2
+ {
3
+ type: "function",
4
+ function: {
5
+ name: "terminal",
6
+ description: "Run a shell command. This demo displays the request but does not execute it.",
7
+ parameters: {
8
+ type: "object",
9
+ properties: { command: { type: "string", description: "The command to run." } },
10
+ required: ["command"],
11
+ },
12
+ },
13
+ },
14
+ {
15
+ type: "function",
16
+ function: {
17
+ name: "read_file",
18
+ description: "Read a UTF-8 text file. This demo only displays the requested path.",
19
+ parameters: {
20
+ type: "object",
21
+ properties: { path: { type: "string", description: "Path of the file to read." } },
22
+ required: ["path"],
23
+ },
24
+ },
25
+ },
26
+ {
27
+ type: "function",
28
+ function: {
29
+ name: "web_search",
30
+ description: "Search the web. This demo displays the query but does not send it.",
31
+ parameters: {
32
+ type: "object",
33
+ properties: { query: { type: "string", description: "The search query." } },
34
+ required: ["query"],
35
+ },
36
+ },
37
+ },
38
+ ];
39
+
40
+ const $ = (selector) => document.querySelector(selector);
41
+ const runButton = $("#run");
42
+ const status = $("#status");
43
+ const answer = $("#answer");
44
+ const calls = $("#calls");
45
+ const latency = $("#latency");
46
+
47
+ function parseValue(value) {
48
+ const trimmed = value.trim();
49
+ try { return JSON.parse(trimmed); } catch { return trimmed; }
50
+ }
51
+
52
+ function parseAtem(text) {
53
+ const parsed = [];
54
+ const invokes = text.matchAll(/<atem:invoke\s+name="([^"]+)">([\s\S]*?)<\/atem:invoke>/g);
55
+ for (const match of invokes) {
56
+ const argumentsObject = {};
57
+ for (const parameter of match[2].matchAll(/<atem:parameter\s+name="([^"]+)">([\s\S]*?)<\/atem:parameter>/g)) {
58
+ argumentsObject[parameter[1]] = parseValue(parameter[2]);
59
+ }
60
+ parsed.push({ name: match[1], arguments: argumentsObject });
61
+ }
62
+ return parsed;
63
+ }
64
+
65
+ function normalizeCalls(message) {
66
+ if (Array.isArray(message.tool_calls) && message.tool_calls.length) {
67
+ return message.tool_calls.map((call) => {
68
+ let argumentsObject = call.function?.arguments ?? {};
69
+ if (typeof argumentsObject === "string") {
70
+ try { argumentsObject = JSON.parse(argumentsObject); } catch { argumentsObject = { raw: argumentsObject }; }
71
+ }
72
+ return { name: call.function?.name ?? "unknown", arguments: argumentsObject };
73
+ });
74
+ }
75
+ return parseAtem(message.content ?? "");
76
+ }
77
+
78
+ function visibleContent(content) {
79
+ if (!content) return "No user-facing answer was produced. See the proposed tool call below.";
80
+ const withoutCalls = content.replace(/<atem:function_calls>[\s\S]*?<\/atem:function_calls>/g, "");
81
+ const withoutProtocol = withoutCalls.replace(/<\|[^>]+\|>/g, "").replace(/^\s*to=[^<\n]+/, "").trim();
82
+ return withoutProtocol || "No user-facing answer was produced. See the proposed tool call below.";
83
+ }
84
+
85
+ async function generate() {
86
+ const endpoint = $("#endpoint").value.trim().replace(/\/+$/, "");
87
+ const prompt = $("#prompt").value.trim();
88
+ if (!endpoint || !prompt) {
89
+ status.textContent = "Enter both a public endpoint and a request.";
90
+ return;
91
+ }
92
+
93
+ runButton.disabled = true;
94
+ status.textContent = "";
95
+ latency.textContent = "Generating…";
96
+ const started = performance.now();
97
+ try {
98
+ const response = await fetch(`${endpoint}/v1/chat/completions`, {
99
+ method: "POST",
100
+ headers: { "Content-Type": "application/json" },
101
+ body: JSON.stringify({
102
+ model: "muse-glimmer-30b",
103
+ messages: [
104
+ {
105
+ role: "system",
106
+ content: `You are a helpful AI assistant. Reasoning strength: ${$("#reasoning").value}. Use a tool only when necessary. Never claim a tool succeeded because this demo does not execute tools. Confirm destructive actions.`,
107
+ },
108
+ { role: "user", content: prompt },
109
+ ],
110
+ tools,
111
+ temperature: Number($("#temperature").value),
112
+ top_p: 0.95,
113
+ max_tokens: Number($("#maxTokens").value),
114
+ }),
115
+ });
116
+ const payload = await response.json().catch(() => ({}));
117
+ if (!response.ok) throw new Error(payload.error?.message || `Endpoint returned HTTP ${response.status}.`);
118
+ const message = payload.choices?.[0]?.message;
119
+ if (!message) throw new Error("The endpoint response did not contain choices[0].message.");
120
+
121
+ const proposed = normalizeCalls(message);
122
+ answer.textContent = visibleContent(message.content);
123
+ answer.classList.remove("empty");
124
+ calls.textContent = JSON.stringify(proposed, null, 2);
125
+ latency.textContent = `${((performance.now() - started) / 1000).toFixed(1)} s · ${payload.usage?.completion_tokens ?? "?"} tokens`;
126
+ } catch (error) {
127
+ status.textContent = `${error.message} Check endpoint reachability, HTTPS, and CORS.`;
128
+ latency.textContent = "Request failed";
129
+ } finally {
130
+ runButton.disabled = false;
131
+ }
132
+ }
133
+
134
+ runButton.addEventListener("click", generate);
135
+ $("#prompt").addEventListener("keydown", (event) => {
136
+ if ((event.ctrlKey || event.metaKey) && event.key === "Enter") generate();
137
+ });
138
+ document.querySelectorAll("[data-prompt]").forEach((button) => {
139
+ button.addEventListener("click", () => { $("#prompt").value = button.dataset.prompt; });
140
+ });