feat: AI测试输出渲染Markdown/流式响应、Coze/Dify适配器优化
- 新增 MarkdownPreview 组件,支持 AI 测试输出 Markdown 渲染 - Coze 适配器优化:支持流式响应、工作流接口调用、SSE事件处理 - Dify 适配器优化:支持停止接口、流式聊天、SSE事件解析 - web-admin 添加 markdown-it 和 highlight.js 依赖 - AI 配置列表页面优化测试对话框输出显示 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -115,33 +115,85 @@ public class CozeProviderAdapter implements AiProviderAdapter {
|
||||
String type = json.getString("type");
|
||||
String content = json.getString("content");
|
||||
if (StringUtils.hasText(content) && (type == null || type.contains("answer") || type.contains("delta"))) {
|
||||
return content;
|
||||
return normalizeOutputText(content);
|
||||
}
|
||||
String output = json.getString("output");
|
||||
if (StringUtils.hasText(output)) {
|
||||
return output;
|
||||
return normalizeOutputText(output);
|
||||
}
|
||||
String answer = json.getString("answer");
|
||||
if (StringUtils.hasText(answer)) {
|
||||
return answer;
|
||||
return normalizeOutputText(answer);
|
||||
}
|
||||
JSONObject message = json.getJSONObject("message");
|
||||
if (message != null && StringUtils.hasText(message.getString("content"))) {
|
||||
return message.getString("content");
|
||||
return normalizeOutputText(message.getString("content"));
|
||||
}
|
||||
JSONObject data = json.getJSONObject("data");
|
||||
if (data != null) {
|
||||
String dataOutput = data.getString("output");
|
||||
if (StringUtils.hasText(dataOutput)) {
|
||||
return dataOutput;
|
||||
return normalizeOutputText(dataOutput);
|
||||
}
|
||||
String dataAnswer = data.getString("answer");
|
||||
if (StringUtils.hasText(dataAnswer)) {
|
||||
return dataAnswer;
|
||||
return normalizeOutputText(dataAnswer);
|
||||
}
|
||||
String dataContent = data.getString("content");
|
||||
if (StringUtils.hasText(dataContent)) {
|
||||
return dataContent;
|
||||
return normalizeOutputText(dataContent);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String normalizeOutputText(String value) {
|
||||
if (!StringUtils.hasText(value)) {
|
||||
return value;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
|
||||
return value;
|
||||
}
|
||||
try {
|
||||
JSONObject json = JSON.parseObject(trimmed);
|
||||
String extracted = firstText(json);
|
||||
return StringUtils.hasText(extracted) ? normalizeOutputText(extracted) : value;
|
||||
} catch (Exception ignored) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private String firstText(JSONObject json) {
|
||||
String direct = firstTextValue(json, "output", "answer", "content", "text", "result");
|
||||
if (StringUtils.hasText(direct)) {
|
||||
return direct;
|
||||
}
|
||||
JSONObject data = json.getJSONObject("data");
|
||||
if (data != null) {
|
||||
String dataText = firstText(data);
|
||||
if (StringUtils.hasText(dataText)) {
|
||||
return dataText;
|
||||
}
|
||||
}
|
||||
JSONObject outputs = json.getJSONObject("outputs");
|
||||
if (outputs != null) {
|
||||
return firstText(outputs);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String firstTextValue(JSONObject json, String... keys) {
|
||||
for (String key : keys) {
|
||||
Object value = json.get(key);
|
||||
if (value instanceof String text && StringUtils.hasText(text)) {
|
||||
return text;
|
||||
}
|
||||
if (value instanceof JSONObject object) {
|
||||
String nested = firstText(object);
|
||||
if (StringUtils.hasText(nested)) {
|
||||
return nested;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -103,11 +103,11 @@ public class DifyProviderAdapter implements AiProviderAdapter {
|
||||
private String extractDifyDelta(JSONObject json) {
|
||||
String event = json.getString("event");
|
||||
if ("message".equals(event) || "agent_message".equals(event)) {
|
||||
return json.getString("answer");
|
||||
return normalizeOutputText(json.getString("answer"));
|
||||
}
|
||||
if ("text_chunk".equals(event)) {
|
||||
JSONObject data = json.getJSONObject("data");
|
||||
return data == null ? null : data.getString("text");
|
||||
return data == null ? null : normalizeOutputText(data.getString("text"));
|
||||
}
|
||||
if ("workflow_finished".equals(event)) {
|
||||
JSONObject data = json.getJSONObject("data");
|
||||
@@ -117,7 +117,59 @@ public class DifyProviderAdapter implements AiProviderAdapter {
|
||||
if (text == null) {
|
||||
text = outputs.get("answer");
|
||||
}
|
||||
return text == null ? null : String.valueOf(text);
|
||||
return text == null ? null : normalizeOutputText(String.valueOf(text));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String normalizeOutputText(String value) {
|
||||
if (!StringUtils.hasText(value)) {
|
||||
return value;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
|
||||
return value;
|
||||
}
|
||||
try {
|
||||
JSONObject json = JSON.parseObject(trimmed);
|
||||
String extracted = firstText(json);
|
||||
return StringUtils.hasText(extracted) ? normalizeOutputText(extracted) : value;
|
||||
} catch (Exception ignored) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private String firstText(JSONObject json) {
|
||||
String direct = firstTextValue(json, "output", "answer", "content", "text", "result");
|
||||
if (StringUtils.hasText(direct)) {
|
||||
return direct;
|
||||
}
|
||||
JSONObject data = json.getJSONObject("data");
|
||||
if (data != null) {
|
||||
String dataText = firstText(data);
|
||||
if (StringUtils.hasText(dataText)) {
|
||||
return dataText;
|
||||
}
|
||||
}
|
||||
JSONObject outputs = json.getJSONObject("outputs");
|
||||
if (outputs != null) {
|
||||
return firstText(outputs);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String firstTextValue(JSONObject json, String... keys) {
|
||||
for (String key : keys) {
|
||||
Object value = json.get(key);
|
||||
if (value instanceof String text && StringUtils.hasText(text)) {
|
||||
return text;
|
||||
}
|
||||
if (value instanceof JSONObject object) {
|
||||
String nested = firstText(object);
|
||||
if (StringUtils.hasText(nested)) {
|
||||
return nested;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user