@@ -19,12 +19,13 @@ package handler
1919import (
2020 "encoding/json"
2121 "net/http"
22+ "strconv"
2223 "strings"
23- "ragflow/internal/common"
2424
2525 "github.com/gin-gonic/gin"
2626 "go.uber.org/zap"
2727
28+ "ragflow/internal/common"
2829 "ragflow/internal/service"
2930)
3031
@@ -35,6 +36,10 @@ type chunkService interface {
3536 List (req * service.ListChunksRequest , userID string ) (* service.ListChunksResponse , error )
3637 UpdateChunk (req * service.UpdateChunkRequest , userID string ) error
3738 RemoveChunks (req * service.RemoveChunksRequest , userID string ) (int64 , error )
39+ ListChunksREST (datasetID , documentID , userID string , page , pageSize int , keywords string , available * bool ) (* service.ListChunksResponse , error )
40+ AddChunk (datasetID , documentID , userID string , req * service.AddChunkRequest ) (map [string ]interface {}, error )
41+ UpdateChunkREST (datasetID , documentID , chunkID , userID string , req * service.UpdateChunkRESTRequest ) error
42+ SwitchChunks (datasetID , documentID , userID string , chunkIDs []string , available bool ) error
3843}
3944
4045// ChunkHandler chunk handler
@@ -387,6 +392,197 @@ func (h *ChunkHandler) UpdateChunk(c *gin.Context) {
387392 })
388393}
389394
395+ // ListChunksREST lists chunks for a document inside a dataset.
396+ // @Summary List Chunks
397+ // @Description List chunks for a document (dataset_id and document_id from path).
398+ // @Tags chunks
399+ // @Produce json
400+ // @Param dataset_id path string true "Dataset ID"
401+ // @Param document_id path string true "Document ID"
402+ // @Param page query int false "Page number (default 1)"
403+ // @Param page_size query int false "Items per page (default 30)"
404+ // @Param keywords query string false "Keyword filter"
405+ // @Param available query bool false "Filter by available status"
406+ // @Success 200 {object} map[string]interface{}
407+ // @Router /api/v1/datasets/{dataset_id}/documents/{document_id}/chunks [get]
408+ func (h * ChunkHandler ) ListChunksREST (c * gin.Context ) {
409+ user , errorCode , errorMessage := GetUser (c )
410+ if errorCode != common .CodeSuccess {
411+ jsonError (c , errorCode , errorMessage )
412+ return
413+ }
414+
415+ datasetID := c .Param ("dataset_id" )
416+ documentID := c .Param ("document_id" )
417+ if datasetID == "" || documentID == "" {
418+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : "dataset_id and document_id are required" })
419+ return
420+ }
421+
422+ page := 1
423+ if v := c .Query ("page" ); v != "" {
424+ if p , err := strconv .Atoi (v ); err == nil && p > 0 {
425+ page = p
426+ }
427+ }
428+ pageSize := 30
429+ if v := c .Query ("page_size" ); v != "" {
430+ if ps , err := strconv .Atoi (v ); err == nil && ps > 0 {
431+ if ps > 100 {
432+ ps = 100
433+ }
434+ pageSize = ps
435+ }
436+ }
437+ keywords := c .Query ("keywords" )
438+
439+ var available * bool
440+ if v := c .Query ("available" ); v != "" {
441+ b := v == "true" || v == "1"
442+ available = & b
443+ }
444+
445+ resp , err := h .chunkService .ListChunksREST (datasetID , documentID , user .ID , page , pageSize , keywords , available )
446+ if err != nil {
447+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : err .Error ()})
448+ return
449+ }
450+
451+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeSuccess , "data" : resp , "message" : "success" })
452+ }
453+
454+ // AddChunk adds a manually created chunk to a document.
455+ // @Summary Add Chunk
456+ // @Description Create a new chunk for a document with content, keywords, and questions.
457+ // @Tags chunks
458+ // @Accept json
459+ // @Produce json
460+ // @Param dataset_id path string true "Dataset ID"
461+ // @Param document_id path string true "Document ID"
462+ // @Param request body service.AddChunkRequest true "chunk content"
463+ // @Success 200 {object} map[string]interface{}
464+ // @Router /api/v1/datasets/{dataset_id}/documents/{document_id}/chunks [post]
465+ func (h * ChunkHandler ) AddChunk (c * gin.Context ) {
466+ user , errorCode , errorMessage := GetUser (c )
467+ if errorCode != common .CodeSuccess {
468+ jsonError (c , errorCode , errorMessage )
469+ return
470+ }
471+
472+ datasetID := c .Param ("dataset_id" )
473+ documentID := c .Param ("document_id" )
474+ if datasetID == "" || documentID == "" {
475+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : "dataset_id and document_id are required" })
476+ return
477+ }
478+
479+ var req service.AddChunkRequest
480+ if err := c .ShouldBindJSON (& req ); err != nil {
481+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : err .Error ()})
482+ return
483+ }
484+
485+ data , err := h .chunkService .AddChunk (datasetID , documentID , user .ID , & req )
486+ if err != nil {
487+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : err .Error ()})
488+ return
489+ }
490+
491+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeSuccess , "data" : data , "message" : "success" })
492+ }
493+
494+ // UpdateChunkREST updates a chunk's content, keywords, and availability.
495+ // Re-embeds the chunk when content or questions change.
496+ // @Summary Update Chunk (REST)
497+ // @Description Partially update a chunk by ID, re-embedding on content/question changes.
498+ // @Tags chunks
499+ // @Accept json
500+ // @Produce json
501+ // @Param dataset_id path string true "Dataset ID"
502+ // @Param document_id path string true "Document ID"
503+ // @Param chunk_id path string true "Chunk ID"
504+ // @Param request body service.UpdateChunkRESTRequest true "fields to update"
505+ // @Success 200 {object} map[string]interface{}
506+ // @Router /api/v1/datasets/{dataset_id}/documents/{document_id}/chunks/{chunk_id} [patch]
507+ func (h * ChunkHandler ) UpdateChunkREST (c * gin.Context ) {
508+ user , errorCode , errorMessage := GetUser (c )
509+ if errorCode != common .CodeSuccess {
510+ jsonError (c , errorCode , errorMessage )
511+ return
512+ }
513+
514+ datasetID := c .Param ("dataset_id" )
515+ documentID := c .Param ("document_id" )
516+ chunkID := c .Param ("chunk_id" )
517+ if datasetID == "" || documentID == "" || chunkID == "" {
518+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : "dataset_id, document_id and chunk_id are required" })
519+ return
520+ }
521+
522+ var req service.UpdateChunkRESTRequest
523+ if err := c .ShouldBindJSON (& req ); err != nil {
524+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : err .Error ()})
525+ return
526+ }
527+
528+ if err := h .chunkService .UpdateChunkREST (datasetID , documentID , chunkID , user .ID , & req ); err != nil {
529+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : err .Error ()})
530+ return
531+ }
532+
533+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeSuccess , "data" : true , "message" : "success" })
534+ }
535+
536+ // SwitchChunks bulk-toggles the available status for a list of chunks.
537+ // @Summary Switch Chunks Availability
538+ // @Description Toggle available_int for a set of chunk IDs.
539+ // @Tags chunks
540+ // @Accept json
541+ // @Produce json
542+ // @Param dataset_id path string true "Dataset ID"
543+ // @Param document_id path string true "Document ID"
544+ // @Param request body object true "chunk_ids + available"
545+ // @Success 200 {object} map[string]interface{}
546+ // @Router /api/v1/datasets/{dataset_id}/documents/{document_id}/chunks [patch]
547+ func (h * ChunkHandler ) SwitchChunks (c * gin.Context ) {
548+ user , errorCode , errorMessage := GetUser (c )
549+ if errorCode != common .CodeSuccess {
550+ jsonError (c , errorCode , errorMessage )
551+ return
552+ }
553+
554+ datasetID := c .Param ("dataset_id" )
555+ documentID := c .Param ("document_id" )
556+ if datasetID == "" || documentID == "" {
557+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : "dataset_id and document_id are required" })
558+ return
559+ }
560+
561+ var body struct {
562+ ChunkIDs []string `json:"chunk_ids"`
563+ Available * bool `json:"available"`
564+ }
565+ if err := c .ShouldBindJSON (& body ); err != nil {
566+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : err .Error ()})
567+ return
568+ }
569+ if len (body .ChunkIDs ) == 0 {
570+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : "`chunk_ids` is required." })
571+ return
572+ }
573+ if body .Available == nil {
574+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : "`available` is required." })
575+ return
576+ }
577+
578+ if err := h .chunkService .SwitchChunks (datasetID , documentID , user .ID , body .ChunkIDs , * body .Available ); err != nil {
579+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeDataError , "data" : false , "message" : err .Error ()})
580+ return
581+ }
582+
583+ c .JSON (http .StatusOK , gin.H {"code" : common .CodeSuccess , "data" : true , "message" : "success" })
584+ }
585+
390586// RemoveChunks handles chunk removal requests
391587// @Summary Remove Chunks
392588// @Description Remove chunks from a document
0 commit comments