Skip to content

Commit 4f69245

Browse files
committed
feat: implement knowledge update functionality for bots
- Added a new hook `useKnowledgeUpdate` to manage knowledge updates. - Integrated knowledge update feature in `BotCard` component with loading state. - Created `updateKnowledge` API in `BotsController` to handle knowledge updates. - Updated FastAPI router to include endpoint for knowledge updates, validating bot existence. - Refactored retrieval logic to check and update knowledge based on document changes.
1 parent bc76d17 commit 4f69245

File tree

6 files changed

+130
-11
lines changed

6 files changed

+130
-11
lines changed

client/app/factory/list/components/BotCard.tsx

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import ErrorBadgeIcon from '@/public/icons/ErrorBadgeIcon';
2525
import CheckBadgeIcon from '@/public/icons/CheckBadgeIcon';
2626
import LoadingIcon from '@/public/icons/LoadingIcon';
2727
import { RagTask } from '@/app/services/BotsController';
28+
import { useKnowledgeUpdate } from '@/app/hooks/useKnowledgeUpdate';
2829

2930
declare type Bot = Tables<'bots'>;
3031

@@ -34,6 +35,8 @@ const BotCard = (props: { bot: Bot }) => {
3435
const router = useRouter();
3536
const { deleteBot, isLoading, isSuccess } = useBotDelete();
3637
const { data: taskInfo } = useGetBotRagTask(bot.id, true, false);
38+
const { mutate: updateKnowledge, isPending: isUpdating } =
39+
useKnowledgeUpdate();
3740

3841
useEffect(() => {
3942
if (isSuccess) {
@@ -69,6 +72,19 @@ const BotCard = (props: { bot: Bot }) => {
6972
);
7073
};
7174

75+
const handleUpdateKnowledge = () => {
76+
updateKnowledge(
77+
{
78+
bot_id: bot.id,
79+
},
80+
{
81+
onSuccess: () => {
82+
// TODO
83+
},
84+
},
85+
);
86+
};
87+
7288
return (
7389
<>
7490
<Card
@@ -124,21 +140,30 @@ const BotCard = (props: { bot: Bot }) => {
124140
placement="top"
125141
content={I18N.components.BotCard.gengXinZhiShiKu}
126142
classNames={{
127-
base: [
128-
// arrow color
129-
'before:bg-[#3F3F46] dark:before:bg-white',
130-
],
143+
base: ['before:bg-[#3F3F46] dark:before:bg-white'],
131144
content: [
132145
'py-2 px-4 rounded-lg shadow-xl text-white',
133146
'bg-[#3F3F46]',
134147
],
135148
}}
136149
>
137-
<Image
138-
src="../images/refresh.svg"
139-
alt={I18N.components.BotCard.gengXinZhiShi}
140-
className="z-10 cursor-pointer"
141-
/>
150+
{isUpdating ? (
151+
<div className="w-6 h-6 flex items-center justify-center">
152+
<span className="animate-spinner-ease-spin">
153+
<LoadingIcon />
154+
</span>
155+
</div>
156+
) : (
157+
<Image
158+
src="../images/refresh.svg"
159+
onClick={(e) => {
160+
e.stopPropagation();
161+
handleUpdateKnowledge();
162+
}}
163+
alt={I18N.components.BotCard.gengXinZhiShi}
164+
className="z-10 cursor-pointer"
165+
/>
166+
)}
142167
</Tooltip>
143168
</div>
144169
</div>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { useMutation } from '@tanstack/react-query';
2+
import { updateKnowledge } from '../services/BotsController';
3+
4+
export function useKnowledgeUpdate() {
5+
return useMutation({
6+
mutationKey: ['updateKnowledge'],
7+
mutationFn: updateKnowledge
8+
});
9+
}

client/app/services/BotsController.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,10 @@ export async function bindBotToRepo(repsConfigs: BindBotToRepoConfig[]) {
135135
});
136136
return response.data;
137137
}
138+
139+
// Add knowledge update API
140+
export async function updateKnowledge(config: {
141+
bot_id: string;
142+
}) {
143+
return axios.post(`${apiDomain}/api/rag/update_knowledge`, config);
144+
}

petercat_utils/rag_helper/git_doc_task.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def handle_tree_node(self):
142142
)
143143

144144
def handle_blob_node(self):
145-
retrieval.add_knowledge_by_doc(
145+
retrieval.check_and_update_knowledge(
146146
RAGGitDocConfig(
147147
repo_name=self.repo_name,
148148
file_path=self.path,

petercat_utils/rag_helper/retrieval.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,40 @@ def get_chunk_list(repo_name: str, page_size: int, page_number: int):
197197
)
198198
total_count = len(count_response.data)
199199
return {"rows": query.data, "total": total_count}
200+
201+
202+
def check_and_update_knowledge(config: RAGGitDocConfig):
203+
# 初始化 GitHub loader 获取最新的文件信息
204+
loader = init_github_file_loader(config)
205+
latest_sha = loader.file_sha
206+
207+
# 获取当前存储的文档
208+
client = get_client()
209+
existing_docs = (
210+
client.table(TABLE_NAME)
211+
.select("id, file_sha")
212+
.eq("repo_name", config.repo_name)
213+
.eq("file_path", config.file_path)
214+
.execute()
215+
)
216+
217+
if not existing_docs.data:
218+
# 如果不存在文档,直接添加
219+
return add_knowledge_by_doc(config)
220+
221+
# 检查 SHA 是否变化
222+
current_sha = existing_docs.data[0]["file_sha"]
223+
224+
if current_sha == latest_sha:
225+
return False
226+
227+
# SHA 不同,需要更新
228+
# 1. 删除旧文档
229+
client.table(TABLE_NAME)\
230+
.delete()\
231+
.eq("repo_name", config.repo_name)\
232+
.eq("file_path", config.file_path)\
233+
.execute()
234+
235+
# 2. 添加新文档
236+
return add_knowledge_by_doc(config)

server/rag/router.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import json
2-
from typing import Optional
2+
from typing import Annotated, Optional
3+
from pydantic import BaseModel
34

5+
from auth.get_user_info import get_user_id
46
from fastapi import APIRouter, Depends
57
from petercat_utils.db.client.supabase import get_client
68

@@ -116,3 +118,42 @@ def get_rag_task(repo_name: str):
116118
return response
117119
except Exception as e:
118120
return json.dumps({"success": False, "message": str(e)})
121+
122+
class UpdateKnowledgeRequest(BaseModel):
123+
bot_id: str
124+
125+
@router.post("/rag/update_knowledge", dependencies=[Depends(verify_rate_limit)])
126+
def update_knowledge(request: UpdateKnowledgeRequest, user_id: Annotated[str | None, Depends(get_user_id)] = None):
127+
try:
128+
# Get config from database using bot_id
129+
supabase = get_client()
130+
response = (
131+
supabase.table("bots")
132+
.select("*")
133+
.eq("id", request.bot_id)
134+
.eq("uid", user_id)
135+
.single()
136+
.execute()
137+
)
138+
139+
if not response.data:
140+
return json.dumps({
141+
"success": False,
142+
"message": f"Bot with id {request.bot_id} not found"
143+
})
144+
145+
bot_config = RAGGitDocConfig(**response.data)
146+
result = retrieval.check_and_update_knowledge(bot_config)
147+
148+
if result:
149+
return json.dumps({
150+
"success": True,
151+
"message": "Knowledge updated successfully!"
152+
})
153+
else:
154+
return json.dumps({
155+
"success": False,
156+
"message": "Knowledge not updated!"
157+
})
158+
except Exception as e:
159+
return json.dumps({"success": False, "message": str(e)})

0 commit comments

Comments
 (0)