mirror of
https://github.com/open-webui/open-webui
synced 2024-11-22 08:07:55 +00:00
enh: feedback exports
This commit is contained in:
parent
58d929fd65
commit
8b61b39c75
@ -5,6 +5,7 @@ from pydantic import BaseModel
|
||||
from open_webui.apps.webui.models.users import Users, UserModel
|
||||
from open_webui.apps.webui.models.feedbacks import (
|
||||
FeedbackModel,
|
||||
FeedbackResponse,
|
||||
FeedbackForm,
|
||||
Feedbacks,
|
||||
)
|
||||
@ -55,27 +56,15 @@ async def update_config(
|
||||
}
|
||||
|
||||
|
||||
@router.get("/feedbacks", response_model=list[FeedbackModel])
|
||||
async def get_feedbacks(user=Depends(get_verified_user)):
|
||||
feedbacks = Feedbacks.get_feedbacks_by_user_id(user.id)
|
||||
return feedbacks
|
||||
|
||||
|
||||
@router.delete("/feedbacks", response_model=bool)
|
||||
async def delete_feedbacks(user=Depends(get_verified_user)):
|
||||
success = Feedbacks.delete_feedbacks_by_user_id(user.id)
|
||||
return success
|
||||
|
||||
|
||||
class FeedbackUserModel(FeedbackModel):
|
||||
class FeedbackUserResponse(FeedbackResponse):
|
||||
user: Optional[UserModel] = None
|
||||
|
||||
|
||||
@router.get("/feedbacks/all", response_model=list[FeedbackUserModel])
|
||||
@router.get("/feedbacks/all", response_model=list[FeedbackUserResponse])
|
||||
async def get_all_feedbacks(user=Depends(get_admin_user)):
|
||||
feedbacks = Feedbacks.get_all_feedbacks()
|
||||
return [
|
||||
FeedbackUserModel(
|
||||
FeedbackUserResponse(
|
||||
**feedback.model_dump(), user=Users.get_user_by_id(feedback.user_id)
|
||||
)
|
||||
for feedback in feedbacks
|
||||
@ -88,6 +77,29 @@ async def delete_all_feedbacks(user=Depends(get_admin_user)):
|
||||
return success
|
||||
|
||||
|
||||
@router.get("/feedbacks/all/export", response_model=list[FeedbackModel])
|
||||
async def get_all_feedbacks(user=Depends(get_admin_user)):
|
||||
feedbacks = Feedbacks.get_all_feedbacks()
|
||||
return [
|
||||
FeedbackModel(
|
||||
**feedback.model_dump(), user=Users.get_user_by_id(feedback.user_id)
|
||||
)
|
||||
for feedback in feedbacks
|
||||
]
|
||||
|
||||
|
||||
@router.get("/feedbacks/user", response_model=list[FeedbackUserResponse])
|
||||
async def get_feedbacks(user=Depends(get_verified_user)):
|
||||
feedbacks = Feedbacks.get_feedbacks_by_user_id(user.id)
|
||||
return feedbacks
|
||||
|
||||
|
||||
@router.delete("/feedbacks", response_model=bool)
|
||||
async def delete_feedbacks(user=Depends(get_verified_user)):
|
||||
success = Feedbacks.delete_feedbacks_by_user_id(user.id)
|
||||
return success
|
||||
|
||||
|
||||
@router.post("/feedback", response_model=FeedbackModel)
|
||||
async def create_feedback(
|
||||
request: Request,
|
||||
|
@ -93,6 +93,37 @@ export const getAllFeedbacks = async (token: string = '') => {
|
||||
return res;
|
||||
};
|
||||
|
||||
export const exportAllFeedbacks = async (token: string = '') => {
|
||||
let error = null;
|
||||
|
||||
const res = await fetch(`${WEBUI_API_BASE_URL}/evaluations/feedbacks/all/export`, {
|
||||
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.log(err);
|
||||
return null;
|
||||
});
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
export const createNewFeedback = async (token: string, feedback: object) => {
|
||||
let error = null;
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
<script lang="ts">
|
||||
import fileSaver from 'file-saver';
|
||||
const { saveAs } = fileSaver;
|
||||
|
||||
import { onMount, getContext } from 'svelte';
|
||||
import dayjs from 'dayjs';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
@ -12,7 +15,7 @@
|
||||
let model = null;
|
||||
|
||||
import { models } from '$lib/stores';
|
||||
import { deleteFeedbackById, getAllFeedbacks } from '$lib/apis/evaluations';
|
||||
import { deleteFeedbackById, exportAllFeedbacks, getAllFeedbacks } from '$lib/apis/evaluations';
|
||||
|
||||
import FeedbackMenu from './Evaluations/FeedbackMenu.svelte';
|
||||
import EllipsisHorizontal from '../icons/EllipsisHorizontal.svelte';
|
||||
@ -24,6 +27,9 @@
|
||||
import CloudArrowUp from '../icons/CloudArrowUp.svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import Spinner from '../common/Spinner.svelte';
|
||||
import DocumentArrowUpSolid from '../icons/DocumentArrowUpSolid.svelte';
|
||||
import DocumentArrowDown from '../icons/DocumentArrowDown.svelte';
|
||||
import ArrowDownTray from '../icons/ArrowDownTray.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
@ -300,6 +306,20 @@
|
||||
window.addEventListener('message', messageHandler, false);
|
||||
};
|
||||
|
||||
const exportHandler = async () => {
|
||||
const _feedbacks = await exportAllFeedbacks(localStorage.token).catch((err) => {
|
||||
toast.error(err);
|
||||
return null;
|
||||
});
|
||||
|
||||
if (_feedbacks) {
|
||||
let blob = new Blob([JSON.stringify(_feedbacks)], {
|
||||
type: 'application/json'
|
||||
});
|
||||
saveAs(blob, `feedback-history-export-${Date.now()}.json`);
|
||||
}
|
||||
};
|
||||
|
||||
const loadEmbeddingModel = async () => {
|
||||
// Check if the tokenizer and model are already loaded and stored in the window object
|
||||
if (!window.tokenizer) {
|
||||
@ -483,6 +503,21 @@
|
||||
|
||||
<span class="text-lg font-medium text-gray-500 dark:text-gray-300">{feedbacks.length}</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<Tooltip content={$i18n.t('Export')}>
|
||||
<button
|
||||
class=" p-2 rounded-xl hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 transition font-medium text-sm flex items-center space-x-1"
|
||||
on:click={() => {
|
||||
exportHandler();
|
||||
}}
|
||||
>
|
||||
<ArrowDownTray className="size-3" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@ -626,18 +661,7 @@
|
||||
</div>
|
||||
|
||||
<div class=" self-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-3.5 h-3.5"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
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 2H4Zm4 9.5a.75.75 0 0 1-.75-.75V8.06l-.72.72a.75.75 0 0 1-1.06-1.06l2-2a.75.75 0 0 1 1.06 0l2 2a.75.75 0 1 1-1.06 1.06l-.72-.72v2.69a.75.75 0 0 1-.75.75Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<CloudArrowUp className="size-3" strokeWidth="3" />
|
||||
</div>
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
19
src/lib/components/icons/DocumentArrowDown.svelte
Normal file
19
src/lib/components/icons/DocumentArrowDown.svelte
Normal file
@ -0,0 +1,19 @@
|
||||
<script lang="ts">
|
||||
export let className = 'size-4';
|
||||
export let strokeWidth = '1.5';
|
||||
</script>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width={strokeWidth}
|
||||
stroke="currentColor"
|
||||
class={className}
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m.75 12 3 3m0 0 3-3m-3 3v-6m-1.5-9H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
|
||||
/>
|
||||
</svg>
|
Loading…
Reference in New Issue
Block a user