document_controller.go 8.8 KB

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