47a930eddb
Node's default fetch sends a bare User-Agent that Google's CDN fronting ollama.com rejects with 403. curl worked because it sends curl/. Fixes organize (and search LLM ranking). Signed-off-by: William Mantly <wmantly@gmail.com>
54 lines
1.6 KiB
JavaScript
54 lines
1.6 KiB
JavaScript
'use strict';
|
|
|
|
const conf = require('>/conf');
|
|
|
|
// Pull the first JSON object out of a model response( tolerates ```json fences / prose).
|
|
function extractJSON(content){
|
|
let text = String(content).replace(/```json/gi, '').replace(/```/g, '').trim();
|
|
let start = text.indexOf('{');
|
|
let end = text.lastIndexOf('}');
|
|
if(start === -1 || end === -1){
|
|
console.error('extractJSON: no JSON object found in:', content);
|
|
throw new Error('No JSON in model response');
|
|
}
|
|
try{
|
|
return JSON.parse(text.slice(start, end + 1));
|
|
}catch(error){
|
|
console.error('extractJSON: parse failed. extracted:', text.slice(start, end + 1));
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// One-shot JSON chat against the Ollama cloud model.
|
|
async function chatJSON(system, user){
|
|
let res = await fetch(`${conf.ollama.url}/api/chat`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer ${conf.ollama.apiKey}`,
|
|
'User-Agent': 'tpbproxy/1.0 (organize; +https://github.com/wmantly/tpbproxy)',
|
|
},
|
|
body: JSON.stringify({
|
|
model: conf.ollama.model,
|
|
stream: false,
|
|
format: 'json',
|
|
messages: [
|
|
{ role: 'system', content: system },
|
|
{ role: 'user', content: user },
|
|
],
|
|
}),
|
|
});
|
|
if(!res.ok){
|
|
let body = await res.text().catch(() => '');
|
|
console.error(`Ollama chat failed (${res.status}):`, body.slice(0, 500));
|
|
let error = new Error('OllamaError');
|
|
error.message = `Ollama chat failed( ${res.status})`;
|
|
error.status = 502;
|
|
throw error;
|
|
}
|
|
let data = await res.json();
|
|
return extractJSON(data.message && data.message.content);
|
|
}
|
|
|
|
module.exports = { chatJSON, extractJSON };
|