forked from open-webui/open-webui
feat: litellm frontend integration
This commit is contained in:
parent
de0084c8df
commit
9b6dca3d7f
8 changed files with 134 additions and 62 deletions
|
@ -12,6 +12,7 @@
|
|||
import { getPrompts } from '$lib/apis/prompts';
|
||||
|
||||
import { getOpenAIModels } from '$lib/apis/openai';
|
||||
import { getLiteLLMModels } from '$lib/apis/litellm';
|
||||
|
||||
import {
|
||||
user,
|
||||
|
@ -59,6 +60,13 @@
|
|||
|
||||
models.push(...(openAIModels ? [{ name: 'hr' }, ...openAIModels] : []));
|
||||
|
||||
const liteLLMModels = await getLiteLLMModels(localStorage.token).catch((error) => {
|
||||
console.log(error);
|
||||
return null;
|
||||
});
|
||||
|
||||
models.push(...(liteLLMModels ? [{ name: 'hr' }, ...liteLLMModels] : []));
|
||||
|
||||
return models;
|
||||
};
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
import ModelSelector from '$lib/components/chat/ModelSelector.svelte';
|
||||
import Navbar from '$lib/components/layout/Navbar.svelte';
|
||||
import { RAGTemplate } from '$lib/utils/rag';
|
||||
import { LITELLM_API_BASE_URL, OPENAI_API_BASE_URL } from '$lib/constants';
|
||||
|
||||
let stopResponseFlag = false;
|
||||
let autoScroll = true;
|
||||
|
@ -277,9 +278,8 @@
|
|||
}
|
||||
|
||||
await Promise.all(
|
||||
selectedModels.map(async (model) => {
|
||||
console.log(model);
|
||||
const modelTag = $models.filter((m) => m.name === model).at(0);
|
||||
selectedModels.map(async (modelId) => {
|
||||
const model = $models.filter((m) => m.id === modelId).at(0);
|
||||
|
||||
// Create response message
|
||||
let responseMessageId = uuidv4();
|
||||
|
@ -289,7 +289,7 @@
|
|||
childrenIds: [],
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
model: model,
|
||||
model: model.id,
|
||||
timestamp: Math.floor(Date.now() / 1000) // Unix epoch
|
||||
};
|
||||
|
||||
|
@ -305,12 +305,12 @@
|
|||
];
|
||||
}
|
||||
|
||||
if (modelTag?.external) {
|
||||
if (model?.external) {
|
||||
await sendPromptOpenAI(model, prompt, responseMessageId, _chatId);
|
||||
} else if (modelTag) {
|
||||
} else if (model) {
|
||||
await sendPromptOllama(model, prompt, responseMessageId, _chatId);
|
||||
} else {
|
||||
toast.error(`Model ${model} not found`);
|
||||
toast.error(`Model ${model.id} not found`);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -319,6 +319,7 @@
|
|||
};
|
||||
|
||||
const sendPromptOllama = async (model, userPrompt, responseMessageId, _chatId) => {
|
||||
model = model.id;
|
||||
const responseMessage = history.messages[responseMessageId];
|
||||
|
||||
// Wait until history/message have been updated
|
||||
|
@ -530,54 +531,58 @@
|
|||
const responseMessage = history.messages[responseMessageId];
|
||||
scrollToBottom();
|
||||
|
||||
const res = await generateOpenAIChatCompletion(localStorage.token, {
|
||||
model: model,
|
||||
stream: true,
|
||||
messages: [
|
||||
$settings.system
|
||||
? {
|
||||
role: 'system',
|
||||
content: $settings.system
|
||||
}
|
||||
: undefined,
|
||||
...messages
|
||||
]
|
||||
.filter((message) => message)
|
||||
.map((message, idx, arr) => ({
|
||||
role: message.role,
|
||||
...(message.files?.filter((file) => file.type === 'image').length > 0 ?? false
|
||||
const res = await generateOpenAIChatCompletion(
|
||||
localStorage.token,
|
||||
{
|
||||
model: model.id,
|
||||
stream: true,
|
||||
messages: [
|
||||
$settings.system
|
||||
? {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text:
|
||||
arr.length - 1 !== idx
|
||||
? message.content
|
||||
: message?.raContent ?? message.content
|
||||
},
|
||||
...message.files
|
||||
.filter((file) => file.type === 'image')
|
||||
.map((file) => ({
|
||||
type: 'image_url',
|
||||
image_url: {
|
||||
url: file.url
|
||||
}
|
||||
}))
|
||||
]
|
||||
role: 'system',
|
||||
content: $settings.system
|
||||
}
|
||||
: {
|
||||
content:
|
||||
arr.length - 1 !== idx ? message.content : message?.raContent ?? message.content
|
||||
})
|
||||
})),
|
||||
seed: $settings?.options?.seed ?? undefined,
|
||||
stop: $settings?.options?.stop ?? undefined,
|
||||
temperature: $settings?.options?.temperature ?? undefined,
|
||||
top_p: $settings?.options?.top_p ?? undefined,
|
||||
num_ctx: $settings?.options?.num_ctx ?? undefined,
|
||||
frequency_penalty: $settings?.options?.repeat_penalty ?? undefined,
|
||||
max_tokens: $settings?.options?.num_predict ?? undefined
|
||||
});
|
||||
: undefined,
|
||||
...messages
|
||||
]
|
||||
.filter((message) => message)
|
||||
.map((message, idx, arr) => ({
|
||||
role: message.role,
|
||||
...(message.files?.filter((file) => file.type === 'image').length > 0 ?? false
|
||||
? {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text:
|
||||
arr.length - 1 !== idx
|
||||
? message.content
|
||||
: message?.raContent ?? message.content
|
||||
},
|
||||
...message.files
|
||||
.filter((file) => file.type === 'image')
|
||||
.map((file) => ({
|
||||
type: 'image_url',
|
||||
image_url: {
|
||||
url: file.url
|
||||
}
|
||||
}))
|
||||
]
|
||||
}
|
||||
: {
|
||||
content:
|
||||
arr.length - 1 !== idx ? message.content : message?.raContent ?? message.content
|
||||
})
|
||||
})),
|
||||
seed: $settings?.options?.seed ?? undefined,
|
||||
stop: $settings?.options?.stop ?? undefined,
|
||||
temperature: $settings?.options?.temperature ?? undefined,
|
||||
top_p: $settings?.options?.top_p ?? undefined,
|
||||
num_ctx: $settings?.options?.num_ctx ?? undefined,
|
||||
frequency_penalty: $settings?.options?.repeat_penalty ?? undefined,
|
||||
max_tokens: $settings?.options?.num_predict ?? undefined
|
||||
},
|
||||
model.source === 'litellm' ? `${LITELLM_API_BASE_URL}/v1` : `${OPENAI_API_BASE_URL}`
|
||||
);
|
||||
|
||||
if (res && res.ok) {
|
||||
const reader = res.body
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue