document_controller.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. package controller
  2. import (
  3. "log"
  4. "net/http"
  5. "strconv"
  6. "github.com/2930134478/AI-CS/backend/service"
  7. "github.com/gin-gonic/gin"
  8. )
  9. // DocumentController 文档控制器
  10. type DocumentController struct {
  11. documentService *service.DocumentService
  12. embeddingConfigService *service.EmbeddingConfigService
  13. }
  14. // NewDocumentController 创建文档控制器实例
  15. func NewDocumentController(documentService *service.DocumentService, embeddingConfigService *service.EmbeddingConfigService) *DocumentController {
  16. return &DocumentController{
  17. documentService: documentService,
  18. embeddingConfigService: embeddingConfigService,
  19. }
  20. }
  21. func (c *DocumentController) checkKBAccess(ctx *gin.Context) bool {
  22. userID := getUserIDFromHeader(ctx)
  23. if userID == 0 {
  24. return true
  25. }
  26. if err := c.embeddingConfigService.CheckKnowledgeBaseAccess(userID); err != nil {
  27. ctx.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
  28. return false
  29. }
  30. return true
  31. }
  32. // ListDocuments 获取文档列表
  33. func (c *DocumentController) ListDocuments(ctx *gin.Context) {
  34. if !c.checkKBAccess(ctx) {
  35. return
  36. }
  37. // 获取查询参数
  38. kbIDStr := ctx.Query("knowledge_base_id")
  39. pageStr := ctx.DefaultQuery("page", "1")
  40. pageSizeStr := ctx.DefaultQuery("page_size", "20")
  41. keyword := ctx.Query("keyword")
  42. status := ctx.Query("status")
  43. var knowledgeBaseID uint
  44. if kbIDStr != "" {
  45. id, err := strconv.ParseUint(kbIDStr, 10, 64)
  46. if err == nil {
  47. knowledgeBaseID = uint(id)
  48. }
  49. }
  50. page, _ := strconv.Atoi(pageStr)
  51. pageSize, _ := strconv.Atoi(pageSizeStr)
  52. result, err := c.documentService.ListDocuments(knowledgeBaseID, page, pageSize, keyword, status)
  53. if err != nil {
  54. log.Printf("获取文档列表失败: %v", err)
  55. ctx.JSON(http.StatusInternalServerError, gin.H{"error": "获取文档列表失败"})
  56. return
  57. }
  58. ctx.JSON(http.StatusOK, result)
  59. }
  60. // GetDocument 获取文档详情
  61. func (c *DocumentController) GetDocument(ctx *gin.Context) {
  62. if !c.checkKBAccess(ctx) {
  63. return
  64. }
  65. idStr := ctx.Param("id")
  66. id, err := strconv.ParseUint(idStr, 10, 64)
  67. if err != nil || id == 0 {
  68. ctx.JSON(http.StatusBadRequest, gin.H{"error": "文档 ID 不合法"})
  69. return
  70. }
  71. doc, err := c.documentService.GetDocument(uint(id))
  72. if err != nil {
  73. log.Printf("获取文档详情失败: %v", err)
  74. ctx.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
  75. return
  76. }
  77. ctx.JSON(http.StatusOK, doc)
  78. }
  79. // CreateDocument 创建文档
  80. func (c *DocumentController) CreateDocument(ctx *gin.Context) {
  81. if !c.checkKBAccess(ctx) {
  82. return
  83. }
  84. var req struct {
  85. KnowledgeBaseID uint `json:"knowledge_base_id" binding:"required"`
  86. Title string `json:"title" binding:"required"`
  87. Content string `json:"content" binding:"required"`
  88. Summary string `json:"summary"`
  89. Type string `json:"type"`
  90. Status string `json:"status"`
  91. }
  92. if err := ctx.ShouldBindJSON(&req); err != nil {
  93. ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  94. return
  95. }
  96. doc, err := c.documentService.CreateDocument(service.CreateDocumentInput{
  97. KnowledgeBaseID: req.KnowledgeBaseID,
  98. Title: req.Title,
  99. Content: req.Content,
  100. Summary: req.Summary,
  101. Type: req.Type,
  102. Status: req.Status,
  103. })
  104. if err != nil {
  105. log.Printf("创建文档失败: %v", err)
  106. ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  107. return
  108. }
  109. ctx.JSON(http.StatusOK, doc)
  110. }
  111. // UpdateDocument 更新文档
  112. func (c *DocumentController) UpdateDocument(ctx *gin.Context) {
  113. if !c.checkKBAccess(ctx) {
  114. return
  115. }
  116. idStr := ctx.Param("id")
  117. id, err := strconv.ParseUint(idStr, 10, 64)
  118. if err != nil || id == 0 {
  119. ctx.JSON(http.StatusBadRequest, gin.H{"error": "文档 ID 不合法"})
  120. return
  121. }
  122. var req struct {
  123. Title *string `json:"title"`
  124. Content *string `json:"content"`
  125. Summary *string `json:"summary"`
  126. Type *string `json:"type"`
  127. Status *string `json:"status"`
  128. }
  129. if err := ctx.ShouldBindJSON(&req); err != nil {
  130. ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  131. return
  132. }
  133. doc, err := c.documentService.UpdateDocument(uint(id), service.UpdateDocumentInput{
  134. Title: req.Title,
  135. Content: req.Content,
  136. Summary: req.Summary,
  137. Type: req.Type,
  138. Status: req.Status,
  139. })
  140. if err != nil {
  141. log.Printf("更新文档失败: %v", err)
  142. ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  143. return
  144. }
  145. ctx.JSON(http.StatusOK, doc)
  146. }
  147. // DeleteDocument 删除文档
  148. func (c *DocumentController) DeleteDocument(ctx *gin.Context) {
  149. if !c.checkKBAccess(ctx) {
  150. return
  151. }
  152. idStr := ctx.Param("id")
  153. id, err := strconv.ParseUint(idStr, 10, 64)
  154. if err != nil || id == 0 {
  155. ctx.JSON(http.StatusBadRequest, gin.H{"error": "文档 ID 不合法"})
  156. return
  157. }
  158. if err := c.documentService.DeleteDocument(uint(id)); err != nil {
  159. log.Printf("删除文档失败: %v", err)
  160. ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  161. return
  162. }
  163. ctx.JSON(http.StatusOK, gin.H{"message": "删除成功"})
  164. }
  165. // SearchDocuments 向量检索搜索文档
  166. func (c *DocumentController) SearchDocuments(ctx *gin.Context) {
  167. if !c.checkKBAccess(ctx) {
  168. return
  169. }
  170. query := ctx.Query("query")
  171. topKStr := ctx.DefaultQuery("top_k", "5")
  172. kbIDStr := ctx.Query("knowledge_base_id")
  173. if query == "" {
  174. ctx.JSON(http.StatusBadRequest, gin.H{"error": "查询内容不能为空"})
  175. return
  176. }
  177. topK, _ := strconv.Atoi(topKStr)
  178. if topK <= 0 {
  179. topK = 5
  180. }
  181. var knowledgeBaseID *uint
  182. if kbIDStr != "" {
  183. id, err := strconv.ParseUint(kbIDStr, 10, 64)
  184. if err == nil {
  185. kbID := uint(id)
  186. knowledgeBaseID = &kbID
  187. }
  188. }
  189. docs, err := c.documentService.SearchDocuments(query, topK, knowledgeBaseID)
  190. if err != nil {
  191. log.Printf("搜索文档失败: %v", err)
  192. ctx.JSON(http.StatusInternalServerError, gin.H{"error": "向量检索失败: " + err.Error()})
  193. return
  194. }
  195. ctx.JSON(http.StatusOK, gin.H{
  196. "count": len(docs),
  197. "documents": docs,
  198. })
  199. }
  200. // HybridSearchDocuments 混合检索搜索文档(当前实现与向量检索相同)
  201. func (c *DocumentController) HybridSearchDocuments(ctx *gin.Context) {
  202. c.SearchDocuments(ctx)
  203. }
  204. // UpdateDocumentStatus 更新文档状态
  205. func (c *DocumentController) UpdateDocumentStatus(ctx *gin.Context) {
  206. if !c.checkKBAccess(ctx) {
  207. return
  208. }
  209. idStr := ctx.Param("id")
  210. id, err := strconv.ParseUint(idStr, 10, 64)
  211. if err != nil || id == 0 {
  212. ctx.JSON(http.StatusBadRequest, gin.H{"error": "文档 ID 不合法"})
  213. return
  214. }
  215. var req struct {
  216. Status string `json:"status" binding:"required"`
  217. }
  218. if err := ctx.ShouldBindJSON(&req); err != nil {
  219. ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  220. return
  221. }
  222. if err := c.documentService.UpdateDocumentStatus(uint(id), req.Status); err != nil {
  223. log.Printf("更新文档状态失败: %v", err)
  224. ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  225. return
  226. }
  227. ctx.JSON(http.StatusOK, gin.H{"message": "更新成功"})
  228. }
  229. // PublishDocument 发布文档
  230. func (c *DocumentController) PublishDocument(ctx *gin.Context) {
  231. if !c.checkKBAccess(ctx) {
  232. return
  233. }
  234. idStr := ctx.Param("id")
  235. id, err := strconv.ParseUint(idStr, 10, 64)
  236. if err != nil || id == 0 {
  237. ctx.JSON(http.StatusBadRequest, gin.H{"error": "文档 ID 不合法"})
  238. return
  239. }
  240. if err := c.documentService.PublishDocument(uint(id)); err != nil {
  241. log.Printf("发布文档失败: %v", err)
  242. ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  243. return
  244. }
  245. ctx.JSON(http.StatusOK, gin.H{"message": "发布成功"})
  246. }
  247. // UnpublishDocument 取消发布文档
  248. func (c *DocumentController) UnpublishDocument(ctx *gin.Context) {
  249. if !c.checkKBAccess(ctx) {
  250. return
  251. }
  252. idStr := ctx.Param("id")
  253. id, err := strconv.ParseUint(idStr, 10, 64)
  254. if err != nil || id == 0 {
  255. ctx.JSON(http.StatusBadRequest, gin.H{"error": "文档 ID 不合法"})
  256. return
  257. }
  258. if err := c.documentService.UnpublishDocument(uint(id)); err != nil {
  259. log.Printf("取消发布文档失败: %v", err)
  260. ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
  261. return
  262. }
  263. ctx.JSON(http.StatusOK, gin.H{"message": "取消发布成功"})
  264. }