Arx / mobile /test /webllm-test.html
umer-wasim's picture
Security assistant uses the fine-tuned Devseis model v0.4 (1.5B)
53e9e4a verified
Raw History Blame Contribute Delete
2.66 kB
<!doctype html><meta charset="utf-8"><title>WebLLM model test</title>
<script type="module">
// Loads a Devseis auditor model build in WebLLM and answers prompts given by mobile/test/webllm-test.cjs.
import * as webllm from '../../app/node_modules/@mlc-ai/web-llm/lib/index.js';
import { SYSTEM_PROMPT, groundingProblems, ANSWER_SCHEMAS } from '../../app/renderer/auditor-core.js';
import { chatProblems } from '../../app/renderer/knowledge.js';
window.loadModel = async (modelUrl) => {
const adapter = await navigator.gpu.requestAdapter();
const f16 = adapter.features.has('shader-f16');
const named = (modelUrl.match(/q0f16|q4f16_1|q4f32_1/) || [])[0];
const quant = named || (f16 ? 'q4f16_1' : 'q4f32_1');
const size = /1\.5b/i.test(modelUrl) ? '1.5B' : '0.5B';
const base = webllm.prebuiltAppConfig.model_list.find(m => m.model_id === `Qwen2.5-${size}-Instruct-${quant}-MLC`);
const url = modelUrl.replace('{quant}', quant);
const custom = { ...base, model: url, model_id: 'devseis-test-' + quant };
// ?ctx=N caps the KV cache (context window); the 1.5B default (32768) breaks after the first answer on some GPUs.
const ctx = +new URLSearchParams(location.search).get('ctx') || 0;
window.engine = await webllm.CreateMLCEngine(custom.model_id, { appConfig: { ...webllm.prebuiltAppConfig, model_list: [custom] } },
ctx ? { context_window_size: ctx } : undefined);
return { quant, url };
};
// task 'chat': messages = the full chat messages (system + user); otherwise prompt = report prompt.
window.ask = async (task, prompt, useSchema) => {
if (new URLSearchParams(location.search).get('reset')) await window.engine.resetChat();
if (task === 'chat') {
const t0 = performance.now();
const r = await window.engine.chat.completions.create({ messages: prompt, temperature: 0, max_tokens: 700 });
const reply = r.choices[0].message.content;
return { seconds: Math.round((performance.now() - t0) / 1000), problems: chatProblems(prompt[prompt.length - 1].content, reply), reply };
}
const t = performance.now();
const r = await window.engine.chat.completions.create({ messages: [{ role: 'system', content: SYSTEM_PROMPT }, { role: 'user', content: prompt }],
temperature: 0, max_tokens: 900, ...(useSchema ? { response_format: { type: 'json_object', schema: JSON.stringify(ANSWER_SCHEMAS[task]) } } : {}) });
const reply = r.choices[0].message.content;
let problems;
try { problems = groundingProblems(task, prompt, JSON.parse(reply)); } catch (e) { problems = ['invalid JSON']; }
return { seconds: Math.round((performance.now() - t) / 1000), problems, reply };
};
window.ready = true;
</script>