cipheron-demo / index.html
bencodez's picture
Upload folder using huggingface_hub
be0a1de verified
Raw
History Blame Contribute Delete
6.32 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Cipheron — Secure Code Review Assistant</title>
<style>
:root { color-scheme: light dark; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
max-width: 820px;
margin: 0 auto;
padding: 24px 16px 60px;
line-height: 1.5;
}
h1 { font-size: 1.5rem; margin-bottom: 4px; }
.sub { opacity: 0.7; margin-top: 0; font-size: 0.95rem; }
.note {
background: rgba(127,127,127,0.12);
border-radius: 8px;
padding: 10px 14px;
font-size: 0.85rem;
margin: 16px 0;
}
#status {
font-size: 0.9rem;
margin: 12px 0;
padding: 10px 14px;
border-radius: 8px;
background: rgba(127,127,127,0.12);
}
progress { width: 100%; height: 10px; margin-top: 6px; }
#chat {
display: flex;
flex-direction: column;
gap: 12px;
margin: 20px 0;
min-height: 100px;
}
.msg { padding: 10px 14px; border-radius: 10px; white-space: pre-wrap; font-size: 0.95rem; }
.msg.user { background: rgba(59,130,246,0.15); align-self: flex-end; max-width: 85%; }
.msg.assistant { background: rgba(127,127,127,0.12); align-self: flex-start; max-width: 90%; }
.msg.assistant code, .msg.assistant pre { font-family: ui-monospace, Consolas, monospace; }
form { display: flex; gap: 8px; margin-top: 12px; }
textarea {
flex: 1;
resize: vertical;
min-height: 70px;
padding: 10px;
border-radius: 8px;
border: 1px solid rgba(127,127,127,0.4);
font-family: inherit;
font-size: 0.95rem;
}
button {
padding: 10px 18px;
border-radius: 8px;
border: none;
background: #3b82f6;
color: white;
font-size: 0.95rem;
cursor: pointer;
}
button:disabled { opacity: 0.5; cursor: not-allowed; }
a { color: #3b82f6; }
</style>
</head>
<body>
<h1>🔐 Cipheron</h1>
<p class="sub">Secure code review assistant — 0.5B params, runs entirely in your browser (nothing sent to a server).</p>
<div class="note">
Reliably good at: <b>SQL injection, command injection</b> fixes.<br />
Weaker at: path traversal, hardcoded secrets, weak hashing, insecure deserialization, XSS —
the training data had very few examples of these.
See the <a href="https://huggingface.co/bencodez/Cipheron" target="_blank">model card</a> for details.
</div>
<div id="status">Click "Load model" to download Cipheron (~500MB, cached by your browser after the first time).</div>
<progress id="progress" value="0" max="1" style="display:none"></progress>
<button id="loadBtn">Load model</button>
<div id="chat"></div>
<form id="form" style="display:none">
<textarea id="input" placeholder="Paste code and ask for a security review...">Review this code for security issues and fix it:
def get_user(username):
query = "SELECT * FROM users WHERE username = '" + username + "'"
return db.execute(query)</textarea>
<button id="sendBtn" type="submit">Send</button>
</form>
<script type="module">
import { Wllama } from "https://cdn.jsdelivr.net/npm/@wllama/wllama@2/esm/index.js";
const CONFIG_PATHS = {
"single-thread/wllama.wasm": "https://cdn.jsdelivr.net/npm/@wllama/wllama@2/src/single-thread/wllama.wasm",
"multi-thread/wllama.wasm": "https://cdn.jsdelivr.net/npm/@wllama/wllama@2/src/multi-thread/wllama.wasm",
};
const MODEL_URL = "https://huggingface.co/bencodez/Cipheron/resolve/main/Cipheron-Q8_0.gguf";
const SYSTEM_PROMPT = "You are a secure coding assistant. Review code for security vulnerabilities and provide fixed, secure versions.";
const statusEl = document.getElementById("status");
const progressEl = document.getElementById("progress");
const loadBtn = document.getElementById("loadBtn");
const form = document.getElementById("form");
const input = document.getElementById("input");
const sendBtn = document.getElementById("sendBtn");
const chatEl = document.getElementById("chat");
let wllama = null;
let history = [];
function addMessage(role, content) {
const div = document.createElement("div");
div.className = "msg " + role;
div.textContent = content;
chatEl.appendChild(div);
div.scrollIntoView({ behavior: "smooth", block: "end" });
return div;
}
function buildPrompt(messages) {
let s = "";
for (const m of messages) {
s += `<|im_start|>${m.role}\n${m.content}<|im_end|>\n`;
}
s += "<|im_start|>assistant\n";
return s;
}
loadBtn.addEventListener("click", async () => {
loadBtn.disabled = true;
progressEl.style.display = "block";
statusEl.textContent = "Downloading model...";
try {
wllama = new Wllama(CONFIG_PATHS);
await wllama.loadModelFromUrl(MODEL_URL, {
n_ctx: 1024,
progressCallback: ({ loaded, total }) => {
if (total) {
progressEl.value = loaded / total;
statusEl.textContent = `Downloading model... ${(loaded / 1e6).toFixed(0)}MB / ${(total / 1e6).toFixed(0)}MB`;
}
},
});
statusEl.textContent = "Model loaded. Ask a question below.";
progressEl.style.display = "none";
loadBtn.style.display = "none";
form.style.display = "flex";
} catch (err) {
statusEl.textContent = "Failed to load model: " + err.message;
loadBtn.disabled = false;
}
});
form.addEventListener("submit", async (e) => {
e.preventDefault();
const userText = input.value.trim();
if (!userText || !wllama) return;
addMessage("user", userText);
history.push({ role: "user", content: userText });
input.value = "";
sendBtn.disabled = true;
const assistantDiv = addMessage("assistant", "");
const messages = [{ role: "system", content: SYSTEM_PROMPT }, ...history];
const prompt = buildPrompt(messages);
let full = "";
try {
await wllama.createCompletion(prompt, {
nPredict: 400,
sampling: { temp: 0.5 },
onNewToken: (token, piece, currentText) => {
full = currentText;
assistantDiv.textContent = full;
assistantDiv.scrollIntoView({ behavior: "smooth", block: "end" });
},
});
} catch (err) {
full = "Error: " + err.message;
assistantDiv.textContent = full;
}
history.push({ role: "assistant", content: full });
sendBtn.disabled = false;
});
</script>
</body>
</html>