mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-10 03:27:57 +00:00
refac
This commit is contained in:
parent
f55e09e50d
commit
6cfd6987e5
9 changed files with 101 additions and 36 deletions
|
|
@ -1404,6 +1404,7 @@ async def chat_completion(
|
|||
if user_message_id and user_message:
|
||||
user_message['childrenIds'] = all_assistant_ids
|
||||
user_message['user_id'] = user.id
|
||||
user_message['user'] = {'id': user.id, 'name': user.name}
|
||||
history_messages[user_message_id] = user_message
|
||||
|
||||
for entry in message_ids:
|
||||
|
|
|
|||
|
|
@ -603,7 +603,9 @@ class ChatTable:
|
|||
await ChatMessages.upsert_message(
|
||||
message_id=message_id,
|
||||
chat_id=id,
|
||||
user_id=user_id,
|
||||
user_id=message.get('user_id')
|
||||
or (message['user'].get('id') if isinstance(message.get('user'), dict) else None)
|
||||
or user_id,
|
||||
data=message,
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
@ -677,7 +679,11 @@ class ChatTable:
|
|||
messages = list((chat.chat.get('history', {}).get('messages') or {}).values())
|
||||
messages.extend(chat.chat.get('messages') or [])
|
||||
for message in messages:
|
||||
message['user_id'] = user_id
|
||||
message['user_id'] = (
|
||||
message.get('user_id')
|
||||
or (message['user'].get('id') if isinstance(message.get('user'), dict) else None)
|
||||
or user_id
|
||||
)
|
||||
return chat
|
||||
|
||||
async def import_chats(
|
||||
|
|
@ -729,7 +735,9 @@ class ChatTable:
|
|||
await ChatMessages.upsert_message(
|
||||
message_id=message_id,
|
||||
chat_id=imported_chat.id,
|
||||
user_id=user_id,
|
||||
user_id=message.get('user_id')
|
||||
or (message['user'].get('id') if isinstance(message.get('user'), dict) else None)
|
||||
or user_id,
|
||||
data=message,
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
@ -1839,7 +1847,8 @@ class ChatTable:
|
|||
if (
|
||||
chat.user_id == user.id
|
||||
or user.role == 'admin'
|
||||
and (ENABLE_ADMIN_CHAT_ACCESS or permission == 'read' and is_internal_chat(chat.meta))
|
||||
and permission == 'read'
|
||||
and (ENABLE_ADMIN_CHAT_ACCESS or is_internal_chat(chat.meta))
|
||||
):
|
||||
return ChatModel.model_validate(chat)
|
||||
from open_webui.models.shared_chats import SharedChats
|
||||
|
|
|
|||
|
|
@ -127,7 +127,9 @@ async def can_read_shared_chat(user, shared, db: AsyncSession) -> bool:
|
|||
)
|
||||
|
||||
|
||||
def shared_chat_response(chat, user=None):
|
||||
async def shared_chat_response(chat, user=None, db=None):
|
||||
from open_webui.models.users import Users
|
||||
|
||||
data = ChatResponse.model_validate(chat, from_attributes=True).model_dump()
|
||||
if user is None or chat.user_id != user.id:
|
||||
data['variables'] = {}
|
||||
|
|
@ -135,9 +137,24 @@ def shared_chat_response(chat, user=None):
|
|||
data['chat'].pop(key, None)
|
||||
messages = list((data['chat'].get('history', {}).get('messages') or {}).values())
|
||||
messages.extend(data['chat'].get('messages') or [])
|
||||
authors = {}
|
||||
for message in messages:
|
||||
if message.get('role') == 'user':
|
||||
author = message.get('user')
|
||||
author = author if isinstance(author, dict) else {}
|
||||
author_id = message.get('user_id') or author.get('id') or chat.user_id
|
||||
message['user_id'] = author_id
|
||||
if author.get('id') == author_id and author.get('name'):
|
||||
authors[author_id] = {'id': author_id, 'name': author['name']}
|
||||
if user is None or (message.get('user_id') or chat.user_id) != user.id:
|
||||
message.pop('meta', None)
|
||||
missing_ids = {message['user_id'] for message in messages if message.get('role') == 'user'} - authors.keys()
|
||||
if missing_ids:
|
||||
for author in await Users.get_users_by_user_ids(list(missing_ids), db=db):
|
||||
authors[author.id] = {'id': author.id, 'name': author.name}
|
||||
for message in messages:
|
||||
if message.get('role') == 'user':
|
||||
message['user'] = authors.get(message['user_id'], {'id': message['user_id'], 'name': ''})
|
||||
return data
|
||||
|
||||
|
||||
|
|
@ -1240,7 +1257,7 @@ async def get_shared_chat_by_id(
|
|||
live = (
|
||||
shared.chat.get('share_mode') == 'continue'
|
||||
and user is not None
|
||||
and await can_read_shared_chat(user, shared, db=db)
|
||||
and await Chats.get_accessible_chat_by_id(shared.chat_id, user, db=db, permission='write') is not None
|
||||
)
|
||||
chat = (
|
||||
await Chats.get_chat_by_id(shared.chat_id, db=db)
|
||||
|
|
@ -1248,7 +1265,7 @@ async def get_shared_chat_by_id(
|
|||
else await Chats.get_chat_by_share_id(share_id, db=db)
|
||||
)
|
||||
if chat:
|
||||
data = shared_chat_response(chat, user)
|
||||
data = await shared_chat_response(chat, user, db=db)
|
||||
data['chat']['share_mode'] = 'continue' if live else None
|
||||
return data
|
||||
|
||||
|
|
@ -1262,7 +1279,13 @@ async def get_shared_chat_by_id(
|
|||
if user is not None and user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS:
|
||||
chat = await Chats.get_chat_by_id(share_id, db=db)
|
||||
if chat:
|
||||
return ChatResponse.model_validate(chat, from_attributes=True)
|
||||
data = await shared_chat_response(chat, user, db=db)
|
||||
data['chat']['share_mode'] = (
|
||||
'continue'
|
||||
if await Chats.get_accessible_chat_by_id(chat.id, user, db=db, permission='write', chat=chat)
|
||||
else None
|
||||
)
|
||||
return data
|
||||
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND)
|
||||
|
||||
|
|
@ -1370,9 +1393,11 @@ async def get_chat_by_id(
|
|||
)
|
||||
|
||||
if chat:
|
||||
data = shared_chat_response(chat, user)
|
||||
data = await shared_chat_response(chat, user, db=db)
|
||||
data['chat']['share_mode'] = (
|
||||
'continue' if await Chats.get_accessible_chat_by_id(id, user, db=db, permission='write', chat=chat) else None
|
||||
'continue'
|
||||
if await Chats.get_accessible_chat_by_id(id, user, db=db, permission='write', chat=chat)
|
||||
else None
|
||||
)
|
||||
data = overlay_response_streams(
|
||||
data,
|
||||
|
|
@ -1746,11 +1771,14 @@ async def fork_chat_by_id(
|
|||
detail=detail,
|
||||
) from exc
|
||||
|
||||
# An unfinished message is stale unless it is awaiting tool approval
|
||||
for message in fork_history['messages'].values():
|
||||
author = (history.get('messages', {}).get(message['id']) or {}).get('user')
|
||||
if isinstance(author, dict) and author.get('id') == message.get('user_id'):
|
||||
message['user'] = author
|
||||
if message.get('role') != 'assistant' or message.get('done') is not False:
|
||||
continue
|
||||
|
||||
# An unfinished message is stale unless it is awaiting tool approval
|
||||
output = message.get('output')
|
||||
if isinstance(output, list) and any(
|
||||
isinstance(item, dict)
|
||||
|
|
@ -1910,7 +1938,7 @@ async def clone_shared_chat_by_id(
|
|||
)
|
||||
|
||||
updated_chat = {
|
||||
**shared_chat_response(chat, user)['chat'],
|
||||
**(await shared_chat_response(chat, user, db=db))['chat'],
|
||||
'originalChatId': chat.id,
|
||||
'branchPointMessageId': chat.chat['history']['currentId'],
|
||||
'title': f'Clone of {chat.title}',
|
||||
|
|
|
|||
|
|
@ -2997,6 +2997,8 @@
|
|||
parentId: parentMessage ? parentMessage.id : null,
|
||||
childrenIds: [responseMessageId],
|
||||
role: 'user',
|
||||
user_id: $user?.id,
|
||||
user: { id: $user?.id, name: $user?.name },
|
||||
content: userPrompt ? userPrompt : `[PROMPT] ${userMessageId}`,
|
||||
timestamp: Math.floor(Date.now() / 1000)
|
||||
};
|
||||
|
|
@ -3279,6 +3281,7 @@
|
|||
parentId: history.currentId ?? null,
|
||||
childrenIds: [],
|
||||
role: 'user',
|
||||
user: { id: $user?.id, name: $user?.name },
|
||||
user_id: $user?.id,
|
||||
content: inputContent,
|
||||
files: _files.length > 0 ? _files : undefined,
|
||||
|
|
@ -4188,6 +4191,8 @@
|
|||
parentId: parentId,
|
||||
childrenIds: [],
|
||||
role: 'user',
|
||||
user_id: $user?.id,
|
||||
user: { id: $user?.id, name: $user?.name },
|
||||
content: userPrompt,
|
||||
models: selectedModels,
|
||||
timestamp: Math.floor(Date.now() / 1000) // Unix epoch
|
||||
|
|
@ -4775,7 +4780,7 @@
|
|||
<Messages
|
||||
bind:this={messagesRef}
|
||||
chatId={$chatId}
|
||||
user={chatOwner ?? $user}
|
||||
user={chatOwner ?? (chat ? { id: chat.user_id } : $user)}
|
||||
{readOnly}
|
||||
shareMode={chat?.chat?.share_mode ?? null}
|
||||
bind:history
|
||||
|
|
|
|||
|
|
@ -333,6 +333,8 @@
|
|||
parentId: history.messages[messageId].parentId,
|
||||
childrenIds: [],
|
||||
role: 'user',
|
||||
user_id: $_user?.id,
|
||||
user: { id: $_user?.id, name: $_user?.name },
|
||||
content: userPrompt,
|
||||
...(files && { files: files }),
|
||||
models: selectedModels,
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
{#if history.messages[messageId]}
|
||||
{#if history.messages[messageId].role === 'user'}
|
||||
<UserMessage
|
||||
user={history.messages[messageId].user ?? user}
|
||||
{user}
|
||||
{chatId}
|
||||
{history}
|
||||
{messageId}
|
||||
|
|
|
|||
|
|
@ -682,7 +682,7 @@
|
|||
>
|
||||
<div class={`shrink-0 ltr:mr-2 rtl:ml-2 hidden @lg:flex mt-0.5 `}>
|
||||
<ProfileImage
|
||||
src={`${WEBUI_API_BASE_URL}/models/model/profile/image?id=${model?.id}&lang=${$i18n.language}`}
|
||||
src={`${WEBUI_API_BASE_URL}/models/model/profile/image?id=${model?.id ?? message.model}&lang=${$i18n.language}`}
|
||||
className={'size-7 assistant-message-profile-image'}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -57,6 +57,17 @@
|
|||
let editScrollContainer: HTMLDivElement;
|
||||
|
||||
let message = structuredClone(history.messages[messageId]);
|
||||
$: authorId = message.user_id || message.user?.id || user?.id;
|
||||
$: author =
|
||||
message.user?.id === authorId
|
||||
? message.user
|
||||
: $_user?.id === authorId
|
||||
? $_user
|
||||
: user?.id === authorId
|
||||
? user
|
||||
: null;
|
||||
$: isOwn = Boolean($_user?.id && authorId === $_user.id);
|
||||
$: authorName = author?.name || $i18n.t('Unknown User');
|
||||
let timerExpanded = false;
|
||||
$: if (history.messages) {
|
||||
const source = history.messages[messageId];
|
||||
|
|
@ -136,14 +147,16 @@
|
|||
id="message-{message.id}"
|
||||
style="scroll-margin-top: 3rem;"
|
||||
>
|
||||
{#if !($settings?.chatBubble ?? true) && !(message?.meta?.internal === true && message?.meta?.type === 'subagent') && !(message?.meta?.internal === true && message?.meta?.type === 'timer')}
|
||||
<div class={`shrink-0 ltr:mr-2 rtl:ml-2 hidden @lg:flex mt-0.5`}>
|
||||
{#if (!($settings?.chatBubble ?? true) || !isOwn) && !(message?.meta?.internal === true && message?.meta?.type === 'subagent') && !(message?.meta?.internal === true && message?.meta?.type === 'timer')}
|
||||
<div
|
||||
class="shrink-0 me-2 {($settings?.chatBubble ?? true) ? 'mt-6' : 'hidden @lg:flex mt-0.5'}"
|
||||
>
|
||||
<!-- LICENSE covers this Open WebUI fallback logo.
|
||||
Do not alter, remove, obscure, or replace it except as LICENSE permits:
|
||||
https://docs.openwebui.com/license. -->
|
||||
<ProfileImage
|
||||
src={user?.id
|
||||
? `${WEBUI_API_BASE_URL}/users/${user.id}/profile/image`
|
||||
src={authorId
|
||||
? `${WEBUI_API_BASE_URL}/users/${authorId}/profile/image`
|
||||
: `${WEBUI_BASE_URL}/static/favicon.png`}
|
||||
className={'size-7 user-message-profile-image'}
|
||||
/>
|
||||
|
|
@ -156,18 +169,17 @@
|
|||
? ''
|
||||
: 'pl-1'}"
|
||||
>
|
||||
{#if !($settings?.chatBubble ?? true) && !(message?.meta?.internal === true && message?.meta?.type === 'subagent') && !(message?.meta?.internal === true && message?.meta?.type === 'timer')}
|
||||
<div>
|
||||
<Name>
|
||||
{#if message.user}
|
||||
{$i18n.t('You')}
|
||||
<span class=" text-gray-500 text-[0.9375rem] font-normal">{message?.user ?? ''}</span>
|
||||
{:else if $settings.showUsername || $_user?.name !== user?.name}
|
||||
{user?.name ?? $i18n.t('You')}
|
||||
{:else}
|
||||
{$i18n.t('You')}
|
||||
{/if}
|
||||
</Name>
|
||||
{#if (!($settings?.chatBubble ?? true) || !isOwn) && !(message?.meta?.internal === true && message?.meta?.type === 'subagent') && !(message?.meta?.internal === true && message?.meta?.type === 'timer')}
|
||||
<div
|
||||
class={($settings?.chatBubble ?? true)
|
||||
? 'mb-1 text-xs text-gray-400 dark:text-gray-500'
|
||||
: ''}
|
||||
>
|
||||
{#if $settings?.chatBubble ?? true}
|
||||
{authorName}
|
||||
{:else}
|
||||
<Name>{isOwn && !$settings.showUsername ? $i18n.t('You') : authorName}</Name>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
|
@ -183,7 +195,9 @@
|
|||
file.url?.startsWith('data') || file.url?.startsWith('http')
|
||||
? file.url
|
||||
: `${WEBUI_API_BASE_URL}/files/${file.url}${file?.content_type ? '/content' : ''}`}
|
||||
<div class={($settings?.chatBubble ?? true) ? 'self-end' : ''}>
|
||||
<div
|
||||
class={($settings?.chatBubble ?? true) ? (isOwn ? 'self-end' : 'self-start') : ''}
|
||||
>
|
||||
{#if file.type === 'image' || isRasterImageContentType(file?.content_type)}
|
||||
<Image src={fileUrl} imageClassName=" max-h-96 rounded-lg" />
|
||||
{:else}
|
||||
|
|
@ -381,11 +395,15 @@
|
|||
<SubagentResultRow content={message.content} result={message.meta} />
|
||||
{:else if message.content !== ''}
|
||||
<div class="w-full">
|
||||
<div class="flex {($settings?.chatBubble ?? true) ? 'justify-end pb-1' : 'w-full'}">
|
||||
<div
|
||||
class="flex {($settings?.chatBubble ?? true)
|
||||
? `${isOwn ? 'justify-end' : 'justify-start'} pb-1`
|
||||
: 'w-full'}"
|
||||
>
|
||||
<div
|
||||
class="rounded-3xl {($settings?.chatBubble ?? true)
|
||||
? `max-w-[90%] px-4 py-1.5 bg-gray-50 dark:bg-gray-850 ${
|
||||
message.files ? 'rounded-tr-lg' : ''
|
||||
message.files ? (isOwn ? 'rounded-se-lg' : 'rounded-ss-lg') : ''
|
||||
}`
|
||||
: ' w-full'}"
|
||||
>
|
||||
|
|
@ -416,7 +434,9 @@
|
|||
{#if edit !== true && !(message?.meta?.internal === true && message?.meta?.type === 'subagent') && !(message?.meta?.internal === true && message?.meta?.type === 'timer')}
|
||||
<div
|
||||
class=" flex {($settings?.chatBubble ?? true)
|
||||
? 'justify-end'
|
||||
? isOwn
|
||||
? 'justify-end'
|
||||
: 'justify-start'
|
||||
: 'items-center'} text-gray-600 dark:text-gray-500"
|
||||
>
|
||||
{#if message.timestamp}
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@
|
|||
class="h-screen max-h-[100dvh] w-full flex flex-col text-gray-700 dark:text-gray-100 bg-white dark:bg-gray-900"
|
||||
>
|
||||
<div class="flex flex-col flex-auto justify-center relative">
|
||||
<div class=" flex flex-col w-full flex-auto overflow-auto h-0" id="messages-container">
|
||||
<div class="@container flex flex-col w-full flex-auto overflow-auto h-0" id="messages-container">
|
||||
<div
|
||||
class="pt-5 px-2 w-full {($settings?.widescreenMode ?? null)
|
||||
? 'max-w-full'
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue