index.ts 11.3 KB
Newer Older
1
import { OLLAMA_API_BASE_URL } from '$lib/constants';
Timothy J. Baek's avatar
Timothy J. Baek committed
2
import { promptTemplate } from '$lib/utils';
3

Timothy J. Baek's avatar
Timothy J. Baek committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
export const getOllamaConfig = async (token: string = '') => {
	let error = null;

	const res = await fetch(`${OLLAMA_API_BASE_URL}/config`, {
		method: 'GET',
		headers: {
			Accept: 'application/json',
			'Content-Type': 'application/json',
			...(token && { authorization: `Bearer ${token}` })
		}
	})
		.then(async (res) => {
			if (!res.ok) throw await res.json();
			return res.json();
		})
		.catch((err) => {
			console.log(err);
			if ('detail' in err) {
				error = err.detail;
			} else {
				error = 'Server connection failed';
			}
			return null;
		});

	if (error) {
		throw error;
	}

	return res;
};

export const updateOllamaConfig = async (token: string = '', enable_ollama_api: boolean) => {
	let error = null;

	const res = await fetch(`${OLLAMA_API_BASE_URL}/config/update`, {
		method: 'POST',
		headers: {
			Accept: 'application/json',
			'Content-Type': 'application/json',
			...(token && { authorization: `Bearer ${token}` })
		},
		body: JSON.stringify({
			enable_ollama_api: enable_ollama_api
		})
	})
		.then(async (res) => {
			if (!res.ok) throw await res.json();
			return res.json();
		})
		.catch((err) => {
			console.log(err);
			if ('detail' in err) {
				error = err.detail;
			} else {
				error = 'Server connection failed';
			}
			return null;
		});

	if (error) {
		throw error;
	}

	return res;
};

71
export const getOllamaUrls = async (token: string = '') => {
72
73
	let error = null;

74
	const res = await fetch(`${OLLAMA_API_BASE_URL}/urls`, {
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
		method: 'GET',
		headers: {
			Accept: 'application/json',
			'Content-Type': 'application/json',
			...(token && { authorization: `Bearer ${token}` })
		}
	})
		.then(async (res) => {
			if (!res.ok) throw await res.json();
			return res.json();
		})
		.catch((err) => {
			console.log(err);
			if ('detail' in err) {
				error = err.detail;
			} else {
				error = 'Server connection failed';
			}
			return null;
		});

	if (error) {
		throw error;
	}

100
	return res.OLLAMA_BASE_URLS;
101
102
};

103
export const updateOllamaUrls = async (token: string = '', urls: string[]) => {
104
105
	let error = null;

106
	const res = await fetch(`${OLLAMA_API_BASE_URL}/urls/update`, {
107
108
109
110
111
112
113
		method: 'POST',
		headers: {
			Accept: 'application/json',
			'Content-Type': 'application/json',
			...(token && { authorization: `Bearer ${token}` })
		},
		body: JSON.stringify({
114
			urls: urls
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
		})
	})
		.then(async (res) => {
			if (!res.ok) throw await res.json();
			return res.json();
		})
		.catch((err) => {
			console.log(err);
			if ('detail' in err) {
				error = err.detail;
			} else {
				error = 'Server connection failed';
			}
			return null;
		});

	if (error) {
		throw error;
	}

135
	return res.OLLAMA_BASE_URLS;
136
137
138
139
140
};

export const getOllamaVersion = async (token: string = '') => {
	let error = null;

141
	const res = await fetch(`${OLLAMA_API_BASE_URL}/api/version`, {
142
143
144
145
146
147
148
149
150
151
152
		method: 'GET',
		headers: {
			Accept: 'application/json',
			'Content-Type': 'application/json',
			...(token && { authorization: `Bearer ${token}` })
		}
	})
		.then(async (res) => {
			if (!res.ok) throw await res.json();
			return res.json();
		})
Timothy J. Baek's avatar
Timothy J. Baek committed
153
154
155
156
		.catch((err) => {
			console.log(err);
			if ('detail' in err) {
				error = err.detail;
157
158
159
160
161
162
163
164
165
166
			} else {
				error = 'Server connection failed';
			}
			return null;
		});

	if (error) {
		throw error;
	}

Timothy J. Baek's avatar
Timothy J. Baek committed
167
	return res?.version ?? '';
168
169
};

170
export const getOllamaModels = async (token: string = '') => {
171
172
	let error = null;

173
	const res = await fetch(`${OLLAMA_API_BASE_URL}/api/tags`, {
174
175
176
177
178
179
180
181
182
183
184
		method: 'GET',
		headers: {
			Accept: 'application/json',
			'Content-Type': 'application/json',
			...(token && { authorization: `Bearer ${token}` })
		}
	})
		.then(async (res) => {
			if (!res.ok) throw await res.json();
			return res.json();
		})
Timothy J. Baek's avatar
Timothy J. Baek committed
185
186
187
188
		.catch((err) => {
			console.log(err);
			if ('detail' in err) {
				error = err.detail;
189
190
191
192
193
194
195
196
197
198
			} else {
				error = 'Server connection failed';
			}
			return null;
		});

	if (error) {
		throw error;
	}

199
200
201
202
203
	return (res?.models ?? [])
		.map((model) => ({ id: model.model, name: model.name ?? model.model, ...model }))
		.sort((a, b) => {
			return a.name.localeCompare(b.name);
		});
204
};
Timothy J. Baek's avatar
Timothy J. Baek committed
205

206
207
208
209
210
211
212
// TODO: migrate to backend
export const generateTitle = async (
	token: string = '',
	template: string,
	model: string,
	prompt: string
) => {
Timothy J. Baek's avatar
Timothy J. Baek committed
213
214
	let error = null;

Timothy J. Baek's avatar
Timothy J. Baek committed
215
	template = promptTemplate(template, prompt);
216
217
218

	console.log(template);

219
	const res = await fetch(`${OLLAMA_API_BASE_URL}/api/generate`, {
Timothy J. Baek's avatar
Timothy J. Baek committed
220
221
		method: 'POST',
		headers: {
222
223
			Accept: 'application/json',
			'Content-Type': 'application/json',
Timothy J. Baek's avatar
Timothy J. Baek committed
224
225
226
227
			Authorization: `Bearer ${token}`
		},
		body: JSON.stringify({
			model: model,
228
			prompt: template,
229
230
231
			stream: false,
			options: {
				// Restrict the number of tokens generated to 50
Timothy J. Baek's avatar
Timothy J. Baek committed
232
				num_predict: 50
233
			}
Timothy J. Baek's avatar
Timothy J. Baek committed
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
		})
	})
		.then(async (res) => {
			if (!res.ok) throw await res.json();
			return res.json();
		})
		.catch((err) => {
			console.log(err);
			if ('detail' in err) {
				error = err.detail;
			}
			return null;
		});

	if (error) {
		throw error;
	}

252
	return res?.response.replace(/["']/g, '') ?? 'New Chat';
Timothy J. Baek's avatar
Timothy J. Baek committed
253
254
};

Timothy J. Baek's avatar
Timothy J. Baek committed
255
256
257
258
export const generatePrompt = async (token: string = '', model: string, conversation: string) => {
	let error = null;

	if (conversation === '') {
259
		conversation = '[no existing conversation]';
Timothy J. Baek's avatar
Timothy J. Baek committed
260
261
	}

262
	const res = await fetch(`${OLLAMA_API_BASE_URL}/api/generate`, {
Timothy J. Baek's avatar
Timothy J. Baek committed
263
264
		method: 'POST',
		headers: {
265
266
			Accept: 'application/json',
			'Content-Type': 'application/json',
Timothy J. Baek's avatar
Timothy J. Baek committed
267
268
269
270
			Authorization: `Bearer ${token}`
		},
		body: JSON.stringify({
			model: model,
271
			prompt: `Conversation:
Timothy J. Baek's avatar
Timothy J. Baek committed
272
273
			${conversation}

274
275
			As USER in the conversation above, your task is to continue the conversation. Remember, Your responses should be crafted as if you're a human conversing in a natural, realistic manner, keeping in mind the context and flow of the dialogue. Please generate a fitting response to the last message in the conversation, or if there is no existing conversation, initiate one as a normal person would.
			
Timothy J. Baek's avatar
Timothy J. Baek committed
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
			Response:
			`
		})
	}).catch((err) => {
		console.log(err);
		if ('detail' in err) {
			error = err.detail;
		}
		return null;
	});

	if (error) {
		throw error;
	}

	return res;
};

294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
export const generateEmbeddings = async (token: string = '', model: string, text: string) => {
	let error = null;

	const res = await fetch(`${OLLAMA_API_BASE_URL}/api/embeddings`, {
		method: 'POST',
		headers: {
			Accept: 'application/json',
			'Content-Type': 'application/json',
			Authorization: `Bearer ${token}`
		},
		body: JSON.stringify({
			model: model,
			prompt: text
		})
	}).catch((err) => {
		error = err;
		return null;
	});

	if (error) {
		throw error;
	}

	return res;
};

320
321
322
export const generateTextCompletion = async (token: string = '', model: string, text: string) => {
	let error = null;

323
	const res = await fetch(`${OLLAMA_API_BASE_URL}/api/generate`, {
324
325
		method: 'POST',
		headers: {
326
327
			Accept: 'application/json',
			'Content-Type': 'application/json',
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
			Authorization: `Bearer ${token}`
		},
		body: JSON.stringify({
			model: model,
			prompt: text,
			stream: true
		})
	}).catch((err) => {
		error = err;
		return null;
	});

	if (error) {
		throw error;
	}

	return res;
};

347
export const generateChatCompletion = async (token: string = '', body: object) => {
348
	let controller = new AbortController();
Timothy J. Baek's avatar
Timothy J. Baek committed
349
350
	let error = null;

351
	const res = await fetch(`${OLLAMA_API_BASE_URL}/api/chat`, {
352
		signal: controller.signal,
Timothy J. Baek's avatar
Timothy J. Baek committed
353
354
		method: 'POST',
		headers: {
355
356
			Accept: 'application/json',
			'Content-Type': 'application/json',
Timothy J. Baek's avatar
Timothy J. Baek committed
357
358
359
360
361
362
363
364
365
366
367
368
			Authorization: `Bearer ${token}`
		},
		body: JSON.stringify(body)
	}).catch((err) => {
		error = err;
		return null;
	});

	if (error) {
		throw error;
	}

369
370
371
	return [res, controller];
};

Timothy J. Baek's avatar
Timothy J. Baek committed
372
export const cancelOllamaRequest = async (token: string = '', requestId: string) => {
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
	let error = null;

	const res = await fetch(`${OLLAMA_API_BASE_URL}/cancel/${requestId}`, {
		method: 'GET',
		headers: {
			'Content-Type': 'text/event-stream',
			Authorization: `Bearer ${token}`
		}
	}).catch((err) => {
		error = err;
		return null;
	});

	if (error) {
		throw error;
	}

Timothy J. Baek's avatar
Timothy J. Baek committed
390
391
	return res;
};
392

393
export const createModel = async (token: string, tagName: string, content: string) => {
394
395
	let error = null;

396
	const res = await fetch(`${OLLAMA_API_BASE_URL}/api/create`, {
397
398
		method: 'POST',
		headers: {
399
400
			Accept: 'application/json',
			'Content-Type': 'application/json',
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
			Authorization: `Bearer ${token}`
		},
		body: JSON.stringify({
			name: tagName,
			modelfile: content
		})
	}).catch((err) => {
		error = err;
		return null;
	});

	if (error) {
		throw error;
	}

	return res;
};

419
export const deleteModel = async (token: string, tagName: string, urlIdx: string | null = null) => {
420
421
	let error = null;

422
423
424
425
426
427
428
429
430
431
432
433
434
435
	const res = await fetch(
		`${OLLAMA_API_BASE_URL}/api/delete${urlIdx !== null ? `/${urlIdx}` : ''}`,
		{
			method: 'DELETE',
			headers: {
				Accept: 'application/json',
				'Content-Type': 'application/json',
				Authorization: `Bearer ${token}`
			},
			body: JSON.stringify({
				name: tagName
			})
		}
	)
436
437
438
439
440
441
442
443
444
445
		.then(async (res) => {
			if (!res.ok) throw await res.json();
			return res.json();
		})
		.then((json) => {
			console.log(json);
			return true;
		})
		.catch((err) => {
			console.log(err);
446
447
448
449
450
451
			error = err;

			if ('detail' in err) {
				error = err.detail;
			}

452
453
454
455
456
457
458
459
460
			return null;
		});

	if (error) {
		throw error;
	}

	return res;
};
461

462
export const pullModel = async (token: string, tagName: string, urlIdx: string | null = null) => {
463
464
	let error = null;

465
	const res = await fetch(`${OLLAMA_API_BASE_URL}/api/pull${urlIdx !== null ? `/${urlIdx}` : ''}`, {
466
467
		method: 'POST',
		headers: {
468
469
			Accept: 'application/json',
			'Content-Type': 'application/json',
470
471
472
473
474
475
			Authorization: `Bearer ${token}`
		},
		body: JSON.stringify({
			name: tagName
		})
	}).catch((err) => {
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
476
		console.log(err);
477
		error = err;
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
478
479
480
481
482

		if ('detail' in err) {
			error = err.detail;
		}

483
484
485
486
487
488
489
		return null;
	});
	if (error) {
		throw error;
	}
	return res;
};
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
490

Timothy J. Baek's avatar
Timothy J. Baek committed
491
492
493
494
495
496
497
498
499
500
501
502
export const downloadModel = async (
	token: string,
	download_url: string,
	urlIdx: string | null = null
) => {
	let error = null;

	const res = await fetch(
		`${OLLAMA_API_BASE_URL}/models/download${urlIdx !== null ? `/${urlIdx}` : ''}`,
		{
			method: 'POST',
			headers: {
Timothy J. Baek's avatar
Timothy J. Baek committed
503
504
				Accept: 'application/json',
				'Content-Type': 'application/json',
Timothy J. Baek's avatar
Timothy J. Baek committed
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
				Authorization: `Bearer ${token}`
			},
			body: JSON.stringify({
				url: download_url
			})
		}
	).catch((err) => {
		console.log(err);
		error = err;

		if ('detail' in err) {
			error = err.detail;
		}

		return null;
	});
	if (error) {
		throw error;
	}
	return res;
};

export const uploadModel = async (token: string, file: File, urlIdx: string | null = null) => {
	let error = null;

	const formData = new FormData();
	formData.append('file', file);

	const res = await fetch(
		`${OLLAMA_API_BASE_URL}/models/upload${urlIdx !== null ? `/${urlIdx}` : ''}`,
		{
			method: 'POST',
			headers: {
				Authorization: `Bearer ${token}`
			},
			body: formData
		}
	).catch((err) => {
		console.log(err);
		error = err;

		if ('detail' in err) {
			error = err.detail;
		}

		return null;
	});
	if (error) {
		throw error;
	}
	return res;
};

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
558
559
560
561
562
563
564
565
566
567
568
569
// export const pullModel = async (token: string, tagName: string) => {
// 	return await fetch(`${OLLAMA_API_BASE_URL}/pull`, {
// 		method: 'POST',
// 		headers: {
// 			'Content-Type': 'text/event-stream',
// 			Authorization: `Bearer ${token}`
// 		},
// 		body: JSON.stringify({
// 			name: tagName
// 		})
// 	});
// };