faq_service.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package service
  2. import (
  3. "errors"
  4. "strings"
  5. "github.com/2930134478/AI-CS/backend/models"
  6. "github.com/2930134478/AI-CS/backend/repository"
  7. "gorm.io/gorm"
  8. )
  9. // FAQService 负责 FAQ(常见问题)管理领域的业务编排。
  10. type FAQService struct {
  11. faqs *repository.FAQRepository
  12. }
  13. // NewFAQService 创建 FAQService 实例。
  14. func NewFAQService(faqs *repository.FAQRepository) *FAQService {
  15. return &FAQService{faqs: faqs}
  16. }
  17. // CreateFAQ 创建新的 FAQ 记录。
  18. func (s *FAQService) CreateFAQ(input CreateFAQInput) (*FAQSummary, error) {
  19. // 验证必填字段
  20. if input.Question == "" {
  21. return nil, errors.New("问题不能为空")
  22. }
  23. if input.Answer == "" {
  24. return nil, errors.New("答案不能为空")
  25. }
  26. // 创建 FAQ 记录
  27. faq := &models.FAQ{
  28. Question: input.Question,
  29. Answer: input.Answer,
  30. Keywords: input.Keywords,
  31. }
  32. if err := s.faqs.Create(faq); err != nil {
  33. return nil, err
  34. }
  35. return s.toSummary(faq), nil
  36. }
  37. // GetFAQ 获取 FAQ 详情。
  38. func (s *FAQService) GetFAQ(id uint) (*FAQSummary, error) {
  39. faq, err := s.faqs.GetByID(id)
  40. if err != nil {
  41. if errors.Is(err, gorm.ErrRecordNotFound) {
  42. return nil, errors.New("FAQ 不存在")
  43. }
  44. return nil, err
  45. }
  46. return s.toSummary(faq), nil
  47. }
  48. // ListFAQs 获取 FAQ 列表,支持关键词搜索。
  49. // query 格式:关键词之间用 % 分隔,例如 "openai%api%调用"
  50. // 搜索逻辑:所有关键词都要包含(AND 查询)
  51. func (s *FAQService) ListFAQs(query string) ([]FAQSummary, error) {
  52. // 解析关键词
  53. keywords := s.parseKeywords(query)
  54. // 查询 FAQ 列表
  55. faqs, err := s.faqs.List(keywords)
  56. if err != nil {
  57. return nil, err
  58. }
  59. // 转换为 Summary
  60. summaries := make([]FAQSummary, 0, len(faqs))
  61. for _, faq := range faqs {
  62. summaries = append(summaries, *s.toSummary(&faq))
  63. }
  64. return summaries, nil
  65. }
  66. // UpdateFAQ 更新 FAQ 记录。
  67. func (s *FAQService) UpdateFAQ(id uint, input UpdateFAQInput) (*FAQSummary, error) {
  68. // 获取现有记录
  69. faq, err := s.faqs.GetByID(id)
  70. if err != nil {
  71. if errors.Is(err, gorm.ErrRecordNotFound) {
  72. return nil, errors.New("FAQ 不存在")
  73. }
  74. return nil, err
  75. }
  76. // 验证必填字段
  77. if input.Question != nil && *input.Question == "" {
  78. return nil, errors.New("问题不能为空")
  79. }
  80. if input.Answer != nil && *input.Answer == "" {
  81. return nil, errors.New("答案不能为空")
  82. }
  83. // 更新字段
  84. if input.Question != nil {
  85. faq.Question = *input.Question
  86. }
  87. if input.Answer != nil {
  88. faq.Answer = *input.Answer
  89. }
  90. if input.Keywords != nil {
  91. faq.Keywords = *input.Keywords
  92. }
  93. // 保存更新
  94. if err := s.faqs.Update(faq); err != nil {
  95. return nil, err
  96. }
  97. return s.toSummary(faq), nil
  98. }
  99. // DeleteFAQ 删除 FAQ 记录。
  100. func (s *FAQService) DeleteFAQ(id uint) error {
  101. // 检查记录是否存在
  102. _, err := s.faqs.GetByID(id)
  103. if err != nil {
  104. if errors.Is(err, gorm.ErrRecordNotFound) {
  105. return errors.New("FAQ 不存在")
  106. }
  107. return err
  108. }
  109. // 删除记录
  110. return s.faqs.Delete(id)
  111. }
  112. // parseKeywords 解析关键词查询字符串。
  113. // 输入格式:关键词之间用 % 分隔,例如 "openai%api%调用"
  114. // 返回:关键词数组
  115. func (s *FAQService) parseKeywords(query string) []string {
  116. if query == "" {
  117. return nil
  118. }
  119. // 按 % 分隔
  120. parts := strings.Split(query, "%")
  121. keywords := make([]string, 0, len(parts))
  122. for _, part := range parts {
  123. // 去除首尾空格
  124. keyword := strings.TrimSpace(part)
  125. if keyword != "" {
  126. keywords = append(keywords, keyword)
  127. }
  128. }
  129. return keywords
  130. }
  131. // toSummary 将 FAQ 模型转换为 Summary。
  132. func (s *FAQService) toSummary(faq *models.FAQ) *FAQSummary {
  133. return &FAQSummary{
  134. ID: faq.ID,
  135. Question: faq.Question,
  136. Answer: faq.Answer,
  137. Keywords: faq.Keywords,
  138. CreatedAt: faq.CreatedAt,
  139. UpdatedAt: faq.UpdatedAt,
  140. }
  141. }