package transport import ( "io" "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/geo-platform/tenant-api/internal/bootstrap" "github.com/geo-platform/tenant-api/internal/shared/response" "github.com/geo-platform/tenant-api/internal/tenant/app" ) type KnowledgeHandler struct { svc *app.KnowledgeService } func NewKnowledgeHandler(a *bootstrap.App) *KnowledgeHandler { return &KnowledgeHandler{ svc: app.NewKnowledgeService( a.DB, a.RetrievalProvider, a.VectorStore, a.ObjectStorage, a.LLM, a.Logger, a.Config.Retrieval, a.Config.LLM, a.Config.Generation.QueueSize, a.Config.Generation.WorkerConcurrency, ), } } func (h *KnowledgeHandler) ListGroups(c *gin.Context) { data, err := h.svc.ListGroups(c.Request.Context()) if err != nil { response.Error(c, err) return } response.Success(c, data) } func (h *KnowledgeHandler) CreateGroup(c *gin.Context) { var req app.KnowledgeGroupRequest if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error())) return } data, err := h.svc.CreateGroup(c.Request.Context(), req) if err != nil { response.Error(c, err) return } response.SuccessWithStatus(c, http.StatusCreated, data) } func (h *KnowledgeHandler) UpdateGroup(c *gin.Context) { groupID, err := strconv.ParseInt(c.Param("gid"), 10, 64) if err != nil { response.Error(c, response.ErrBadRequest(40001, "invalid_id", "knowledge group id must be a number")) return } var req app.KnowledgeGroupRequest if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error())) return } if err := h.svc.UpdateGroup(c.Request.Context(), groupID, req); err != nil { response.Error(c, err) return } response.Success(c, nil) } func (h *KnowledgeHandler) DeleteGroup(c *gin.Context) { groupID, err := strconv.ParseInt(c.Param("gid"), 10, 64) if err != nil { response.Error(c, response.ErrBadRequest(40001, "invalid_id", "knowledge group id must be a number")) return } if err := h.svc.DeleteGroup(c.Request.Context(), groupID); err != nil { response.Error(c, err) return } response.Success(c, nil) } func (h *KnowledgeHandler) ListItems(c *gin.Context) { var groupID *int64 if raw := c.Query("group_id"); raw != "" { parsed, err := strconv.ParseInt(raw, 10, 64) if err != nil { response.Error(c, response.ErrBadRequest(40001, "invalid_group_id", "group id must be a number")) return } groupID = &parsed } data, err := h.svc.ListItems(c.Request.Context(), groupID) if err != nil { response.Error(c, err) return } response.Success(c, data) } func (h *KnowledgeHandler) GetItemDetail(c *gin.Context) { itemID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { response.Error(c, response.ErrBadRequest(40001, "invalid_id", "knowledge item id must be a number")) return } data, err := h.svc.GetItemDetail(c.Request.Context(), itemID) if err != nil { response.Error(c, err) return } response.Success(c, data) } func (h *KnowledgeHandler) CreateTextItem(c *gin.Context) { var req app.KnowledgeTextItemRequest if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error())) return } data, err := h.svc.CreateTextItem(c.Request.Context(), req) if err != nil { response.Error(c, err) return } response.SuccessWithStatus(c, http.StatusCreated, data) } func (h *KnowledgeHandler) CreateURLItem(c *gin.Context) { var req app.KnowledgeURLItemRequest if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error())) return } data, err := h.svc.CreateURLItem(c.Request.Context(), req) if err != nil { response.Error(c, err) return } response.SuccessWithStatus(c, http.StatusCreated, data) } func (h *KnowledgeHandler) CreateFileItem(c *gin.Context) { groupID, err := strconv.ParseInt(c.PostForm("group_id"), 10, 64) if err != nil || groupID <= 0 { response.Error(c, response.ErrBadRequest(40001, "invalid_group_id", "group id must be a number")) return } name := c.PostForm("name") fileHeader, err := c.FormFile("file") if err != nil { response.Error(c, response.ErrBadRequest(40001, "invalid_file", "file is required")) return } file, err := fileHeader.Open() if err != nil { response.Error(c, response.ErrBadRequest(40001, "invalid_file", "file cannot be opened")) return } defer file.Close() content, err := io.ReadAll(file) if err != nil { response.Error(c, response.ErrBadRequest(40001, "invalid_file", "file cannot be read")) return } data, err := h.svc.CreateFileItem(c.Request.Context(), groupID, name, fileHeader.Filename, content) if err != nil { response.Error(c, err) return } response.SuccessWithStatus(c, http.StatusCreated, data) } func (h *KnowledgeHandler) DeleteItem(c *gin.Context) { itemID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { response.Error(c, response.ErrBadRequest(40001, "invalid_id", "knowledge item id must be a number")) return } if err := h.svc.DeleteItem(c.Request.Context(), itemID); err != nil { response.Error(c, err) return } response.Success(c, nil) }