index.ts 11.1 KB
Newer Older
1
import { OLLAMA_API_BASE_URL } from '$lib/constants';
2
import { titleGenerationTemplate } 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
export const getOllamaVersion = async (token: string, urlIdx?: number) => {
139
140
	let error = null;

141
	const res = await fetch(`${OLLAMA_API_BASE_URL}/api/version${urlIdx ? `/${urlIdx}` : ''}`, {
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 ?? false;
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;

215
	template = titleGenerationTemplate(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];
};

372
373
374
375
376
377
export const createModel = async (
	token: string,
	tagName: string,
	content: string,
	urlIdx: string | null = null
) => {
378
379
	let error = null;

380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
	const res = await fetch(
		`${OLLAMA_API_BASE_URL}/api/create${urlIdx !== null ? `/${urlIdx}` : ''}`,
		{
			method: 'POST',
			headers: {
				Accept: 'application/json',
				'Content-Type': 'application/json',
				Authorization: `Bearer ${token}`
			},
			body: JSON.stringify({
				name: tagName,
				modelfile: content
			})
		}
	).catch((err) => {
395
396
397
398
399
400
401
402
403
404
405
		error = err;
		return null;
	});

	if (error) {
		throw error;
	}

	return res;
};

406
export const deleteModel = async (token: string, tagName: string, urlIdx: string | null = null) => {
407
408
	let error = null;

409
410
411
412
413
414
415
416
417
418
419
420
421
422
	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
			})
		}
	)
423
424
425
426
427
428
429
430
431
432
		.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);
433
434
435
436
437
438
			error = err;

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

439
440
441
442
443
444
445
446
447
			return null;
		});

	if (error) {
		throw error;
	}

	return res;
};
448

449
export const pullModel = async (token: string, tagName: string, urlIdx: string | null = null) => {
450
	let error = null;
451
	const controller = new AbortController();
452

453
	const res = await fetch(`${OLLAMA_API_BASE_URL}/api/pull${urlIdx !== null ? `/${urlIdx}` : ''}`, {
454
		signal: controller.signal,
455
456
		method: 'POST',
		headers: {
457
458
			Accept: 'application/json',
			'Content-Type': 'application/json',
459
460
461
462
463
464
			Authorization: `Bearer ${token}`
		},
		body: JSON.stringify({
			name: tagName
		})
	}).catch((err) => {
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
465
		console.log(err);
466
		error = err;
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
467
468
469
470
471

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

472
473
474
475
476
		return null;
	});
	if (error) {
		throw error;
	}
477
	return [res, controller];
478
};
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
479

Timothy J. Baek's avatar
Timothy J. Baek committed
480
481
482
483
484
485
486
487
488
489
490
491
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
492
493
				Accept: 'application/json',
				'Content-Type': 'application/json',
Timothy J. Baek's avatar
Timothy J. Baek committed
494
495
496
497
498
499
500
501
502
503
504
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
				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
547
548
549
550
551
552
553
554
555
556
557
558
// 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
// 		})
// 	});
// };