← back to Fleet Rag
lib/embed.js
56 lines
'use strict';
// Ollama embedder using nomic-embed-text on Mac Studio 1
const OLLAMA_BASE = process.env.OLLAMA_BASE || 'http://192.168.1.133:11434';
const EMBED_MODEL = process.env.EMBED_MODEL || 'nomic-embed-text';
const GEN_MODEL = process.env.GEN_MODEL || 'qwen3:14b';
async function embed(text) {
const ac = new AbortController();
const t = setTimeout(() => ac.abort(), 30_000); // 30s embed timeout
try {
const res = await fetch(`${OLLAMA_BASE}/api/embeddings`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ model: EMBED_MODEL, prompt: text }),
signal: ac.signal,
});
if (!res.ok) throw new Error(`Embed HTTP ${res.status}: ${await res.text()}`);
const { embedding } = await res.json();
return embedding; // float[]
} finally {
clearTimeout(t);
}
}
async function generate(prompt) {
const timeoutMs = parseInt(process.env.GEN_TIMEOUT_MS || '180000', 10); // 3 min default
const ac = new AbortController();
const t = setTimeout(() => ac.abort(), timeoutMs);
try {
const res = await fetch(`${OLLAMA_BASE}/api/generate`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ model: GEN_MODEL, prompt, stream: false }),
signal: ac.signal,
});
if (!res.ok) throw new Error(`Generate HTTP ${res.status}: ${await res.text()}`);
const { response } = await res.json();
return response;
} finally {
clearTimeout(t);
}
}
function cosineSim(a, b) {
let dot = 0, na = 0, nb = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
na += a[i] * a[i];
nb += b[i] * b[i];
}
return dot / (Math.sqrt(na) * Math.sqrt(nb) + 1e-10);
}
module.exports = { embed, generate, cosineSim, OLLAMA_BASE, EMBED_MODEL, GEN_MODEL };