document_chunk_controller.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package controller
  2. import (
  3. "log"
  4. "net/http"
  5. "strconv"
  6. "github.com/2930134478/AI-CS/backend/models"
  7. "github.com/2930134478/AI-CS/backend/service"
  8. "github.com/gin-gonic/gin"
  9. )
  10. // DocumentChunkController 文档分段控制器
  11. type DocumentChunkController struct {
  12. chunkService *service.ChunkService
  13. users *service.UserService
  14. }
  15. // NewDocumentChunkController 创建文档分段控制器实例
  16. func NewDocumentChunkController(chunkService *service.ChunkService, users *service.UserService) *DocumentChunkController {
  17. return &DocumentChunkController{
  18. chunkService: chunkService,
  19. users: users,
  20. }
  21. }
  22. // ExecuteChunking 执行分段
  23. // POST /api/documents/:id/chunks
  24. func (c *DocumentChunkController) ExecuteChunking(ctx *gin.Context) {
  25. if !requirePermission(ctx, c.users, string(service.PermKnowledge)) {
  26. return
  27. }
  28. idStr := ctx.Param("id")
  29. id, err := strconv.ParseUint(idStr, 10, 64)
  30. if err != nil || id == 0 {
  31. ctx.JSON(http.StatusBadRequest, gin.H{"error": "文档 ID 不合法"})
  32. return
  33. }
  34. var req service.ChunkRequest
  35. if err := ctx.ShouldBindJSON(&req); err != nil {
  36. ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  37. return
  38. }
  39. if req.Method != "char_count" && req.Method != "separator" {
  40. ctx.JSON(http.StatusBadRequest, gin.H{"error": "分段方式必须为 char_count 或 separator"})
  41. return
  42. }
  43. chunks, err := c.chunkService.ExecuteChunking(ctx, uint(id), req)
  44. if err != nil {
  45. log.Printf("[分段] 执行分段失败 (doc=%d): %v", id, err)
  46. ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  47. return
  48. }
  49. ctx.JSON(http.StatusOK, gin.H{
  50. "message": "分段完成",
  51. "chunk_count": len(chunks),
  52. "chunks": chunks,
  53. })
  54. }
  55. // GetChunks 获取文档分段列表
  56. // GET /api/documents/:id/chunks?page=1&page_size=20
  57. func (c *DocumentChunkController) GetChunks(ctx *gin.Context) {
  58. if !requirePermission(ctx, c.users, string(service.PermKnowledge)) {
  59. return
  60. }
  61. idStr := ctx.Param("id")
  62. id, err := strconv.ParseUint(idStr, 10, 64)
  63. if err != nil || id == 0 {
  64. ctx.JSON(http.StatusBadRequest, gin.H{"error": "文档 ID 不合法"})
  65. return
  66. }
  67. page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
  68. pageSize, _ := strconv.Atoi(ctx.DefaultQuery("page_size", "20"))
  69. chunks, total, err := c.chunkService.GetChunks(uint(id), page, pageSize)
  70. if err != nil {
  71. log.Printf("[分段] 获取分段列表失败 (doc=%d): %v", id, err)
  72. ctx.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
  73. return
  74. }
  75. if chunks == nil {
  76. chunks = []models.DocumentChunk{}
  77. }
  78. totalPage := int(total) / pageSize
  79. if int(total)%pageSize > 0 {
  80. totalPage++
  81. }
  82. ctx.JSON(http.StatusOK, gin.H{
  83. "chunks": chunks,
  84. "total": int(total),
  85. "page": page,
  86. "page_size": pageSize,
  87. "total_page": totalPage,
  88. })
  89. }
  90. // UpdateChunk 更新单个分段
  91. // PUT /api/documents/:id/chunks/:chunkId
  92. func (c *DocumentChunkController) UpdateChunk(ctx *gin.Context) {
  93. if !requirePermission(ctx, c.users, string(service.PermKnowledge)) {
  94. return
  95. }
  96. chunkIDStr := ctx.Param("chunkId")
  97. chunkID, err := strconv.ParseUint(chunkIDStr, 10, 64)
  98. if err != nil || chunkID == 0 {
  99. ctx.JSON(http.StatusBadRequest, gin.H{"error": "分段 ID 不合法"})
  100. return
  101. }
  102. var req struct {
  103. Content string `json:"content" binding:"required"`
  104. }
  105. if err := ctx.ShouldBindJSON(&req); err != nil {
  106. ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  107. return
  108. }
  109. chunk, err := c.chunkService.UpdateChunk(ctx, uint(chunkID), req.Content)
  110. if err != nil {
  111. log.Printf("[分段] 更新分段失败 (chunk=%d): %v", chunkID, err)
  112. ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  113. return
  114. }
  115. ctx.JSON(http.StatusOK, chunk)
  116. }
  117. // DeleteChunks 删除文档所有分段
  118. // DELETE /api/documents/:id/chunks
  119. func (c *DocumentChunkController) DeleteChunks(ctx *gin.Context) {
  120. if !requirePermission(ctx, c.users, string(service.PermKnowledge)) {
  121. return
  122. }
  123. idStr := ctx.Param("id")
  124. id, err := strconv.ParseUint(idStr, 10, 64)
  125. if err != nil || id == 0 {
  126. ctx.JSON(http.StatusBadRequest, gin.H{"error": "文档 ID 不合法"})
  127. return
  128. }
  129. if err := c.chunkService.DeleteChunks(ctx, uint(id)); err != nil {
  130. log.Printf("[分段] 删除分段失败 (doc=%d): %v", id, err)
  131. ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  132. return
  133. }
  134. ctx.JSON(http.StatusOK, gin.H{"message": "分段已删除"})
  135. }