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:
2026-05-23 16:24:07 +08:00
parent d3746fa6c7
commit bdb4fd8c8e
9 changed files with 479 additions and 17 deletions
+31 -1
View File
@@ -296,6 +296,36 @@ function parseSseFrame(frame: string): AiRuntimeStreamEvent | null {
}
}
export function normalizeAiText(value?: string): string {
if (!value) return ''
const trimmed = value.trim()
if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) return value
try {
const parsed = JSON.parse(trimmed)
const extracted = extractTextValue(parsed)
return extracted ? normalizeAiText(extracted) : value
} catch {
return value
}
}
function extractTextValue(value: any): string {
if (!value || typeof value !== 'object' || Array.isArray(value)) return ''
for (const key of ['output', 'answer', 'content', 'text', 'result']) {
const item = value[key]
if (typeof item === 'string' && item.trim()) return item
if (item && typeof item === 'object' && !Array.isArray(item)) {
const nested = extractTextValue(item)
if (nested) return nested
}
}
for (const key of ['data', 'outputs', 'message']) {
const nested = extractTextValue(value[key])
if (nested) return nested
}
return ''
}
async function fetchSseStream(
url: string,
body: Record<string, any>,
@@ -327,7 +357,7 @@ async function fetchSseStream(
const event = parseSseFrame(frame)
if (!event) return
if (event.type === 'delta') {
output += event.content || ''
output += normalizeAiText(event.content || '')
}
onEvent(event, output)
if (event.type === 'error') {