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

Merge pull request #4434 from open-webui/dev

0.3.13
parents 8d257ed5 c8badfe2
...@@ -134,8 +134,10 @@ ...@@ -134,8 +134,10 @@
"Continue Response": "Продовжити відповідь", "Continue Response": "Продовжити відповідь",
"Continue with {{provider}}": "Продовжити з {{provider}}", "Continue with {{provider}}": "Продовжити з {{provider}}",
"Controls": "Керування", "Controls": "Керування",
"Copied": "Скопійовано",
"Copied shared chat URL to clipboard!": "Скопійовано URL-адресу спільного чату в буфер обміну!", "Copied shared chat URL to clipboard!": "Скопійовано URL-адресу спільного чату в буфер обміну!",
"Copy": "Копіювати", "Copy": "Копіювати",
"Copy Code": "Копіювати код",
"Copy last code block": "Копіювати останній блок коду", "Copy last code block": "Копіювати останній блок коду",
"Copy last response": "Копіювати останню відповідь", "Copy last response": "Копіювати останню відповідь",
"Copy Link": "Копіювати посилання", "Copy Link": "Копіювати посилання",
...@@ -312,6 +314,7 @@ ...@@ -312,6 +314,7 @@
"Google PSE API Key": "Ключ API Google PSE", "Google PSE API Key": "Ключ API Google PSE",
"Google PSE Engine Id": "Id рушія Google PSE", "Google PSE Engine Id": "Id рушія Google PSE",
"h:mm a": "h:mm a", "h:mm a": "h:mm a",
"Haptic Feedback": "",
"has no conversations.": "не має розмов.", "has no conversations.": "не має розмов.",
"Hello, {{name}}": "Привіт, {{name}}", "Hello, {{name}}": "Привіт, {{name}}",
"Help": "Допоможіть", "Help": "Допоможіть",
...@@ -375,7 +378,7 @@ ...@@ -375,7 +378,7 @@
"Memory deleted successfully": "Пам'ять успішно видалено", "Memory deleted successfully": "Пам'ять успішно видалено",
"Memory updated successfully": "Пам'ять успішно оновлено", "Memory updated successfully": "Пам'ять успішно оновлено",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Повідомлення, які ви надішлете після створення посилання, не будуть доступні для інших. Користувачі, які мають URL, зможуть переглядати спільний чат.", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Повідомлення, які ви надішлете після створення посилання, не будуть доступні для інших. Користувачі, які мають URL, зможуть переглядати спільний чат.",
"Min P": "", "Min P": "Min P",
"Minimum Score": "Мінімальний бал", "Minimum Score": "Мінімальний бал",
"Mirostat": "Mirostat", "Mirostat": "Mirostat",
"Mirostat Eta": "Mirostat Eta", "Mirostat Eta": "Mirostat Eta",
...@@ -416,6 +419,7 @@ ...@@ -416,6 +419,7 @@
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Примітка: Якщо ви встановите мінімальну кількість балів, пошук поверне лише документи з кількістю балів, більшою або рівною мінімальній кількості балів.", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Примітка: Якщо ви встановите мінімальну кількість балів, пошук поверне лише документи з кількістю балів, більшою або рівною мінімальній кількості балів.",
"Notifications": "Сповіщення", "Notifications": "Сповіщення",
"November": "Листопад", "November": "Листопад",
"num_gpu (Ollama)": "",
"num_thread (Ollama)": "num_thread (Ollama)", "num_thread (Ollama)": "num_thread (Ollama)",
"OAuth ID": "OAuth ID", "OAuth ID": "OAuth ID",
"October": "Жовтень", "October": "Жовтень",
...@@ -499,6 +503,7 @@ ...@@ -499,6 +503,7 @@
"Rosé Pine": "Rosé Pine", "Rosé Pine": "Rosé Pine",
"Rosé Pine Dawn": "Rosé Pine Dawn", "Rosé Pine Dawn": "Rosé Pine Dawn",
"RTL": "RTL", "RTL": "RTL",
"Run": "Запустити",
"Run Llama 2, Code Llama, and other models. Customize and create your own.": "Запустіть Llama 2, Code Llama та інші моделі. Налаштуйте та створіть власну.", "Run Llama 2, Code Llama, and other models. Customize and create your own.": "Запустіть Llama 2, Code Llama та інші моделі. Налаштуйте та створіть власну.",
"Running": "Виконується", "Running": "Виконується",
"Save": "Зберегти", "Save": "Зберегти",
...@@ -509,7 +514,7 @@ ...@@ -509,7 +514,7 @@
"Scan": "Сканування", "Scan": "Сканування",
"Scan complete!": "Сканування завершено!", "Scan complete!": "Сканування завершено!",
"Scan for documents from {{path}}": "Сканування документів з {{path}}", "Scan for documents from {{path}}": "Сканування документів з {{path}}",
"Scroll to bottom when switching between branches": "", "Scroll to bottom when switching between branches": "Перемотувати до кінця при перемиканні між гілками",
"Search": "Пошук", "Search": "Пошук",
"Search a model": "Шукати модель", "Search a model": "Шукати модель",
"Search Chats": "Пошук в чатах", "Search Chats": "Пошук в чатах",
......
...@@ -134,8 +134,10 @@ ...@@ -134,8 +134,10 @@
"Continue Response": "Tiếp tục trả lời", "Continue Response": "Tiếp tục trả lời",
"Continue with {{provider}}": "Tiếp tục với {{provider}}", "Continue with {{provider}}": "Tiếp tục với {{provider}}",
"Controls": "", "Controls": "",
"Copied": "",
"Copied shared chat URL to clipboard!": "Đã sao chép link chia sẻ trò chuyện vào clipboard!", "Copied shared chat URL to clipboard!": "Đã sao chép link chia sẻ trò chuyện vào clipboard!",
"Copy": "Sao chép", "Copy": "Sao chép",
"Copy Code": "",
"Copy last code block": "Sao chép khối mã cuối cùng", "Copy last code block": "Sao chép khối mã cuối cùng",
"Copy last response": "Sao chép phản hồi cuối cùng", "Copy last response": "Sao chép phản hồi cuối cùng",
"Copy Link": "Sao chép link", "Copy Link": "Sao chép link",
...@@ -312,6 +314,7 @@ ...@@ -312,6 +314,7 @@
"Google PSE API Key": "Khóa API Google PSE", "Google PSE API Key": "Khóa API Google PSE",
"Google PSE Engine Id": "ID công cụ Google PSE", "Google PSE Engine Id": "ID công cụ Google PSE",
"h:mm a": "h:mm a", "h:mm a": "h:mm a",
"Haptic Feedback": "",
"has no conversations.": "không có hội thoại", "has no conversations.": "không có hội thoại",
"Hello, {{name}}": "Xin chào {{name}}", "Hello, {{name}}": "Xin chào {{name}}",
"Help": "Trợ giúp", "Help": "Trợ giúp",
...@@ -416,6 +419,7 @@ ...@@ -416,6 +419,7 @@
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Lưu ý: Nếu bạn đặt điểm (Score) tối thiểu thì tìm kiếm sẽ chỉ trả về những tài liệu có điểm lớn hơn hoặc bằng điểm tối thiểu.", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Lưu ý: Nếu bạn đặt điểm (Score) tối thiểu thì tìm kiếm sẽ chỉ trả về những tài liệu có điểm lớn hơn hoặc bằng điểm tối thiểu.",
"Notifications": "Thông báo trên máy tính (Notification)", "Notifications": "Thông báo trên máy tính (Notification)",
"November": "Tháng 11", "November": "Tháng 11",
"num_gpu (Ollama)": "",
"num_thread (Ollama)": "num_thread (Ollama)", "num_thread (Ollama)": "num_thread (Ollama)",
"OAuth ID": "", "OAuth ID": "",
"October": "Tháng 10", "October": "Tháng 10",
...@@ -499,6 +503,7 @@ ...@@ -499,6 +503,7 @@
"Rosé Pine": "Rosé Pine", "Rosé Pine": "Rosé Pine",
"Rosé Pine Dawn": "Rosé Pine Dawn", "Rosé Pine Dawn": "Rosé Pine Dawn",
"RTL": "RTL", "RTL": "RTL",
"Run": "",
"Run Llama 2, Code Llama, and other models. Customize and create your own.": "Chạy Llama 2, Code Llama và các mô hình khác. Tùy chỉnh hoặc mô hình riêng của bạn.", "Run Llama 2, Code Llama, and other models. Customize and create your own.": "Chạy Llama 2, Code Llama và các mô hình khác. Tùy chỉnh hoặc mô hình riêng của bạn.",
"Running": "Đang chạy", "Running": "Đang chạy",
"Save": "Lưu", "Save": "Lưu",
......
...@@ -134,8 +134,10 @@ ...@@ -134,8 +134,10 @@
"Continue Response": "继续生成", "Continue Response": "继续生成",
"Continue with {{provider}}": "使用 {{provider}} 继续", "Continue with {{provider}}": "使用 {{provider}} 继续",
"Controls": "对话高级设置", "Controls": "对话高级设置",
"Copied": "已复制",
"Copied shared chat URL to clipboard!": "已复制此对话分享链接至剪贴板!", "Copied shared chat URL to clipboard!": "已复制此对话分享链接至剪贴板!",
"Copy": "复制", "Copy": "复制",
"Copy Code": "复制代码",
"Copy last code block": "复制最后一个代码块中的代码", "Copy last code block": "复制最后一个代码块中的代码",
"Copy last response": "复制最后一次回复内容", "Copy last response": "复制最后一次回复内容",
"Copy Link": "复制链接", "Copy Link": "复制链接",
...@@ -312,6 +314,7 @@ ...@@ -312,6 +314,7 @@
"Google PSE API Key": "Google PSE API 密钥", "Google PSE API Key": "Google PSE API 密钥",
"Google PSE Engine Id": "Google PSE 引擎 ID", "Google PSE Engine Id": "Google PSE 引擎 ID",
"h:mm a": "HH:mm", "h:mm a": "HH:mm",
"Haptic Feedback": "",
"has no conversations.": "没有对话。", "has no conversations.": "没有对话。",
"Hello, {{name}}": "您好,{{name}}", "Hello, {{name}}": "您好,{{name}}",
"Help": "帮助", "Help": "帮助",
...@@ -416,6 +419,7 @@ ...@@ -416,6 +419,7 @@
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "注意:如果设置了最低分数,搜索只会返回分数大于或等于最低分数的文档。", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "注意:如果设置了最低分数,搜索只会返回分数大于或等于最低分数的文档。",
"Notifications": "桌面通知", "Notifications": "桌面通知",
"November": "十一月", "November": "十一月",
"num_gpu (Ollama)": "",
"num_thread (Ollama)": "num_thread(Ollama)", "num_thread (Ollama)": "num_thread(Ollama)",
"OAuth ID": "OAuth ID", "OAuth ID": "OAuth ID",
"October": "十月", "October": "十月",
...@@ -499,6 +503,7 @@ ...@@ -499,6 +503,7 @@
"Rosé Pine": "Rosé Pine", "Rosé Pine": "Rosé Pine",
"Rosé Pine Dawn": "Rosé Pine Dawn", "Rosé Pine Dawn": "Rosé Pine Dawn",
"RTL": "从右至左", "RTL": "从右至左",
"Run": "运行",
"Run Llama 2, Code Llama, and other models. Customize and create your own.": "运行 Llama 2、Code Llama 和其他模型。自定义和创建您自己的模型。", "Run Llama 2, Code Llama, and other models. Customize and create your own.": "运行 Llama 2、Code Llama 和其他模型。自定义和创建您自己的模型。",
"Running": "运行中", "Running": "运行中",
"Save": "保存", "Save": "保存",
...@@ -509,7 +514,7 @@ ...@@ -509,7 +514,7 @@
"Scan": "立即扫描", "Scan": "立即扫描",
"Scan complete!": "扫描完成!", "Scan complete!": "扫描完成!",
"Scan for documents from {{path}}": "从 {{path}} 扫描文档", "Scan for documents from {{path}}": "从 {{path}} 扫描文档",
"Scroll to bottom when switching between branches": "", "Scroll to bottom when switching between branches": "在分支间切换时滚动到底部",
"Search": "搜索", "Search": "搜索",
"Search a model": "搜索模型", "Search a model": "搜索模型",
"Search Chats": "搜索对话", "Search Chats": "搜索对话",
......
...@@ -134,8 +134,10 @@ ...@@ -134,8 +134,10 @@
"Continue Response": "繼續回應", "Continue Response": "繼續回應",
"Continue with {{provider}}": "使用 {{provider}} 繼續", "Continue with {{provider}}": "使用 {{provider}} 繼續",
"Controls": "控制項", "Controls": "控制項",
"Copied": "",
"Copied shared chat URL to clipboard!": "已複製共用對話 URL 到剪貼簿!", "Copied shared chat URL to clipboard!": "已複製共用對話 URL 到剪貼簿!",
"Copy": "複製", "Copy": "複製",
"Copy Code": "",
"Copy last code block": "複製最後一個程式碼區塊", "Copy last code block": "複製最後一個程式碼區塊",
"Copy last response": "複製最後一個回應", "Copy last response": "複製最後一個回應",
"Copy Link": "複製連結", "Copy Link": "複製連結",
...@@ -312,6 +314,7 @@ ...@@ -312,6 +314,7 @@
"Google PSE API Key": "Google PSE API 金鑰", "Google PSE API Key": "Google PSE API 金鑰",
"Google PSE Engine Id": "Google PSE 引擎 ID", "Google PSE Engine Id": "Google PSE 引擎 ID",
"h:mm a": "h:mm a", "h:mm a": "h:mm a",
"Haptic Feedback": "",
"has no conversations.": "沒有對話。", "has no conversations.": "沒有對話。",
"Hello, {{name}}": "您好,{{name}}", "Hello, {{name}}": "您好,{{name}}",
"Help": "說明", "Help": "說明",
...@@ -416,6 +419,7 @@ ...@@ -416,6 +419,7 @@
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "注意:如果您設定了最低分數,則搜尋只會回傳分數大於或等於最低分數的文件。", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "注意:如果您設定了最低分數,則搜尋只會回傳分數大於或等於最低分數的文件。",
"Notifications": "通知", "Notifications": "通知",
"November": "11 月", "November": "11 月",
"num_gpu (Ollama)": "",
"num_thread (Ollama)": "num_thread (Ollama)", "num_thread (Ollama)": "num_thread (Ollama)",
"OAuth ID": "OAuth ID", "OAuth ID": "OAuth ID",
"October": "10 月", "October": "10 月",
...@@ -499,6 +503,7 @@ ...@@ -499,6 +503,7 @@
"Rosé Pine": "玫瑰松", "Rosé Pine": "玫瑰松",
"Rosé Pine Dawn": "黎明玫瑰松", "Rosé Pine Dawn": "黎明玫瑰松",
"RTL": "從右到左", "RTL": "從右到左",
"Run": "",
"Run Llama 2, Code Llama, and other models. Customize and create your own.": "執行 Llama 2、Code Llama 和其他模型。自訂並建立您自己的模型。", "Run Llama 2, Code Llama, and other models. Customize and create your own.": "執行 Llama 2、Code Llama 和其他模型。自訂並建立您自己的模型。",
"Running": "運作中", "Running": "運作中",
"Save": "儲存", "Save": "儲存",
......
...@@ -9,7 +9,7 @@ import { WEBUI_BASE_URL } from '$lib/constants'; ...@@ -9,7 +9,7 @@ import { WEBUI_BASE_URL } from '$lib/constants';
const convertLatexToSingleLine = (content) => { const convertLatexToSingleLine = (content) => {
// Patterns to match multiline LaTeX blocks // Patterns to match multiline LaTeX blocks
const patterns = [ const patterns = [
/(\$\$[\s\S]*?\$\$)/g, // Match $$ ... $$ /(\$\$\s[\s\S]*?\s\$\$)/g, // Match $$ ... $$
/(\\\[[\s\S]*?\\\])/g, // Match \[ ... \] /(\\\[[\s\S]*?\\\])/g, // Match \[ ... \]
/(\\begin\{[a-z]+\}[\s\S]*?\\end\{[a-z]+\})/g // Match \begin{...} ... \end{...} /(\\begin\{[a-z]+\}[\s\S]*?\\end\{[a-z]+\})/g // Match \begin{...} ... \end{...}
]; ];
...@@ -25,7 +25,8 @@ const convertLatexToSingleLine = (content) => { ...@@ -25,7 +25,8 @@ const convertLatexToSingleLine = (content) => {
export const sanitizeResponseContent = (content: string) => { export const sanitizeResponseContent = (content: string) => {
// replace single backslash with double backslash // replace single backslash with double backslash
content = content.replace(/\\/g, '\\\\'); content = content.replace(/\\\\/g, '\\\\\\\\');
content = convertLatexToSingleLine(content); content = convertLatexToSingleLine(content);
// First, temporarily replace valid <video> tags with a placeholder // First, temporarily replace valid <video> tags with a placeholder
...@@ -87,7 +88,7 @@ export const replaceTokens = (content, char, user) => { ...@@ -87,7 +88,7 @@ export const replaceTokens = (content, char, user) => {
}; };
export const revertSanitizedResponseContent = (content: string) => { export const revertSanitizedResponseContent = (content: string) => {
return content.replaceAll('&lt;', '<').replaceAll('&gt;', '>'); return content.replaceAll('&lt;', '<').replaceAll('&gt;', '>').replaceAll('\\\\', '\\');
}; };
export function unescapeHtml(html: string) { export function unescapeHtml(html: string) {
...@@ -226,7 +227,7 @@ export const generateInitialsImage = (name) => { ...@@ -226,7 +227,7 @@ export const generateInitialsImage = (name) => {
const initials = const initials =
sanitizedName.length > 0 sanitizedName.length > 0
? sanitizedName[0] + ? sanitizedName[0] +
(sanitizedName.split(' ').length > 1 (sanitizedName.split(' ').length > 1
? sanitizedName[sanitizedName.lastIndexOf(' ') + 1] ? sanitizedName[sanitizedName.lastIndexOf(' ') + 1]
: '') : '')
: ''; : '';
...@@ -285,7 +286,7 @@ export const compareVersion = (latest, current) => { ...@@ -285,7 +286,7 @@ export const compareVersion = (latest, current) => {
numeric: true, numeric: true,
sensitivity: 'case', sensitivity: 'case',
caseFirst: 'upper' caseFirst: 'upper'
}) < 0; }) < 0;
}; };
export const findWordIndices = (text) => { export const findWordIndices = (text) => {
......
import katex from 'katex';
const DELIMITER_LIST = [
{ left: '$$', right: '$$', display: false },
{ left: '$', right: '$', display: false },
{ left: '\\pu{', right: '}', display: false },
{ left: '\\ce{', right: '}', display: false },
{ left: '\\(', right: '\\)', display: false },
{ left: '( ', right: ' )', display: false },
{ left: '\\[', right: '\\]', display: true },
{ left: '[ ', right: ' ]', display: true }
];
// const DELIMITER_LIST = [
// { left: '$$', right: '$$', display: false },
// { left: '$', right: '$', display: false },
// ];
// const inlineRule = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\$]))\1(?=[\s?!\.,:?!。,:]|$)/;
// const blockRule = /^(\${1,2})\n((?:\\[^]|[^\\])+?)\n\1(?:\n|$)/;
let inlinePatterns = [];
let blockPatterns = [];
function escapeRegex(string) {
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}
function generateRegexRules(delimiters) {
delimiters.forEach((delimiter) => {
const { left, right } = delimiter;
// Ensure regex-safe delimiters
const escapedLeft = escapeRegex(left);
const escapedRight = escapeRegex(right);
// Inline pattern - Capture group $1, token content, followed by end delimiter and normal punctuation marks.
// Example: $text$
inlinePatterns.push(
`${escapedLeft}((?:\\\\.|[^\\\\\\n])*?(?:\\\\.|[^\\\\\\n${escapedRight}]))${escapedRight}`
);
// Block pattern - Starts and ends with the delimiter on new lines. Example:
// $$\ncontent here\n$$
blockPatterns.push(`${escapedLeft}\n((?:\\\\[^]|[^\\\\])+?)\n${escapedRight}`);
});
const inlineRule = new RegExp(`^(${inlinePatterns.join('|')})(?=[\\s?!.,:?!。,:]|$)`, 'u');
const blockRule = new RegExp(`^(${blockPatterns.join('|')})(?:\n|$)`, 'u');
return { inlineRule, blockRule };
}
const { inlineRule, blockRule } = generateRegexRules(DELIMITER_LIST);
export default function (options = {}) {
return {
extensions: [
inlineKatex(options, createRenderer(options, false)),
blockKatex(options, createRenderer(options, true))
]
};
}
function createRenderer(options, newlineAfter) {
return (token) =>
katex.renderToString(token.text, { ...options, displayMode: token.displayMode }) +
(newlineAfter ? '\n' : '');
}
function inlineKatex(options, renderer) {
const ruleReg = inlineRule;
return {
name: 'inlineKatex',
level: 'inline',
start(src) {
let index;
let indexSrc = src;
while (indexSrc) {
index = indexSrc.indexOf('$');
if (index === -1) {
return;
}
const f = index === 0 || indexSrc.charAt(index - 1) === ' ';
if (f) {
const possibleKatex = indexSrc.substring(index);
if (possibleKatex.match(ruleReg)) {
return index;
}
}
indexSrc = indexSrc.substring(index + 1).replace(/^\$+/, '');
}
},
tokenizer(src, tokens) {
const match = src.match(ruleReg);
if (match) {
const text = match
.slice(2)
.filter((item) => item)
.find((item) => item.trim());
return {
type: 'inlineKatex',
raw: match[0],
text: text
};
}
},
renderer
};
}
function blockKatex(options, renderer) {
return {
name: 'blockKatex',
level: 'block',
tokenizer(src, tokens) {
const match = src.match(blockRule);
if (match) {
const text = match
.slice(2)
.filter((item) => item)
.find((item) => item.trim());
return {
type: 'blockKatex',
raw: match[0],
text: text
};
}
},
renderer
};
}
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
import { onMount, tick, getContext } from 'svelte'; import { onMount, tick, getContext } from 'svelte';
import { openDB, deleteDB } from 'idb'; import { openDB, deleteDB } from 'idb';
import fileSaver from 'file-saver'; import fileSaver from 'file-saver';
import mermaid from 'mermaid';
const { saveAs } = fileSaver; const { saveAs } = fileSaver;
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
...@@ -178,6 +180,7 @@ ...@@ -178,6 +180,7 @@
await tick(); await tick();
} }
await mermaid.initialize({ startOnLoad: false });
loaded = true; loaded = true;
}); });
</script> </script>
......
...@@ -319,32 +319,34 @@ ...@@ -319,32 +319,34 @@
<ChatBubbles /> <ChatBubbles />
</button> </button>
</Tooltip> </Tooltip>
{/if}
<Tooltip content={$i18n.t('Edit User')}> <Tooltip content={$i18n.t('Edit User')}>
<button <button
class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl" class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
on:click={async () => { on:click={async () => {
showEditUserModal = !showEditUserModal; showEditUserModal = !showEditUserModal;
selectedUser = user; selectedUser = user;
}} }}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
> >
<svg <path
xmlns="http://www.w3.org/2000/svg" stroke-linecap="round"
fill="none" stroke-linejoin="round"
viewBox="0 0 24 24" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125"
stroke-width="1.5" />
stroke="currentColor" </svg>
class="w-4 h-4" </button>
> </Tooltip>
<path
stroke-linecap="round" {#if user.role !== 'admin'}
stroke-linejoin="round"
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125"
/>
</svg>
</button>
</Tooltip>
<Tooltip content={$i18n.t('Delete User')}> <Tooltip content={$i18n.t('Delete User')}>
<button <button
class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl" class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
...@@ -369,31 +371,6 @@ ...@@ -369,31 +371,6 @@
</svg> </svg>
</button> </button>
</Tooltip> </Tooltip>
{:else}
<Tooltip content={$i18n.t('Edit User')}>
<button
class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
on:click={async () => {
showEditUserModal = !showEditUserModal;
selectedUser = user;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125"
/>
</svg>
</button>
</Tooltip>
{/if} {/if}
</div> </div>
</td> </td>
......
...@@ -143,7 +143,7 @@ ...@@ -143,7 +143,7 @@
: { : {
id: model.id, id: model.id,
name: model.name name: model.name
} }
) )
) )
}; };
...@@ -154,9 +154,9 @@ ...@@ -154,9 +154,9 @@
params = { ...params, ...model?.info?.params }; params = { ...params, ...model?.info?.params };
params.stop = params?.stop params.stop = params?.stop
? (typeof params.stop === 'string' ? params.stop.split(',') : params?.stop ?? []).join( ? (typeof params.stop === 'string' ? params.stop.split(',') : (params?.stop ?? [])).join(
',' ','
) )
: null; : null;
if (model?.info?.meta?.knowledge) { if (model?.info?.meta?.knowledge) {
......
...@@ -111,6 +111,10 @@ ...@@ -111,6 +111,10 @@
if ($config) { if ($config) {
const _socket = io(`${WEBUI_BASE_URL}` || undefined, { const _socket = io(`${WEBUI_BASE_URL}` || undefined, {
reconnection: true,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
randomizationFactor: 0.5,
path: '/ws/socket.io', path: '/ws/socket.io',
auth: { token: localStorage.token } auth: { token: localStorage.token }
}); });
...@@ -119,6 +123,21 @@ ...@@ -119,6 +123,21 @@
console.log('connected'); console.log('connected');
}); });
_socket.on('reconnect_attempt', (attempt) => {
console.log('reconnect_attempt', attempt);
});
_socket.on('reconnect_failed', () => {
console.log('reconnect_failed');
});
_socket.on('disconnect', (reason, details) => {
console.log(`Socket ${socket.id} disconnected due to ${reason}`);
if (details) {
console.log('Additional details:', details);
}
});
await socket.set(_socket); await socket.set(_socket);
_socket.on('user-count', (data) => { _socket.on('user-count', (data) => {
......
...@@ -352,8 +352,23 @@ ...@@ -352,8 +352,23 @@
<style> <style>
.font-mona { .font-mona {
font-family: 'Mona Sans', -apple-system, 'Inter', ui-sans-serif, system-ui, 'Segoe UI', Roboto, font-family:
Ubuntu, Cantarell, 'Noto Sans', sans-serif, 'Helvetica Neue', Arial, 'Apple Color Emoji', 'Mona Sans',
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; -apple-system,
'Inter',
ui-sans-serif,
system-ui,
'Segoe UI',
Roboto,
Ubuntu,
Cantarell,
'Noto Sans',
sans-serif,
'Helvetica Neue',
Arial,
'Apple Color Emoji',
'Segoe UI Emoji',
'Segoe UI Symbol',
'Noto Color Emoji';
} }
</style> </style>
import adapter from '@sveltejs/adapter-static'; import adapter from '@sveltejs/adapter-static';
import { vitePreprocess } from '@sveltejs/kit/vite'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {
......
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