channel.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package service
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/QuantumNous/new-api/common"
  6. "github.com/QuantumNous/new-api/dto"
  7. "github.com/QuantumNous/new-api/model"
  8. "github.com/QuantumNous/new-api/setting/operation_setting"
  9. "github.com/QuantumNous/new-api/types"
  10. )
  11. func formatNotifyType(channelId int, status int) string {
  12. return fmt.Sprintf("%s_%d_%d", dto.NotifyTypeChannelUpdate, channelId, status)
  13. }
  14. // disable & notify
  15. func DisableChannel(channelError types.ChannelError, reason string) {
  16. common.SysLog(fmt.Sprintf("通道「%s」(#%d)发生错误,准备禁用,原因:%s", channelError.ChannelName, channelError.ChannelId, reason))
  17. // 检查是否启用自动禁用功能
  18. if !channelError.AutoBan {
  19. common.SysLog(fmt.Sprintf("通道「%s」(#%d)未启用自动禁用功能,跳过禁用操作", channelError.ChannelName, channelError.ChannelId))
  20. return
  21. }
  22. success := model.UpdateChannelStatus(channelError.ChannelId, channelError.UsingKey, common.ChannelStatusAutoDisabled, reason)
  23. if success {
  24. subject := fmt.Sprintf("通道「%s」(#%d)已被禁用", channelError.ChannelName, channelError.ChannelId)
  25. content := fmt.Sprintf("通道「%s」(#%d)已被禁用,原因:%s", channelError.ChannelName, channelError.ChannelId, reason)
  26. NotifyRootUser(formatNotifyType(channelError.ChannelId, common.ChannelStatusAutoDisabled), subject, content)
  27. }
  28. }
  29. func EnableChannel(channelId int, usingKey string, channelName string) {
  30. success := model.UpdateChannelStatus(channelId, usingKey, common.ChannelStatusEnabled, "")
  31. if success {
  32. subject := fmt.Sprintf("通道「%s」(#%d)已被启用", channelName, channelId)
  33. content := fmt.Sprintf("通道「%s」(#%d)已被启用", channelName, channelId)
  34. NotifyRootUser(formatNotifyType(channelId, common.ChannelStatusEnabled), subject, content)
  35. }
  36. }
  37. func ShouldDisableChannel(channelType int, err *types.NewAPIError) bool {
  38. if !common.AutomaticDisableChannelEnabled {
  39. return false
  40. }
  41. if err == nil {
  42. return false
  43. }
  44. if types.IsChannelError(err) {
  45. return true
  46. }
  47. if types.IsSkipRetryError(err) {
  48. return false
  49. }
  50. if operation_setting.ShouldDisableByStatusCode(err.StatusCode) {
  51. return true
  52. }
  53. //if err.StatusCode == http.StatusUnauthorized {
  54. // return true
  55. //}
  56. //if err.StatusCode == http.StatusForbidden {
  57. // switch channelType {
  58. // case constant.ChannelTypeGemini:
  59. // return true
  60. // }
  61. //}
  62. oaiErr := err.ToOpenAIError()
  63. switch oaiErr.Code {
  64. case "invalid_api_key":
  65. return true
  66. case "account_deactivated":
  67. return true
  68. case "billing_not_active":
  69. return true
  70. case "pre_consume_token_quota_failed":
  71. return true
  72. case "Arrearage":
  73. return true
  74. }
  75. switch oaiErr.Type {
  76. case "insufficient_quota":
  77. return true
  78. case "insufficient_user_quota":
  79. return true
  80. // https://docs.anthropic.com/claude/reference/errors
  81. case "authentication_error":
  82. return true
  83. case "permission_error":
  84. return true
  85. case "forbidden":
  86. return true
  87. }
  88. lowerMessage := strings.ToLower(err.Error())
  89. search, _ := AcSearch(lowerMessage, operation_setting.AutomaticDisableKeywords, true)
  90. return search
  91. }
  92. func ShouldEnableChannel(newAPIError *types.NewAPIError, status int) bool {
  93. if !common.AutomaticEnableChannelEnabled {
  94. return false
  95. }
  96. if newAPIError != nil {
  97. return false
  98. }
  99. if status != common.ChannelStatusAutoDisabled {
  100. return false
  101. }
  102. return true
  103. }