Instructions to use patdev/k3-a40-bootstrap with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use patdev/k3-a40-bootstrap with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf patdev/k3-a40-bootstrap:BF16 # Run inference directly in the terminal: llama cli -hf patdev/k3-a40-bootstrap:BF16
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf patdev/k3-a40-bootstrap:BF16 # Run inference directly in the terminal: llama cli -hf patdev/k3-a40-bootstrap:BF16
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf patdev/k3-a40-bootstrap:BF16 # Run inference directly in the terminal: ./llama-cli -hf patdev/k3-a40-bootstrap:BF16
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf patdev/k3-a40-bootstrap:BF16 # Run inference directly in the terminal: ./build/bin/llama-cli -hf patdev/k3-a40-bootstrap:BF16
Use Docker
docker model run hf.co/patdev/k3-a40-bootstrap:BF16
- LM Studio
- Jan
- Ollama
How to use patdev/k3-a40-bootstrap with Ollama:
ollama run hf.co/patdev/k3-a40-bootstrap:BF16
- Unsloth Desktop
- Docker Model Runner
How to use patdev/k3-a40-bootstrap with Docker Model Runner:
docker model run hf.co/patdev/k3-a40-bootstrap:BF16
- Lemonade
How to use patdev/k3-a40-bootstrap with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull patdev/k3-a40-bootstrap:BF16
Run and chat with the model
lemonade run user.k3-a40-bootstrap-BF16
List all available models
lemonade list
- Atomic Chat
| <title>Console vLLM</title> | |
| <style> | |
| :root{ | |
| --bg:#fbfbfa; --panel:#fff; --ink:#1c1b19; --muted:#6b6963; --line:#e5e3de; | |
| --accent:#a8543a; --accent-soft:#f4ece8; --think:#f5f2ee; --tool:#eef3f0; | |
| --tool-line:#b9cfc3; --warn:#8a5a1f; | |
| } | |
| @media (prefers-color-scheme: dark){ | |
| :root:not([data-theme="light"]){ | |
| --bg:#17161a; --panel:#1e1d22; --ink:#eceae6; --muted:#9a978f; --line:#302e35; | |
| --accent:#d98b6c; --accent-soft:#2a2028; --think:#232128; --tool:#1c2622; | |
| --tool-line:#3a5648; --warn:#d0a260; | |
| } | |
| } | |
| :root[data-theme="dark"]{ | |
| --bg:#17161a; --panel:#1e1d22; --ink:#eceae6; --muted:#9a978f; --line:#302e35; | |
| --accent:#d98b6c; --accent-soft:#2a2028; --think:#232128; --tool:#1c2622; | |
| --tool-line:#3a5648; --warn:#d0a260; | |
| } | |
| *{box-sizing:border-box} | |
| body{margin:0;background:var(--bg);color:var(--ink); | |
| font:15px/1.55 ui-sans-serif,-apple-system,"Segoe UI",Roboto,sans-serif; | |
| display:flex;flex-direction:column;height:100vh;overflow:hidden} | |
| header{display:flex;gap:10px;align-items:center;flex-wrap:wrap; | |
| padding:10px 16px;border-bottom:1px solid var(--line);background:var(--panel)} | |
| h1{font-size:15px;margin:0 8px 0 0;font-weight:650;letter-spacing:-.01em} | |
| select,input,textarea,button{font:inherit;color:var(--ink);background:var(--panel); | |
| border:1px solid var(--line);border-radius:7px;padding:5px 9px} | |
| input[type=number]{width:82px} | |
| button{cursor:pointer;background:var(--accent);color:#fff;border-color:transparent;font-weight:600} | |
| button.ghost{background:transparent;color:var(--muted);font-weight:500} | |
| button:disabled{opacity:.45;cursor:default} | |
| label{font-size:12px;color:var(--muted);display:flex;gap:5px;align-items:center} | |
| #stats{margin-left:auto;font:12px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace; | |
| color:var(--muted);text-align:right;white-space:nowrap} | |
| #stats b{color:var(--accent);font-weight:650} | |
| #syswrap{padding:0 16px;border-bottom:1px solid var(--line);background:var(--panel)} | |
| #syswrap[hidden]{display:none} | |
| #sys{width:100%;height:74px;margin:10px 0;resize:vertical;font-size:13px; | |
| font-family:ui-monospace,SFMono-Regular,Menlo,monospace} | |
| #log{flex:1;overflow-y:auto;padding:18px 16px;display:flex;flex-direction:column;gap:14px} | |
| .msg{max-width:min(860px,100%);width:fit-content;padding:10px 14px;border-radius:12px; | |
| border:1px solid var(--line);background:var(--panel);white-space:pre-wrap; | |
| overflow-wrap:anywhere} | |
| .user{align-self:flex-end;background:var(--accent-soft);border-color:transparent} | |
| .role{font-size:11px;text-transform:uppercase;letter-spacing:.07em; | |
| color:var(--muted);margin-bottom:5px;font-weight:600} | |
| details.think{background:var(--think);border:1px solid var(--line);border-radius:10px; | |
| padding:7px 12px;margin:0 0 9px;font-size:13px;color:var(--muted)} | |
| details.think summary{cursor:pointer;font-size:11px;text-transform:uppercase; | |
| letter-spacing:.07em;font-weight:600} | |
| details.think div{white-space:pre-wrap;margin-top:7px} | |
| .tool{background:var(--tool);border:1px solid var(--tool-line);border-radius:10px; | |
| padding:9px 12px;margin:9px 0 0;font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace; | |
| overflow-x:auto} | |
| .tool .n{color:var(--accent);font-weight:700} | |
| .tool pre{margin:6px 0 0;white-space:pre-wrap;overflow-wrap:anywhere} | |
| .err{border-color:var(--warn);color:var(--warn)} | |
| footer{display:flex;gap:9px;padding:12px 16px;border-top:1px solid var(--line); | |
| background:var(--panel)} | |
| #q{flex:1;height:60px;resize:vertical;font-size:14px} | |
| .hint{font-size:11px;color:var(--muted);padding:0 16px 9px;background:var(--panel)} | |
| </style> | |
| <header> | |
| <h1>Console vLLM</h1> | |
| <select id="model"></select> | |
| <label>max <input type="number" id="maxtok" value="4096" min="1" max="200000"></label> | |
| <label>temp <input type="number" id="temp" value="0" min="0" max="2" step="0.1"></label> | |
| <label><input type="checkbox" id="think" checked> raisonnement</label> | |
| <button class="ghost" id="togsys">système</button> | |
| <button class="ghost" id="clear">effacer</button> | |
| <div id="stats">prêt</div> | |
| </header> | |
| <div id="syswrap" hidden> | |
| <textarea id="sys" placeholder="Prompt système (laisser vide pour aucun)…"></textarea> | |
| </div> | |
| <div id="log"></div> | |
| <div class="hint">Entrée pour envoyer · Maj+Entrée pour un saut de ligne · le débit est mesuré entre le premier et le dernier jeton</div> | |
| <footer> | |
| <textarea id="q" placeholder="Votre message…"></textarea> | |
| <button id="send">Envoyer</button> | |
| <button class="ghost" id="stop" disabled>Stop</button> | |
| </footer> | |
| <script> | |
| const $ = s => document.querySelector(s); | |
| const log = $('#log'); | |
| let history = []; // messages Anthropic | |
| let ctrl = null; | |
| function el(tag, cls, txt){ | |
| const e = document.createElement(tag); | |
| if (cls) e.className = cls; | |
| if (txt != null) e.textContent = txt; | |
| return e; | |
| } | |
| function bubble(role, cls){ | |
| const d = el('div', 'msg ' + (cls || '')); | |
| d.appendChild(el('div', 'role', role)); | |
| log.appendChild(d); | |
| log.scrollTop = log.scrollHeight; | |
| return d; | |
| } | |
| // Les identifiants viennent de /v1/models. On envoie l'en-tete anthropic-version | |
| // pour obtenir les alias claude-*, seuls acceptes par les clients Anthropic. | |
| fetch('/v1/models', {headers:{'anthropic-version':'2023-06-01'}}) | |
| .then(r => r.json()) | |
| .then(d => { | |
| const sel = $('#model'); | |
| (d.data || []).forEach(m => sel.appendChild(new Option(m.id, m.id))); | |
| const ctx = (d.data || [])[0] && (d.data || [])[0].context_window; | |
| if (ctx) $('#stats').textContent = 'contexte ' + ctx.toLocaleString('fr'); | |
| }) | |
| .catch(() => { $('#stats').textContent = 'modèles injoignables'; }); | |
| $('#togsys').onclick = () => { $('#syswrap').hidden = !$('#syswrap').hidden; }; | |
| $('#clear').onclick = () => { history = []; log.innerHTML = ''; $('#stats').textContent = 'prêt'; }; | |
| $('#stop').onclick = () => { if (ctrl) ctrl.abort(); }; | |
| $('#q').addEventListener('keydown', e => { | |
| if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } | |
| }); | |
| $('#send').onclick = send; | |
| async function send(){ | |
| const text = $('#q').value.trim(); | |
| if (!text || ctrl) return; | |
| $('#q').value = ''; | |
| history.push({role:'user', content:text}); | |
| bubble('vous', 'user').appendChild(el('div', null, text)); | |
| const out = bubble($('#model').value || 'assistant'); | |
| const body = out.appendChild(el('div')); | |
| let think = null, thinkBody = null; | |
| const blocks = {}; // index -> {type,name,node,buf} | |
| const body_req = { | |
| model: $('#model').value, | |
| max_tokens: +$('#maxtok').value, | |
| temperature: +$('#temp').value, | |
| stream: true, | |
| messages: history, | |
| }; | |
| const sys = $('#sys').value.trim(); | |
| if (sys) body_req.system = sys; | |
| // Le raisonnement est actif par defaut cote modele ; il consomme des jetons | |
| // avant le premier caractere de reponse, ce qui pese sur les tours courts. | |
| if (!$('#think').checked) body_req.thinking = {type:'disabled'}; | |
| ctrl = new AbortController(); | |
| $('#send').disabled = true; $('#stop').disabled = false; | |
| const t0 = performance.now(); | |
| let tFirst = null, chars = 0, usage = null, stop = null; | |
| try { | |
| const r = await fetch('/v1/messages', { | |
| method:'POST', signal: ctrl.signal, | |
| headers:{'Content-Type':'application/json','anthropic-version':'2023-06-01', | |
| 'Accept':'text/event-stream'}, | |
| body: JSON.stringify(body_req), | |
| }); | |
| if (!r.ok) throw new Error('HTTP ' + r.status + ' ' + (await r.text()).slice(0,300)); | |
| const rd = r.body.getReader(), dec = new TextDecoder(); | |
| let buf = ''; | |
| for(;;){ | |
| const {done, value} = await rd.read(); | |
| if (done) break; | |
| buf += dec.decode(value, {stream:true}); | |
| const parts = buf.split('\n'); | |
| buf = parts.pop(); | |
| for (const line of parts){ | |
| if (!line.startsWith('data:')) continue; | |
| let d; try { d = JSON.parse(line.slice(5).trim()); } catch { continue; } | |
| if (d.type === 'content_block_start'){ | |
| const cb = d.content_block || {}; | |
| if (cb.type === 'tool_use'){ | |
| const n = el('div','tool'); | |
| n.appendChild(el('span','n', '⚙ ' + (cb.name || 'outil'))); | |
| const pre = n.appendChild(el('pre')); | |
| body.parentNode.appendChild(n); | |
| blocks[d.index] = {type:'tool_use', node:pre, buf:''}; | |
| } else if (cb.type === 'thinking'){ | |
| blocks[d.index] = {type:'thinking'}; | |
| } else { | |
| blocks[d.index] = {type:'text'}; | |
| } | |
| } | |
| else if (d.type === 'content_block_delta'){ | |
| const dl = d.delta || {}, b = blocks[d.index] || {type:'text'}; | |
| if (tFirst === null) tFirst = performance.now(); | |
| if (dl.type === 'input_json_delta'){ | |
| b.buf = (b.buf || '') + dl.partial_json; | |
| if (b.node) b.node.textContent = b.buf; | |
| chars += dl.partial_json.length; | |
| } else if (dl.type === 'thinking_delta' || b.type === 'thinking'){ | |
| if (!think){ | |
| think = el('details','think'); | |
| think.appendChild(el('summary','', 'raisonnement')); | |
| thinkBody = think.appendChild(el('div')); | |
| body.parentNode.insertBefore(think, body); | |
| } | |
| thinkBody.textContent += (dl.thinking || dl.text || ''); | |
| } else if (dl.text){ | |
| body.textContent += dl.text; | |
| chars += dl.text.length; | |
| } | |
| log.scrollTop = log.scrollHeight; | |
| } | |
| else if (d.type === 'message_delta'){ | |
| usage = d.usage || usage; | |
| stop = (d.delta || {}).stop_reason || stop; | |
| } | |
| } | |
| } | |
| // On rejoue la reponse dans l'historique pour que le tour suivant en herite. | |
| const content = []; | |
| if (body.textContent) content.push({type:'text', text: body.textContent}); | |
| for (const k of Object.keys(blocks)){ | |
| const b = blocks[k]; | |
| if (b.type === 'tool_use' && b.buf){ | |
| try { content.push({type:'text', text:'[appel outil] ' + b.buf}); } catch {} | |
| } | |
| } | |
| if (content.length) history.push({role:'assistant', content}); | |
| const dt = (performance.now() - t0) / 1000; | |
| const gen = tFirst ? (performance.now() - tFirst) / 1000 : dt; | |
| const toks = usage && usage.output_tokens ? usage.output_tokens : Math.round(chars / 4); | |
| const tps = gen > 0 ? (toks / gen) : 0; | |
| $('#stats').innerHTML = | |
| `<b>${tps.toFixed(1)} tok/s</b> · ${toks} jetons · 1er ${(tFirst ? (tFirst - t0) / 1000 : 0).toFixed(1)}s` | |
| + ` · total ${dt.toFixed(1)}s` + (stop ? ` · ${stop}` : '') | |
| + (usage && usage.input_tokens ? ` · entrée ${usage.input_tokens}` : ''); | |
| } catch (e){ | |
| const n = bubble('erreur','err'); | |
| n.appendChild(el('div', null, String(e.message || e))); | |
| } finally { | |
| ctrl = null; | |
| $('#send').disabled = false; $('#stop').disabled = true; | |
| $('#q').focus(); | |
| } | |
| } | |
| $('#q').focus(); | |
| </script> | |