mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix(tts): surface provider response diagnostics (#555)
This commit is contained in:
parent
b196dc73fd
commit
7563d2dd19
@ -0,0 +1,31 @@
|
||||
package vip.mate.tts;
|
||||
|
||||
/**
|
||||
* Compact diagnostics for HTTP-based TTS provider failures.
|
||||
*/
|
||||
public final class TtsResponseDiagnostics {
|
||||
|
||||
static final int MAX_SNIPPET_CHARS = 200;
|
||||
|
||||
private TtsResponseDiagnostics() {
|
||||
}
|
||||
|
||||
public static String failureMessage(String provider, String endpoint, int status, String body) {
|
||||
return provider + " 失败: endpoint=" + endpoint
|
||||
+ ", status=" + status
|
||||
+ ", body=" + snippet(body);
|
||||
}
|
||||
|
||||
public static String snippet(String body) {
|
||||
if (body == null || body.isBlank()) {
|
||||
return "(空响应体)";
|
||||
}
|
||||
String collapsed = body.trim()
|
||||
.replaceAll("(?i)Bearer\\s+[A-Za-z0-9._~+/=-]+", "Bearer [REDACTED]")
|
||||
.replaceAll("\\s+", " ");
|
||||
if (collapsed.length() <= MAX_SNIPPET_CHARS) {
|
||||
return collapsed;
|
||||
}
|
||||
return collapsed.substring(0, MAX_SNIPPET_CHARS) + "...";
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,7 @@ import vip.mate.llm.service.ModelProviderService;
|
||||
import vip.mate.system.model.SystemSettingsDTO;
|
||||
import vip.mate.tts.TtsProvider;
|
||||
import vip.mate.tts.TtsRequest;
|
||||
import vip.mate.tts.TtsResponseDiagnostics;
|
||||
import vip.mate.tts.TtsResult;
|
||||
|
||||
import java.util.List;
|
||||
@ -101,7 +102,8 @@ public class DashScopeTtsProvider implements TtsProvider {
|
||||
body.put("speed", request.getSpeed());
|
||||
}
|
||||
|
||||
HttpResponse response = HttpRequest.post(BASE_URL + "/audio/speech")
|
||||
String endpoint = BASE_URL + "/audio/speech";
|
||||
HttpResponse response = HttpRequest.post(endpoint)
|
||||
.header("Authorization", "Bearer " + apiKey)
|
||||
.header("Content-Type", "application/json")
|
||||
.body(body.toString())
|
||||
@ -115,7 +117,8 @@ public class DashScopeTtsProvider implements TtsProvider {
|
||||
} else {
|
||||
String errBody = response.body();
|
||||
log.warn("[DashScope TTS] Failed: HTTP {} - {}", response.getStatus(), errBody);
|
||||
return TtsResult.failure("DashScope TTS 失败: HTTP " + response.getStatus());
|
||||
return TtsResult.failure(TtsResponseDiagnostics.failureMessage(
|
||||
"DashScope TTS", endpoint, response.getStatus(), errBody));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[DashScope TTS] Error: {}", e.getMessage(), e);
|
||||
|
||||
@ -11,6 +11,7 @@ import vip.mate.llm.service.ModelProviderService;
|
||||
import vip.mate.system.model.SystemSettingsDTO;
|
||||
import vip.mate.tts.TtsProvider;
|
||||
import vip.mate.tts.TtsRequest;
|
||||
import vip.mate.tts.TtsResponseDiagnostics;
|
||||
import vip.mate.tts.TtsResult;
|
||||
|
||||
import java.util.List;
|
||||
@ -112,7 +113,8 @@ public class OpenAiTtsProvider implements TtsProvider {
|
||||
} else {
|
||||
String errBody = response.body();
|
||||
log.warn("[OpenAI TTS] Failed: HTTP {} - {}", response.getStatus(), errBody);
|
||||
return TtsResult.failure("OpenAI TTS 失败: HTTP " + response.getStatus());
|
||||
return TtsResult.failure(TtsResponseDiagnostics.failureMessage(
|
||||
"OpenAI TTS", url, response.getStatus(), errBody));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[OpenAI TTS] Error: {}", e.getMessage(), e);
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
package vip.mate.tts;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class TtsResponseDiagnosticsTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("failureMessage includes provider, endpoint, status and sanitized body snippet")
|
||||
void failureMessageIncludesActionableDiagnostics() {
|
||||
String message = TtsResponseDiagnostics.failureMessage(
|
||||
"DashScope TTS",
|
||||
"https://dashscope.aliyuncs.com/compatible-mode/v1/audio/speech",
|
||||
400,
|
||||
"""
|
||||
{"code":"InvalidParameter","message":"voice does not exist"}
|
||||
""");
|
||||
|
||||
assertTrue(message.contains("DashScope TTS 失败"));
|
||||
assertTrue(message.contains("endpoint=https://dashscope.aliyuncs.com/compatible-mode/v1/audio/speech"));
|
||||
assertTrue(message.contains("status=400"));
|
||||
assertTrue(message.contains("body={\"code\":\"InvalidParameter\",\"message\":\"voice does not exist\"}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("failureMessage truncates long response bodies")
|
||||
void failureMessageTruncatesLongBodies() {
|
||||
String body = "x".repeat(800);
|
||||
|
||||
String message = TtsResponseDiagnostics.failureMessage(
|
||||
"OpenAI TTS",
|
||||
"https://api.openai.com/v1/audio/speech",
|
||||
500,
|
||||
body);
|
||||
|
||||
assertTrue(message.contains("OpenAI TTS 失败"));
|
||||
assertTrue(message.contains("status=500"));
|
||||
assertTrue(message.contains("body="));
|
||||
assertTrue(message.endsWith("..."));
|
||||
assertTrue(message.length() < 420);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("snippet redacts bearer tokens and collapses whitespace")
|
||||
void snippetRedactsSecretsAndCollapsesWhitespace() {
|
||||
String snippet = TtsResponseDiagnostics.snippet("""
|
||||
Authorization: Bearer sk-abcdef123456
|
||||
gateway failed
|
||||
""");
|
||||
|
||||
assertEquals("Authorization: Bearer [REDACTED] gateway failed", snippet);
|
||||
assertFalse(snippet.contains("sk-abcdef"));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user