fix: 修复 Dify 非流式测试 user_id 缺失和超时问题
- enrichInputs 增加 user_id 下划线字段注入(Dify API 要求下划线格式) - testAiRuntime 接口超时从 15 秒延长到 60 秒 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,11 @@ import request from '@/utils/request'
|
||||
import type {
|
||||
AiConfigPageRequest,
|
||||
AiConfigCreateRequest,
|
||||
AiConfigUpdateRequest
|
||||
AiConfigUpdateRequest,
|
||||
AiProvider,
|
||||
AiEndpointConfig,
|
||||
AiSceneBinding,
|
||||
AiRuntimeRequest
|
||||
} from '@/types/aiconfig'
|
||||
|
||||
// 分页查询AI配置
|
||||
@@ -215,3 +219,119 @@ export function updateAiConfigFromTest(data: any) {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function listAiProviders() {
|
||||
return request({ url: '/ai/providers', method: 'get' })
|
||||
}
|
||||
|
||||
export function saveAiProvider(data: AiProvider) {
|
||||
return request({ url: '/ai/providers', method: data.id ? 'put' : 'post', data })
|
||||
}
|
||||
|
||||
export function deleteAiProvider(id: string) {
|
||||
return request({ url: '/ai/providers', method: 'delete', params: { id } })
|
||||
}
|
||||
|
||||
export function listAiEndpoints() {
|
||||
return request({ url: '/ai/endpoints', method: 'get' })
|
||||
}
|
||||
|
||||
export function saveAiEndpoint(data: AiEndpointConfig) {
|
||||
return request({ url: '/ai/endpoints', method: data.id ? 'put' : 'post', data })
|
||||
}
|
||||
|
||||
export function deleteAiEndpoint(id: string) {
|
||||
return request({ url: '/ai/endpoints', method: 'delete', params: { id } })
|
||||
}
|
||||
|
||||
export function listAiScenes() {
|
||||
return request({ url: '/ai/scenes', method: 'get' })
|
||||
}
|
||||
|
||||
export function saveAiScene(data: AiSceneBinding) {
|
||||
return request({ url: '/ai/scenes', method: data.id ? 'put' : 'post', data })
|
||||
}
|
||||
|
||||
export function deleteAiScene(id: string) {
|
||||
return request({ url: '/ai/scenes', method: 'delete', params: { id } })
|
||||
}
|
||||
|
||||
export function listAiCallLogs(limit = 50) {
|
||||
return request({ url: '/ai/call-logs', method: 'get', params: { limit } })
|
||||
}
|
||||
|
||||
export function testAiRuntime(data: AiRuntimeRequest) {
|
||||
return request({ url: '/ai/runtime/test', method: 'post', data, timeout: 60000 })
|
||||
}
|
||||
|
||||
export interface AiRuntimeStreamEvent {
|
||||
type: string
|
||||
content?: string
|
||||
code?: string
|
||||
message?: string
|
||||
seq?: number
|
||||
metadata?: Record<string, any>
|
||||
}
|
||||
|
||||
function parseSseFrame(frame: string): AiRuntimeStreamEvent | null {
|
||||
const event = { type: 'message', data: '' }
|
||||
frame.split(/\r?\n/).forEach((line) => {
|
||||
if (line.startsWith('event:')) event.type = line.slice(6).trim()
|
||||
if (line.startsWith('data:')) event.data += line.slice(5).trim()
|
||||
})
|
||||
if (!event.data) return null
|
||||
try {
|
||||
return JSON.parse(event.data)
|
||||
} catch {
|
||||
return { type: event.type, content: event.data }
|
||||
}
|
||||
}
|
||||
|
||||
export async function streamAiRuntime(
|
||||
data: AiRuntimeRequest,
|
||||
onEvent: (event: AiRuntimeStreamEvent, output: string) => void
|
||||
) {
|
||||
const token = localStorage.getItem('adminToken')
|
||||
const response = await fetch(`${import.meta.env.VITE_APP_BASE_API}/ai/runtime/stream`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {})
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
if (!response.ok || !response.body) {
|
||||
throw new Error(`流式测试请求失败(${response.status})`)
|
||||
}
|
||||
|
||||
const reader = response.body.getReader()
|
||||
const decoder = new TextDecoder('utf-8')
|
||||
let buffer = ''
|
||||
let output = ''
|
||||
|
||||
const consumeText = (text: string) => {
|
||||
buffer += text
|
||||
const frames = buffer.split(/\r?\n\r?\n/)
|
||||
buffer = frames.pop() || ''
|
||||
frames.forEach((frame) => {
|
||||
const event = parseSseFrame(frame)
|
||||
if (!event) return
|
||||
if (event.type === 'delta') {
|
||||
output += event.content || ''
|
||||
}
|
||||
onEvent(event, output)
|
||||
if (event.type === 'error') {
|
||||
throw new Error(event.message || event.code || '流式测试失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const { value, done } = await reader.read()
|
||||
if (done) break
|
||||
consumeText(decoder.decode(value, { stream: true }))
|
||||
}
|
||||
consumeText(decoder.decode())
|
||||
if (buffer.trim()) consumeText('\n\n')
|
||||
return output
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user