forked from open-webui/open-webui
		
	feat: export all chats from db
admin only
This commit is contained in:
		
							parent
							
								
									c4ca46637e
								
							
						
					
					
						commit
						7c2f297c84
					
				
					 4 changed files with 103 additions and 9 deletions
				
			
		|  | @ -70,9 +70,9 @@ class ChatTable: | ||||||
|             **{ |             **{ | ||||||
|                 "id": id, |                 "id": id, | ||||||
|                 "user_id": user_id, |                 "user_id": user_id, | ||||||
|                 "title": form_data.chat["title"] |                 "title": ( | ||||||
|                 if "title" in form_data.chat |                     form_data.chat["title"] if "title" in form_data.chat else "New Chat" | ||||||
|                 else "New Chat", |                 ), | ||||||
|                 "chat": json.dumps(form_data.chat), |                 "chat": json.dumps(form_data.chat), | ||||||
|                 "timestamp": int(time.time()), |                 "timestamp": int(time.time()), | ||||||
|             } |             } | ||||||
|  | @ -131,6 +131,12 @@ class ChatTable: | ||||||
|             .order_by(Chat.timestamp.desc()) |             .order_by(Chat.timestamp.desc()) | ||||||
|         ] |         ] | ||||||
| 
 | 
 | ||||||
|  |     def get_all_chats(self) -> List[ChatModel]: | ||||||
|  |         return [ | ||||||
|  |             ChatModel(**model_to_dict(chat)) | ||||||
|  |             for chat in Chat.select().order_by(Chat.timestamp.desc()) | ||||||
|  |         ] | ||||||
|  | 
 | ||||||
|     def get_all_chats_by_user_id(self, user_id: str) -> List[ChatModel]: |     def get_all_chats_by_user_id(self, user_id: str) -> List[ChatModel]: | ||||||
|         return [ |         return [ | ||||||
|             ChatModel(**model_to_dict(chat)) |             ChatModel(**model_to_dict(chat)) | ||||||
|  |  | ||||||
|  | @ -54,6 +54,25 @@ async def get_all_user_chats(user=Depends(get_current_user)): | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | ############################ | ||||||
|  | # GetAllChatsInDB | ||||||
|  | ############################ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @router.get("/all/db", response_model=List[ChatResponse]) | ||||||
|  | async def get_all_user_chats_in_db(user=Depends(get_current_user)): | ||||||
|  |     if user.role == "admin": | ||||||
|  |         return [ | ||||||
|  |             ChatResponse(**{**chat.model_dump(), "chat": json.loads(chat.chat)}) | ||||||
|  |             for chat in Chats.get_all_chats() | ||||||
|  |         ] | ||||||
|  |     else: | ||||||
|  |         raise HTTPException( | ||||||
|  |             status_code=status.HTTP_403_FORBIDDEN, | ||||||
|  |             detail=ERROR_MESSAGES.ACCESS_PROHIBITED, | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| ############################ | ############################ | ||||||
| # CreateNewChat | # CreateNewChat | ||||||
| ############################ | ############################ | ||||||
|  |  | ||||||
|  | @ -93,6 +93,37 @@ export const getAllChats = async (token: string) => { | ||||||
| 	return res; | 	return res; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | export const getAllUserChats = async (token: string) => { | ||||||
|  | 	let error = null; | ||||||
|  | 
 | ||||||
|  | 	const res = await fetch(`${WEBUI_API_BASE_URL}/chats/all/db`, { | ||||||
|  | 		method: 'GET', | ||||||
|  | 		headers: { | ||||||
|  | 			Accept: 'application/json', | ||||||
|  | 			'Content-Type': 'application/json', | ||||||
|  | 			...(token && { authorization: `Bearer ${token}` }) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 		.then(async (res) => { | ||||||
|  | 			if (!res.ok) throw await res.json(); | ||||||
|  | 			return res.json(); | ||||||
|  | 		}) | ||||||
|  | 		.then((json) => { | ||||||
|  | 			return json; | ||||||
|  | 		}) | ||||||
|  | 		.catch((err) => { | ||||||
|  | 			error = err; | ||||||
|  | 			console.log(err); | ||||||
|  | 			return null; | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  | 	if (error) { | ||||||
|  | 		throw error; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return res; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| export const getAllChatTags = async (token: string) => { | export const getAllChatTags = async (token: string) => { | ||||||
| 	let error = null; | 	let error = null; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -17,7 +17,13 @@ | ||||||
| 		deleteModel | 		deleteModel | ||||||
| 	} from '$lib/apis/ollama'; | 	} from '$lib/apis/ollama'; | ||||||
| 	import { updateUserPassword } from '$lib/apis/auths'; | 	import { updateUserPassword } from '$lib/apis/auths'; | ||||||
| 	import { createNewChat, deleteAllChats, getAllChats, getChatList } from '$lib/apis/chats'; | 	import { | ||||||
|  | 		createNewChat, | ||||||
|  | 		deleteAllChats, | ||||||
|  | 		getAllChats, | ||||||
|  | 		getAllUserChats, | ||||||
|  | 		getChatList | ||||||
|  | 	} from '$lib/apis/chats'; | ||||||
| 	import { WEB_UI_VERSION, WEBUI_API_BASE_URL } from '$lib/constants'; | 	import { WEB_UI_VERSION, WEBUI_API_BASE_URL } from '$lib/constants'; | ||||||
| 
 | 
 | ||||||
| 	import { config, models, voices, settings, user, chats } from '$lib/stores'; | 	import { config, models, voices, settings, user, chats } from '$lib/stores'; | ||||||
|  | @ -179,6 +185,13 @@ | ||||||
| 		saveAs(blob, `chat-export-${Date.now()}.json`); | 		saveAs(blob, `chat-export-${Date.now()}.json`); | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
|  | 	const exportAllUserChats = async () => { | ||||||
|  | 		let blob = new Blob([JSON.stringify(await getAllUserChats(localStorage.token))], { | ||||||
|  | 			type: 'application/json' | ||||||
|  | 		}); | ||||||
|  | 		saveAs(blob, `all-chats-export-${Date.now()}.json`); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
| 	const deleteChats = async () => { | 	const deleteChats = async () => { | ||||||
| 		await goto('/'); | 		await goto('/'); | ||||||
| 		await deleteAllChats(localStorage.token); | 		await deleteAllChats(localStorage.token); | ||||||
|  | @ -1962,23 +1975,48 @@ | ||||||
| 											fill="currentColor" | 											fill="currentColor" | ||||||
| 											class="w-4 h-4" | 											class="w-4 h-4" | ||||||
| 										> | 										> | ||||||
| 											<path |  | ||||||
| 												d="M2 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3Z" |  | ||||||
| 											/> |  | ||||||
| 											<path | 											<path | ||||||
| 												fill-rule="evenodd" | 												fill-rule="evenodd" | ||||||
| 												d="M13 6H3v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V6ZM5.72 7.47a.75.75 0 0 1 1.06 0L8 8.69l1.22-1.22a.75.75 0 1 1 1.06 1.06L9.06 9.75l1.22 1.22a.75.75 0 1 1-1.06 1.06L8 10.81l-1.22 1.22a.75.75 0 0 1-1.06-1.06l1.22-1.22-1.22-1.22a.75.75 0 0 1 0-1.06Z" | 												d="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm7 7a.75.75 0 0 1-.75.75h-4.5a.75.75 0 0 1 0-1.5h4.5A.75.75 0 0 1 11 9Z" | ||||||
| 												clip-rule="evenodd" | 												clip-rule="evenodd" | ||||||
| 											/> | 											/> | ||||||
| 										</svg> | 										</svg> | ||||||
| 									</div> | 									</div> | ||||||
| 									<div class=" self-center text-sm font-medium">Delete All Chats</div> | 									<div class=" self-center text-sm font-medium">Delete Chats</div> | ||||||
| 								</button> | 								</button> | ||||||
| 							{/if} | 							{/if} | ||||||
| 
 | 
 | ||||||
| 							{#if $user?.role === 'admin'} | 							{#if $user?.role === 'admin'} | ||||||
| 								<hr class=" dark:border-gray-700" /> | 								<hr class=" dark:border-gray-700" /> | ||||||
| 
 | 
 | ||||||
|  | 								<button | ||||||
|  | 									class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition" | ||||||
|  | 									on:click={() => { | ||||||
|  | 										exportAllUserChats(); | ||||||
|  | 									}} | ||||||
|  | 								> | ||||||
|  | 									<div class=" self-center mr-3"> | ||||||
|  | 										<svg | ||||||
|  | 											xmlns="http://www.w3.org/2000/svg" | ||||||
|  | 											viewBox="0 0 16 16" | ||||||
|  | 											fill="currentColor" | ||||||
|  | 											class="w-4 h-4" | ||||||
|  | 										> | ||||||
|  | 											<path | ||||||
|  | 												d="M2 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3Z" | ||||||
|  | 											/> | ||||||
|  | 											<path | ||||||
|  | 												fill-rule="evenodd" | ||||||
|  | 												d="M13 6H3v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V6ZM8.75 7.75a.75.75 0 0 0-1.5 0v2.69L6.03 9.22a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l2.5-2.5a.75.75 0 1 0-1.06-1.06l-1.22 1.22V7.75Z" | ||||||
|  | 												clip-rule="evenodd" | ||||||
|  | 											/> | ||||||
|  | 										</svg> | ||||||
|  | 									</div> | ||||||
|  | 									<div class=" self-center text-sm font-medium">Export All Chats (All Users)</div> | ||||||
|  | 								</button> | ||||||
|  | 
 | ||||||
|  | 								<hr class=" dark:border-gray-700" /> | ||||||
|  | 
 | ||||||
| 								<button | 								<button | ||||||
| 									class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition" | 									class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition" | ||||||
| 									on:click={() => { | 									on:click={() => { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Timothy J. Baek
						Timothy J. Baek