Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

210 строки
7.8 KiB

  1. package controller
  2. import (
  3. "net/http"
  4. "net/http/httptest"
  5. "strings"
  6. "testing"
  7. "github.com/QuantumNous/new-api/common"
  8. "github.com/QuantumNous/new-api/constant"
  9. "github.com/QuantumNous/new-api/model"
  10. relaycommon "github.com/QuantumNous/new-api/relay/common"
  11. "github.com/gin-gonic/gin"
  12. "github.com/stretchr/testify/require"
  13. )
  14. func TestConvertAipingNativeVideoRequestPreservesNativeContentOrder(t *testing.T) {
  15. req, err := convertAipingNativeVideoRequest([]byte(`{
  16. "model":"doubao-seedance-2-0-260128",
  17. "content":[
  18. {"type":"text","text":"first prompt"},
  19. {"type":"image_url","image_url":{"url":"asset://img1"},"role":"reference_image"},
  20. {"type":"text","text":"second prompt"},
  21. {"type":"video_url","video_url":{"url":"https://example.test/input.mp4"},"role":"reference_video"}
  22. ],
  23. "duration":5,
  24. "resolution":"480p",
  25. "tools":[{"type":"web_search"}]
  26. }`))
  27. require.NoError(t, err)
  28. require.Equal(t, "doubao-seedance-2-0-260128", req.Model)
  29. require.Empty(t, req.Prompt)
  30. require.Equal(t, float64(5), req.Metadata["duration"])
  31. require.Equal(t, "480p", req.Metadata["resolution"])
  32. require.NotNil(t, req.Metadata["tools"])
  33. content, ok := req.Metadata["content"].([]any)
  34. require.True(t, ok)
  35. require.Len(t, content, 4)
  36. require.Equal(t, "text", content[0].(map[string]any)["type"])
  37. require.Equal(t, "image_url", content[1].(map[string]any)["type"])
  38. require.Equal(t, "text", content[2].(map[string]any)["type"])
  39. require.Equal(t, "video_url", content[3].(map[string]any)["type"])
  40. }
  41. func TestConvertAipingNativeVideoRequestPreservesArkDocumentFields(t *testing.T) {
  42. req, err := convertAipingNativeVideoRequest([]byte(`{
  43. "model":"doubao-seedance-2-0-260128",
  44. "content":[
  45. {"type":"text","text":"开场:海边日落"},
  46. {"type":"image_url","image_url":{"url":"asset://image-1"},"role":"reference_image"},
  47. {"type":"video_url","video_url":{"url":"asset://video-1"},"role":"reference_video"},
  48. {"type":"audio_url","audio_url":{"url":"asset://audio-1"},"role":"reference_audio"},
  49. {"type":"draft_task","draft_task":{"id":"cgt-draft"}}
  50. ],
  51. "callback_url":"https://example.test/callback",
  52. "return_last_frame":true,
  53. "service_tier":"default",
  54. "execution_expires_after":3600,
  55. "generate_audio":false,
  56. "draft":true,
  57. "tools":[{"type":"web_search"}],
  58. "safety_identifier":"user-hash-1",
  59. "priority":5,
  60. "resolution":"480p",
  61. "ratio":"1:1",
  62. "duration":5,
  63. "frames":29,
  64. "seed":11,
  65. "camera_fixed":false,
  66. "watermark":true
  67. }`))
  68. require.NoError(t, err)
  69. require.Equal(t, "doubao-seedance-2-0-260128", req.Model)
  70. require.Empty(t, req.Prompt)
  71. require.Equal(t, "https://example.test/callback", req.Metadata["callback_url"])
  72. require.Equal(t, true, req.Metadata["return_last_frame"])
  73. require.Equal(t, "default", req.Metadata["service_tier"])
  74. require.Equal(t, float64(3600), req.Metadata["execution_expires_after"])
  75. require.Equal(t, false, req.Metadata["generate_audio"])
  76. require.Equal(t, true, req.Metadata["draft"])
  77. require.Equal(t, "user-hash-1", req.Metadata["safety_identifier"])
  78. require.Equal(t, float64(5), req.Metadata["priority"])
  79. require.Equal(t, "480p", req.Metadata["resolution"])
  80. require.Equal(t, "1:1", req.Metadata["ratio"])
  81. require.Equal(t, float64(5), req.Metadata["duration"])
  82. require.Equal(t, float64(29), req.Metadata["frames"])
  83. require.Equal(t, float64(11), req.Metadata["seed"])
  84. require.Equal(t, false, req.Metadata["camera_fixed"])
  85. require.Equal(t, true, req.Metadata["watermark"])
  86. content, ok := req.Metadata["content"].([]any)
  87. require.True(t, ok)
  88. require.Len(t, content, 5)
  89. require.Equal(t, "audio_url", content[3].(map[string]any)["type"])
  90. require.Equal(t, "draft_task", content[4].(map[string]any)["type"])
  91. tools, ok := req.Metadata["tools"].([]any)
  92. require.True(t, ok)
  93. require.Equal(t, "web_search", tools[0].(map[string]any)["type"])
  94. }
  95. func TestConvertAipingNativeVideoRequestRejectsMissingModel(t *testing.T) {
  96. _, err := convertAipingNativeVideoRequest([]byte(`{"content":[{"type":"text","text":"prompt"}]}`))
  97. require.ErrorContains(t, err, "model")
  98. }
  99. func TestPrepareAipingNativeVideoSubmitStoresConvertedRequest(t *testing.T) {
  100. c := newControllerJSONContext(t, "/api/v3/contents/generations/tasks", `{
  101. "model":"doubao-seedance-2-0-260128",
  102. "content":[{"type":"text","text":"prompt"}]
  103. }`)
  104. info := &relaycommon.RelayInfo{TaskRelayInfo: &relaycommon.TaskRelayInfo{}}
  105. err := prepareAipingNativeVideoSubmit(c, info)
  106. require.NoError(t, err)
  107. stored, err := relaycommon.GetTaskRequest(c)
  108. require.NoError(t, err)
  109. require.Equal(t, "doubao-seedance-2-0-260128", stored.Model)
  110. require.Empty(t, stored.Prompt)
  111. content, ok := stored.Metadata["content"].([]any)
  112. require.True(t, ok)
  113. require.Equal(t, "prompt", content[0].(map[string]any)["text"])
  114. require.Equal(t, constant.TaskActionGenerate, info.Action)
  115. require.Equal(t, "doubao-seedance-2-0-260128", info.OriginModelName)
  116. }
  117. func TestBuildAipingNativeFetchResponseRewritesIDAndPreservesUpstreamFields(t *testing.T) {
  118. task := &model.Task{
  119. TaskID: "task_public",
  120. Status: model.TaskStatusSuccess,
  121. CreatedAt: 1781496040,
  122. UpdatedAt: 1781496278,
  123. Properties: model.Properties{OriginModelName: "doubao-seedance-2-0-260128"},
  124. Data: []byte(`{
  125. "id":"cgt-upstream",
  126. "aiping_id":"3d2c8c17-36ad-4138-8602-88b3c60e56c6",
  127. "model":"doubao-seedance-2-0-260128",
  128. "status":"succeeded",
  129. "content":{"video_url":"https://example.test/output.mp4"},
  130. "usage":{"completion_tokens":48400,"total_tokens":48400},
  131. "created_at":1781496040,
  132. "updated_at":1781496278,
  133. "seed":73812,
  134. "resolution":"480p",
  135. "ratio":"1:1",
  136. "duration":5,
  137. "framespersecond":24,
  138. "service_tier":"default",
  139. "execution_expires_after":172800,
  140. "generate_audio":true,
  141. "draft":false,
  142. "priority":0
  143. }`),
  144. }
  145. data, err := buildAipingNativeFetchResponse(task)
  146. require.NoError(t, err)
  147. var payload map[string]any
  148. require.NoError(t, common.Unmarshal(data, &payload))
  149. require.Equal(t, "task_public", payload["id"])
  150. require.Equal(t, "succeeded", payload["status"])
  151. require.Equal(t, "doubao-seedance-2-0-260128", payload["model"])
  152. require.Equal(t, "https://example.test/output.mp4", payload["content"].(map[string]any)["video_url"])
  153. require.Equal(t, float64(48400), payload["usage"].(map[string]any)["total_tokens"])
  154. require.Equal(t, float64(73812), payload["seed"])
  155. require.Equal(t, "480p", payload["resolution"])
  156. require.Equal(t, "1:1", payload["ratio"])
  157. require.Equal(t, float64(5), payload["duration"])
  158. require.Equal(t, float64(24), payload["framespersecond"])
  159. require.Equal(t, "default", payload["service_tier"])
  160. require.Equal(t, float64(172800), payload["execution_expires_after"])
  161. require.Equal(t, true, payload["generate_audio"])
  162. require.Equal(t, false, payload["draft"])
  163. require.Equal(t, float64(0), payload["priority"])
  164. require.Contains(t, payload, "error")
  165. require.Nil(t, payload["error"])
  166. require.NotContains(t, payload, "aiping_id")
  167. }
  168. func TestBuildAipingNativeFetchResponseFallsBackForFailedTask(t *testing.T) {
  169. task := &model.Task{
  170. TaskID: "task_public",
  171. Status: model.TaskStatusFailure,
  172. CreatedAt: 100,
  173. UpdatedAt: 200,
  174. Properties: model.Properties{OriginModelName: "doubao-seedance-2-0-260128"},
  175. Data: []byte(`{"id":"cgt-upstream","status":"failed","error":{"code":"InvalidParameter","message":"duration is invalid"}}`),
  176. }
  177. data, err := buildAipingNativeFetchResponse(task)
  178. require.NoError(t, err)
  179. require.Contains(t, string(data), `"id":"task_public"`)
  180. require.Contains(t, string(data), `"code":"InvalidParameter"`)
  181. require.Contains(t, string(data), `"message":"duration is invalid"`)
  182. require.NotContains(t, string(data), `"error":null`)
  183. }
  184. func newControllerJSONContext(t *testing.T, path string, body string) *gin.Context {
  185. t.Helper()
  186. w := httptest.NewRecorder()
  187. c, _ := gin.CreateTestContext(w)
  188. c.Request = httptest.NewRequest(http.MethodPost, path, strings.NewReader(body))
  189. c.Request.Header.Set("Content-Type", "application/json")
  190. return c
  191. }