From 4c0aa682a5711f37d56e71bc71e5edd10f219258 Mon Sep 17 00:00:00 2001 From: ddcat666 <26564566+ddcat666@users.noreply.github.com> Date: Wed, 30 Sep 2026 14:38:40 +0800 Subject: [PATCH] =?UTF-8?q?fix(media):=20=E5=AA=92=E4=BD=93=E6=81=A2?= =?UTF-8?q?=E5=A4=8D=20-=20=E4=BF=9D=E7=95=99=E9=9F=B3=E9=A2=91=E5=A4=9A?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E5=B9=B6=E5=85=BC=E5=AE=B9=E5=8D=95=E6=95=B0?= =?UTF-8?q?=E5=93=8D=E5=BA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/app/task_media_recovery.go | 7 ++-- .../internal/app/task_media_recovery_test.go | 34 +++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/backend/internal/app/task_media_recovery.go b/backend/internal/app/task_media_recovery.go index b81540e0b..e6746e586 100644 --- a/backend/internal/app/task_media_recovery.go +++ b/backend/internal/app/task_media_recovery.go @@ -110,9 +110,6 @@ func recoverProtocolMedia(ctx context.Context, config providerConfig, mode strin if len(references) == 0 || len(references) > 32 { return nil, true, &mediaRecoveryError{stage: "checkpoint", cause: errors.New("生成结果数量超过恢复限制")} } - if mode != "image" { - references = references[:1] - } if task.MediaRecoveryJSON != "" { result, err := s.resumeTaskMedia(ctx, task) return result, true, err @@ -246,6 +243,10 @@ func (s *Service) materializeTaskMedia(ctx context.Context, task *model.Task, co result = map[string]interface{}{"mode": checkpoint.Mode} if checkpoint.Mode == "image" { result["images"] = items + } else if checkpoint.Mode == "audio" { + result["audios"] = items + // Keep the legacy singular field for clients that render one audio result. + result["audio"] = items[0] } else { result[checkpoint.Mode] = items[0] } diff --git a/backend/internal/app/task_media_recovery_test.go b/backend/internal/app/task_media_recovery_test.go index d3ba3e95d..0d9c80927 100644 --- a/backend/internal/app/task_media_recovery_test.go +++ b/backend/internal/app/task_media_recovery_test.go @@ -409,3 +409,37 @@ func TestMediaRecoveryExpiredLeaseAndStagingLimits(t *testing.T) { t.Fatal("staging budget exceeded") } } + +func TestMediaRecoveryAudioKeepsAllReturnedResults(t *testing.T) { + t.Setenv("CANVAS_ALLOWED_PRIVATE_UPSTREAM_HOSTS", "127.0.0.1") + s, db := newMediaRecoveryTestService(t) + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "audio/mpeg") + _, _ = w.Write([]byte("audio-result")) + })) + defer server.Close() + expires := time.Now().Add(time.Hour) + input, err := json.Marshal(canvasGenerationInput{Mode: "audio", Config: providerConfig{BaseURL: server.URL}, Prompt: "test"}) + if err != nil { + t.Fatal(err) + } + task := &model.Task{ID: newID(), UserID: "media-user", Type: "canvas_audio", Status: model.TaskStatusRunning, InputJSON: string(input), LeaseOwner: "worker-a", LeaseExpiresAt: &expires, RouteRun: 1, CreatedAt: time.Now()} + if err := db.Create(task).Error; err != nil { + t.Fatal(err) + } + ctx := context.WithValue(withProviderAnalytics(context.Background(), s, *task), mediaExecutionTaskKey{}, *task) + result, handled, recoveryErr := recoverProtocolMedia(ctx, providerConfig{BaseURL: server.URL}, "audio", []protocol.MediaReference{ + {URL: server.URL + "/voice.wav", MIMEType: "audio/mpeg"}, + {URL: server.URL + "/emotion.wav", MIMEType: "audio/mpeg"}, + }) + if !handled || recoveryErr != nil { + t.Fatalf("handled=%v err=%v", handled, recoveryErr) + } + audios, ok := result["audios"].([]interface{}) + if !ok || len(audios) != 2 { + t.Fatalf("audios=%#v result=%#v", result["audios"], result) + } + if _, ok := result["audio"]; !ok { + t.Fatal("legacy singular audio result missing") + } +}