mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-12 12:25:20 +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 fastapi import APIRouter, Depends, HTTPException, Request, status, BackgroundTasks
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
from pydantic import field_validator
|
||||||
|
|
||||||
from open_webui.socket.main import (
|
from open_webui.socket.main import (
|
||||||
emit_to_users,
|
emit_to_users,
|
||||||
|
|
@ -666,7 +666,16 @@ async def delete_channel_by_id(
|
||||||
|
|
||||||
|
|
||||||
class MessageUserResponse(MessageResponse):
|
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])
|
@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(
|
async def get_channel_message(
|
||||||
id: str, message_id: str, user=Depends(get_verified_user)
|
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()
|
status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT()
|
||||||
)
|
)
|
||||||
|
|
||||||
return MessageUserResponse(
|
return MessageResponse(
|
||||||
**{
|
**{
|
||||||
**message.model_dump(),
|
**message.model_dump(),
|
||||||
"user": UserNameResponse(
|
"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
|
# PinChannelMessage
|
||||||
############################
|
############################
|
||||||
|
|
|
||||||
|
|
@ -491,6 +491,44 @@ export const getChannelThreadMessages = async (
|
||||||
return res;
|
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 = {
|
type MessageForm = {
|
||||||
temp_id?: string;
|
temp_id?: string;
|
||||||
reply_to_id?: string;
|
reply_to_id?: string;
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,7 @@
|
||||||
{#each messageList as message, messageIdx (id ? `${id}-${message.id}` : message.id)}
|
{#each messageList as message, messageIdx (id ? `${id}-${message.id}` : message.id)}
|
||||||
<Message
|
<Message
|
||||||
{message}
|
{message}
|
||||||
|
{channel}
|
||||||
{thread}
|
{thread}
|
||||||
replyToMessage={replyToMessage?.id === message.id}
|
replyToMessage={replyToMessage?.id === message.id}
|
||||||
disabled={!channel?.write_access || message?.temp_id}
|
disabled={!channel?.write_access || message?.temp_id}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
import { settings, user, shortCodesToEmojis } from '$lib/stores';
|
import { settings, user, shortCodesToEmojis } from '$lib/stores';
|
||||||
import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants';
|
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 Markdown from '$lib/components/chat/Messages/Markdown.svelte';
|
||||||
import ProfileImage from '$lib/components/chat/Messages/ProfileImage.svelte';
|
import ProfileImage from '$lib/components/chat/Messages/ProfileImage.svelte';
|
||||||
|
|
@ -42,6 +43,8 @@
|
||||||
export let className = '';
|
export let className = '';
|
||||||
|
|
||||||
export let message;
|
export let message;
|
||||||
|
export let channel;
|
||||||
|
|
||||||
export let showUserProfile = true;
|
export let showUserProfile = true;
|
||||||
export let thread = false;
|
export let thread = false;
|
||||||
|
|
||||||
|
|
@ -61,6 +64,21 @@
|
||||||
let edit = false;
|
let edit = false;
|
||||||
let editedContent = null;
|
let editedContent = null;
|
||||||
let showDeleteConfirmDialog = false;
|
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>
|
</script>
|
||||||
|
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
|
|
@ -314,7 +332,12 @@
|
||||||
</Name>
|
</Name>
|
||||||
{/if}
|
{/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">
|
<div class="my-2.5 w-full flex overflow-x-auto gap-2 flex-wrap">
|
||||||
{#each message?.data?.files as file}
|
{#each message?.data?.files as file}
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue