From 6aec8058bb60bc5e9a58a8e1d112428bf7416982 Mon Sep 17 00:00:00 2001 From: chanx <1243304602@qq.com> Date: Tue, 14 Apr 2026 15:19:31 +0800 Subject: [PATCH] refactor: Remove knowledge base-related API handlers that are already included in the dataset. (#14094) ### What problem does this PR solve? refactor: Remove knowledge base-related API handlers that are already included in the dataset. ### Type of change - [x] Refactoring --- internal/handler/kb.go | 160 +----------------------------- internal/router/router.go | 13 +-- internal/service/datasets.go | 11 ++- internal/service/kb.go | 184 ----------------------------------- web/vite.config.ts | 2 +- 5 files changed, 17 insertions(+), 353 deletions(-) diff --git a/internal/handler/kb.go b/internal/handler/kb.go index 1644dfa50f..580e24fdca 100644 --- a/internal/handler/kb.go +++ b/internal/handler/kb.go @@ -23,7 +23,6 @@ import ( "ragflow/internal/common" "ragflow/internal/engine" "ragflow/internal/service" - "strconv" "strings" "github.com/gin-gonic/gin" @@ -82,39 +81,6 @@ var ( ErrForbidden = &HTTPError{Code: common.CodeForbidden, Message: "Forbidden user"} ) -// CreateKB handles the create knowledge base request -// @Summary Create Knowledge Base -// @Description Create a new knowledge base (dataset) -// @Tags knowledgebase -// @Accept json -// @Produce json -// @Security ApiKeyAuth -// @Param request body service.CreateKBRequest true "knowledge base info" -// @Success 200 {object} map[string]interface{} -// @Router /v1/kb/create [post] -func (h *KnowledgebaseHandler) CreateKB(c *gin.Context) { - user, errorCode, errorMessage := GetUser(c) - if errorCode != common.CodeSuccess { - jsonError(c, errorCode, errorMessage) - return - } - - var req service.CreateKBRequest - if err := c.ShouldBindJSON(&req); err != nil { - jsonError(c, common.CodeDataError, err.Error()) - return - } - - result, code, err := h.kbService.CreateKB(&req, user.ID) - if err != nil { - jsonError(c, code, err.Error()) - return - } - - jsonResponse(c, common.CodeSuccess, result, "success") -} - -// UpdateKB handles the update knowledge base request // @Summary Update Knowledge Base // @Description Update an existing knowledge base // @Tags knowledgebase @@ -215,131 +181,7 @@ func (h *KnowledgebaseHandler) GetDetail(c *gin.Context) { return } - jsonResponse(c, common.CodeSuccess, result, "success") -} - -// ListKbs handles the list knowledge bases request -// @Summary List Knowledge Bases -// @Description List knowledge bases with pagination and filtering -// @Tags knowledgebase -// @Accept json -// @Produce json -// @Security ApiKeyAuth -// @Param request body service.ListKbsRequest true "list options" -// @Success 200 {object} map[string]interface{} -// @Router /v1/kb/list [post] -func (h *KnowledgebaseHandler) ListKbs(c *gin.Context) { - user, errorCode, errorMessage := GetUser(c) - if errorCode != common.CodeSuccess { - jsonError(c, errorCode, errorMessage) - return - } - - var req service.ListKbsRequest - if c.Request.ContentLength > 0 { - if err := c.ShouldBindJSON(&req); err != nil { - jsonError(c, common.CodeDataError, err.Error()) - return - } - } - - // Get parameters from request or query string - keywords := "" - if req.Keywords != nil { - keywords = *req.Keywords - } else if queryKeywords := c.Query("keywords"); queryKeywords != "" { - keywords = queryKeywords - } - - page := 0 - if req.Page != nil { - page = *req.Page - } else if pageStr := c.Query("page"); pageStr != "" { - if p, err := strconv.Atoi(pageStr); err == nil && p > 0 { - page = p - } - } - - pageSize := 0 - if req.PageSize != nil { - pageSize = *req.PageSize - } else if pageSizeStr := c.Query("page_size"); pageSizeStr != "" { - if ps, err := strconv.Atoi(pageSizeStr); err == nil && ps > 0 { - pageSize = ps - } - } - - parserID := "" - if req.ParserID != nil { - parserID = *req.ParserID - } else if queryParserID := c.Query("parser_id"); queryParserID != "" { - parserID = queryParserID - } - - orderby := "update_time" - if req.Orderby != nil { - orderby = *req.Orderby - } else if queryOrderby := c.Query("orderby"); queryOrderby != "" { - orderby = queryOrderby - } - - desc := true - if req.Desc != nil { - desc = *req.Desc - } else if descStr := c.Query("desc"); descStr != "" { - desc = strings.ToLower(descStr) == "true" - } - - var ownerIDs []string - if req.OwnerIDs != nil { - ownerIDs = *req.OwnerIDs - } - - result, code, err := h.kbService.ListKbs(keywords, page, pageSize, parserID, orderby, desc, ownerIDs, user.ID) - if err != nil { - jsonError(c, code, err.Error()) - return - } - - jsonResponse(c, common.CodeSuccess, result, "success") -} - -// DeleteKB handles the delete knowledge base request -// @Summary Delete Knowledge Base -// @Description Soft delete a knowledge base -// @Tags knowledgebase -// @Accept json -// @Produce json -// @Security ApiKeyAuth -// @Param request body object{kb_id string} true "knowledge base id" -// @Success 200 {object} map[string]interface{} -// @Router /v1/kb/rm [post] -func (h *KnowledgebaseHandler) DeleteKB(c *gin.Context) { - user, errorCode, errorMessage := GetUser(c) - if errorCode != common.CodeSuccess { - jsonError(c, errorCode, errorMessage) - return - } - - var req struct { - KBID string `json:"kb_id" binding:"required"` - } - if err := c.ShouldBindJSON(&req); err != nil { - jsonError(c, common.CodeDataError, err.Error()) - return - } - - code, err := h.kbService.DeleteKB(req.KBID, user.ID) - if err != nil { - if strings.Contains(err.Error(), "authorization") { - jsonError(c, common.CodeAuthenticationError, err.Error()) - return - } - jsonError(c, code, err.Error()) - return - } - - jsonResponse(c, common.CodeSuccess, true, "success") + jsonResponse(c, common.CodeSuccess, result, "success") } // ListTags handles the list tags request for a knowledge base diff --git a/internal/router/router.go b/internal/router/router.go index e3e6a5d7f1..db61d7702e 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -175,11 +175,11 @@ func (r *Router) Setup(engine *gin.Engine) { // message.GET("/:memory_id/:message_id/content", r.memoryHandler.GetMessageContent) // } - chats := v1.Group("/chats") - { - chats.GET("", r.chatHandler.ListChats) - chats.GET("/:chat_id", r.chatHandler.GetChat) - } + chats := v1.Group("/chats") + { + chats.GET("", r.chatHandler.ListChats) + chats.GET("/:chat_id", r.chatHandler.GetChat) + } searches := v1.Group("/searches") { @@ -245,12 +245,9 @@ func (r *Router) Setup(engine *gin.Engine) { // Knowledge base routes kb := authorized.Group("/v1/kb") { - kb.POST("/create", r.knowledgebaseHandler.CreateKB) kb.POST("/update", r.knowledgebaseHandler.UpdateKB) kb.POST("/update_metadata_setting", r.knowledgebaseHandler.UpdateMetadataSetting) kb.GET("/detail", r.knowledgebaseHandler.GetDetail) - kb.POST("/list", r.knowledgebaseHandler.ListKbs) - kb.POST("/rm", r.knowledgebaseHandler.DeleteKB) kb.GET("/tags", r.knowledgebaseHandler.ListTagsFromKbs) kb.GET("/get_meta", r.knowledgebaseHandler.GetMeta) kb.GET("/basic_info", r.knowledgebaseHandler.GetBasicInfo) diff --git a/internal/service/datasets.go b/internal/service/datasets.go index 0d5bfba72c..4c6172043f 100644 --- a/internal/service/datasets.go +++ b/internal/service/datasets.go @@ -395,9 +395,18 @@ func (s *DatasetsService) CreateDataset(req *CreateDatasetRequest, tenantID stri now := time.Now().Unix() nowDate := time.Now().Truncate(time.Second) status := string(entity.StatusValid) + // Deduplicate name within tenant + duplicateName, err := common.DuplicateName(func(n, tid string) bool { + existing, err := s.kbDAO.GetByName(n, tid) + return err == nil && existing != nil + }, name, tenantID) + if err != nil { + return nil, common.CodeDataError, err + } + kb := &entity.Knowledgebase{ ID: kbID, - Name: s.kbDAO.DuplicateName(name, tenantID), + Name: duplicateName, TenantID: tenantID, CreatedBy: tenantID, ParserID: parserID, diff --git a/internal/service/kb.go b/internal/service/kb.go index 42d049c884..77d2577926 100644 --- a/internal/service/kb.go +++ b/internal/service/kb.go @@ -52,22 +52,6 @@ func NewKnowledgebaseService() *KnowledgebaseService { } } -// CreateKBRequest represents the request for creating a knowledge base -type CreateKBRequest struct { - Name string `json:"name" binding:"required"` - ParserID *string `json:"parser_id,omitempty"` - Description *string `json:"description,omitempty"` - Language *string `json:"language,omitempty"` - Permission *string `json:"permission,omitempty"` - Avatar *string `json:"avatar,omitempty"` - ParserConfig map[string]interface{} `json:"parser_config,omitempty"` -} - -// CreateKBResponse represents the response for creating a knowledge base -type CreateKBResponse struct { - KBID string `json:"kb_id"` -} - // UpdateKBRequest represents the request for updating a knowledge base type UpdateKBRequest struct { KBID string `json:"kb_id" binding:"required"` @@ -89,106 +73,12 @@ type UpdateMetadataSettingRequest struct { EnableMetadata *bool `json:"enable_metadata,omitempty"` } -// ListKbsRequest represents the request for listing knowledge bases -type ListKbsRequest struct { - Keywords *string `json:"keywords,omitempty"` - Page *int `json:"page,omitempty"` - PageSize *int `json:"page_size,omitempty"` - ParserID *string `json:"parser_id,omitempty"` - Orderby *string `json:"orderby,omitempty"` - Desc *bool `json:"desc,omitempty"` - OwnerIDs *[]string `json:"owner_ids,omitempty"` -} - // ListKbsResponse represents the response for listing knowledge bases type ListKbsResponse struct { KBs []map[string]interface{} `json:"kbs"` Total int64 `json:"total"` } -// CreateKB creates a new knowledge base -// This matches the Python create endpoint in kb_app.py -func (s *KnowledgebaseService) CreateKB(req *CreateKBRequest, tenantID string) (*CreateKBResponse, common.ErrorCode, error) { - // Validate name is a string - if !isValidString(req.Name) { - return nil, common.CodeDataError, errors.New("Dataset name must be string.") - } - - // Trim and validate name - name := strings.TrimSpace(req.Name) - if name == "" { - return nil, common.CodeDataError, errors.New("Dataset name can't be empty.") - } - - // Check name length (using UTF-8 byte length like Python) - if len(name) > entity.DatasetNameLimit { - return nil, common.CodeDataError, fmt.Errorf("Dataset name length is %d which is large than %d", len(name), entity.DatasetNameLimit) - } - - // Verify tenant exists - tenant, err := s.tenantDAO.GetByID(tenantID) - if err != nil { - return nil, common.CodeDataError, errors.New("Tenant not found.") - } - - // Deduplicate name within tenant - duplicateName := s.kbDAO.DuplicateName(name, tenantID) - - // Get parser ID (default to "naive") - parserID := "naive" - if req.ParserID != nil && *req.ParserID != "" { - parserID = *req.ParserID - } - - // Get parser config with defaults - parserConfig := getParserConfig(parserID, req.ParserConfig) - parserConfig["llm_id"] = tenant.LLMID - - // Generate KB ID - kbID := common.GenerateUUID() - - // Create knowledge base model - now := time.Now().Unix() - nowDate := time.Now().Truncate(time.Second) - kb := &entity.Knowledgebase{ - ID: kbID, - Name: duplicateName, - TenantID: tenantID, - CreatedBy: tenantID, - ParserID: parserID, - ParserConfig: parserConfig, - Permission: "me", - EmbdID: "", - } - kb.CreateTime = &now - kb.UpdateTime = &now - kb.CreateDate = &nowDate - kb.UpdateDate = &nowDate - status := string(entity.StatusValid) - kb.Status = &status - - // Set optional fields - if req.Description != nil { - kb.Description = req.Description - } - if req.Language != nil { - kb.Language = req.Language - } - if req.Permission != nil { - kb.Permission = *req.Permission - } - if req.Avatar != nil { - kb.Avatar = req.Avatar - } - - // Create in database - if err = s.kbDAO.Create(kb); err != nil { - return nil, common.CodeServerError, fmt.Errorf("failed to create knowledge base: %w", err) - } - - return &CreateKBResponse{KBID: kbID}, common.CodeSuccess, nil -} - // CreateDatasetTableRequest represents the request for creating a dataset table type CreateDatasetTableRequest struct { KBID string `json:"kb_id" binding:"required"` @@ -394,80 +284,6 @@ func (s *KnowledgebaseService) GetDetail(kbID, userID string) (*entity.Knowledge return detail, common.CodeSuccess, nil } -// ListKbs lists knowledge bases with pagination and filtering -// This matches the Python list endpoint in kb_app.py -func (s *KnowledgebaseService) ListKbs(keywords string, page int, pageSize int, parserID string, orderby string, desc bool, ownerIDs []string, userID string) (*ListKbsResponse, common.ErrorCode, error) { - var kbs []*entity.KnowledgebaseListItem - var total int64 - var err error - - if len(ownerIDs) > 0 { - // List by owner IDs - kbs, total, err = s.kbDAO.GetByTenantIDs(ownerIDs, userID, page, pageSize, orderby, desc, keywords, parserID) - } else { - // Get tenant IDs for user - tenantIDs, err := s.userTenantDAO.GetTenantIDsByUserID(userID) - if err != nil { - return nil, common.CodeServerError, err - } - - kbs, total, err = s.kbDAO.GetByTenantIDs(tenantIDs, userID, page, pageSize, orderby, desc, keywords, parserID) - } - - if err != nil { - return nil, common.CodeServerError, err - } - - // Convert to map slice - kbMaps := make([]map[string]interface{}, len(kbs)) - for i, kb := range kbs { - kbMaps[i] = map[string]interface{}{ - "id": kb.ID, - "avatar": kb.Avatar, - "name": kb.Name, - "language": kb.Language, - "description": kb.Description, - "tenant_id": kb.TenantID, - "permission": kb.Permission, - "doc_num": kb.DocNum, - "token_num": kb.TokenNum, - "chunk_num": kb.ChunkNum, - "parser_id": kb.ParserID, - "embd_id": kb.EmbdID, - "nickname": kb.Nickname, - "tenant_avatar": kb.TenantAvatar, - "update_time": kb.UpdateTime, - } - } - - return &ListKbsResponse{ - KBs: kbMaps, - Total: total, - }, common.CodeSuccess, nil -} - -// DeleteKB soft deletes a knowledge base -// This matches the Python rm endpoint in kb_app.py -func (s *KnowledgebaseService) DeleteKB(kbID, userID string) (common.ErrorCode, error) { - // Check authorization - if !s.kbDAO.Accessible4Deletion(kbID, userID) { - return common.CodeAuthenticationError, errors.New("No authorization.") - } - - // Verify ownership - kbs, err := s.kbDAO.Query(map[string]interface{}{"created_by": userID, "id": kbID}) - if err != nil || len(kbs) == 0 { - return common.CodeOperatingError, errors.New("only owner of dataset authorized for this operation") - } - - // Soft delete - if err := s.kbDAO.Delete(kbID); err != nil { - return common.CodeServerError, fmt.Errorf("database error (knowledgebase removal): %w", err) - } - - return common.CodeSuccess, nil -} - // Accessible checks if a knowledge base is accessible by a user func (s *KnowledgebaseService) Accessible(kbID, userID string) bool { return s.kbDAO.Accessible(kbID, userID) diff --git a/web/vite.config.ts b/web/vite.config.ts index 4149abaa9c..7ee919a220 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -60,7 +60,7 @@ export default defineConfig(({ mode }) => { }, }, hybrid: { - '^(/api/v1/memories)|^(/v1/user/info)|^(/v1/user/tenant_info)|^(/v1/tenant/list)|^(/v1/system/config)|^(/v1/user/login)|^(/v1/user/logout)|^(/api/v1/files)': + '^(/v1/kb)|^(/v1/document)|^(/v1/llm/list)|^(/api/v1/datasets)|^(/api/v1/memories)|^(/v1/user)|^(/v1/user/tenant_info)|^(/v1/tenant/list)|^(/v1/system/config)|^(/v1/user/login)|^(/v1/user/logout)|^(/api/v1/files)': { target: 'http://127.0.0.1:9384/', changeOrigin: true,