import * as webllm from "https://esm.run/@mlc-ai/web-llm"; import hljs from "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js"; import { Type } from "./lib/typebox/index.mjs"; let engine = null; const availableModels = webllm.prebuiltAppConfig.model_list .filter( (m) => m.model_id.startsWith("Llama-3") || // m.model_id.startsWith("Hermes-2") || m.model_id.startsWith("Phi-3") ) .map((m) => m.model_id); let selectedModel = availableModels[0]; availableModels.forEach((modelId) => { const option = document.createElement("option"); option.value = modelId; option.textContent = modelId; document.getElementById("model-selection").appendChild(option); }); document.getElementById("model-selection").value = selectedModel; document.getElementById("model-selection").onchange = (e) => { selectedModel = e.target.value; engine = null; }; document.getElementById( "prompt" ).value = `Hermione Granger is a character in Harry Potter. Please fill in the following information about this character in JSON format. Name is a string of character name. House is one of Gryffindor, Hufflepuff, Ravenclaw, Slytherin. Blood status is one of Pure-blood, Half-blood, Muggle-born. Occupation is one of Student, Professor, Ministry of Magic, Other. Wand is an object with wood, core, and length. Alive is a boolean. Patronus is a string. `; // JSON editor setup const editor = ace.edit("schema", { // mode: "ace/mode/javascript", mode: "ace/mode/javascript", theme: 'ace/theme/github', wrap: true, }); editor.setTheme("ace/theme/github"); editor.setValue(`Type.Object({ "name": Type.String(), "house": Type.Enum({ "Gryffindor": "Gryffindor", "Hufflepuff": "Hufflepuff", "Ravenclaw": "Ravenclaw", "Slytherin": "Slytherin", }), "blood_status": Type.Enum({ "Pure-blood": "Pure-blood", "Half-blood": "Half-blood", "Muggle-born": "Muggle-born", }), "occupation": Type.Enum({ "Student": "Student", "Professor": "Professor", "Ministry of Magic": "Ministry of Magic", "Other": "Other", }), "wand": Type.Object({ "wood": Type.String(), "core": Type.String(), "length": Type.Number(), }), "alive": Type.Boolean(), "patronus": Type.String(), })`); // Generate button document.getElementById("generate").onclick = async () => { const schemaInput = editor.getValue(); let T; try { T = eval(schemaInput); } catch (e) { console.error("Invalid schema", e); return; } const schema = JSON.stringify(T); if (!engine) { engine = await webllm.CreateMLCEngine(selectedModel, { initProgressCallback: (progress) => { console.log(progress); document.getElementById("output").textContent = progress.text; }, }); } const request = { stream: true, messages: [ { role: "user", content: document.getElementById("prompt").value, }, ], max_tokens: 128, response_format: { type: "json_object", schema: schema, }, }; let curMessage = ""; const generator = await engine.chatCompletion(request); for await (const chunk of generator) { const curDelta = chunk.choices[0]?.delta.content; if (curDelta) { curMessage += curDelta; } console.log(curMessage); document.getElementById("output").textContent = curMessage; } const finalMessage = await engine.getMessage(); console.log(finalMessage); if (hljs) { document.getElementById("output").innerHTML = hljs.highlight(finalMessage, { language: "json", }).value; } else { document.getElementById("output").textContent = finalMessage; } };