Update from Vibe Studio
This commit is contained in:
136
src/api/ai-content-generator.ts
Normal file
136
src/api/ai-content-generator.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
// Dify API 配置
|
||||
const API_BASE = 'https://copilot.sino-bridge.com'
|
||||
const API_KEY = 'app-ZA5VuDW1OPQZfY4hrGyFGH6s'
|
||||
|
||||
interface UploadResponse {
|
||||
id: string
|
||||
name: string
|
||||
size: number
|
||||
extension: string
|
||||
mime_type: string
|
||||
}
|
||||
|
||||
interface GeneratedFile {
|
||||
file_id: string
|
||||
filename: string
|
||||
preview_url?: string
|
||||
transfer_method: string
|
||||
user: string
|
||||
}
|
||||
|
||||
interface GenerateContentParams {
|
||||
inputs: {
|
||||
user_input: string
|
||||
}
|
||||
query: string
|
||||
response_mode: 'streaming' | 'blocking'
|
||||
files?: GeneratedFile[]
|
||||
}
|
||||
|
||||
interface GenerateContentResponse {
|
||||
event: string
|
||||
task_id?: string
|
||||
id?: string
|
||||
message?: string
|
||||
mode?: string
|
||||
answer?: string
|
||||
metadata?: {
|
||||
usage: {
|
||||
total_price: number
|
||||
currency: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到 Dify
|
||||
*/
|
||||
export async function uploadFile(file: File): Promise<UploadResponse> {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
|
||||
const response = await fetch(`${API_BASE}/v1/files/upload`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${API_KEY}`
|
||||
},
|
||||
body: formData
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`上传失败: ${response.status} ${response.statusText} - ${errorText}`)
|
||||
}
|
||||
|
||||
return response.json()
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 Dify 生成内容(流式响应)
|
||||
*/
|
||||
export async function generateContent(
|
||||
params: GenerateContentParams,
|
||||
onChunk: (chunk: string) => void,
|
||||
signal?: AbortSignal
|
||||
): Promise<void> {
|
||||
const response = await fetch(`${API_BASE}/v1/chat-messages`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${API_KEY}`
|
||||
},
|
||||
body: JSON.stringify(params),
|
||||
signal
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`请求失败: ${response.status} ${response.statusText} - ${errorText}`)
|
||||
}
|
||||
|
||||
const reader = response.body?.getReader()
|
||||
if (!reader) {
|
||||
throw new Error('无法读取响应流')
|
||||
}
|
||||
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
if (done) break
|
||||
|
||||
const chunk = decoder.decode(value)
|
||||
const lines = chunk.split('\n').filter(line => line.trim())
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('data: ')) {
|
||||
const data = line.slice(6)
|
||||
if (data === '[DONE]') {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed: GenerateContentResponse = JSON.parse(data)
|
||||
|
||||
// 处理不同的消息事件
|
||||
if (parsed.event === 'message') {
|
||||
if (parsed.answer) {
|
||||
onChunk(parsed.answer)
|
||||
}
|
||||
} else if (parsed.event === 'message_file') {
|
||||
// 处理文件相关消息(如果有)
|
||||
console.log('Message file event:', parsed)
|
||||
} else if (parsed.event === 'error') {
|
||||
throw new Error(parsed.message || '生成过程中发生错误')
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.warn('解析响应数据失败:', data, parseError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
reader.releaseLock()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user