diff --git a/.env.example b/.env.example index 4ede4652bd..5ca052422d 100644 --- a/.env.example +++ b/.env.example @@ -24,10 +24,6 @@ ENABLE_MEMORY_SYSTEM_CONTEXT=true # Set to true to add compact row/column stats to parsed CSV retrieval context. ENABLE_RAG_CSV_SUMMARY=false -# Opt in to automatic sending of URL-provided prompts (including links from other sites). -# Defaults to prefill only; enabling this requires a backend restart. -ENABLE_URL_QUERY_SUBMISSION=false - # Set to true to preserve backing file records, storage blobs, and per-file vectors when files are removed from knowledge bases. ENABLE_KNOWLEDGE_FILE_RETENTION=false diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index bfacfed5c6..7b4fb5a9a0 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1742,8 +1742,6 @@ RESPONSE_WATERMARK = os.getenv('RESPONSE_WATERMARK', '') IFRAME_CSP = os.getenv('IFRAME_CSP', '') -ENABLE_URL_QUERY_SUBMISSION = os.getenv('ENABLE_URL_QUERY_SUBMISSION', 'False').lower() == 'true' - USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS = ( os.getenv('USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS', 'False').lower() == 'true' ) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 17f6077e69..0ed3d753ea 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -53,7 +53,6 @@ from open_webui.config import ( ENABLE_ADMIN_EXPORT, ENABLE_ONEDRIVE_BUSINESS, ENABLE_ONEDRIVE_PERSONAL, - ENABLE_URL_QUERY_SUBMISSION, # OpenAI ENV, FRONTEND_BUILD_DIR, @@ -2394,7 +2393,6 @@ async def get_app_config(request: Request): 'enable_code_interpreter': config.get('code_interpreter.enable'), 'enable_image_generation': config.get('image_generation.enable'), 'enable_autocomplete_generation': config.get('task.autocomplete.enable'), - 'enable_url_query_submission': ENABLE_URL_QUERY_SUBMISSION, 'enable_community_sharing': config.get('ui.enable_community_sharing'), 'enable_message_rating': config.get('ui.enable_message_rating'), 'enable_user_webhooks': config.get('ui.enable_user_webhooks'), diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 0f0464be8d..222b39a048 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -164,6 +164,7 @@ let navbarElement; let showEventConfirmation = false; + let pendingUrlActions: { urls: string[]; call: boolean } | null = null; let eventConfirmationTitle = ''; let eventConfirmationMessage = ''; let eventConfirmationInput = false; @@ -2264,7 +2265,10 @@ }); return () => bridge?.end(); }); - beforeNavigate(() => bridge?.end()); + beforeNavigate(() => { + bridge?.end(); + pendingUrlActions = null; + }); $: if (!$user && (bridge?.connected || bridge?.connecting)) bridge.end(); $: if (selectedModelIds && $models && $config) bridge?.syncModel(); @@ -2540,13 +2544,14 @@ taskIds = null; chatTasks = []; - if ($page.url.searchParams.get('youtube')) { - await uploadWeb(`https://www.youtube.com/watch?v=${$page.url.searchParams.get('youtube')}`); - } - - if ($page.url.searchParams.get('load-url')) { - await uploadWeb($page.url.searchParams.get('load-url')); - } + const youtube = $page.url.searchParams.get('youtube'); + const loadUrl = $page.url.searchParams.get('load-url'); + const urls = [ + ...(youtube ? [`https://www.youtube.com/watch?v=${youtube}`] : []), + ...(loadUrl ? [loadUrl] : []) + ]; + const call = $page.url.searchParams.get('call') === 'true'; + pendingUrlActions = urls.length || call ? { urls, call } : null; if ($page.url.searchParams.get('web-search') === 'true') { webSearchEnabled = true; @@ -2583,10 +2588,6 @@ } } - if ($page.url.searchParams.get('call') === 'true') { - openCallOverlay(); - } - // Consume one-shot desktop event (e.g. Spotlight query, call shortcut) if ($desktopEvent) { const event = $desktopEvent; @@ -2622,14 +2623,7 @@ } else if ($page.url.searchParams.get('q')) { const q = $page.url.searchParams.get('q') ?? ''; - if ( - $config?.features?.enable_url_query_submission && - ($page.url.searchParams.get('submit') ?? 'true') === 'true' - ) { - messageInput?.setText(q, () => submitHandler(prompt)); - } else { - messageInput?.setText(q); - } + messageInput?.setText(q); } selectedModels = selectedModels.map((modelId) => @@ -4658,6 +4652,35 @@ /> {/if} + { + const actions = pendingUrlActions; + const url = $page.url.href; + pendingUrlActions = null; + if (!actions) return; + for (const source of actions.urls) { + if ($page.url.href !== url) return; + await uploadWeb(source); + } + if (actions.call && $page.url.href === url) openCallOverlay(); + }} + on:cancel={() => (pendingUrlActions = null)} +> + + {#if pendingUrlActions?.urls.length} + {$i18n.t('Load content from these URLs?')} + {#each pendingUrlActions.urls as url} + {url} + {/each} + {/if} + {#if pendingUrlActions?.call} + {$i18n.t('Start a voice call using your microphone?')} + {/if} + + + { + setToolServers().catch((e) => { console.error('Failed to load tool servers:', e); terminalServers.set([]); }); - if ( - $config?.features?.enable_url_query_submission && - $page.url.searchParams.get('q') && - ($page.url.searchParams.get('submit') ?? 'true') === 'true' - ) { - await loadToolServers; - } const setupKeyboardShortcuts = () => { document.addEventListener('keydown', async (event) => { diff --git a/src/routes/(app)/notes/+page.svelte b/src/routes/(app)/notes/+page.svelte index 8384639428..8bb6047296 100644 --- a/src/routes/(app)/notes/+page.svelte +++ b/src/routes/(app)/notes/+page.svelte @@ -1,5 +1,5 @@ + { + const res = await createNoteHandler(title, content); + if (res) goto(`/notes/${res.id}`, { replaceState: true }); + else showConfirm = true; + }} +> + + {title} + {content} + + + - import { onMount } from 'svelte'; + import { getContext } from 'svelte'; + import type { Writable } from 'svelte/store'; + import type { i18n as I18n } from 'i18next'; import { goto } from '$app/navigation'; import { page } from '$app/stores'; import dayjs from '$lib/dayjs'; import { createNoteHandler } from '$lib/components/notes/utils'; + import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte'; - onMount(async () => { - const title = $page.url.searchParams.get('title') ?? dayjs().format('YYYY-MM-DD'); - const content = $page.url.searchParams.get('content') ?? ''; + const i18n = getContext>('i18n'); + const title = $page.url.searchParams.get('title') ?? dayjs().format('YYYY-MM-DD'); + const content = $page.url.searchParams.get('content') ?? ''; + let showConfirm = true; + const createNote = async () => { const res = await createNoteHandler(title, content); if (res) { goto(`/notes/${res.id}`, { replaceState: true }); + } else { + showConfirm = true; } - }); + }; + + goto('/notes', { replaceState: true })} +> + + {title} + {content} + +
{$i18n.t('Load content from these URLs?')}
{url}
{$i18n.t('Start a voice call using your microphone?')}