package v1 import ( "errors" "github.com/labstack/echo/v4" "github.com/samber/lo" "github.com/chaitin/panda-wiki/consts" "github.com/chaitin/panda-wiki/domain" "github.com/chaitin/panda-wiki/handler" "github.com/chaitin/panda-wiki/log" "github.com/chaitin/panda-wiki/middleware" "github.com/chaitin/panda-wiki/usecase" ) type KnowledgeBaseHandler struct { *handler.BaseHandler usecase *usecase.KnowledgeBaseUsecase llmUsecase *usecase.LLMUsecase logger *log.Logger auth middleware.AuthMiddleware } func NewKnowledgeBaseHandler( baseHandler *handler.BaseHandler, echo *echo.Echo, usecase *usecase.KnowledgeBaseUsecase, llmUsecase *usecase.LLMUsecase, auth middleware.AuthMiddleware, logger *log.Logger, ) *KnowledgeBaseHandler { h := &KnowledgeBaseHandler{ BaseHandler: baseHandler, logger: logger.WithModule("handler.v1.knowledge_base"), usecase: usecase, llmUsecase: llmUsecase, auth: auth, } group := echo.Group("/api/v1/knowledge_base", h.auth.Authorize) group.POST("", h.CreateKnowledgeBase, h.auth.ValidateUserRole(consts.UserRoleAdmin)) group.GET("/list", h.GetKnowledgeBaseList) group.GET("/detail", h.GetKnowledgeBaseDetail, h.auth.ValidateKBUserPerm(consts.UserKBPermissionNotNull)) group.PUT("/detail", h.UpdateKnowledgeBase, h.auth.ValidateKBUserPerm(consts.UserKBPermissionFullControl)) group.DELETE("/detail", h.DeleteKnowledgeBase, h.auth.ValidateUserRole(consts.UserRoleAdmin)) // user management userGroup := group.Group("/user", h.auth.ValidateKBUserPerm(consts.UserKBPermissionFullControl)) userGroup.GET("/list", h.KBUserList) userGroup.POST("/invite", h.KBUserInvite) userGroup.PATCH("/update", h.KBUserUpdate) userGroup.DELETE("/delete", h.KBUserDelete) // release releaseGroup := group.Group("/release", h.auth.ValidateKBUserPerm(consts.UserKBPermissionDocManage)) releaseGroup.POST("", h.CreateKBRelease) releaseGroup.GET("/list", h.GetKBReleaseList) return h } // CreateKnowledgeBase // // @Summary CreateKnowledgeBase // @Description CreateKnowledgeBase // @Tags knowledge_base // @Accept json // @Produce json // @Param body body domain.CreateKnowledgeBaseReq true "CreateKnowledgeBase Request" // @Success 200 {object} domain.Response // @Router /api/v1/knowledge_base [post] func (h *KnowledgeBaseHandler) CreateKnowledgeBase(c echo.Context) error { var req domain.CreateKnowledgeBaseReq if err := c.Bind(&req); err != nil { return h.NewResponseWithError(c, "invalid request", err) } if err := c.Validate(&req); err != nil { return h.NewResponseWithError(c, "invalid request", err) } req.Hosts = lo.Uniq(req.Hosts) req.Ports = lo.Uniq(req.Ports) req.SSLPorts = lo.Uniq(req.SSLPorts) if len(req.Hosts) == 0 { return h.NewResponseWithError(c, "hosts is required", nil) } if len(req.Ports)+len(req.SSLPorts) == 0 { return h.NewResponseWithError(c, "ports is required", nil) } req.MaxKB = domain.GetBaseEditionLimitation(c.Request().Context()).MaxKb did, err := h.usecase.CreateKnowledgeBase(c.Request().Context(), &req) if err != nil { if errors.Is(err, domain.ErrPortHostAlreadyExists) { return h.NewResponseWithError(c, "端口或域名已被其他知识库占用", nil) } if errors.Is(err, domain.ErrSyncCaddyConfigFailed) { return h.NewResponseWithError(c, "保存配置失败,请检查端口或证书配置", nil) } return h.NewResponseWithError(c, "failed to create knowledge base", err) } return h.NewResponseWithData(c, map[string]string{ "id": did, }) } // GetKnowledgeBaseList // // @Summary GetKnowledgeBaseList // @Description GetKnowledgeBaseList // @Tags knowledge_base // @Accept json // @Produce json // @Success 200 {object} domain.PWResponse{data=[]domain.KnowledgeBaseListItem} // @Router /api/v1/knowledge_base/list [get] func (h *KnowledgeBaseHandler) GetKnowledgeBaseList(c echo.Context) error { knowledgeBases, err := h.usecase.GetKnowledgeBaseListByUserId(c.Request().Context()) if err != nil { return h.NewResponseWithError(c, "failed to get knowledge base list", err) } return h.NewResponseWithData(c, knowledgeBases) } // UpdateKnowledgeBase // // @Summary UpdateKnowledgeBase // @Description UpdateKnowledgeBase // @Tags knowledge_base // @Accept json // @Produce json // @Param body body domain.UpdateKnowledgeBaseReq true "UpdateKnowledgeBase Request" // @Success 200 {object} domain.Response // @Router /api/v1/knowledge_base/detail [put] func (h *KnowledgeBaseHandler) UpdateKnowledgeBase(c echo.Context) error { var req domain.UpdateKnowledgeBaseReq if err := c.Bind(&req); err != nil { return h.NewResponseWithError(c, "invalid request", err) } if err := c.Validate(&req); err != nil { return h.NewResponseWithError(c, "invalid request", err) } err := h.usecase.UpdateKnowledgeBase(c.Request().Context(), &req) if err != nil { if errors.Is(err, domain.ErrPortHostAlreadyExists) { return h.NewResponseWithError(c, "端口或域名已被其他知识库占用", nil) } if errors.Is(err, domain.ErrSyncCaddyConfigFailed) { return h.NewResponseWithError(c, "保存配置失败,请检查端口或证书配置", nil) } return h.NewResponseWithError(c, "failed to update knowledge base", err) } return h.NewResponseWithData(c, nil) } // GetKnowledgeBaseDetail // // @Summary GetKnowledgeBaseDetail // @Description GetKnowledgeBaseDetail // @Tags knowledge_base // @Accept json // @Produce json // @Security bearerAuth // @Param id query string true "Knowledge Base ID" // @Success 200 {object} domain.PWResponse{data=domain.KnowledgeBaseDetail} // @Router /api/v1/knowledge_base/detail [get] func (h *KnowledgeBaseHandler) GetKnowledgeBaseDetail(c echo.Context) error { kbID := c.QueryParam("id") if kbID == "" { return h.NewResponseWithError(c, "kb id is required", nil) } kb, err := h.usecase.GetKnowledgeBase(c.Request().Context(), kbID) if err != nil { return h.NewResponseWithError(c, "failed to get knowledge base detail", err) } perm, err := h.usecase.GetKnowledgeBasePerm(c.Request().Context(), kbID) if err != nil { return h.NewResponseWithError(c, "failed to get knowledge base permission", err) } if perm != consts.UserKBPermissionFullControl { kb.AccessSettings.PrivateKey = "" kb.AccessSettings.PublicKey = "" } return h.NewResponseWithData(c, &domain.KnowledgeBaseDetail{ ID: kb.ID, Name: kb.Name, DatasetID: kb.DatasetID, Perm: perm, AccessSettings: kb.AccessSettings, CreatedAt: kb.CreatedAt, UpdatedAt: kb.UpdatedAt, }) } // DeleteKnowledgeBase // // @Summary DeleteKnowledgeBase // @Description DeleteKnowledgeBase // @Tags knowledge_base // @Accept json // @Produce json // @Param id query string true "Knowledge Base ID" // @Success 200 {object} domain.Response // @Router /api/v1/knowledge_base/detail [delete] func (h *KnowledgeBaseHandler) DeleteKnowledgeBase(c echo.Context) error { kbID := c.QueryParam("id") if kbID == "" { return h.NewResponseWithError(c, "kb id is required", nil) } err := h.usecase.DeleteKnowledgeBase(c.Request().Context(), kbID) if err != nil { return h.NewResponseWithError(c, "failed to delete knowledge base", err) } return h.NewResponseWithData(c, nil) } // CreateKBRelease // // @Summary CreateKBRelease // @Description CreateKBRelease // @Tags knowledge_base // @Accept json // @Produce json // @Param body body domain.CreateKBReleaseReq true "CreateKBRelease Request" // @Success 200 {object} domain.Response // @Router /api/v1/knowledge_base/release [post] func (h *KnowledgeBaseHandler) CreateKBRelease(c echo.Context) error { ctx := c.Request().Context() authInfo := domain.GetAuthInfoFromCtx(ctx) if authInfo == nil { return h.NewResponseWithError(c, "authInfo not found in context", nil) } req := &domain.CreateKBReleaseReq{} if err := c.Bind(req); err != nil { return h.NewResponseWithError(c, "request body is invalid", err) } if err := c.Validate(req); err != nil { return h.NewResponseWithError(c, "validate request body failed", err) } id, err := h.usecase.CreateKBRelease(ctx, req, authInfo.UserId) if err != nil { return h.NewResponseWithError(c, "create kb release failed", err) } return h.NewResponseWithData(c, map[string]any{ "id": id, }) } // GetKBReleaseList // // @Summary GetKBReleaseList // @Description GetKBReleaseList // @Tags knowledge_base // @Accept json // @Produce json // @Param kb_id query string true "Knowledge Base ID" // @Success 200 {object} domain.PWResponse{data=domain.GetKBReleaseListResp} // @Router /api/v1/knowledge_base/release/list [get] func (h *KnowledgeBaseHandler) GetKBReleaseList(c echo.Context) error { var req domain.GetKBReleaseListReq if err := c.Bind(&req); err != nil { return h.NewResponseWithError(c, "request params is invalid", err) } if err := c.Validate(req); err != nil { return h.NewResponseWithError(c, "validate request params failed", err) } resp, err := h.usecase.GetKBReleaseList(c.Request().Context(), &req) if err != nil { return h.NewResponseWithError(c, "get kb release list failed", err) } return h.NewResponseWithData(c, resp) }