refac
This commit is contained in:
+13
-13
@@ -220,7 +220,11 @@ from open_webui.utils.chat import (
|
||||
from open_webui.utils.chat import (
|
||||
generate_chat_completion as chat_completion_handler,
|
||||
)
|
||||
from open_webui.utils.chat_id import is_saved_chat_id
|
||||
from open_webui.utils.chat_id import (
|
||||
get_temporary_chat_session_id,
|
||||
is_saved_chat_id,
|
||||
is_temporary_chat_id,
|
||||
)
|
||||
from open_webui.utils.chat_variables import (
|
||||
normalize_chat_variables,
|
||||
)
|
||||
@@ -1245,9 +1249,7 @@ async def chat_completion(
|
||||
detail=ERROR_MESSAGES.DEFAULT(),
|
||||
)
|
||||
|
||||
if not chat_id.startswith('local:') and not chat_id.startswith(
|
||||
'channel:'
|
||||
): # temporary/channel chats are not stored
|
||||
if is_saved_chat_id(chat_id):
|
||||
if is_new_chat:
|
||||
# Build the full history upfront with ALL assistant placeholders
|
||||
user_message = metadata.get('user_message') or {}
|
||||
@@ -1577,9 +1579,7 @@ async def chat_completion(
|
||||
if metadata.get('chat_id') and metadata.get('message_id'):
|
||||
# Update the chat message with the error
|
||||
try:
|
||||
if not metadata.get('chat_id', '').startswith('local:') and not metadata.get(
|
||||
'chat_id', ''
|
||||
).startswith('channel:'):
|
||||
if is_saved_chat_id(metadata.get('chat_id')):
|
||||
await Chats.upsert_message_to_chat_by_id_and_message_id(
|
||||
metadata['chat_id'],
|
||||
metadata['message_id'],
|
||||
@@ -1930,8 +1930,8 @@ async def generate_messages(
|
||||
|
||||
|
||||
async def verify_chat_ownership(chat_id: str | None, user) -> None:
|
||||
"""`local:` chats are per-socket and never persisted, so they have no owner to check."""
|
||||
if not chat_id or chat_id.startswith('local:'):
|
||||
"""Temporary chats are per-socket and unsaved, so they have no owner to check."""
|
||||
if not chat_id or is_temporary_chat_id(chat_id):
|
||||
return
|
||||
|
||||
# Channel messages need the membership and write-access gate that only /api/chat/completions has.
|
||||
@@ -2004,8 +2004,8 @@ async def list_tasks_endpoint(request: Request, user=Depends(get_admin_user)):
|
||||
|
||||
@app.get('/api/tasks/chat/{chat_id:path}')
|
||||
async def list_tasks_by_chat_id_endpoint(request: Request, chat_id: str, user=Depends(get_verified_user)):
|
||||
if chat_id.startswith('local:') or chat_id.startswith('channel:'):
|
||||
socket_id = chat_id[len('local:') :]
|
||||
socket_id = get_temporary_chat_session_id(chat_id)
|
||||
if socket_id:
|
||||
owner_id = get_user_id_from_session_pool(socket_id)
|
||||
if owner_id != user.id and user.role != 'admin':
|
||||
return {'task_ids': []}
|
||||
@@ -2022,8 +2022,8 @@ async def list_tasks_by_chat_id_endpoint(request: Request, chat_id: str, user=De
|
||||
|
||||
@app.post('/api/tasks/chat/{chat_id:path}/stop')
|
||||
async def stop_tasks_by_chat_id_endpoint(request: Request, chat_id: str, user=Depends(get_verified_user)):
|
||||
if chat_id.startswith('local:') or chat_id.startswith('channel:'):
|
||||
socket_id = chat_id[len('local:') :]
|
||||
socket_id = get_temporary_chat_session_id(chat_id)
|
||||
if socket_id:
|
||||
owner_id = get_user_id_from_session_pool(socket_id)
|
||||
if owner_id != user.id and user.role != 'admin':
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND)
|
||||
|
||||
@@ -1,8 +1,27 @@
|
||||
from typing import Optional
|
||||
|
||||
|
||||
NON_SAVED_CHAT_ID_PREFIXES = ('local:', 'channel:')
|
||||
TEMPORARY_CHAT_ID_PREFIX = 'temporary:'
|
||||
LEGACY_TEMPORARY_CHAT_ID_PREFIX = 'local:' # Legacy temporary chat prefix.
|
||||
CHANNEL_CHAT_ID_PREFIX = 'channel:'
|
||||
|
||||
TEMPORARY_CHAT_ID_PREFIXES = (
|
||||
TEMPORARY_CHAT_ID_PREFIX,
|
||||
LEGACY_TEMPORARY_CHAT_ID_PREFIX,
|
||||
)
|
||||
NON_SAVED_CHAT_ID_PREFIXES = (*TEMPORARY_CHAT_ID_PREFIXES, CHANNEL_CHAT_ID_PREFIX)
|
||||
|
||||
|
||||
def is_saved_chat_id(chat_id: Optional[str]) -> bool:
|
||||
return bool(chat_id) and not chat_id.startswith(NON_SAVED_CHAT_ID_PREFIXES)
|
||||
|
||||
|
||||
def is_temporary_chat_id(chat_id: Optional[str]) -> bool:
|
||||
return bool(chat_id) and chat_id.startswith(TEMPORARY_CHAT_ID_PREFIXES)
|
||||
|
||||
|
||||
def get_temporary_chat_session_id(chat_id: str) -> Optional[str]:
|
||||
for prefix in TEMPORARY_CHAT_ID_PREFIXES:
|
||||
if chat_id.startswith(prefix):
|
||||
return chat_id.removeprefix(prefix)
|
||||
return None
|
||||
|
||||
@@ -7,6 +7,7 @@ from typing import Any
|
||||
from fastapi.responses import JSONResponse
|
||||
from open_webui.models.chats import Chats
|
||||
from open_webui.models.config import Config
|
||||
from open_webui.utils.chat_id import is_saved_chat_id
|
||||
from open_webui.utils.misc import get_content_from_message, get_last_user_message, get_message_list
|
||||
from open_webui.utils.task import (
|
||||
get_task_model_id,
|
||||
@@ -110,7 +111,7 @@ async def compact_messages_for_request(
|
||||
checkpoint_message_id = (
|
||||
recent_messages[0].get('id') or metadata.get('user_message_id') or metadata.get('message_id')
|
||||
)
|
||||
if chat_id and checkpoint_message_id and not chat_id.startswith(('local:', 'channel:')):
|
||||
if is_saved_chat_id(chat_id) and checkpoint_message_id:
|
||||
await Chats.upsert_message_to_chat_by_id_and_message_id(
|
||||
chat_id,
|
||||
checkpoint_message_id,
|
||||
|
||||
@@ -1553,7 +1553,7 @@ async def add_file_context(messages: list, chat_id: str, user) -> list:
|
||||
"""
|
||||
Add file URLs to messages for native function calling.
|
||||
"""
|
||||
if not chat_id or chat_id.startswith('local:') or chat_id.startswith('channel:'):
|
||||
if not is_saved_chat_id(chat_id):
|
||||
return messages
|
||||
|
||||
chat = await Chats.get_chat_by_id_and_user_id(chat_id, user.id)
|
||||
@@ -1609,7 +1609,7 @@ async def chat_image_generation_handler(request: Request, form_data: dict, extra
|
||||
if not chat_id or not isinstance(chat_id, str) or not __event_emitter__:
|
||||
return form_data
|
||||
|
||||
if chat_id.startswith('local:') or chat_id.startswith('channel:'):
|
||||
if not is_saved_chat_id(chat_id):
|
||||
message_list = form_data.get('messages', [])
|
||||
else:
|
||||
chat = await Chats.get_chat_by_id_and_user_id(chat_id, user.id)
|
||||
@@ -2270,7 +2270,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
||||
chat_id = metadata.get('chat_id')
|
||||
user_message_id = metadata.get('user_message_id')
|
||||
|
||||
if chat_id and user_message_id and not chat_id.startswith('local:') and not chat_id.startswith('channel:'):
|
||||
if is_saved_chat_id(chat_id) and user_message_id:
|
||||
db_messages = await load_messages_from_db(chat_id, user_message_id)
|
||||
if db_messages:
|
||||
# Continue: frontend sends assistant_message_id when continuing
|
||||
@@ -2317,7 +2317,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
||||
if regeneration_prompt:
|
||||
form_data['messages'].append({'role': 'user', 'content': regeneration_prompt})
|
||||
|
||||
if chat_id and user_message_id and not chat_id.startswith('local:') and not chat_id.startswith('channel:'):
|
||||
if is_saved_chat_id(chat_id) and user_message_id:
|
||||
if getattr(request.state, 'direct', False) and hasattr(request.state, 'model'):
|
||||
compaction_models = {
|
||||
request.state.model['id']: request.state.model,
|
||||
@@ -2574,7 +2574,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
||||
available_skills = []
|
||||
view_skill_ids = []
|
||||
chat = None
|
||||
if metadata.get('chat_id') and not metadata['chat_id'].startswith(('local:', 'channel:')):
|
||||
if is_saved_chat_id(metadata.get('chat_id')):
|
||||
chat = await Chats.get_chat_by_id(metadata['chat_id'])
|
||||
|
||||
if chat and (chat.meta or {}).get('internal') is True and (chat.meta or {}).get('type') == 'note':
|
||||
@@ -3138,11 +3138,7 @@ async def background_tasks_handler(ctx):
|
||||
message = None
|
||||
messages = []
|
||||
|
||||
if (
|
||||
'chat_id' in metadata
|
||||
and not metadata.get('chat_id', '').startswith('local:')
|
||||
and not metadata.get('chat_id', '').startswith('channel:')
|
||||
):
|
||||
if is_saved_chat_id(metadata.get('chat_id')):
|
||||
messages_map = await Chats.get_messages_map_by_chat_id(metadata['chat_id'])
|
||||
if not messages_map:
|
||||
# Chat was deleted while the response was streaming — skip background tasks
|
||||
@@ -3225,9 +3221,7 @@ async def background_tasks_handler(ctx):
|
||||
}
|
||||
)
|
||||
|
||||
if not metadata.get('chat_id', '').startswith('local:') and not metadata.get(
|
||||
'chat_id', ''
|
||||
).startswith('channel:'):
|
||||
if is_saved_chat_id(metadata.get('chat_id')):
|
||||
await Chats.upsert_message_to_chat_by_id_and_message_id(
|
||||
metadata['chat_id'],
|
||||
metadata['message_id'],
|
||||
@@ -3240,9 +3234,7 @@ async def background_tasks_handler(ctx):
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
if not metadata.get('chat_id', '').startswith('local:') and not metadata.get('chat_id', '').startswith(
|
||||
'channel:'
|
||||
): # Only update titles and tags for non-temp chats
|
||||
if is_saved_chat_id(metadata.get('chat_id')): # Only update titles and tags for saved chats
|
||||
if TASKS.TITLE_GENERATION in tasks:
|
||||
user_message = get_last_user_message(messages)
|
||||
if user_message and len(user_message) > 100:
|
||||
@@ -3378,11 +3370,11 @@ async def outlet_filter_handler(ctx):
|
||||
if not message_id:
|
||||
message_id = output_id('msg')
|
||||
|
||||
is_temp_chat = chat_id.startswith('local:') or chat_id.startswith('channel:')
|
||||
is_unsaved_chat = not is_saved_chat_id(chat_id)
|
||||
try:
|
||||
messages_map = None
|
||||
|
||||
if is_temp_chat or not chat_id:
|
||||
if is_unsaved_chat:
|
||||
form_messages = ctx.get('form_data', {}).get('messages', [])
|
||||
assistant_message = ctx.get('assistant_message', {})
|
||||
|
||||
@@ -3658,7 +3650,7 @@ async def non_streaming_chat_response_handler(response, ctx):
|
||||
if (
|
||||
getattr(request.state, 'internal', False) is not True
|
||||
and chat_id
|
||||
and not chat_id.startswith(('channel:', 'local:'))
|
||||
and is_saved_chat_id(chat_id)
|
||||
):
|
||||
webui_url = await Config.get('webui.url')
|
||||
await publish_event(
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
displayFileHandler
|
||||
} from '$lib/utils';
|
||||
import { AudioQueue } from '$lib/utils/audio';
|
||||
import { createTemporaryChatId, isTemporaryChatId } from '$lib/utils/chatId';
|
||||
import { getOutputText } from './Messages/structuredOutput';
|
||||
|
||||
import {
|
||||
@@ -451,7 +452,7 @@
|
||||
const saveChatVariables = async (values) => {
|
||||
chatVariables = { ...chatVariables, ...values };
|
||||
|
||||
if ($chatId && !$temporaryChatEnabled && !$chatId.startsWith('local:')) {
|
||||
if ($chatId && !$temporaryChatEnabled && !isTemporaryChatId($chatId)) {
|
||||
const res = await updateChatById(localStorage.token, $chatId, {}, chatVariables).catch(
|
||||
(err) => {
|
||||
console.error('[chat variables save]', err);
|
||||
@@ -2845,7 +2846,7 @@
|
||||
chatFiles = mergeFiles(chatFiles, createdChat?.chat?.files ?? []);
|
||||
await onSelectEmbeddedChat?.(_chatId);
|
||||
} else if ($temporaryChatEnabled) {
|
||||
_chatId = `local:${$socket?.id}`;
|
||||
_chatId = createTemporaryChatId($socket?.id);
|
||||
await chatId.set(_chatId);
|
||||
}
|
||||
await tick();
|
||||
@@ -3098,7 +3099,7 @@
|
||||
// Only send terminal_id if the model has terminal capability enabled
|
||||
const terminalEnabled = model.info?.meta?.capabilities?.terminal ?? true;
|
||||
const useChatVariablesFallback =
|
||||
!_chatId || $temporaryChatEnabled || _chatId.startsWith('local:');
|
||||
!_chatId || $temporaryChatEnabled || isTemporaryChatId(_chatId);
|
||||
|
||||
const res = await generateOpenAIChatCompletion(
|
||||
localStorage.token,
|
||||
@@ -3503,7 +3504,7 @@
|
||||
|
||||
selectedFolder.set(null);
|
||||
} else {
|
||||
_chatId = `local:${$socket?.id}`; // Use socket id for temporary chat
|
||||
_chatId = createTemporaryChatId($socket?.id);
|
||||
await chatId.set(_chatId);
|
||||
}
|
||||
await tick();
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
import ChatPlus from '../icons/ChatPlus.svelte';
|
||||
import ChatCheck from '../icons/ChatCheck.svelte';
|
||||
import Knobs from '../icons/Knobs.svelte';
|
||||
import { isTemporaryChatId } from '$lib/utils/chatId';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
@@ -247,7 +248,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if $temporaryChatEnabled && ($chatId ?? '').startsWith('local:')}
|
||||
{#if $temporaryChatEnabled && isTemporaryChatId($chatId)}
|
||||
<div class=" w-full z-30 text-center">
|
||||
<div class="text-xs text-gray-500">{$i18n.t('Temporary Chat')}</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
const TEMPORARY_CHAT_ID_PREFIX = 'temporary:';
|
||||
const LEGACY_TEMPORARY_CHAT_ID_PREFIX = 'local:'; // Legacy temporary chat prefix.
|
||||
|
||||
export const createTemporaryChatId = (sessionId: string | undefined) =>
|
||||
`${TEMPORARY_CHAT_ID_PREFIX}${sessionId}`;
|
||||
|
||||
export const isTemporaryChatId = (chatId: string | null | undefined) =>
|
||||
!!chatId &&
|
||||
(chatId.startsWith(TEMPORARY_CHAT_ID_PREFIX) ||
|
||||
chatId.startsWith(LEGACY_TEMPORARY_CHAT_ID_PREFIX));
|
||||
@@ -54,6 +54,7 @@
|
||||
import { getSessionUser, updateUserTimezone, userSignOut } from '$lib/apis/auths';
|
||||
import { getAllTags } from '$lib/apis/chats';
|
||||
import { chatCompletion } from '$lib/apis/openai';
|
||||
import { isTemporaryChatId } from '$lib/utils/chatId';
|
||||
import {
|
||||
addOpenAIConnection,
|
||||
removeOpenAIConnection,
|
||||
@@ -497,7 +498,7 @@
|
||||
// Skip events from temporary chats that are not the current chat.
|
||||
// This prevents notifications from being sent to other tabs/devices
|
||||
// for privacy, since temporary chats are not meant to be persisted or visible elsewhere.
|
||||
const isTemporaryChat = event.chat_id?.startsWith('local:');
|
||||
const isTemporaryChat = isTemporaryChatId(event.chat_id);
|
||||
if (isTemporaryChat && event.chat_id !== $chatId) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user