"...research_projects/diffusion_dpo/train_diffusion_dpo.py" did not exist on "ae060fc4f1ba8b9b9a7de35888138415808bfcd6"
Unverified Commit 68c182db authored by Timothy Jaeryang Baek's avatar Timothy Jaeryang Baek Committed by GitHub
Browse files

Merge branch 'dev' into main

parents 242e70d1 876853f2
ollama:
resources:
requests:
cpu: "2000m"
memory: "2Gi"
limits:
cpu: "4000m"
memory: "4Gi"
nvidia.com/gpu: "0"
service:
type: ClusterIP
gpu:
enabled: false
webui:
resources:
requests:
cpu: "500m"
memory: "500Mi"
limits:
cpu: "1000m"
memory: "1Gi"
ingress:
enabled: true
host: open-webui.minikube.local
service:
type: NodePort
nameOverride: ""
ollama:
externalHost: ""
annotations: {}
podAnnotations: {}
replicaCount: 1
image:
repository: ollama/ollama
tag: latest
pullPolicy: Always
resources: {}
persistence:
enabled: true
size: 30Gi
existingClaim: ""
accessModes:
- ReadWriteOnce
storageClass: ""
selector: {}
annotations: {}
nodeSelector: {}
# -- If using a special runtime container such as nvidia, set it here.
runtimeClassName: ""
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
service:
type: ClusterIP
annotations: {}
port: 80
containerPort: 11434
gpu:
# -- Enable additional ENV values to help Ollama discover GPU usage
enabled: false
webui:
annotations: {}
podAnnotations: {}
replicaCount: 1
image:
repository: ghcr.io/open-webui/open-webui
tag: ""
pullPolicy: Always
resources: {}
ingress:
enabled: false
class: ""
# -- Use appropriate annotations for your Ingress controller, e.g., for NGINX:
# nginx.ingress.kubernetes.io/rewrite-target: /
annotations: {}
host: ""
tls: false
existingSecret: ""
persistence:
enabled: true
size: 2Gi
existingClaim: ""
# -- If using multiple replicas, you must update accessModes to ReadWriteMany
accessModes:
- ReadWriteOnce
storageClass: ""
selector: {}
annotations: {}
nodeSelector: {}
tolerations: []
service:
type: ClusterIP
annotations: {}
port: 80
containerPort: 8080
nodePort: ""
labels: {}
loadBalancerClass: ""
...@@ -82,3 +82,12 @@ select { ...@@ -82,3 +82,12 @@ select {
.katex-mathml { .katex-mathml {
display: none; display: none;
} }
.scrollbar-none:active::-webkit-scrollbar-thumb,
.scrollbar-none:focus::-webkit-scrollbar-thumb,
.scrollbar-none:hover::-webkit-scrollbar-thumb {
visibility: visible;
}
.scrollbar-none::-webkit-scrollbar-thumb {
visibility: hidden;
}
...@@ -6,6 +6,12 @@ ...@@ -6,6 +6,12 @@
<link rel="manifest" href="%sveltekit.assets%/manifest.json" crossorigin="use-credentials" /> <link rel="manifest" href="%sveltekit.assets%/manifest.json" crossorigin="use-credentials" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<meta name="robots" content="noindex,nofollow" /> <meta name="robots" content="noindex,nofollow" />
<link
rel="search"
type="application/opensearchdescription+xml"
title="Open WebUI"
href="/opensearch.xml"
/>
<script> <script>
// On page load or when changing themes, best to add inline in `head` to avoid FOUC // On page load or when changing themes, best to add inline in `head` to avoid FOUC
(() => { (() => {
......
import { WEBUI_API_BASE_URL } from '$lib/constants'; import { WEBUI_API_BASE_URL } from '$lib/constants';
import { getTimeRange } from '$lib/utils';
export const createNewChat = async (token: string, chat: object) => { export const createNewChat = async (token: string, chat: object) => {
let error = null; let error = null;
...@@ -59,7 +60,10 @@ export const getChatList = async (token: string = '') => { ...@@ -59,7 +60,10 @@ export const getChatList = async (token: string = '') => {
throw error; throw error;
} }
return res; return res.map((chat) => ({
...chat,
time_range: getTimeRange(chat.updated_at)
}));
}; };
export const getChatListByUserId = async (token: string = '', userId: string) => { export const getChatListByUserId = async (token: string = '', userId: string) => {
...@@ -90,7 +94,10 @@ export const getChatListByUserId = async (token: string = '', userId: string) => ...@@ -90,7 +94,10 @@ export const getChatListByUserId = async (token: string = '', userId: string) =>
throw error; throw error;
} }
return res; return res.map((chat) => ({
...chat,
time_range: getTimeRange(chat.updated_at)
}));
}; };
export const getArchivedChatList = async (token: string = '') => { export const getArchivedChatList = async (token: string = '') => {
...@@ -220,13 +227,16 @@ export const getAllChatTags = async (token: string) => { ...@@ -220,13 +227,16 @@ export const getAllChatTags = async (token: string) => {
export const getChatListByTagName = async (token: string = '', tagName: string) => { export const getChatListByTagName = async (token: string = '', tagName: string) => {
let error = null; let error = null;
const res = await fetch(`${WEBUI_API_BASE_URL}/chats/tags/tag/${tagName}`, { const res = await fetch(`${WEBUI_API_BASE_URL}/chats/tags`, {
method: 'GET', method: 'POST',
headers: { headers: {
Accept: 'application/json', Accept: 'application/json',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
...(token && { authorization: `Bearer ${token}` }) ...(token && { authorization: `Bearer ${token}` })
} },
body: JSON.stringify({
name: tagName
})
}) })
.then(async (res) => { .then(async (res) => {
if (!res.ok) throw await res.json(); if (!res.ok) throw await res.json();
...@@ -245,7 +255,10 @@ export const getChatListByTagName = async (token: string = '', tagName: string) ...@@ -245,7 +255,10 @@ export const getChatListByTagName = async (token: string = '', tagName: string)
throw error; throw error;
} }
return res; return res.map((chat) => ({
...chat,
time_range: getTimeRange(chat.updated_at)
}));
}; };
export const getChatById = async (token: string, id: string) => { export const getChatById = async (token: string, id: string) => {
......
...@@ -159,7 +159,11 @@ export const generateTitle = async ( ...@@ -159,7 +159,11 @@ export const generateTitle = async (
body: JSON.stringify({ body: JSON.stringify({
model: model, model: model,
prompt: template, prompt: template,
stream: false stream: false,
options: {
// Restrict the number of tokens generated to 50
num_predict: 50
}
}) })
}) })
.then(async (res) => { .then(async (res) => {
...@@ -178,7 +182,7 @@ export const generateTitle = async ( ...@@ -178,7 +182,7 @@ export const generateTitle = async (
throw error; throw error;
} }
return res?.response ?? 'New Chat'; return res?.response.replace(/["']/g, '') ?? 'New Chat';
}; };
export const generatePrompt = async (token: string = '', model: string, conversation: string) => { export const generatePrompt = async (token: string = '', model: string, conversation: string) => {
......
...@@ -295,7 +295,9 @@ export const generateTitle = async ( ...@@ -295,7 +295,9 @@ export const generateTitle = async (
content: template content: template
} }
], ],
stream: false stream: false,
// Restricting the max tokens to 50 to avoid long titles
max_tokens: 50
}) })
}) })
.then(async (res) => { .then(async (res) => {
...@@ -314,5 +316,5 @@ export const generateTitle = async ( ...@@ -314,5 +316,5 @@ export const generateTitle = async (
throw error; throw error;
} }
return res?.choices[0]?.message?.content ?? 'New Chat'; return res?.choices[0]?.message?.content.replace(/["']/g, '') ?? 'New Chat';
}; };
...@@ -33,8 +33,9 @@ type ChunkConfigForm = { ...@@ -33,8 +33,9 @@ type ChunkConfigForm = {
}; };
type RAGConfigForm = { type RAGConfigForm = {
pdf_extract_images: boolean; pdf_extract_images?: boolean;
chunk: ChunkConfigForm; chunk?: ChunkConfigForm;
web_loader_ssl_verification?: boolean;
}; };
export const updateRAGConfig = async (token: string, payload: RAGConfigForm) => { export const updateRAGConfig = async (token: string, payload: RAGConfigForm) => {
......
...@@ -4,6 +4,8 @@ import type { ParsedEvent } from 'eventsource-parser'; ...@@ -4,6 +4,8 @@ import type { ParsedEvent } from 'eventsource-parser';
type TextStreamUpdate = { type TextStreamUpdate = {
done: boolean; done: boolean;
value: string; value: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
citations?: any;
}; };
// createOpenAITextStream takes a responseBody with a SSE response, // createOpenAITextStream takes a responseBody with a SSE response,
...@@ -45,6 +47,11 @@ async function* openAIStreamToIterator( ...@@ -45,6 +47,11 @@ async function* openAIStreamToIterator(
const parsedData = JSON.parse(data); const parsedData = JSON.parse(data);
console.log(parsedData); console.log(parsedData);
if (parsedData.citations) {
yield { done: false, value: '', citations: parsedData.citations };
continue;
}
yield { done: false, value: parsedData.choices?.[0]?.delta?.content ?? '' }; yield { done: false, value: parsedData.choices?.[0]?.delta?.content ?? '' };
} catch (e) { } catch (e) {
console.error('Error extracting delta from SSE event:', e); console.error('Error extracting delta from SSE event:', e);
...@@ -62,6 +69,10 @@ async function* streamLargeDeltasAsRandomChunks( ...@@ -62,6 +69,10 @@ async function* streamLargeDeltasAsRandomChunks(
yield textStreamUpdate; yield textStreamUpdate;
return; return;
} }
if (textStreamUpdate.citations) {
yield textStreamUpdate;
continue;
}
let content = textStreamUpdate.value; let content = textStreamUpdate.value;
if (content.length < 5) { if (content.length < 5) {
yield { done: false, value: content }; yield { done: false, value: content };
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
</script> </script>
<Modal bind:show> <Modal bind:show>
<div class="px-5 py-4 dark:text-gray-300 text-gray-700"> <div class="px-5 pt-4 dark:text-gray-300 text-gray-700">
<div class="flex justify-between items-start"> <div class="flex justify-between items-start">
<div class="text-xl font-bold"> <div class="text-xl font-bold">
{$i18n.t('What’s New in')} {$i18n.t('What’s New in')}
...@@ -57,10 +57,8 @@ ...@@ -57,10 +57,8 @@
</div> </div>
</div> </div>
<hr class=" dark:border-gray-800" />
<div class=" w-full p-4 px-5 text-gray-700 dark:text-gray-100"> <div class=" w-full p-4 px-5 text-gray-700 dark:text-gray-100">
<div class=" overflow-y-scroll max-h-80"> <div class=" overflow-y-scroll max-h-80 scrollbar-none">
<div class="mb-3"> <div class="mb-3">
{#if changelog} {#if changelog}
{#each Object.keys(changelog) as version} {#each Object.keys(changelog) as version}
......
...@@ -107,7 +107,7 @@ ...@@ -107,7 +107,7 @@
reader.readAsText(file); reader.readAsText(file);
} else { } else {
toast.error(`File not found.`); toast.error($i18n.t('File not found.'));
} }
} }
}; };
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
{ {
name: 'All Documents', name: 'All Documents',
type: 'collection', type: 'collection',
title: 'All Documents', title: $i18n.t('All Documents'),
collection_names: $documents.map((doc) => doc.collection_name) collection_names: $documents.map((doc) => doc.collection_name)
} }
] ]
......
<script lang="ts"> <script lang="ts">
import Bolt from '$lib/components/icons/Bolt.svelte'; import Bolt from '$lib/components/icons/Bolt.svelte';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
const i18n = getContext('i18n');
export let submitPrompt: Function; export let submitPrompt: Function;
export let suggestionPrompts = []; export let suggestionPrompts = [];
...@@ -33,7 +35,7 @@ ...@@ -33,7 +35,7 @@
{#if prompts.length > 0} {#if prompts.length > 0}
<div class="mb-2 flex gap-1 text-sm font-medium items-center text-gray-400 dark:text-gray-600"> <div class="mb-2 flex gap-1 text-sm font-medium items-center text-gray-400 dark:text-gray-600">
<Bolt /> <Bolt />
Suggested {$i18n.t('Suggested')}
</div> </div>
{/if} {/if}
...@@ -71,7 +73,7 @@ ...@@ -71,7 +73,7 @@
<div <div
class="text-xs text-gray-400 group-hover:text-gray-500 dark:text-gray-600 dark:group-hover:text-gray-500 transition self-center" class="text-xs text-gray-400 group-hover:text-gray-500 dark:text-gray-600 dark:group-hover:text-gray-500 transition self-center"
> >
Prompt {$i18n.t('Prompt')}
</div> </div>
<div <div
......
<script lang="ts">
import { getContext, onMount, tick } from 'svelte';
import Modal from '$lib/components/common/Modal.svelte';
const i18n = getContext('i18n');
export let show = false;
export let citation;
let mergedDocuments = [];
$: if (citation) {
mergedDocuments = citation.document?.map((c, i) => {
return {
source: citation.source,
document: c,
metadata: citation.metadata?.[i]
};
});
}
</script>
<Modal size="lg" bind:show>
<div>
<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-2">
<div class=" text-lg font-medium self-center capitalize">
{$i18n.t('Citation')}
</div>
<button
class="self-center"
on:click={() => {
show = false;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-5 h-5"
>
<path
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
/>
</svg>
</button>
</div>
<div class="flex flex-col md:flex-row w-full px-6 pb-5 md:space-x-4">
<div
class="flex flex-col w-full dark:text-gray-200 overflow-y-scroll max-h-[22rem] scrollbar-none"
>
{#each mergedDocuments as document, documentIdx}
<div class="flex flex-col w-full">
<div class="text-sm font-medium dark:text-gray-300">
{$i18n.t('Source')}
</div>
<div class="text-sm dark:text-gray-400">
{document.source?.name ?? $i18n.t('No source available')}
</div>
</div>
<div class="flex flex-col w-full">
<div class=" text-sm font-medium dark:text-gray-300">
{$i18n.t('Content')}
</div>
<pre class="text-sm dark:text-gray-400 whitespace-pre-line">
{document.document}
</pre>
</div>
{#if documentIdx !== mergedDocuments.length - 1}
<hr class=" dark:border-gray-850 my-3" />
{/if}
{/each}
</div>
</div>
</div>
</Modal>
...@@ -123,7 +123,7 @@ ...@@ -123,7 +123,7 @@
submitHandler(); submitHandler();
}} }}
> >
Submit {$i18n.t('Submit')}
</button> </button>
</div> </div>
</div> </div>
...@@ -23,15 +23,16 @@ ...@@ -23,15 +23,16 @@
revertSanitizedResponseContent, revertSanitizedResponseContent,
sanitizeResponseContent sanitizeResponseContent
} from '$lib/utils'; } from '$lib/utils';
import { WEBUI_BASE_URL } from '$lib/constants';
import Name from './Name.svelte'; import Name from './Name.svelte';
import ProfileImage from './ProfileImage.svelte'; import ProfileImage from './ProfileImage.svelte';
import Skeleton from './Skeleton.svelte'; import Skeleton from './Skeleton.svelte';
import CodeBlock from './CodeBlock.svelte'; import CodeBlock from './CodeBlock.svelte';
import Image from '$lib/components/common/Image.svelte'; import Image from '$lib/components/common/Image.svelte';
import { WEBUI_BASE_URL } from '$lib/constants';
import Tooltip from '$lib/components/common/Tooltip.svelte'; import Tooltip from '$lib/components/common/Tooltip.svelte';
import RateComment from './RateComment.svelte'; import RateComment from './RateComment.svelte';
import CitationsModal from '$lib/components/chat/Messages/CitationsModal.svelte';
export let modelfiles = []; export let modelfiles = [];
export let message; export let message;
...@@ -65,6 +66,9 @@ ...@@ -65,6 +66,9 @@
let showRateComment = false; let showRateComment = false;
let showCitationModal = false;
let selectedCitation = null;
$: tokens = marked.lexer(sanitizeResponseContent(message.content)); $: tokens = marked.lexer(sanitizeResponseContent(message.content));
const renderer = new marked.Renderer(); const renderer = new marked.Renderer();
...@@ -324,6 +328,8 @@ ...@@ -324,6 +328,8 @@
}); });
</script> </script>
<CitationsModal bind:show={showCitationModal} citation={selectedCitation} />
{#key message.id} {#key message.id}
<div class=" flex w-full message-{message.id}" id="message-{message.id}"> <div class=" flex w-full message-{message.id}" id="message-{message.id}">
<ProfileImage <ProfileImage
...@@ -442,6 +448,44 @@ ...@@ -442,6 +448,44 @@
<!-- {@html marked(message.content.replaceAll('\\', '\\\\'))} --> <!-- {@html marked(message.content.replaceAll('\\', '\\\\'))} -->
{/if} {/if}
{#if message.citations}
<hr class=" dark:border-gray-800 my-1" />
<div class="my-2.5 w-full flex flex-col gap-1">
{#each message.citations.reduce((acc, citation) => {
citation.document.forEach((document, index) => {
const metadata = citation.metadata?.[index];
const id = metadata?.source ?? 'N/A';
const existingSource = acc.find((item) => item.id === id);
if (existingSource) {
existingSource.document.push(document);
existingSource.metadata.push(metadata);
} else {
acc.push( { id: id, source: citation?.source, document: [document], metadata: metadata ? [metadata] : [] } );
}
});
return acc;
}, []) as citation, idx}
<div class="flex gap-1 text-xs font-semibold">
<div>
[{idx + 1}]
</div>
<button
class="dark:text-gray-500 underline"
on:click={() => {
showCitationModal = true;
selectedCitation = citation;
}}
>
{citation.source.name}
</button>
</div>
{/each}
</div>
{/if}
{#if message.done} {#if message.done}
<div <div
class=" flex justify-start space-x-1 overflow-x-auto buttons text-gray-700 dark:text-gray-500" class=" flex justify-start space-x-1 overflow-x-auto buttons text-gray-700 dark:text-gray-500"
......
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
</div> </div>
{:else} {:else}
<div class=" self-center disabled:text-gray-600 disabled:hover:text-gray-600 mr-2"> <div class=" self-center disabled:text-gray-600 disabled:hover:text-gray-600 mr-2">
<Tooltip content="Remove Model"> <Tooltip content={$i18n.t('Remove Model')}>
<button <button
{disabled} {disabled}
on:click={() => { on:click={() => {
......
...@@ -151,7 +151,7 @@ ...@@ -151,7 +151,7 @@
models.set(await getModels(localStorage.token)); models.set(await getModels(localStorage.token));
} else { } else {
toast.error('Download canceled'); toast.error($i18n.t('Download canceled'));
} }
delete $MODEL_DOWNLOAD_POOL[sanitizedModelTag]; delete $MODEL_DOWNLOAD_POOL[sanitizedModelTag];
...@@ -305,7 +305,7 @@ ...@@ -305,7 +305,7 @@
{:else} {:else}
<div> <div>
<div class="block px-3 py-2 text-sm text-gray-700 dark:text-gray-100"> <div class="block px-3 py-2 text-sm text-gray-700 dark:text-gray-100">
No results found {$i18n.t('No results found')}
</div> </div>
</div> </div>
{/each} {/each}
...@@ -317,7 +317,7 @@ ...@@ -317,7 +317,7 @@
pullModelHandler(); pullModelHandler();
}} }}
> >
Pull "{searchValue}" from Ollama.com {$i18n.t(`Pull "{{searchValue}}" from Ollama.com`, { searchValue: searchValue })}
</button> </button>
{/if} {/if}
...@@ -368,7 +368,7 @@ ...@@ -368,7 +368,7 @@
</div> </div>
<div class="mr-2 translate-y-0.5"> <div class="mr-2 translate-y-0.5">
<Tooltip content="Cancel"> <Tooltip content={$i18n.t('Cancel')}>
<button <button
class="text-gray-800 dark:text-gray-100" class="text-gray-800 dark:text-gray-100"
on:click={() => { on:click={() => {
......
...@@ -447,7 +447,7 @@ ...@@ -447,7 +447,7 @@
{/if} {/if}
</button> </button>
<Tooltip content="Create new key"> <Tooltip content={$i18n.t('Create new key')}>
<button <button
class=" px-1.5 py-1 dark:hover:bg-gray-850transition rounded-lg" class=" px-1.5 py-1 dark:hover:bg-gray-850transition rounded-lg"
on:click={() => { on:click={() => {
...@@ -479,7 +479,7 @@ ...@@ -479,7 +479,7 @@
> >
<Plus strokeWidth="2" className=" size-3.5" /> <Plus strokeWidth="2" className=" size-3.5" />
Create new secret key</button {$i18n.t('Create new secret key')}</button
> >
{/if} {/if}
</div> </div>
......
...@@ -164,7 +164,7 @@ ...@@ -164,7 +164,7 @@
<div class="flex gap-1.5"> <div class="flex gap-1.5">
<input <input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none" class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
placeholder="Enter URL (e.g. http://localhost:11434)" placeholder={$i18n.t('Enter URL (e.g. http://localhost:11434)')}
bind:value={url} bind:value={url}
/> />
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment