diff --git a/src/lib/apis/chats/index.ts b/src/lib/apis/chats/index.ts
index 9c421816..0abac06a 100644
--- a/src/lib/apis/chats/index.ts
+++ b/src/lib/apis/chats/index.ts
@@ -31,7 +31,7 @@ export const createNewChat = async (token: string, chat: object) => {
return res;
};
-export const getChatlist = async (token: string = '') => {
+export const getChatList = async (token: string = '') => {
let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/chats/`, {
diff --git a/src/lib/apis/ollama/index.ts b/src/lib/apis/ollama/index.ts
index 268806fd..9964e227 100644
--- a/src/lib/apis/ollama/index.ts
+++ b/src/lib/apis/ollama/index.ts
@@ -69,3 +69,68 @@ export const getOllamaModels = async (
return res?.models ?? [];
};
+
+export const generateTitle = async (
+ base_url: string = OLLAMA_API_BASE_URL,
+ token: string = '',
+ model: string,
+ prompt: string
+) => {
+ let error = null;
+
+ const res = await fetch(`${base_url}/generate`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'text/event-stream',
+ Authorization: `Bearer ${token}`
+ },
+ body: JSON.stringify({
+ model: model,
+ prompt: `Generate a brief 3-5 word title for this question, excluding the term 'title.' Then, please reply with only the title: ${prompt}`,
+ stream: false
+ })
+ })
+ .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;
+ }
+
+ return res?.response ?? 'New Chat';
+};
+
+export const generateChatCompletion = async (
+ base_url: string = OLLAMA_API_BASE_URL,
+ token: string = '',
+ body: object
+) => {
+ let error = null;
+
+ const res = await fetch(`${base_url}/chat`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'text/event-stream',
+ Authorization: `Bearer ${token}`
+ },
+ body: JSON.stringify(body)
+ }).catch((err) => {
+ error = err;
+ return null;
+ });
+
+ if (error) {
+ throw error;
+ }
+
+ return res;
+};
diff --git a/src/lib/apis/openai/index.ts b/src/lib/apis/openai/index.ts
index 8a2e9767..89776268 100644
--- a/src/lib/apis/openai/index.ts
+++ b/src/lib/apis/openai/index.ts
@@ -27,8 +27,6 @@ export const getOpenAIModels = async (
let models = Array.isArray(res) ? res : res?.data ?? null;
- console.log(models);
-
return models
.map((model) => ({ name: model.id, external: true }))
.filter((model) => (base_url.includes('openai') ? model.name.includes('gpt') : true));
diff --git a/src/lib/components/chat/Messages.svelte b/src/lib/components/chat/Messages.svelte
index 6b6e66eb..8b9fd4c6 100644
--- a/src/lib/components/chat/Messages.svelte
+++ b/src/lib/components/chat/Messages.svelte
@@ -8,10 +8,11 @@
import auto_render from 'katex/dist/contrib/auto-render.mjs';
import 'katex/dist/katex.min.css';
- import { config, db, modelfiles, settings, user } from '$lib/stores';
+ import { chats, config, db, modelfiles, settings, user } from '$lib/stores';
import { tick } from 'svelte';
import toast from 'svelte-french-toast';
+ import { getChatList, updateChatById } from '$lib/apis/chats';
export let chatId = '';
export let sendPrompt: Function;
@@ -262,10 +263,12 @@
return message;
});
- $db.updateChatById(chatId, {
+ await updateChatById(localStorage.token, chatId, {
messages: messages,
history: history
});
+
+ await chats.set(await getChatList(localStorage.token));
};
const showPreviousMessage = async (message) => {
diff --git a/src/lib/components/layout/Navbar.svelte b/src/lib/components/layout/Navbar.svelte
index 219801bf..fb350fb0 100644
--- a/src/lib/components/layout/Navbar.svelte
+++ b/src/lib/components/layout/Navbar.svelte
@@ -1,7 +1,5 @@
{
return `https://www.gravatar.com/avatar/${hash}`;
};
-const copyToClipboard = (text) => {
+export const copyToClipboard = (text) => {
if (!navigator.clipboard) {
- var textArea = document.createElement('textarea');
+ const textArea = document.createElement('textarea');
textArea.value = text;
// Avoid scrolling to bottom
@@ -81,8 +81,8 @@ const copyToClipboard = (text) => {
textArea.select();
try {
- var successful = document.execCommand('copy');
- var msg = successful ? 'successful' : 'unsuccessful';
+ const successful = document.execCommand('copy');
+ const msg = successful ? 'successful' : 'unsuccessful';
console.log('Fallback: Copying text command was ' + msg);
} catch (err) {
console.error('Fallback: Oops, unable to copy', err);
diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte
index a3c0095e..e91a776d 100644
--- a/src/routes/(app)/+layout.svelte
+++ b/src/routes/(app)/+layout.svelte
@@ -1,37 +1,18 @@
diff --git a/src/routes/(app)/c/[id]/+page.svelte b/src/routes/(app)/c/[id]/+page.svelte
index a2054c7b..efa5ee1f 100644
--- a/src/routes/(app)/c/[id]/+page.svelte
+++ b/src/routes/(app)/c/[id]/+page.svelte
@@ -13,6 +13,7 @@
import ModelSelector from '$lib/components/chat/ModelSelector.svelte';
import Navbar from '$lib/components/layout/Navbar.svelte';
import { page } from '$app/stores';
+ import { createNewChat, getChatById, getChatList } from '$lib/apis/chats';
let loaded = false;
let stopResponseFlag = false;
@@ -70,7 +71,7 @@
const loadChat = async () => {
await chatId.set($page.params.id);
- chat = await $db.getChatById($chatId);
+ chat = await getChatById(localStorage.token, $chatId);
const chatContent = chat.chat;
@@ -159,11 +160,11 @@
})
);
- await chats.set(await $db.getChats());
+ await chats.set(await getChatList(localStorage.token));
};
const sendPromptOllama = async (model, userPrompt, parentId, _chatId) => {
- console.log('sendPromptOllama');
+ // Create response message
let responseMessageId = uuidv4();
let responseMessage = {
parentId: parentId,
@@ -174,8 +175,11 @@
model: model
};
+ // Add message to history and Set currentId to messageId
history.messages[responseMessageId] = responseMessage;
history.currentId = responseMessageId;
+
+ // Append messageId to childrenIds of parent message
if (parentId !== null) {
history.messages[parentId].childrenIds = [
...history.messages[parentId].childrenIds,
@@ -183,17 +187,16 @@
];
}
+ // Wait until history/message have been updated
await tick();
+
+ // Scroll down
window.scrollTo({ top: document.body.scrollHeight });
- const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/chat`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'text/event-stream',
- ...($settings.authHeader && { Authorization: $settings.authHeader }),
- ...($user && { Authorization: `Bearer ${localStorage.token}` })
- },
- body: JSON.stringify({
+ const res = await generateChatCompletion(
+ $settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
+ localStorage.token,
+ {
model: model,
messages: [
$settings.system
@@ -215,20 +218,11 @@
})
})),
options: {
- seed: $settings.seed ?? undefined,
- temperature: $settings.temperature ?? undefined,
- repeat_penalty: $settings.repeat_penalty ?? undefined,
- top_k: $settings.top_k ?? undefined,
- top_p: $settings.top_p ?? undefined,
- num_ctx: $settings.num_ctx ?? undefined,
...($settings.options ?? {})
},
format: $settings.requestFormat ?? undefined
- })
- }).catch((err) => {
- console.log(err);
- return null;
- });
+ }
+ );
if (res && res.ok) {
const reader = res.body
@@ -320,23 +314,11 @@
}
if ($chatId == _chatId) {
- chat = await $db.updateChatById(_chatId, {
- ...chat.chat,
- title: title === '' ? 'New Chat' : title,
- models: selectedModels,
- system: $settings.system ?? undefined,
- options: {
- seed: $settings.seed ?? undefined,
- temperature: $settings.temperature ?? undefined,
- repeat_penalty: $settings.repeat_penalty ?? undefined,
- top_k: $settings.top_k ?? undefined,
- top_p: $settings.top_p ?? undefined,
- num_ctx: $settings.num_ctx ?? undefined,
- ...($settings.options ?? {})
- },
+ chat = await updateChatById(localStorage.token, _chatId, {
messages: messages,
history: history
});
+ await chats.set(await getChatList(localStorage.token));
}
} else {
if (res !== null) {
@@ -362,6 +344,7 @@
stopResponseFlag = false;
await tick();
+
if (autoScroll) {
window.scrollTo({ top: document.body.scrollHeight });
}
@@ -507,23 +490,11 @@
}
if ($chatId == _chatId) {
- chat = await $db.updateChatById(_chatId, {
- ...chat.chat,
- title: title === '' ? 'New Chat' : title,
- models: selectedModels,
- system: $settings.system ?? undefined,
- options: {
- seed: $settings.seed ?? undefined,
- temperature: $settings.temperature ?? undefined,
- repeat_penalty: $settings.repeat_penalty ?? undefined,
- top_k: $settings.top_k ?? undefined,
- top_p: $settings.top_p ?? undefined,
- num_ctx: $settings.num_ctx ?? undefined,
- ...($settings.options ?? {})
- },
+ chat = await updateChatById(localStorage.token, _chatId, {
messages: messages,
history: history
});
+ await chats.set(await getChatList(localStorage.token));
}
} else {
if (res !== null) {
@@ -573,10 +544,13 @@
if (selectedModels.includes('')) {
toast.error('Model not selected');
} else if (messages.length != 0 && messages.at(-1).done != true) {
+ // Response not done
console.log('wait');
} else {
+ // Reset chat message textarea height
document.getElementById('chat-textarea').style.height = '';
+ // Create user message
let userMessageId = uuidv4();
let userMessage = {
id: userMessageId,
@@ -587,47 +561,42 @@
files: files.length > 0 ? files : undefined
};
+ // Add message to history and Set currentId to messageId
+ history.messages[userMessageId] = userMessage;
+ history.currentId = userMessageId;
+
+ // Append messageId to childrenIds of parent message
if (messages.length !== 0) {
history.messages[messages.at(-1).id].childrenIds.push(userMessageId);
}
- history.messages[userMessageId] = userMessage;
- history.currentId = userMessageId;
-
+ // Wait until history/message have been updated
await tick();
+ // Create new chat if only one message in messages
if (messages.length == 1) {
- chat = await $db.createNewChat({
+ chat = await createNewChat(localStorage.token, {
id: $chatId,
title: 'New Chat',
models: selectedModels,
system: $settings.system ?? undefined,
options: {
- seed: $settings.seed ?? undefined,
- temperature: $settings.temperature ?? undefined,
- repeat_penalty: $settings.repeat_penalty ?? undefined,
- top_k: $settings.top_k ?? undefined,
- top_p: $settings.top_p ?? undefined,
- num_ctx: $settings.num_ctx ?? undefined,
...($settings.options ?? {})
},
messages: messages,
- history: history
+ history: history,
+ timestamp: Date.now()
});
-
- console.log(chat);
-
+ await chats.set(await getChatList(localStorage.token));
await chatId.set(chat.id);
await tick();
}
+ // Reset chat input textarea
prompt = '';
files = [];
- setTimeout(() => {
- window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
- }, 50);
-
+ // Send prompt
await sendPrompt(userPrompt, userMessageId);
}
};
@@ -638,9 +607,7 @@
};
const regenerateResponse = async () => {
- const _chatId = JSON.parse(JSON.stringify($chatId));
- console.log('regenerateResponse', _chatId);
-
+ console.log('regenerateResponse');
if (messages.length != 0 && messages.at(-1).done == true) {
messages.splice(messages.length - 1, 1);
messages = messages;
@@ -648,41 +615,21 @@
let userMessage = messages.at(-1);
let userPrompt = userMessage.content;
- await sendPrompt(userPrompt, userMessage.id, _chatId);
+ await sendPrompt(userPrompt, userMessage.id);
}
};
const generateChatTitle = async (_chatId, userPrompt) => {
if ($settings.titleAutoGenerate ?? true) {
- console.log('generateChatTitle');
+ const title = await generateTitle(
+ $settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
+ localStorage.token,
+ selectedModels[0],
+ userPrompt
+ );
- const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/generate`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'text/event-stream',
- ...($settings.authHeader && { Authorization: $settings.authHeader }),
- ...($user && { Authorization: `Bearer ${localStorage.token}` })
- },
- body: JSON.stringify({
- model: selectedModels[0],
- prompt: `Generate a brief 3-5 word title for this question, excluding the term 'title.' Then, please reply with only the title: ${userPrompt}`,
- stream: false
- })
- })
- .then(async (res) => {
- if (!res.ok) throw await res.json();
- return res.json();
- })
- .catch((error) => {
- if ('detail' in error) {
- toast.error(error.detail);
- }
- console.log(error);
- return null;
- });
-
- if (res) {
- await setChatTitle(_chatId, res.response === '' ? 'New Chat' : res.response);
+ if (title) {
+ await setChatTitle(_chatId, title);
}
} else {
await setChatTitle(_chatId, `${userPrompt}`);
@@ -690,13 +637,12 @@
};
const setChatTitle = async (_chatId, _title) => {
- chat = await $db.updateChatById(_chatId, {
- ...chat.chat,
- title: _title
- });
if (_chatId === $chatId) {
title = _title;
}
+
+ chat = await updateChatById(localStorage.token, _chatId, { title: _title });
+ await chats.set(await getChatList(localStorage.token));
};