Unverified Commit b8d7fdf1 authored by Timothy Jaeryang Baek's avatar Timothy Jaeryang Baek Committed by GitHub
Browse files

Merge pull request #1965 from open-webui/dev

0.1.124
parents 30b05311 b44ae536
apiVersion: v2
name: open-webui
version: 1.0.0
appVersion: "latest"
home: https://www.openwebui.com/
icon: https://raw.githubusercontent.com/open-webui/open-webui/main/static/favicon.png
description: "Open WebUI: A User-Friendly Web Interface for Chat Interactions 👋"
keywords:
- llm
- chat
- web-ui
sources:
- https://github.com/open-webui/open-webui/tree/main/kubernetes/helm
- https://hub.docker.com/r/ollama/ollama
- https://github.com/open-webui/open-webui/pkgs/container/open-webui
annotations:
licenses: MIT
# Helm Charts
Open WebUI Helm Charts are now hosted in a separate repo, which can be found here: https://github.com/open-webui/helm-charts
The charts are released at https://helm.openwebui.com.
\ No newline at end of file
{{- define "open-webui.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end -}}
{{- define "ollama.name" -}}
ollama
{{- end -}}
{{- define "ollama.url" -}}
{{- if .Values.ollama.externalHost }}
{{- printf .Values.ollama.externalHost }}
{{- else }}
{{- printf "http://%s.%s.svc.cluster.local:%d" (include "ollama.name" .) (.Release.Namespace) (.Values.ollama.service.port | int) }}
{{- end }}
{{- end }}
{{- define "chart.name" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- define "base.labels" -}}
helm.sh/chart: {{ include "chart.name" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{- define "base.selectorLabels" -}}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
{{- define "open-webui.selectorLabels" -}}
{{ include "base.selectorLabels" . }}
app.kubernetes.io/component: {{ .Chart.Name }}
{{- end }}
{{- define "open-webui.labels" -}}
{{ include "base.labels" . }}
{{ include "open-webui.selectorLabels" . }}
{{- end }}
{{- define "ollama.selectorLabels" -}}
{{ include "base.selectorLabels" . }}
app.kubernetes.io/component: {{ include "ollama.name" . }}
{{- end }}
{{- define "ollama.labels" -}}
{{ include "base.labels" . }}
{{ include "ollama.selectorLabels" . }}
{{- end }}
{{- if not .Values.ollama.externalHost }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "ollama.name" . }}
labels:
{{- include "ollama.labels" . | nindent 4 }}
{{- with .Values.ollama.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
selector:
{{- include "ollama.selectorLabels" . | nindent 4 }}
{{- with .Values.ollama.service }}
type: {{ .type }}
ports:
- protocol: TCP
name: http
port: {{ .port }}
targetPort: http
{{- end }}
{{- end }}
{{- if not .Values.ollama.externalHost }}
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ include "ollama.name" . }}
labels:
{{- include "ollama.labels" . | nindent 4 }}
{{- with .Values.ollama.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
serviceName: {{ include "ollama.name" . }}
replicas: {{ .Values.ollama.replicaCount }}
selector:
matchLabels:
{{- include "ollama.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "ollama.labels" . | nindent 8 }}
{{- with .Values.ollama.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
enableServiceLinks: false
automountServiceAccountToken: false
{{- with .Values.ollama.runtimeClassName }}
runtimeClassName: {{ . }}
{{- end }}
containers:
- name: {{ include "ollama.name" . }}
{{- with .Values.ollama.image }}
image: {{ .repository }}:{{ .tag }}
imagePullPolicy: {{ .pullPolicy }}
{{- end }}
tty: true
ports:
- name: http
containerPort: {{ .Values.ollama.service.containerPort }}
env:
{{- if .Values.ollama.gpu.enabled }}
- name: PATH
value: /usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- name: LD_LIBRARY_PATH
value: /usr/local/nvidia/lib:/usr/local/nvidia/lib64
- name: NVIDIA_DRIVER_CAPABILITIES
value: compute,utility
{{- end }}
{{- with .Values.ollama.resources }}
resources: {{- toYaml . | nindent 10 }}
{{- end }}
volumeMounts:
- name: data
mountPath: /root/.ollama
{{- with .Values.ollama.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.ollama.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
{{- if and .Values.ollama.persistence.enabled .Values.ollama.persistence.existingClaim }}
- name: data
persistentVolumeClaim:
claimName: {{ .Values.ollama.persistence.existingClaim }}
{{- else if not .Values.ollama.persistence.enabled }}
- name: data
emptyDir: {}
{{- else if and .Values.ollama.persistence.enabled (not .Values.ollama.persistence.existingClaim) }}
[]
volumeClaimTemplates:
- metadata:
name: data
labels:
{{- include "ollama.selectorLabels" . | nindent 8 }}
{{- with .Values.ollama.persistence.annotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
accessModes:
{{- range .Values.ollama.persistence.accessModes }}
- {{ . | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.ollama.persistence.size | quote }}
storageClassName: {{ .Values.ollama.persistence.storageClass }}
{{- with .Values.ollama.persistence.selector }}
selector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
{{- end }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "open-webui.name" . }}
labels:
{{- include "open-webui.labels" . | nindent 4 }}
{{- with .Values.webui.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.webui.replicaCount }}
selector:
matchLabels:
{{- include "open-webui.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "open-webui.labels" . | nindent 8 }}
{{- with .Values.webui.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
enableServiceLinks: false
automountServiceAccountToken: false
containers:
- name: {{ .Chart.Name }}
{{- with .Values.webui.image }}
image: {{ .repository }}:{{ .tag | default $.Chart.AppVersion }}
imagePullPolicy: {{ .pullPolicy }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.webui.service.containerPort }}
{{- with .Values.webui.resources }}
resources: {{- toYaml . | nindent 10 }}
{{- end }}
volumeMounts:
- name: data
mountPath: /app/backend/data
env:
- name: OLLAMA_BASE_URL
value: {{ include "ollama.url" . | quote }}
tty: true
{{- with .Values.webui.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
{{- if and .Values.webui.persistence.enabled .Values.webui.persistence.existingClaim }}
- name: data
persistentVolumeClaim:
claimName: {{ .Values.webui.persistence.existingClaim }}
{{- else if not .Values.webui.persistence.enabled }}
- name: data
emptyDir: {}
{{- else if and .Values.webui.persistence.enabled (not .Values.webui.persistence.existingClaim) }}
- name: data
persistentVolumeClaim:
claimName: {{ include "open-webui.name" . }}
{{- end }}
{{- if .Values.webui.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "open-webui.name" . }}
labels:
{{- include "open-webui.labels" . | nindent 4 }}
{{- with .Values.webui.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.webui.ingress.class }}
ingressClassName: {{ . }}
{{- end }}
{{- if .Values.webui.ingress.tls }}
tls:
- hosts:
- {{ .Values.webui.ingress.host | quote }}
secretName: {{ default (printf "%s-tls" .Release.Name) .Values.webui.ingress.existingSecret }}
{{- end }}
rules:
- host: {{ .Values.webui.ingress.host }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ include "open-webui.name" . }}
port:
name: http
{{- end }}
{{- if and .Values.webui.persistence.enabled (not .Values.webui.persistence.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "open-webui.name" . }}
labels:
{{- include "open-webui.selectorLabels" . | nindent 4 }}
{{- with .Values.webui.persistence.annotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
accessModes:
{{- range .Values.webui.persistence.accessModes }}
- {{ . | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.webui.persistence.size }}
{{- if .Values.webui.persistence.storageClass }}
storageClassName: {{ .Values.webui.persistence.storageClass }}
{{- end }}
{{- with .Values.webui.persistence.selector }}
selector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "open-webui.name" . }}
labels:
{{- include "open-webui.labels" . | nindent 4 }}
{{- with .Values.webui.service.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.webui.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
selector:
{{- include "open-webui.selectorLabels" . | nindent 4 }}
type: {{ .Values.webui.service.type | default "ClusterIP" }}
ports:
- protocol: TCP
name: http
port: {{ .Values.webui.service.port }}
targetPort: http
{{- if .Values.webui.service.nodePort }}
nodePort: {{ .Values.webui.service.nodePort | int }}
{{- end }}
{{- if .Values.webui.service.loadBalancerClass }}
loadBalancerClass: {{ .Values.webui.service.loadBalancerClass | quote }}
{{- end }}
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: ""
{ {
"name": "open-webui", "name": "open-webui",
"version": "0.1.123", "version": "0.1.124",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "open-webui", "name": "open-webui",
"version": "0.1.123", "version": "0.1.124",
"dependencies": { "dependencies": {
"@sveltejs/adapter-node": "^1.3.1", "@sveltejs/adapter-node": "^1.3.1",
"async": "^3.2.5", "async": "^3.2.5",
......
{ {
"name": "open-webui", "name": "open-webui",
"version": "0.1.123", "version": "0.1.124",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite dev --host", "dev": "vite dev --host",
......
...@@ -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
(() => { (() => {
......
...@@ -30,6 +30,8 @@ export const getAudioConfig = async (token: string) => { ...@@ -30,6 +30,8 @@ export const getAudioConfig = async (token: string) => {
type OpenAIConfigForm = { type OpenAIConfigForm = {
url: string; url: string;
key: string; key: string;
model: string;
speaker: string;
}; };
export const updateAudioConfig = async (token: string, payload: OpenAIConfigForm) => { export const updateAudioConfig = async (token: string, payload: OpenAIConfigForm) => {
...@@ -95,7 +97,8 @@ export const transcribeAudio = async (token: string, file: File) => { ...@@ -95,7 +97,8 @@ export const transcribeAudio = async (token: string, file: File) => {
export const synthesizeOpenAISpeech = async ( export const synthesizeOpenAISpeech = async (
token: string = '', token: string = '',
speaker: string = 'alloy', speaker: string = 'alloy',
text: string = '' text: string = '',
model: string = 'tts-1'
) => { ) => {
let error = null; let error = null;
...@@ -106,7 +109,7 @@ export const synthesizeOpenAISpeech = async ( ...@@ -106,7 +109,7 @@ export const synthesizeOpenAISpeech = async (
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ body: JSON.stringify({
model: 'tts-1', model: model,
input: text, input: text,
voice: speaker voice: speaker
}) })
......
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) => {
......
...@@ -239,7 +239,8 @@ export const generateOpenAIChatCompletion = async ( ...@@ -239,7 +239,8 @@ export const generateOpenAIChatCompletion = async (
export const synthesizeOpenAISpeech = async ( export const synthesizeOpenAISpeech = async (
token: string = '', token: string = '',
speaker: string = 'alloy', speaker: string = 'alloy',
text: string = '' text: string = '',
model: string = 'tts-1'
) => { ) => {
let error = null; let error = null;
...@@ -250,7 +251,7 @@ export const synthesizeOpenAISpeech = async ( ...@@ -250,7 +251,7 @@ export const synthesizeOpenAISpeech = async (
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ body: JSON.stringify({
model: 'tts-1', model: model,
input: text, input: text,
voice: speaker voice: speaker
}) })
...@@ -295,7 +296,9 @@ export const generateTitle = async ( ...@@ -295,7 +296,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 +317,5 @@ export const generateTitle = async ( ...@@ -314,5 +317,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';
}; };
...@@ -32,9 +32,16 @@ type ChunkConfigForm = { ...@@ -32,9 +32,16 @@ type ChunkConfigForm = {
chunk_overlap: number; chunk_overlap: number;
}; };
type YoutubeConfigForm = {
language: string[];
translation?: string | null;
};
type RAGConfigForm = { type RAGConfigForm = {
pdf_extract_images: boolean; pdf_extract_images?: boolean;
chunk: ChunkConfigForm; chunk?: ChunkConfigForm;
web_loader_ssl_verification?: boolean;
youtube?: YoutubeConfigForm;
}; };
export const updateRAGConfig = async (token: string, payload: RAGConfigForm) => { export const updateRAGConfig = async (token: string, payload: RAGConfigForm) => {
......
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