25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

129 satır
4.4 KiB

  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "net/http"
  6. "strings"
  7. "github.com/QuantumNous/new-api/common"
  8. "github.com/QuantumNous/new-api/constant"
  9. "github.com/QuantumNous/new-api/model"
  10. )
  11. type chinaMobileAssetGroupCreator func(context.Context, int, *model.Channel) (string, *AssetError)
  12. func IsChinaMobileAssetChannel(channel *model.Channel) bool {
  13. return channel != nil && channel.Type == constant.ChannelTypeChinaMobileSeedance
  14. }
  15. func IsAssetGroupOperation(operation AssetOperation) bool {
  16. return strings.HasPrefix(string(operation), "asset_group.")
  17. }
  18. func GetOrCreateChinaMobileUserAssetGroup(ctx context.Context, userId int, channel *model.Channel, createGroup chinaMobileAssetGroupCreator) (string, *AssetError) {
  19. if channel == nil {
  20. return "", newAssetError(AssetErrorServer, "China Mobile asset channel is required", http.StatusInternalServerError)
  21. }
  22. binding, err := model.GetUserAssetGroup(userId, channel.Id)
  23. if err != nil {
  24. return "", newAssetError(AssetErrorServer, err.Error(), http.StatusInternalServerError)
  25. }
  26. if binding != nil {
  27. return binding.GroupId, nil
  28. }
  29. groupId, assetErr := createGroup(ctx, userId, channel)
  30. if assetErr != nil {
  31. return "", assetErr
  32. }
  33. if strings.TrimSpace(groupId) == "" {
  34. return "", newAssetError(AssetErrorUpstream, "China Mobile asset group creation returned an empty group ID", http.StatusBadGateway)
  35. }
  36. if err := model.CreateUserAssetGroup(userId, channel.Id, groupId); err == nil {
  37. return groupId, nil
  38. }
  39. // Another first request may have persisted the binding while this one created its upstream group.
  40. binding, readErr := model.GetUserAssetGroup(userId, channel.Id)
  41. if readErr == nil && binding != nil {
  42. return binding.GroupId, nil
  43. }
  44. if readErr != nil {
  45. return "", newAssetError(AssetErrorServer, readErr.Error(), http.StatusInternalServerError)
  46. }
  47. return "", newAssetError(AssetErrorServer, "failed to persist China Mobile user asset group", http.StatusInternalServerError)
  48. }
  49. func CreateChinaMobileUserAssetGroup(ctx context.Context, userId int, adapter AssetAdapter, channel *model.Channel) (string, *AssetError) {
  50. spec, ok := ParseAssetAction("CreateAssetGroup")
  51. if !ok {
  52. return "", newAssetError(AssetErrorServer, "CreateAssetGroup action is not registered", http.StatusInternalServerError)
  53. }
  54. resp, assetErr := adapter.DoAssetRequest(ctx, channel, AssetRequest{
  55. Action: spec,
  56. Version: "2024-01-01",
  57. Body: map[string]any{
  58. "GroupType": "AIGC",
  59. "Name": fmt.Sprintf("new-api-user-%d-channel-%d", userId, channel.Id),
  60. },
  61. })
  62. if assetErr != nil {
  63. return "", assetErr
  64. }
  65. var payload struct {
  66. Result struct {
  67. GroupId string `json:"GroupId"`
  68. } `json:"Result"`
  69. }
  70. if err := common.Unmarshal(resp.Body, &payload); err != nil {
  71. return "", newAssetError(AssetErrorUpstream, fmt.Sprintf("invalid China Mobile asset group response: %v", err), http.StatusBadGateway)
  72. }
  73. return strings.TrimSpace(payload.Result.GroupId), nil
  74. }
  75. func ScopeChinaMobileAssetRequest(req *AssetRequest, groupId string) {
  76. switch req.Action.Operation {
  77. case AssetOperationAssetCreate:
  78. req.Body["GroupId"] = groupId
  79. case AssetOperationAssetList:
  80. filter := mapValue(req.Body, "Filter")
  81. if filter == nil {
  82. return
  83. }
  84. filter["GroupIds"] = []string{groupId}
  85. req.Body["Filter"] = filter
  86. }
  87. }
  88. func RequireChinaMobileAssetOwnership(ctx context.Context, adapter AssetAdapter, channel *model.Channel, request AssetRequest, groupId string) *AssetError {
  89. spec, ok := ParseAssetAction("GetAsset")
  90. if !ok {
  91. return newAssetError(AssetErrorServer, "GetAsset action is not registered", http.StatusInternalServerError)
  92. }
  93. assetId := strings.TrimSpace(stringValue(request.Body, "Id"))
  94. resp, assetErr := adapter.DoAssetRequest(ctx, channel, AssetRequest{
  95. Action: spec,
  96. Version: request.Version,
  97. Body: map[string]any{"Id": assetId},
  98. })
  99. if assetErr != nil {
  100. if assetErr.HTTPStatus == http.StatusNotFound {
  101. return newAssetError(AssetErrorNotFound, "asset not found", http.StatusNotFound)
  102. }
  103. return assetErr
  104. }
  105. var payload struct {
  106. Result struct {
  107. GroupId string `json:"GroupId"`
  108. } `json:"Result"`
  109. }
  110. if err := common.Unmarshal(resp.Body, &payload); err != nil {
  111. return newAssetError(AssetErrorUpstream, fmt.Sprintf("invalid China Mobile asset response: %v", err), http.StatusBadGateway)
  112. }
  113. if strings.TrimSpace(payload.Result.GroupId) != groupId {
  114. return newAssetError(AssetErrorNotFound, "asset not found", http.StatusNotFound)
  115. }
  116. return nil
  117. }