mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-11 20:05:19 +00:00
enh/refac: channels message lazy load data
This commit is contained in:
parent
133618aaf0
commit
54b7ec56d6
4 changed files with 118 additions and 5 deletions
|
|
@ -5,7 +5,7 @@ from typing import Optional
|
|||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, status, BackgroundTasks
|
||||
from pydantic import BaseModel
|
||||
|
||||
from pydantic import field_validator
|
||||
|
||||
from open_webui.socket.main import (
|
||||
emit_to_users,
|
||||
|
|
@ -666,7 +666,16 @@ async def delete_channel_by_id(
|
|||
|
||||
|
||||
class MessageUserResponse(MessageResponse):
|
||||
pass
|
||||
data: bool | None = None
|
||||
|
||||
@field_validator("data", mode="before")
|
||||
def convert_data_to_bool(cls, v):
|
||||
# No data or not a dict → False
|
||||
if not isinstance(v, dict):
|
||||
return False
|
||||
|
||||
# True if ANY value in the dict is non-empty
|
||||
return any(bool(val) for val in v.values())
|
||||
|
||||
|
||||
@router.get("/{id}/messages", response_model=list[MessageUserResponse])
|
||||
|
|
@ -1108,7 +1117,7 @@ async def post_new_message(
|
|||
############################
|
||||
|
||||
|
||||
@router.get("/{id}/messages/{message_id}", response_model=Optional[MessageUserResponse])
|
||||
@router.get("/{id}/messages/{message_id}", response_model=Optional[MessageResponse])
|
||||
async def get_channel_message(
|
||||
id: str, message_id: str, user=Depends(get_verified_user)
|
||||
):
|
||||
|
|
@ -1142,7 +1151,7 @@ async def get_channel_message(
|
|||
status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT()
|
||||
)
|
||||
|
||||
return MessageUserResponse(
|
||||
return MessageResponse(
|
||||
**{
|
||||
**message.model_dump(),
|
||||
"user": UserNameResponse(
|
||||
|
|
@ -1152,6 +1161,48 @@ async def get_channel_message(
|
|||
)
|
||||
|
||||
|
||||
############################
|
||||
# GetChannelMessageData
|
||||
############################
|
||||
|
||||
|
||||
@router.get("/{id}/messages/{message_id}/data", response_model=Optional[dict])
|
||||
async def get_channel_message_data(
|
||||
id: str, message_id: str, user=Depends(get_verified_user)
|
||||
):
|
||||
channel = Channels.get_channel_by_id(id)
|
||||
if not channel:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND
|
||||
)
|
||||
|
||||
if channel.type in ["group", "dm"]:
|
||||
if not Channels.is_user_channel_member(channel.id, user.id):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()
|
||||
)
|
||||
else:
|
||||
if user.role != "admin" and not has_access(
|
||||
user.id, type="read", access_control=channel.access_control
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()
|
||||
)
|
||||
|
||||
message = Messages.get_message_by_id(message_id)
|
||||
if not message:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND
|
||||
)
|
||||
|
||||
if message.channel_id != id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT()
|
||||
)
|
||||
|
||||
return message.data
|
||||
|
||||
|
||||
############################
|
||||
# PinChannelMessage
|
||||
############################
|
||||
|
|
|
|||
|
|
@ -491,6 +491,44 @@ export const getChannelThreadMessages = async (
|
|||
return res;
|
||||
};
|
||||
|
||||
export const getMessageData = async (
|
||||
token: string = '',
|
||||
channel_id: string,
|
||||
message_id: string
|
||||
) => {
|
||||
let error = null;
|
||||
|
||||
const res = await fetch(
|
||||
`${WEBUI_API_BASE_URL}/channels/${channel_id}/messages/${message_id}/data`,
|
||||
{
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
authorization: `Bearer ${token}`
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(async (res) => {
|
||||
if (!res.ok) throw await res.json();
|
||||
return res.json();
|
||||
})
|
||||
.then((json) => {
|
||||
return json;
|
||||
})
|
||||
.catch((err) => {
|
||||
error = err.detail;
|
||||
console.error(err);
|
||||
return null;
|
||||
});
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
type MessageForm = {
|
||||
temp_id?: string;
|
||||
reply_to_id?: string;
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@
|
|||
{#each messageList as message, messageIdx (id ? `${id}-${message.id}` : message.id)}
|
||||
<Message
|
||||
{message}
|
||||
{channel}
|
||||
{thread}
|
||||
replyToMessage={replyToMessage?.id === message.id}
|
||||
disabled={!channel?.write_access || message?.temp_id}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
import { settings, user, shortCodesToEmojis } from '$lib/stores';
|
||||
import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants';
|
||||
import { getMessageData } from '$lib/apis/channels';
|
||||
|
||||
import Markdown from '$lib/components/chat/Messages/Markdown.svelte';
|
||||
import ProfileImage from '$lib/components/chat/Messages/ProfileImage.svelte';
|
||||
|
|
@ -42,6 +43,8 @@
|
|||
export let className = '';
|
||||
|
||||
export let message;
|
||||
export let channel;
|
||||
|
||||
export let showUserProfile = true;
|
||||
export let thread = false;
|
||||
|
||||
|
|
@ -61,6 +64,21 @@
|
|||
let edit = false;
|
||||
let editedContent = null;
|
||||
let showDeleteConfirmDialog = false;
|
||||
|
||||
const loadMessageData = async () => {
|
||||
if (message && message?.data) {
|
||||
const res = await getMessageData(localStorage.token, channel?.id, message.id);
|
||||
if (res) {
|
||||
message.data = res;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
if (message && message?.data) {
|
||||
await loadMessageData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<ConfirmDialog
|
||||
|
|
@ -314,7 +332,12 @@
|
|||
</Name>
|
||||
{/if}
|
||||
|
||||
{#if (message?.data?.files ?? []).length > 0}
|
||||
{#if message?.data === true}
|
||||
<!-- loading indicator -->
|
||||
<div class=" my-2">
|
||||
<Skeleton />
|
||||
</div>
|
||||
{:else if (message?.data?.files ?? []).length > 0}
|
||||
<div class="my-2.5 w-full flex overflow-x-auto gap-2 flex-wrap">
|
||||
{#each message?.data?.files as file}
|
||||
<div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue