const fetch = require('node-fetch');

let MODEL = 'llama3:8b';
const history = [
  { role: 'system', content: 'Всегда веди рассуждения и отвечай на том же языке, на котором задан вопрос.' }
];

let pending = Promise.resolve();

async function askStream(prompt) {
  let dashes = '-'.repeat(prompt.length);
  console.log(`\n${dashes}\nВопрос: ${prompt}\n${dashes}\n`);
  pending = pending.then(() => _askStream(prompt));
  return pending;
}

async function _askStream(prompt) {
  history.push({ role: 'user', content: prompt });

  const res = await fetch('http://127.0.0.1:11434/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: MODEL,
      messages: history,
      stream: true,
      keep_alive: '10m'
    })
  });

  if (!res.ok) throw new Error(await res.text());

  const reader = res.body.getReader();
  const decoder = new TextDecoder();
  let buf = '';
  let assistantText = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buf += decoder.decode(value, { stream: true });
    let lines = buf.split(/\r?\n/); // handle CRLF too
    buf = lines.pop();

    for (const line of lines) {
      if (!line.trim()) continue;
      let obj;
      try { obj = JSON.parse(line); } catch { continue; }

      if (obj.message?.content) {
        process.stdout.write(obj.message.content);
        assistantText += obj.message.content;
      }

      if (obj.done) process.stdout.write('\n');
    }
  }

  // Flush any leftover without newline
  if (buf.trim()) {
    try {
      const obj = JSON.parse(buf);
      if (obj.message?.content) {
        process.stdout.write(obj.message.content);
        assistantText += obj.message.content;
      }
    } catch {}
  }

  history.push({ role: 'assistant', content: assistantText.trim() });
  return assistantText.trim();
}

// Example
(async () => {
  await askStream('Сколько в мире котов и кошек?');
  await askStream('Найди веб ссылки на материалы');
})();
