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
This commit is contained in:
chanx
2026-04-14 15:19:31 +08:00
committed by GitHub
parent 2b6c50734f
commit 6aec8058bb
5 changed files with 17 additions and 353 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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,

View File

@@ -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)

View File

@@ -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,