forked from open-webui/open-webui
merged from main and added new translation keys
This commit is contained in:
commit
aa3985e879
13 changed files with 368 additions and 172 deletions
|
@ -1,9 +1,9 @@
|
|||
import { RAG_API_BASE_URL } from '$lib/constants';
|
||||
|
||||
export const getChunkParams = async (token: string) => {
|
||||
export const getRAGConfig = async (token: string) => {
|
||||
let error = null;
|
||||
|
||||
const res = await fetch(`${RAG_API_BASE_URL}/chunk`, {
|
||||
const res = await fetch(`${RAG_API_BASE_URL}/config`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
@ -27,18 +27,27 @@ export const getChunkParams = async (token: string) => {
|
|||
return res;
|
||||
};
|
||||
|
||||
export const updateChunkParams = async (token: string, size: number, overlap: number) => {
|
||||
type ChunkConfigForm = {
|
||||
chunk_size: number;
|
||||
chunk_overlap: number;
|
||||
};
|
||||
|
||||
type RAGConfigForm = {
|
||||
pdf_extract_images: boolean;
|
||||
chunk: ChunkConfigForm;
|
||||
};
|
||||
|
||||
export const updateRAGConfig = async (token: string, payload: RAGConfigForm) => {
|
||||
let error = null;
|
||||
|
||||
const res = await fetch(`${RAG_API_BASE_URL}/chunk/update`, {
|
||||
const res = await fetch(`${RAG_API_BASE_URL}/config/update`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
chunk_size: size,
|
||||
chunk_overlap: overlap
|
||||
...payload
|
||||
})
|
||||
})
|
||||
.then(async (res) => {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
import { splitStream } from '$lib/utils';
|
||||
import { onMount, getContext } from 'svelte';
|
||||
import { addLiteLLMModel, deleteLiteLLMModel, getLiteLLMModelInfo } from '$lib/apis/litellm';
|
||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
|
@ -39,6 +40,10 @@
|
|||
|
||||
let OLLAMA_URLS = [];
|
||||
let selectedOllamaUrlIdx: string | null = null;
|
||||
|
||||
let updateModelId = null;
|
||||
let updateProgress = null;
|
||||
|
||||
let showExperimentalOllama = false;
|
||||
let ollamaVersion = '';
|
||||
const MAX_PARALLEL_DOWNLOADS = 3;
|
||||
|
@ -63,6 +68,71 @@
|
|||
|
||||
let deleteModelTag = '';
|
||||
|
||||
const updateModelsHandler = async () => {
|
||||
for (const model of $models.filter(
|
||||
(m) =>
|
||||
m.size != null &&
|
||||
(selectedOllamaUrlIdx === null ? true : (m?.urls ?? []).includes(selectedOllamaUrlIdx))
|
||||
)) {
|
||||
console.log(model);
|
||||
|
||||
updateModelId = model.id;
|
||||
const res = await pullModel(localStorage.token, model.id, selectedOllamaUrlIdx).catch(
|
||||
(error) => {
|
||||
toast.error(error);
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
if (res) {
|
||||
const reader = res.body
|
||||
.pipeThrough(new TextDecoderStream())
|
||||
.pipeThrough(splitStream('\n'))
|
||||
.getReader();
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
let lines = value.split('\n');
|
||||
|
||||
for (const line of lines) {
|
||||
if (line !== '') {
|
||||
let data = JSON.parse(line);
|
||||
|
||||
console.log(data);
|
||||
if (data.error) {
|
||||
throw data.error;
|
||||
}
|
||||
if (data.detail) {
|
||||
throw data.detail;
|
||||
}
|
||||
if (data.status) {
|
||||
if (data.digest) {
|
||||
updateProgress = 0;
|
||||
if (data.completed) {
|
||||
updateProgress = Math.round((data.completed / data.total) * 1000) / 10;
|
||||
} else {
|
||||
updateProgress = 100;
|
||||
}
|
||||
} else {
|
||||
toast.success(data.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateModelId = null;
|
||||
updateProgress = null;
|
||||
};
|
||||
|
||||
const pullModelHandler = async () => {
|
||||
const sanitizedModelTag = modelTag.trim();
|
||||
if (modelDownloadStatus[sanitizedModelTag]) {
|
||||
|
@ -389,7 +459,7 @@
|
|||
return [];
|
||||
});
|
||||
|
||||
if (OLLAMA_URLS.length > 1) {
|
||||
if (OLLAMA_URLS.length > 0) {
|
||||
selectedOllamaUrlIdx = 0;
|
||||
}
|
||||
|
||||
|
@ -404,18 +474,51 @@
|
|||
<div class="space-y-2 pr-1.5">
|
||||
<div class="text-sm font-medium">{$i18n.t('Manage Ollama Models')}</div>
|
||||
|
||||
{#if OLLAMA_URLS.length > 1}
|
||||
<div class="flex-1 pb-1">
|
||||
<select
|
||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||
bind:value={selectedOllamaUrlIdx}
|
||||
placeholder={$i18n.t('Select an Ollama instance')}
|
||||
>
|
||||
{#each OLLAMA_URLS as url, idx}
|
||||
<option value={idx} class="bg-gray-100 dark:bg-gray-700">{url}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{#if OLLAMA_URLS.length > 0}
|
||||
<div class="flex gap-2">
|
||||
<div class="flex-1 pb-1">
|
||||
<select
|
||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||
bind:value={selectedOllamaUrlIdx}
|
||||
placeholder="Select an Ollama instance"
|
||||
>
|
||||
{#each OLLAMA_URLS as url, idx}
|
||||
<option value={idx} class="bg-gray-100 dark:bg-gray-700">{url}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="flex w-full justify-end">
|
||||
<Tooltip content="Update All Models" placement="top">
|
||||
<button
|
||||
class="p-2.5 flex gap-2 items-center bg-gray-100 hover:bg-gray-200 text-gray-800 dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-gray-100 rounded-lg transition"
|
||||
on:click={() => {
|
||||
updateModelsHandler();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
d="M7 1a.75.75 0 0 1 .75.75V6h-1.5V1.75A.75.75 0 0 1 7 1ZM6.25 6v2.94L5.03 7.72a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l2.5-2.5a.75.75 0 1 0-1.06-1.06L7.75 8.94V6H10a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2.25Z"
|
||||
/>
|
||||
<path
|
||||
d="M4.268 14A2 2 0 0 0 6 15h6a2 2 0 0 0 2-2v-3a2 2 0 0 0-1-1.732V11a3 3 0 0 1-3 3H4.268Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if updateModelId}
|
||||
Updating "{updateModelId}" {updateProgress ? `(${updateProgress}%)` : ''}
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<div class="space-y-2">
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { getDocs } from '$lib/apis/documents';
|
||||
import {
|
||||
getChunkParams,
|
||||
getRAGConfig,
|
||||
updateRAGConfig,
|
||||
getQuerySettings,
|
||||
scanDocs,
|
||||
updateChunkParams,
|
||||
updateQuerySettings
|
||||
} from '$lib/apis/rag';
|
||||
import { documents } from '$lib/stores';
|
||||
|
@ -19,6 +19,7 @@
|
|||
|
||||
let chunkSize = 0;
|
||||
let chunkOverlap = 0;
|
||||
let pdfExtractImages = true;
|
||||
|
||||
let querySettings = {
|
||||
template: '',
|
||||
|
@ -37,16 +38,24 @@
|
|||
};
|
||||
|
||||
const submitHandler = async () => {
|
||||
const res = await updateChunkParams(localStorage.token, chunkSize, chunkOverlap);
|
||||
const res = await updateRAGConfig(localStorage.token, {
|
||||
pdf_extract_images: pdfExtractImages,
|
||||
chunk: {
|
||||
chunk_overlap: chunkOverlap,
|
||||
chunk_size: chunkSize
|
||||
}
|
||||
});
|
||||
querySettings = await updateQuerySettings(localStorage.token, querySettings);
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
const res = await getChunkParams(localStorage.token);
|
||||
const res = await getRAGConfig(localStorage.token);
|
||||
|
||||
if (res) {
|
||||
chunkSize = res.chunk_size;
|
||||
chunkOverlap = res.chunk_overlap;
|
||||
pdfExtractImages = res.pdf_extract_images;
|
||||
|
||||
chunkSize = res.chunk.chunk_size;
|
||||
chunkOverlap = res.chunk.chunk_overlap;
|
||||
}
|
||||
|
||||
querySettings = await getQuerySettings(localStorage.token);
|
||||
|
@ -163,6 +172,22 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="flex justify-between items-center text-xs">
|
||||
<div class=" text-xs font-medium">{$i18n.t('PDF Extract Images (OCR)')}</div>
|
||||
|
||||
<button
|
||||
class=" text-xs font-medium text-gray-500"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
pdfExtractImages = !pdfExtractImages;
|
||||
}}>{pdfExtractImages ? $i18n.t('On') : $i18n.t('Off')}</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class=" text-sm font-medium">{$i18n.t('Query Params')}</div>
|
||||
|
||||
<div class=" flex">
|
||||
|
@ -182,19 +207,19 @@
|
|||
</div>
|
||||
|
||||
<!-- <div class="flex w-full">
|
||||
<div class=" self-center text-xs font-medium min-w-fit">Chunk Overlap</div>
|
||||
|
||||
<div class="self-center p-3">
|
||||
<input
|
||||
class="w-full rounded py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none border border-gray-100 dark:border-gray-600"
|
||||
type="number"
|
||||
placeholder="Enter Chunk Overlap"
|
||||
bind:value={chunkOverlap}
|
||||
autocomplete="off"
|
||||
min="0"
|
||||
/>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class=" self-center text-xs font-medium min-w-fit">Chunk Overlap</div>
|
||||
|
||||
<div class="self-center p-3">
|
||||
<input
|
||||
class="w-full rounded py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none border border-gray-100 dark:border-gray-600"
|
||||
type="number"
|
||||
placeholder="Enter Chunk Overlap"
|
||||
bind:value={chunkOverlap}
|
||||
autocomplete="off"
|
||||
min="0"
|
||||
/>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
|
@ -236,7 +236,7 @@
|
|||
"Prompts": "Prompts",
|
||||
"Pull a model from Ollama.com": "Ein Modell von Ollama.com abrufen",
|
||||
"Pull Progress": "Fortschritt abrufen",
|
||||
"Query Params": "",
|
||||
"Query Params": "Query Parameter",
|
||||
"RAG Template": "RAG-Vorlage",
|
||||
"Raw Format": "Rohformat",
|
||||
"Record voice": "Stimme aufnehmen",
|
||||
|
@ -346,5 +346,6 @@
|
|||
"Write a summary in 50 words that summarizes [topic or keyword].": "Schreibe eine kurze Zusammenfassung in 50 Wörtern, die [Thema oder Schlüsselwort] zusammenfasst.",
|
||||
"You": "Du",
|
||||
"You're a helpful assistant.": "Du bist ein hilfreicher Assistent.",
|
||||
"You're now logged in.": "Du bist nun eingeloggt."
|
||||
"You're now logged in.": "Du bist nun eingeloggt.",
|
||||
"PDF Extract Images (OCR)": "Text von Bilder aus PDFs extrahieren (OCR)"
|
||||
}
|
||||
|
|
|
@ -236,7 +236,7 @@
|
|||
"Prompts": "Prompts",
|
||||
"Pull a model from Ollama.com": "Pull a model from Ollama.com",
|
||||
"Pull Progress": "Pull Progress",
|
||||
"Query Params": "",
|
||||
"Query Params": "Query Params",
|
||||
"RAG Template": "RAG Template",
|
||||
"Raw Format": "Raw Format",
|
||||
"Record voice": "Record voice",
|
||||
|
@ -346,5 +346,6 @@
|
|||
"Write a summary in 50 words that summarizes [topic or keyword].": "Write a summary in 50 words that summarizes [topic or keyword].",
|
||||
"You": "You",
|
||||
"You're a helpful assistant.": "You're a helpful assistant.",
|
||||
"You're now logged in.": "You're now logged in."
|
||||
"You're now logged in.": "You're now logged in.",
|
||||
"PDF Extract Images (OCR)": "PDF Extract Images (OCR)"
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue