File size: 4,245 Bytes
053ee0d 92f6062 053ee0d 92f6062 053ee0d 92f6062 053ee0d d256fda 053ee0d f18f414 053ee0d d256fda 053ee0d d256fda 053ee0d d256fda 053ee0d d256fda d4e1d86 053ee0d 92f6062 d4e1d86 f18f414 d4e1d86 053ee0d 92f6062 d4e1d86 053ee0d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | import { pipeline, TextStreamer } from "https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.5.0/dist/transformers.min.js";
const MODEL_ID = "onnx-community/Qwen2.5-Coder-1.5B-Instruct";
const DTYPE_CANDIDATES = ["q4f16", "q4", "fp16"];
let generator = null;
let isLoaded = false;
let activeDtype = null;
export async function loadModel(onProgress) {
if (isLoaded) return;
const errors = [];
for (const dtype of DTYPE_CANDIDATES) {
try {
onProgress?.({ status: "attempt", dtype });
generator = await pipeline("text-generation", MODEL_ID, {
dtype,
device: "webgpu",
progress_callback: (progress) => onProgress?.({ ...progress, dtype }),
});
activeDtype = dtype;
isLoaded = true;
return;
} catch (error) {
console.error(`Model load failed for dtype=${dtype}`, error);
errors.push(`${dtype}: ${formatError(error)}`);
}
}
throw new Error(`All WebGPU dtype attempts failed. ${errors.join(" | ")}`);
}
export async function generateCode(prompt, language, onToken, onComplete) {
if (!generator) throw new Error("Model not loaded");
let streamedText = "";
const messages = [
{
role: "system",
content: [
`You are an expert ${language} programmer.`,
"Return raw source code only.",
"Do not use markdown fences.",
"Do not add explanations, bullet points, headings, comments, or usage notes.",
"Do not wrap the answer in ```.",
"The response must be directly executable or pasteable as a source file.",
].join(" "),
},
{
role: "user",
content: `${prompt}\n\nReturn only the ${language} code. No markdown. No comments. No explanation.`,
},
];
const streamer = new TextStreamer(generator.tokenizer, {
skip_prompt: true,
callback_function: (token) => {
streamedText += token;
onToken(token);
},
});
const result = await generator(messages, {
max_new_tokens: 1024,
do_sample: false,
streamer,
});
const generated = result?.[0]?.generated_text;
const resultText = Array.isArray(generated)
? generated.at(-1).content
: String(generated || "");
const fullCodeRaw = resultText && resultText.trim() ? resultText : streamedText;
const fullCode = stripMarkdownCodeFence(fullCodeRaw);
onComplete(fullCode);
return fullCode;
}
export function isWebGPUSupported() {
return Boolean(navigator.gpu);
}
export function getActiveDtype() {
return activeDtype;
}
function formatError(error) {
if (!error) return "unknown error";
if (error.message) return error.message;
if (typeof error === "string") return error;
try {
return JSON.stringify(error);
} catch {
return String(error);
}
}
export function stripMarkdownCodeFence(text) {
const trimmed = String(text || "").trim();
if (!trimmed) return "";
let code = trimmed;
const openingFence = code.match(/^```(?:[a-zA-Z0-9_+#.-]+)?\s*\n?/);
if (openingFence) {
code = code.slice(openingFence[0].length);
const closingIndex = code.indexOf("```");
if (closingIndex >= 0) code = code.slice(0, closingIndex);
} else {
const firstFence = code.indexOf("```");
if (firstFence >= 0) code = code.slice(0, firstFence);
}
return trimMarkdownExplanation(code);
}
function trimMarkdownExplanation(text) {
const lines = String(text || "").split(/\r?\n/);
const explanationPattern =
/^\s*(?:[-*]\s+|\d+\.\s+|#{1,6}\s+|Explanation\s*:|Steps\s*:|Notes?\s*:|The code\b|This code\b)/i;
let cutIndex = lines.length;
for (let i = 0; i < lines.length; i += 1) {
if (explanationPattern.test(lines[i])) {
cutIndex = i;
break;
}
}
return lines.slice(0, cutIndex).join("\n").trim();
}
Object.assign(window, {
loadModel,
generateCode,
isWebGPUSupported,
getActiveDtype,
stripMarkdownCodeFence,
});
|