This commit is contained in:
Joshua 2025-06-21 10:09:00 -07:00 committed by GitHub
commit 2b0f8e3d6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 126 additions and 26 deletions

View File

@ -456,7 +456,7 @@ export const executeToolServer = async (
...(token && { authorization: `Bearer ${token}` })
};
let requestOptions: RequestInit = {
const requestOptions: RequestInit = {
method: httpMethod.toUpperCase(),
headers
};
@ -1005,7 +1005,7 @@ export const getPipelinesList = async (token: string = '') => {
throw error;
}
let pipelines = res?.data ?? [];
const pipelines = res?.data ?? [];
return pipelines;
};
@ -1148,7 +1148,7 @@ export const getPipelines = async (token: string, urlIdx?: string) => {
throw error;
}
let pipelines = res?.data ?? [];
const pipelines = res?.data ?? [];
return pipelines;
};

View File

@ -331,7 +331,7 @@ export const generateTextCompletion = async (token: string = '', model: string,
};
export const generateChatCompletion = async (token: string = '', body: object) => {
let controller = new AbortController();
const controller = new AbortController();
let error = null;
const res = await fetch(`${OLLAMA_API_BASE_URL}/api/chat`, {

View File

@ -126,7 +126,7 @@ export const getUsers = async (
let error = null;
let res = null;
let searchParams = new URLSearchParams();
const searchParams = new URLSearchParams();
searchParams.set('page', `${page}`);

View File

@ -336,7 +336,7 @@
<div class=" flex-1 self-center {(model?.is_active ?? true) ? '' : 'text-gray-500'}">
<Tooltip
content={marked.parse(
!!model?.meta?.description
model?.meta?.description
? model?.meta?.description
: model?.ollama?.digest
? `${model?.ollama?.digest} **(${model?.ollama?.modified_at})**`
@ -349,7 +349,7 @@
</Tooltip>
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1 text-gray-500">
<span class=" line-clamp-1">
{!!model?.meta?.description
{model?.meta?.description
? model?.meta?.description
: model?.ollama?.digest
? `${model.id} (${model?.ollama?.digest})`

View File

@ -125,6 +125,7 @@
let imageGenerationEnabled = false;
let webSearchEnabled = false;
let codeInterpreterEnabled = false;
let thinkingEnabled = false;
let chat = null;
let tags = [];
@ -152,6 +153,8 @@
selectedFilterIds = [];
webSearchEnabled = false;
imageGenerationEnabled = false;
codeInterpreterEnabled = false;
thinkingEnabled = false;
if (sessionStorage.getItem(`chat-input${chatIdProp ? `-${chatIdProp}` : ''}`)) {
try {
@ -167,6 +170,7 @@
webSearchEnabled = input.webSearchEnabled;
imageGenerationEnabled = input.imageGenerationEnabled;
codeInterpreterEnabled = input.codeInterpreterEnabled;
thinkingEnabled = input.thinkingEnabled;
}
} catch (e) {}
}
@ -215,6 +219,7 @@
webSearchEnabled = false;
imageGenerationEnabled = false;
codeInterpreterEnabled = false;
thinkingEnabled = false;
};
const setToolIds = async () => {
@ -454,6 +459,7 @@
webSearchEnabled = false;
imageGenerationEnabled = false;
codeInterpreterEnabled = false;
thinkingEnabled = false;
try {
const input = JSON.parse(
@ -468,6 +474,7 @@
webSearchEnabled = input.webSearchEnabled;
imageGenerationEnabled = input.imageGenerationEnabled;
codeInterpreterEnabled = input.codeInterpreterEnabled;
thinkingEnabled = input.thinkingEnabled;
}
} catch (e) {}
}
@ -1659,6 +1666,19 @@
: undefined
},
// Add thinking mode option for compatible models
...(thinkingEnabled && (model.owned_by === 'ollama' || model?.info?.meta?.owned_by === 'ollama') &&
(() => {
const modelName = model?.name?.toLowerCase() || model.id.toLowerCase();
return modelName.includes('deepseek-r1') || modelName.includes('qwen3') || modelName.includes('magistral');
})()
? {
options: {
thinking: true
}
}
: {}),
files: (files?.length ?? 0) > 0 ? files : undefined,
filter_ids: selectedFilterIds.length > 0 ? selectedFilterIds : undefined,
@ -2112,6 +2132,7 @@
bind:imageGenerationEnabled
bind:codeInterpreterEnabled
bind:webSearchEnabled
bind:thinkingEnabled
bind:atSelectedModel
toolServers={$toolServers}
transparentBackground={$settings?.backgroundImageUrl ?? false}
@ -2171,6 +2192,7 @@
bind:imageGenerationEnabled
bind:codeInterpreterEnabled
bind:webSearchEnabled
bind:thinkingEnabled
bind:atSelectedModel
transparentBackground={$settings?.backgroundImageUrl ?? false}
toolServers={$toolServers}

View File

@ -89,6 +89,9 @@
export let webSearchEnabled = false;
export let codeInterpreterEnabled = false;
// Add thinking mode state
export let thinkingEnabled = false;
$: onChange({
prompt,
files: files
@ -104,7 +107,8 @@
selectedFilterIds,
imageGenerationEnabled,
webSearchEnabled,
codeInterpreterEnabled
codeInterpreterEnabled,
thinkingEnabled
});
let showTools = false;
@ -159,6 +163,15 @@
$models.find((m) => m.id === model)?.info?.meta?.capabilities?.code_interpreter ?? true
);
// Add thinking capable models check
let thinkingCapableModels = [];
$: thinkingCapableModels = (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).filter(
(model) => {
const modelName = $models.find((m) => m.id === model)?.name?.toLowerCase() || model.toLowerCase();
return modelName.includes('deepseek-r1') || modelName.includes('qwen3') || modelName.includes('magistral');
}
);
let toggleFilters = [];
$: toggleFilters = (atSelectedModel?.id ? [atSelectedModel.id] : selectedModels)
.map((id) => ($models.find((model) => model.id === id) || {})?.filters ?? [])
@ -188,6 +201,12 @@
$config?.features?.enable_code_interpreter &&
($_user.role === 'admin' || $_user?.permissions?.features?.code_interpreter);
let showThinkingButton = false;
$: showThinkingButton =
(atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).length ===
thinkingCapableModels.length &&
thinkingCapableModels.length > 0; // Only show if at least one model supports thinking
const scrollToBottom = () => {
const element = document.getElementById('messages-container');
element.scrollTo({
@ -744,6 +763,28 @@
</div>
{/if}
{#if thinkingEnabled && showThinkingButton}
<div class="mx-2.5 mt-2 -mb-1">
<div class="flex items-center gap-2 px-2.5 py-1.5 bg-sky-50 dark:bg-sky-200/5 border border-sky-200 dark:border-sky-800 rounded-lg text-sky-600 dark:text-sky-300">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
class="size-4 animate-pulse"
>
<path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2Z" />
<path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2Z" />
<path d="M2 12h20" />
</svg>
<span class="text-sm font-medium">{$i18n.t('Thinking mode enabled - Model may take longer but respond better')}</span>
</div>
</div>
{/if}
<div class="px-2.5">
{#if $settings?.richTextInput ?? true}
<div
@ -1268,7 +1309,7 @@
</button>
</InputMenu>
{#if $_user && (showToolsButton || (toggleFilters && toggleFilters.length > 0) || showWebSearchButton || showImageGenerationButton || showCodeInterpreterButton)}
{#if $_user && (showToolsButton || (toggleFilters && toggleFilters.length > 0) || showWebSearchButton || showImageGenerationButton || showCodeInterpreterButton || showThinkingButton)}
<div
class="flex self-center w-[1px] h-4 mx-1.5 bg-gray-50 dark:bg-gray-800"
/>
@ -1394,6 +1435,38 @@
</button>
</Tooltip>
{/if}
{#if showThinkingButton}
<Tooltip content={$i18n.t('Enable thinking mode - Model may take longer but respond better')} placement="top">
<button
on:click|preventDefault={() => (thinkingEnabled = !thinkingEnabled)}
type="button"
class="px-2 @xl:px-2.5 py-2 flex gap-1.5 items-center text-sm rounded-full transition-colors duration-300 focus:outline-hidden max-w-full overflow-hidden hover:bg-gray-50 dark:hover:bg-gray-800 {thinkingEnabled
? ' text-sky-500 dark:text-sky-300 bg-sky-50 dark:bg-sky-200/5'
: 'bg-transparent text-gray-600 dark:text-gray-300 '}"
>
<!-- Brain/Thinking icon -->
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
class="size-4"
>
<path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2Z" />
<path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2Z" />
<path d="M2 12h20" />
</svg>
<span
class="hidden @xl:block whitespace-nowrap overflow-hidden text-ellipsis leading-none pr-0.5"
>{$i18n.t('Thinking')}</span
>
</button>
</Tooltip>
{/if}
</div>
{/if}
</div>

View File

@ -50,7 +50,7 @@
const devices = await navigator.mediaDevices.enumerateDevices();
videoInputDevices = devices.filter((device) => device.kind === 'videoinput');
if (!!navigator.mediaDevices.getDisplayMedia) {
if (navigator.mediaDevices.getDisplayMedia) {
videoInputDevices = [
...videoInputDevices,
{

View File

@ -39,6 +39,7 @@
export let imageGenerationEnabled = false;
export let codeInterpreterEnabled = false;
export let webSearchEnabled = false;
export let thinkingEnabled = false;
export let toolServers = [];
@ -213,6 +214,7 @@
bind:imageGenerationEnabled
bind:codeInterpreterEnabled
bind:webSearchEnabled
bind:thinkingEnabled
bind:atSelectedModel
{toolServers}
{transparentBackground}

View File

@ -130,7 +130,7 @@
TTSModel = await KokoroTTS.from_pretrained(model_id, {
dtype: TTSEngineConfig.dtype, // Options: "fp32", "fp16", "q8", "q4", "q4f16"
device: !!navigator?.gpu ? 'webgpu' : 'wasm', // Detect WebGPU
device: navigator?.gpu ? 'webgpu' : 'wasm', // Detect WebGPU
progress_callback: (e) => {
TTSModelProgress = e;
console.log(e);

View File

@ -38,10 +38,10 @@ const createIsLoadingStore = (i18n: i18nType) => {
};
export const initI18n = (defaultLocale?: string | undefined) => {
let detectionOrder = defaultLocale
const detectionOrder = defaultLocale
? ['querystring', 'localStorage']
: ['querystring', 'localStorage', 'navigator'];
let fallbackDefaultLocale = defaultLocale ? [defaultLocale] : ['en-US'];
const fallbackDefaultLocale = defaultLocale ? [defaultLocale] : ['en-US'];
const loadResource = (language: string, namespace: string) =>
import(`./locales/${language}/${namespace}.json`);

View File

@ -221,6 +221,9 @@
"Code Interpreter": "",
"Code Interpreter Engine": "",
"Code Interpreter Prompt Template": "",
"Thinking": "Thinking",
"Enable thinking mode - Model may take longer but respond better": "Enable thinking mode - Model may take longer but respond better",
"Thinking mode enabled - Model may take longer but respond better": "Thinking mode enabled - Model may take longer but respond better",
"Collapse": "",
"Collection": "",
"Color": "",

View File

@ -74,15 +74,15 @@ const readPngChunks = (data) => {
if (!isValidPng) throw new Error('Invalid PNG file');
let chunks = [];
const chunks = [];
let offset = 8; // Skip PNG signature
while (offset < data.length) {
let length =
const length =
(data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3];
let type = String.fromCharCode.apply(null, data.slice(offset + 4, offset + 8));
let chunkData = data.slice(offset + 8, offset + 8 + length);
let crc =
const type = String.fromCharCode.apply(null, data.slice(offset + 4, offset + 8));
const chunkData = data.slice(offset + 8, offset + 8 + length);
const crc =
(data[offset + 8 + length] << 24) |
(data[offset + 8 + length + 1] << 16) |
(data[offset + 8 + length + 2] << 8) |

View File

@ -23,8 +23,8 @@ const ALLOWED_SURROUNDING_CHARS =
// const inlineRule = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\$]))\1(?=[\s?!\.,:?!。,:]|$)/;
// const blockRule = /^(\${1,2})\n((?:\\[^]|[^\\])+?)\n\1(?:\n|$)/;
let inlinePatterns = [];
let blockPatterns = [];
const inlinePatterns = [];
const blockPatterns = [];
function escapeRegex(string) {
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
@ -69,7 +69,7 @@ export default function (options = {}) {
}
function katexStart(src, displayMode: boolean) {
let ruleReg = displayMode ? blockRule : inlineRule;
const ruleReg = displayMode ? blockRule : inlineRule;
let indexSrc = src;
@ -78,7 +78,7 @@ function katexStart(src, displayMode: boolean) {
let startIndex = -1;
let startDelimiter = '';
let endDelimiter = '';
for (let delimiter of DELIMITER_LIST) {
for (const delimiter of DELIMITER_LIST) {
if (delimiter.display !== displayMode) {
continue;
}
@ -115,8 +115,8 @@ function katexStart(src, displayMode: boolean) {
}
function katexTokenizer(src, tokens, displayMode: boolean) {
let ruleReg = displayMode ? blockRule : inlineRule;
let type = displayMode ? 'blockKatex' : 'inlineKatex';
const ruleReg = displayMode ? blockRule : inlineRule;
const type = displayMode ? 'blockKatex' : 'inlineKatex';
const match = src.match(ruleReg);

View File

@ -20,7 +20,7 @@ self.onmessage = async (event) => {
try {
tts = await KokoroTTS.from_pretrained(model_id, {
dtype,
device: !!navigator?.gpu ? 'webgpu' : 'wasm' // Detect WebGPU
device: navigator?.gpu ? 'webgpu' : 'wasm' // Detect WebGPU
});
isInitialized = true; // Mark as initialized after successful loading
self.postMessage({ status: 'init:complete' });

View File

@ -40,7 +40,7 @@ async function loadPyodideAndPackages(packages: string[] = []) {
packages: ['micropip']
});
let mountDir = '/mnt';
const mountDir = '/mnt';
self.pyodide.FS.mkdirTree(mountDir);
// self.pyodide.FS.mount(self.pyodide.FS.filesystems.IDBFS, {}, mountDir);