Log bounded TTS failure categories for real calls
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -109,6 +110,36 @@ func synthesizeBailianTTS(ctx context.Context, approved TTSConfig, text string)
|
||||
return pcm.Bytes(), nil
|
||||
}
|
||||
|
||||
// bailianFailureSummary emits only fixed categories and HTTP status codes;
|
||||
// provider responses, signed URLs, credentials and prompt text stay private.
|
||||
func bailianFailureSummary(err error) (string, int) {
|
||||
if err == nil {
|
||||
return "none", 0
|
||||
}
|
||||
message := err.Error()
|
||||
for _, item := range []struct{ prefix, kind string }{
|
||||
{"Bailian TTS rejected request: HTTP ", "generation_http"},
|
||||
{"Bailian audio download rejected: HTTP ", "audio_http"},
|
||||
} {
|
||||
if status, err := strconv.Atoi(strings.TrimPrefix(message, item.prefix)); strings.HasPrefix(message, item.prefix) && err == nil && status >= 100 && status <= 599 {
|
||||
return item.kind, status
|
||||
}
|
||||
}
|
||||
for _, item := range []struct{ prefix, kind string }{
|
||||
{"Bailian TTS response has no complete audio reference", "missing_audio"},
|
||||
{"Bailian TTS request failed:", "generation_transport"},
|
||||
{"Bailian audio download failed:", "audio_transport"},
|
||||
{"Bailian audio conversion failed:", "audio_conversion"},
|
||||
{"Bailian TTS deadline or cancellation:", "deadline"},
|
||||
{"Bailian TTS returned incomplete PCM16 audio", "incomplete_audio"},
|
||||
} {
|
||||
if strings.HasPrefix(message, item.prefix) {
|
||||
return item.kind, 0
|
||||
}
|
||||
}
|
||||
return "unknown", 0
|
||||
}
|
||||
|
||||
type boundedPCM struct{ bytes.Buffer }
|
||||
|
||||
func (w *boundedPCM) Write(data []byte) (int, error) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package ai
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os/exec"
|
||||
@@ -50,6 +51,23 @@ func mockBailianTTS(t *testing.T, pcm []byte, observe func(string)) (string, *at
|
||||
return server.URL + "/api/v1/services/aigc/multimodal-generation/generation", calls
|
||||
}
|
||||
|
||||
func TestBailianFailureSummaryNeverLogsProviderPayload(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
message, kind string
|
||||
status int
|
||||
}{
|
||||
{"Bailian TTS rejected request: HTTP 403", "generation_http", 403},
|
||||
{"Bailian audio download rejected: HTTP 502", "audio_http", 502},
|
||||
{"Bailian TTS response has no complete audio reference", "missing_audio", 0},
|
||||
{"Authorization: Bearer private-signature and prompt", "unknown", 0},
|
||||
} {
|
||||
kind, status := bailianFailureSummary(errors.New(tc.message))
|
||||
if kind != tc.kind || status != tc.status || strings.Contains(kind, "private") {
|
||||
t.Fatalf("unsafe failure summary: kind=%q status=%d", kind, status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBailianTTSDownloadFailureDoesNotLeakSignedURLOrRetry(t *testing.T) {
|
||||
if _, err := exec.LookPath("ffmpeg"); err != nil {
|
||||
t.Skip("Bailian TTS conversion requires ffmpeg")
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -55,6 +56,7 @@ func (c *Call) Open(ctx context.Context) ([]byte, error) {
|
||||
}
|
||||
audio, err := c.bound.Synthesize(ctx, c.bound.Opening)
|
||||
if err != nil {
|
||||
slog.Error("approved opening synthesis failed", "stage", "opening")
|
||||
return nil, err
|
||||
}
|
||||
c.mu.Lock()
|
||||
@@ -233,6 +235,8 @@ func (b Binding) synthesize(ctx context.Context, text string, alreadyPending int
|
||||
// missing or failed response never counts as queued audio.
|
||||
audio, err := synthesizeBailianTTS(ctx, *b.TTS, text)
|
||||
if err != nil {
|
||||
kind, status := bailianFailureSummary(err)
|
||||
slog.Error("approved TTS synthesis failed", "category", kind, "http_status", status, "cause_type", fmt.Sprintf("%T", err))
|
||||
return nil, 0, err
|
||||
}
|
||||
return audio, 1, nil
|
||||
|
||||
Reference in New Issue
Block a user