embedding_config_service.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package service
  2. import (
  3. "errors"
  4. "fmt"
  5. "time"
  6. "github.com/2930134478/AI-CS/backend/models"
  7. "github.com/2930134478/AI-CS/backend/repository"
  8. "github.com/2930134478/AI-CS/backend/utils"
  9. )
  10. // EmbeddingConfigService 知识库向量配置服务
  11. type EmbeddingConfigService struct {
  12. repo *repository.EmbeddingConfigRepository
  13. userRepo *repository.UserRepository
  14. }
  15. // NewEmbeddingConfigService 创建服务实例
  16. func NewEmbeddingConfigService(repo *repository.EmbeddingConfigRepository, userRepo *repository.UserRepository) *EmbeddingConfigService {
  17. return &EmbeddingConfigService{repo: repo, userRepo: userRepo}
  18. }
  19. // GetForAPI 返回给前端的配置(API Key 脱敏,不返回明文)
  20. func (s *EmbeddingConfigService) GetForAPI() (*EmbeddingConfigResult, error) {
  21. c, err := s.repo.Get()
  22. if err != nil {
  23. return nil, err
  24. }
  25. if c == nil {
  26. return &EmbeddingConfigResult{
  27. EmbeddingType: "openai",
  28. APIURL: "",
  29. APIKeyMasked: "",
  30. Model: "text-embedding-3-small",
  31. CustomerCanUseKB: true,
  32. }, nil
  33. }
  34. masked := ""
  35. if c.APIKey != "" {
  36. masked = "sk-***"
  37. }
  38. return &EmbeddingConfigResult{
  39. ID: c.ID,
  40. EmbeddingType: c.EmbeddingType,
  41. APIURL: c.APIURL,
  42. APIKeyMasked: masked,
  43. Model: c.Model,
  44. CustomerCanUseKB: c.CustomerCanUseKB,
  45. UpdatedAt: c.UpdatedAt,
  46. }, nil
  47. }
  48. // GetRaw 供 embedding 工厂使用,返回含解密后 API Key 的配置;若 DB 无有效配置返回 nil, nil
  49. func (s *EmbeddingConfigService) GetRaw() (embeddingType, apiURL, apiKey, model string, err error) {
  50. c, err := s.repo.Get()
  51. if err != nil || c == nil || c.APIKey == "" {
  52. return "", "", "", "", nil
  53. }
  54. decrypted, err := utils.DecryptAPIKey(c.APIKey)
  55. if err != nil {
  56. return "", "", "", "", fmt.Errorf("解密 API Key 失败: %w", err)
  57. }
  58. return c.EmbeddingType, c.APIURL, decrypted, c.Model, nil
  59. }
  60. // CustomerCanUseKB 是否开放知识库给客服使用
  61. func (s *EmbeddingConfigService) CustomerCanUseKB() (bool, error) {
  62. c, err := s.repo.Get()
  63. if err != nil {
  64. return false, err
  65. }
  66. if c == nil {
  67. return true, nil // 默认开放
  68. }
  69. return c.CustomerCanUseKB, nil
  70. }
  71. // CheckKnowledgeBaseAccess 校验当前用户是否允许使用知识库(创建/上传/导入等)
  72. // 若未开放且用户非 admin 则返回 error
  73. func (s *EmbeddingConfigService) CheckKnowledgeBaseAccess(userID uint) error {
  74. ok, err := s.CustomerCanUseKB()
  75. if err != nil {
  76. return err
  77. }
  78. if ok {
  79. return nil
  80. }
  81. user, err := s.userRepo.GetByID(userID)
  82. if err != nil || user == nil {
  83. return errors.New("用户不存在")
  84. }
  85. if user.Role == "admin" {
  86. return nil
  87. }
  88. return errors.New("当前未开放知识库功能,仅管理员可使用")
  89. }
  90. // Update 更新配置(仅管理员可调);若传入 api_key 为空则保留原密钥
  91. func (s *EmbeddingConfigService) Update(userID uint, input UpdateEmbeddingConfigInput) (*EmbeddingConfigResult, error) {
  92. user, err := s.userRepo.GetByID(userID)
  93. if err != nil || user == nil {
  94. return nil, errors.New("用户不存在")
  95. }
  96. if user.Role != "admin" {
  97. return nil, errors.New("仅管理员可修改知识库向量配置")
  98. }
  99. c, err := s.repo.Get()
  100. if err != nil {
  101. return nil, err
  102. }
  103. if c == nil {
  104. c = &models.EmbeddingConfig{ID: 1}
  105. }
  106. if input.EmbeddingType != nil {
  107. c.EmbeddingType = *input.EmbeddingType
  108. }
  109. if input.APIURL != nil {
  110. c.APIURL = *input.APIURL
  111. }
  112. if input.APIKey != nil && *input.APIKey != "" {
  113. encrypted, err := utils.EncryptAPIKey(*input.APIKey)
  114. if err != nil {
  115. return nil, fmt.Errorf("加密 API Key 失败: %v", err)
  116. }
  117. c.APIKey = encrypted
  118. }
  119. if input.Model != nil {
  120. c.Model = *input.Model
  121. }
  122. if input.CustomerCanUseKB != nil {
  123. c.CustomerCanUseKB = *input.CustomerCanUseKB
  124. }
  125. if err := s.repo.Save(c); err != nil {
  126. return nil, err
  127. }
  128. return s.GetForAPI()
  129. }
  130. // EmbeddingConfigResult 返回给前端的结构(不含明文 API Key)
  131. type EmbeddingConfigResult struct {
  132. ID uint `json:"id"`
  133. EmbeddingType string `json:"embedding_type"`
  134. APIURL string `json:"api_url"`
  135. APIKeyMasked string `json:"api_key_masked"`
  136. Model string `json:"model"`
  137. CustomerCanUseKB bool `json:"customer_can_use_kb"`
  138. UpdatedAt time.Time `json:"updated_at,omitempty"`
  139. }
  140. // UpdateEmbeddingConfigInput 更新入参
  141. type UpdateEmbeddingConfigInput struct {
  142. EmbeddingType *string `json:"embedding_type"`
  143. APIURL *string `json:"api_url"`
  144. APIKey *string `json:"api_key"`
  145. Model *string `json:"model"`
  146. CustomerCanUseKB *bool `json:"customer_can_use_kb"`
  147. }