You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

227 lines
6.8 KiB

  1. package service
  2. import (
  3. "errors"
  4. "sort"
  5. "strings"
  6. "github.com/QuantumNous/new-api/common"
  7. "github.com/QuantumNous/new-api/constant"
  8. "github.com/QuantumNous/new-api/model"
  9. "gorm.io/gorm"
  10. )
  11. type VideoAssetFamily string
  12. const (
  13. VideoAssetFamilySeedance VideoAssetFamily = "seedance"
  14. VideoAssetFamilyKling VideoAssetFamily = "kling"
  15. )
  16. func VideoAssetFamilies() []VideoAssetFamily {
  17. return []VideoAssetFamily{VideoAssetFamilySeedance, VideoAssetFamilyKling}
  18. }
  19. func VideoAssetChannelTypesForFamily(family VideoAssetFamily) []int {
  20. switch family {
  21. case VideoAssetFamilySeedance:
  22. return []int{
  23. constant.ChannelTypeDoubaoVideoCompatibleAiping,
  24. constant.ChannelTypeDoubaoVideoCompatibleTianyiYun,
  25. constant.ChannelTypeChinaMobileSeedance,
  26. }
  27. case VideoAssetFamilyKling:
  28. return []int{
  29. constant.ChannelTypeKlingAiping,
  30. }
  31. default:
  32. return nil
  33. }
  34. }
  35. func VideoAssetFamilyForChannelType(channelType int) (VideoAssetFamily, bool) {
  36. for _, family := range []VideoAssetFamily{VideoAssetFamilySeedance, VideoAssetFamilyKling} {
  37. if channelTypeAllowed(channelType, VideoAssetChannelTypesForFamily(family)) {
  38. return family, true
  39. }
  40. }
  41. return "", false
  42. }
  43. func GetBoundVideoAssetChannelForModel(userId int, tokenGroup string, modelName string, family VideoAssetFamily) (*model.Channel, error) {
  44. bindings, err := model.GetUserAssetChannelsByTypes(userId, VideoAssetChannelTypesForFamily(family), tokenGroup)
  45. if err != nil {
  46. return nil, err
  47. }
  48. for _, binding := range bindings {
  49. channel, err := model.CacheGetChannel(binding.ChannelId)
  50. if err != nil {
  51. if errors.Is(err, gorm.ErrRecordNotFound) || common.MemoryCacheEnabled {
  52. continue
  53. }
  54. return nil, err
  55. }
  56. if IsUsableVideoAssetChannelForFamily(channel, tokenGroup, modelName, family) {
  57. return channel, nil
  58. }
  59. }
  60. return nil, nil
  61. }
  62. func ResolveVideoAssetChannelForModel(userId int, tokenGroup string, modelName string, family VideoAssetFamily) (*model.Channel, error) {
  63. channel, err := GetBoundVideoAssetChannelForModel(userId, tokenGroup, modelName, family)
  64. if err != nil {
  65. return nil, err
  66. }
  67. if channel != nil {
  68. return channel, nil
  69. }
  70. channel, err = autoMatchVideoAssetChannelForModel(tokenGroup, modelName, family)
  71. if err != nil {
  72. return nil, err
  73. }
  74. if channel == nil {
  75. return nil, nil
  76. }
  77. if err = BindVideoAssetChannel(userId, tokenGroup, channel, family); err != nil {
  78. return nil, err
  79. }
  80. return channel, nil
  81. }
  82. func BindVideoAssetChannel(userId int, tokenGroup string, channel *model.Channel, family VideoAssetFamily) error {
  83. if channel == nil {
  84. return nil
  85. }
  86. channelTypes := VideoAssetChannelTypesForFamily(family)
  87. if len(channelTypes) == 0 || !channelTypeAllowed(channel.Type, channelTypes) {
  88. return nil
  89. }
  90. otherTypes := make([]int, 0, len(channelTypes))
  91. for _, channelType := range channelTypes {
  92. if channelType != channel.Type {
  93. otherTypes = append(otherTypes, channelType)
  94. }
  95. }
  96. return model.DB.Transaction(func(tx *gorm.DB) error {
  97. if err := model.DeleteUserAssetChannelsByTypesWithTx(tx, userId, otherTypes, tokenGroup); err != nil {
  98. return err
  99. }
  100. return model.BindUserAssetChannelWithTx(tx, userId, channel.Type, tokenGroup, channel.Id)
  101. })
  102. }
  103. func ClearVideoAssetChannelBinding(userId int, tokenGroup string, family VideoAssetFamily) error {
  104. channelTypes := VideoAssetChannelTypesForFamily(family)
  105. if len(channelTypes) == 0 {
  106. return nil
  107. }
  108. return model.DB.Transaction(func(tx *gorm.DB) error {
  109. return model.DeleteUserAssetChannelsByTypesWithTx(tx, userId, channelTypes, tokenGroup)
  110. })
  111. }
  112. func GetVideoAssetChannelCandidates(tokenGroup string, family VideoAssetFamily) ([]*model.Channel, error) {
  113. channelTypes := VideoAssetChannelTypesForFamily(family)
  114. if len(channelTypes) == 0 {
  115. return nil, nil
  116. }
  117. candidates := make(map[int]*model.Channel)
  118. for _, channelType := range channelTypes {
  119. for startIdx := 0; ; startIdx += DoubaoAssetChannelPageSize {
  120. channels, err := model.GetChannelsByType(startIdx, DoubaoAssetChannelPageSize, true, channelType)
  121. if err != nil {
  122. return nil, err
  123. }
  124. for _, candidate := range channels {
  125. if candidate == nil || candidate.Status != common.ChannelStatusEnabled || !MatchDoubaoAssetGroup(candidate.GetGroups(), tokenGroup) {
  126. continue
  127. }
  128. channel, err := model.GetChannelById(candidate.Id, true)
  129. if err != nil {
  130. return nil, err
  131. }
  132. if channel.Status == common.ChannelStatusEnabled && strings.TrimSpace(channel.Key) != "" && MatchDoubaoAssetGroup(channel.GetGroups(), tokenGroup) {
  133. channel.Key = ""
  134. channel.Keys = nil
  135. candidates[channel.Id] = channel
  136. }
  137. }
  138. if len(channels) < DoubaoAssetChannelPageSize {
  139. break
  140. }
  141. }
  142. }
  143. result := make([]*model.Channel, 0, len(candidates))
  144. for _, channel := range candidates {
  145. result = append(result, channel)
  146. }
  147. sort.Slice(result, func(i, j int) bool { return result[i].Id < result[j].Id })
  148. return result, nil
  149. }
  150. func HasVideoAssetChannelForGroupModel(tokenGroup string, modelName string, family VideoAssetFamily) bool {
  151. tokenGroup = strings.TrimSpace(tokenGroup)
  152. modelName = strings.TrimSpace(modelName)
  153. if tokenGroup == "" || modelName == "" {
  154. return false
  155. }
  156. channel, err := autoMatchVideoAssetChannelForModel(tokenGroup, modelName, family)
  157. return err == nil && channel != nil
  158. }
  159. func autoMatchVideoAssetChannelForModel(tokenGroup string, modelName string, family VideoAssetFamily) (*model.Channel, error) {
  160. for _, channelType := range VideoAssetChannelTypesForFamily(family) {
  161. for startIdx := 0; ; startIdx += DoubaoAssetChannelPageSize {
  162. candidates, err := model.GetChannelsByType(startIdx, DoubaoAssetChannelPageSize, true, channelType)
  163. if err != nil {
  164. return nil, err
  165. }
  166. for _, candidate := range candidates {
  167. if candidate == nil || !MatchDoubaoAssetGroup(candidate.GetGroups(), tokenGroup) {
  168. continue
  169. }
  170. channel, err := model.CacheGetChannel(candidate.Id)
  171. if err != nil {
  172. if errors.Is(err, gorm.ErrRecordNotFound) || common.MemoryCacheEnabled {
  173. continue
  174. }
  175. return nil, err
  176. }
  177. if IsUsableVideoAssetChannelForFamily(channel, tokenGroup, modelName, family) {
  178. return channel, nil
  179. }
  180. }
  181. if len(candidates) < DoubaoAssetChannelPageSize {
  182. break
  183. }
  184. }
  185. }
  186. return nil, nil
  187. }
  188. func IsUsableVideoAssetChannelForFamily(channel *model.Channel, tokenGroup string, modelName string, family VideoAssetFamily) bool {
  189. if channel == nil {
  190. return false
  191. }
  192. channelTypes := VideoAssetChannelTypesForFamily(family)
  193. if len(channelTypes) == 0 || !channelTypeAllowed(channel.Type, channelTypes) {
  194. return false
  195. }
  196. if channel.Status != common.ChannelStatusEnabled {
  197. return false
  198. }
  199. if strings.TrimSpace(channel.Key) == "" || len(channel.GetKeys()) == 0 {
  200. return false
  201. }
  202. if !MatchDoubaoAssetGroup(channel.GetGroups(), tokenGroup) {
  203. return false
  204. }
  205. modelName = strings.TrimSpace(modelName)
  206. if modelName == "" {
  207. return true
  208. }
  209. return model.IsChannelEnabledForGroupModel(tokenGroup, modelName, channel.Id)
  210. }