refac
This commit is contained in:
@@ -1402,7 +1402,7 @@ async def chat_completion(
|
|||||||
updated['files'] = chat_files
|
updated['files'] = chat_files
|
||||||
if selected_chat_models:
|
if selected_chat_models:
|
||||||
updated['models'] = selected_chat_models
|
updated['models'] = selected_chat_models
|
||||||
await Chats.update_chat_by_id(chat_id, updated)
|
await Chats.update_chat_by_id(chat_id, updated, touch=False)
|
||||||
|
|
||||||
await Chats.update_chat_variables_by_id(chat_id, chat_variables)
|
await Chats.update_chat_variables_by_id(chat_id, chat_variables)
|
||||||
|
|
||||||
|
|||||||
@@ -614,17 +614,18 @@ class ChatTable:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def update_chat_last_read_at_by_id(self, id: str, user_id: str, db: AsyncSession | None = None) -> bool:
|
async def update_chat_last_read_at_by_id(self, id: str, user_id: str, db: AsyncSession | None = None) -> int | None:
|
||||||
try:
|
try:
|
||||||
async with get_async_db_context(db) as session:
|
async with get_async_db_context(db) as session:
|
||||||
chat = await session.get(Chat, id)
|
chat = await session.get(Chat, id)
|
||||||
if chat and chat.user_id == user_id:
|
if chat and chat.user_id == user_id:
|
||||||
chat.last_read_at = int(time.time())
|
last_read_at = int(time.time())
|
||||||
|
chat.last_read_at = last_read_at
|
||||||
await session.commit()
|
await session.commit()
|
||||||
return True
|
return last_read_at
|
||||||
return False
|
return None
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return None
|
||||||
|
|
||||||
async def update_chat_title_by_id(self, id: str, title: str) -> ChatModel | None:
|
async def update_chat_title_by_id(self, id: str, title: str) -> ChatModel | None:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ from open_webui.env import (
|
|||||||
from open_webui.models.access_grants import AccessGrants
|
from open_webui.models.access_grants import AccessGrants
|
||||||
from open_webui.models.channels import Channels
|
from open_webui.models.channels import Channels
|
||||||
from open_webui.models.chats import Chats
|
from open_webui.models.chats import Chats
|
||||||
|
from open_webui.models.folders import Folders
|
||||||
from open_webui.models.notes import Notes, NoteUpdateForm
|
from open_webui.models.notes import Notes, NoteUpdateForm
|
||||||
from open_webui.models.users import UserNameResponse, Users
|
from open_webui.models.users import UserNameResponse, Users
|
||||||
from open_webui.socket.utils import RedisDict, RedisLock, YdocManager
|
from open_webui.socket.utils import RedisDict, RedisLock, YdocManager
|
||||||
@@ -508,6 +509,24 @@ async def channel_events(sid, data):
|
|||||||
await Channels.update_member_last_read_at(data['channel_id'], user['id'])
|
await Channels.update_member_last_read_at(data['channel_id'], user['id'])
|
||||||
|
|
||||||
|
|
||||||
|
async def get_folder_unread_counts(user_id: str) -> dict[str, int]:
|
||||||
|
folder_list = await Folders.get_folders_by_user_id(user_id)
|
||||||
|
parent_by_id = {folder.id: folder.parent_id for folder in folder_list}
|
||||||
|
unread_counts = dict.fromkeys(parent_by_id.keys(), 0)
|
||||||
|
|
||||||
|
direct_unread_counts = await Chats.count_unread_by_folder_ids(user_id, list(parent_by_id.keys()))
|
||||||
|
for unread_folder_id, unread_count in direct_unread_counts.items():
|
||||||
|
current_id = unread_folder_id
|
||||||
|
seen = set()
|
||||||
|
while current_id and current_id not in seen:
|
||||||
|
seen.add(current_id)
|
||||||
|
if current_id in unread_counts:
|
||||||
|
unread_counts[current_id] += unread_count
|
||||||
|
current_id = parent_by_id.get(current_id)
|
||||||
|
|
||||||
|
return unread_counts
|
||||||
|
|
||||||
|
|
||||||
@sio.on('events:chat')
|
@sio.on('events:chat')
|
||||||
async def chat_events(sid, data):
|
async def chat_events(sid, data):
|
||||||
try:
|
try:
|
||||||
@@ -526,13 +545,21 @@ async def chat_events(sid, data):
|
|||||||
event_type = event_data.get('type')
|
event_type = event_data.get('type')
|
||||||
|
|
||||||
if event_type == 'last_read_at':
|
if event_type == 'last_read_at':
|
||||||
if not await Chats.update_chat_last_read_at_by_id(data['chat_id'], user['id']):
|
last_read_at = await Chats.update_chat_last_read_at_by_id(data['chat_id'], user['id'])
|
||||||
|
if not last_read_at:
|
||||||
return
|
return
|
||||||
await sio.emit(
|
await sio.emit(
|
||||||
'events',
|
'events',
|
||||||
{
|
{
|
||||||
'chat_id': data['chat_id'],
|
'chat_id': data['chat_id'],
|
||||||
'data': {'type': 'chat:list'},
|
'data': {
|
||||||
|
'type': 'chat:list',
|
||||||
|
'data': {
|
||||||
|
'chat_id': data['chat_id'],
|
||||||
|
'last_read_at': last_read_at,
|
||||||
|
'folder_unread_counts': await get_folder_unread_counts(user['id']),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
room=f'user:{user["id"]}',
|
room=f'user:{user["id"]}',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -31,7 +31,8 @@
|
|||||||
loadNextChatListPage,
|
loadNextChatListPage,
|
||||||
refreshChatList,
|
refreshChatList,
|
||||||
registerFolderRefreshHandler,
|
registerFolderRefreshHandler,
|
||||||
setChatActive
|
setChatActive,
|
||||||
|
setChatReadAt
|
||||||
} from '$lib/stores/chatList';
|
} from '$lib/stores/chatList';
|
||||||
import { onMount, getContext, tick, onDestroy } from 'svelte';
|
import { onMount, getContext, tick, onDestroy } from 'svelte';
|
||||||
|
|
||||||
@@ -691,7 +692,14 @@
|
|||||||
const chatActiveEventHandler = async (event: {
|
const chatActiveEventHandler = async (event: {
|
||||||
chat_id: string;
|
chat_id: string;
|
||||||
message_id: string;
|
message_id: string;
|
||||||
data: { type: string; data: { active?: boolean } };
|
data: {
|
||||||
|
type: string;
|
||||||
|
data: {
|
||||||
|
active?: boolean;
|
||||||
|
last_read_at?: number;
|
||||||
|
folder_unread_counts?: Record<string, number>;
|
||||||
|
};
|
||||||
|
};
|
||||||
}) => {
|
}) => {
|
||||||
if (event.data?.type === 'chat:active') {
|
if (event.data?.type === 'chat:active') {
|
||||||
const active = event.data.data.active ?? false;
|
const active = event.data.data.active ?? false;
|
||||||
@@ -700,6 +708,29 @@
|
|||||||
await refreshChatRows();
|
await refreshChatRows();
|
||||||
}
|
}
|
||||||
} else if (event.data?.type === 'chat:list') {
|
} else if (event.data?.type === 'chat:list') {
|
||||||
|
const eventData = event.data.data ?? {};
|
||||||
|
const folderUnreadCounts = eventData.folder_unread_counts;
|
||||||
|
if (folderUnreadCounts) {
|
||||||
|
folders = Object.fromEntries(
|
||||||
|
Object.entries(folders).map(([id, folder]) => [
|
||||||
|
id,
|
||||||
|
id in folderUnreadCounts ? { ...folder, unread_count: folderUnreadCounts[id] } : folder
|
||||||
|
])
|
||||||
|
);
|
||||||
|
_folders.update((folderList) =>
|
||||||
|
folderList.map((folder) =>
|
||||||
|
folder.id in folderUnreadCounts
|
||||||
|
? { ...folder, unread_count: folderUnreadCounts[folder.id] }
|
||||||
|
: folder
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof eventData.last_read_at === 'number') {
|
||||||
|
setChatReadAt(event.chat_id, eventData.last_read_at);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
refreshChatRows();
|
refreshChatRows();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
import RecursiveFolder from './RecursiveFolder.svelte';
|
import RecursiveFolder from './RecursiveFolder.svelte';
|
||||||
import { chatId } from '$lib/stores';
|
|
||||||
|
|
||||||
export let folderRegistry = {};
|
export let folderRegistry = {};
|
||||||
|
|
||||||
@@ -42,16 +41,6 @@
|
|||||||
folderRegistry[e.originFolderId]?.setFolderItems();
|
folderRegistry[e.originFolderId]?.setFolderItems();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadFolderItems = () => {
|
|
||||||
for (const folderId of Object.keys(folders)) {
|
|
||||||
folderRegistry[folderId]?.setFolderItems();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$: if (folders || $chatId) {
|
|
||||||
loadFolderItems();
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#each ownedList as folderId (folderId)}
|
{#each ownedList as folderId (folderId)}
|
||||||
|
|||||||
@@ -433,10 +433,16 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$: if (open) {
|
$: if (open && chats === null) {
|
||||||
setFolderItems();
|
setFolderItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: if (!open && chats !== null) {
|
||||||
|
chats = null;
|
||||||
|
chatsPage = 1;
|
||||||
|
hasMoreChats = false;
|
||||||
|
}
|
||||||
|
|
||||||
const renameHandler = async () => {
|
const renameHandler = async () => {
|
||||||
console.log('Edit');
|
console.log('Edit');
|
||||||
await tick();
|
await tick();
|
||||||
|
|||||||
@@ -123,6 +123,21 @@ export const setChatActive = (chatId: string, active: boolean): boolean => {
|
|||||||
return found;
|
return found;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setChatReadAt = (chatId: string, lastReadAt: number): boolean => {
|
||||||
|
let found = false;
|
||||||
|
const updateChat = (chat: ChatListItem) => {
|
||||||
|
if (chat.id !== chatId) {
|
||||||
|
return chat;
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
return { ...chat, last_read_at: lastReadAt };
|
||||||
|
};
|
||||||
|
|
||||||
|
chatsStore.update((items) => (items ? items.map(updateChat) : items));
|
||||||
|
pinnedChatsStore.update((items) => items.map(updateChat));
|
||||||
|
return found;
|
||||||
|
};
|
||||||
|
|
||||||
export const resetChatListState = () => {
|
export const resetChatListState = () => {
|
||||||
requestGeneration += 1;
|
requestGeneration += 1;
|
||||||
currentPage = 1;
|
currentPage = 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user