فهرست منبع

enh: knowledge author info

Timothy Jaeryang Baek 5 ماه پیش
والد
کامیت
6c3e6710ef

+ 16 - 12
backend/open_webui/apps/webui/models/knowledge.py

@@ -8,6 +8,7 @@ from open_webui.apps.webui.internal.db import Base, get_db
 from open_webui.env import SRC_LOG_LEVELS
 
 from open_webui.apps.webui.models.files import FileMetadataResponse
+from open_webui.apps.webui.models.users import Users, UserResponse
 
 
 from pydantic import BaseModel, ConfigDict
@@ -79,17 +80,15 @@ class KnowledgeModel(BaseModel):
 ####################
 
 
-class KnowledgeResponse(BaseModel):
-    id: str
-    name: str
-    description: str
-    data: Optional[dict] = None
-    meta: Optional[dict] = None
+class KnowledgeUserModel(KnowledgeModel):
+    user: Optional[UserResponse] = None
+
+
+class KnowledgeResponse(KnowledgeModel):
+    files: Optional[list[FileMetadataResponse | dict]] = None
 
-    access_control: Optional[dict] = None
-    created_at: int  # timestamp in epoch
-    updated_at: int  # timestamp in epoch
 
+class KnowledgeUserResponse(KnowledgeUserModel):
     files: Optional[list[FileMetadataResponse | dict]] = None
 
 
@@ -127,10 +126,15 @@ class KnowledgeTable:
             except Exception:
                 return None
 
-    def get_knowledge_bases(self) -> list[KnowledgeModel]:
+    def get_knowledge_bases(self) -> list[KnowledgeUserModel]:
         with get_db() as db:
             return [
-                KnowledgeModel.model_validate(knowledge)
+                KnowledgeUserModel.model_validate(
+                    {
+                        **KnowledgeModel.model_validate(knowledge).model_dump(),
+                        "user": Users.get_user_by_id(knowledge.user_id).model_dump(),
+                    }
+                )
                 for knowledge in db.query(Knowledge)
                 .order_by(Knowledge.updated_at.desc())
                 .all()
@@ -138,7 +142,7 @@ class KnowledgeTable:
 
     def get_knowledge_bases_by_user_id(
         self, user_id: str, permission: str = "write"
-    ) -> list[KnowledgeModel]:
+    ) -> list[KnowledgeUserModel]:
         knowledge_bases = self.get_knowledge_bases()
         return [
             knowledge_base

+ 3 - 2
backend/open_webui/apps/webui/routers/knowledge.py

@@ -8,6 +8,7 @@ from open_webui.apps.webui.models.knowledge import (
     Knowledges,
     KnowledgeForm,
     KnowledgeResponse,
+    KnowledgeUserResponse,
 )
 from open_webui.apps.webui.models.files import Files, FileModel
 from open_webui.apps.retrieval.vector.connector import VECTOR_DB_CLIENT
@@ -32,7 +33,7 @@ router = APIRouter()
 ############################
 
 
-@router.get("/", response_model=list[KnowledgeResponse])
+@router.get("/", response_model=list[KnowledgeUserResponse])
 async def get_knowledge(user=Depends(get_verified_user)):
     knowledge_bases = []
 
@@ -77,7 +78,7 @@ async def get_knowledge(user=Depends(get_verified_user)):
     return knowledge_bases
 
 
-@router.get("/list", response_model=list[KnowledgeResponse])
+@router.get("/list", response_model=list[KnowledgeUserResponse])
 async def get_knowledge_list(user=Depends(get_verified_user)):
     knowledge_bases = []
 

+ 20 - 8
src/lib/components/workspace/Knowledge.svelte

@@ -24,6 +24,8 @@
 	import Search from '../icons/Search.svelte';
 	import Plus from '../icons/Plus.svelte';
 	import Spinner from '../common/Spinner.svelte';
+	import { capitalizeFirstLetter } from '$lib/utils';
+	import Tooltip from '../common/Tooltip.svelte';
 
 	let loaded = false;
 
@@ -137,7 +139,11 @@
 			>
 				<div class=" w-full">
 					<div class="flex items-center justify-between -mt-1">
-						<div class=" font-semibold line-clamp-1 h-fit">{item.name}</div>
+						{#if item?.meta?.document}
+							<Badge type="muted" content={$i18n.t('Document')} />
+						{:else}
+							<Badge type="success" content={$i18n.t('Collection')} />
+						{/if}
 
 						<div class=" flex self-center">
 							<ItemMenu
@@ -150,17 +156,23 @@
 					</div>
 
 					<div class=" self-center flex-1">
+						<div class=" font-semibold line-clamp-1 h-fit">{item.name}</div>
+
 						<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1">
 							{item.description}
 						</div>
 
-						<div class="mt-5 flex justify-between">
-							<div>
-								{#if item?.meta?.document}
-									<Badge type="muted" content={$i18n.t('Document')} />
-								{:else}
-									<Badge type="success" content={$i18n.t('Collection')} />
-								{/if}
+						<div class="mt-3 flex justify-between">
+							<div class="text-xs">
+								<Tooltip
+									content={item?.user?.email}
+									className="flex shrink-0"
+									placement="top-start"
+								>
+									{$i18n.t('By {{name}}', {
+										name: capitalizeFirstLetter(item?.user?.name ?? item?.user?.email)
+									})}
+								</Tooltip>
 							</div>
 							<div class=" text-xs text-gray-500 line-clamp-1">
 								{$i18n.t('Updated')}

+ 4 - 1
src/lib/components/workspace/Models.svelte

@@ -32,6 +32,7 @@
 	import ChevronRight from '../icons/ChevronRight.svelte';
 	import Switch from '../common/Switch.svelte';
 	import Spinner from '../common/Spinner.svelte';
+	import { capitalizeFirstLetter } from '$lib/utils';
 
 	let shiftKey = false;
 
@@ -288,7 +289,9 @@
 						<div class="flex gap-1 text-xs overflow-hidden">
 							<Tooltip content={model?.user?.email} className="flex shrink-0" placement="top-start">
 								<div class="shrink-0 text-gray-500">
-									By <span class=" capitalize">{model?.user?.name ?? model?.user?.email}</span>
+									{$i18n.t('By {{name}}', {
+										name: capitalizeFirstLetter(model?.user?.name ?? model?.user?.email)
+									})}
 								</div>
 							</Tooltip>
 						</div>

+ 1 - 0
src/lib/utils/index.ts

@@ -8,6 +8,7 @@ import { TTS_RESPONSE_SPLIT } from '$lib/types';
 // Helper functions
 //////////////////////////
 
+
 export const replaceTokens = (content, char, user) => {
 	const charToken = /{{char}}/gi;
 	const userToken = /{{user}}/gi;