import type { NitroFetchOptions, NitroFetchRequest } from 'nitropack' import { FetchError } from 'ofetch' /** * 封装 HTTP 请求 * @param url 请求的路径 * @param options 请求选项 * @returns 返回请求结果 * * @throws {FetchError} 请求失败时抛出错误 */ export const http = async ( url: string, options?: NitroFetchOptions, ) => { const loginState = useLoginState() const runtimeConfig = useRuntimeConfig() const baseURL = runtimeConfig.public.baseURL as string try { const data = await $fetch(url, { baseURL, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${loginState.token}`, }, ...options, }) return data } catch (err: unknown) { if (err instanceof FetchError) { throw err } else { throw new FetchError('请求失败') } } } export const http_stream = async ( endpoint: string, params: ReqT, events: { onStart?: (id: string, created_at?: number) => void onTextChunk?: (message: string) => void onComplete?: (id: string | null, finished_at?: number) => void }) => { const { onStart, onTextChunk, onComplete } = events const loginState = useLoginState() const runtimeConfig = useRuntimeConfig() const baseURL = runtimeConfig.public.baseURL as string const response = await fetch(new URL(endpoint, baseURL), { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'text/event-stream', 'Authorization': `Bearer ${loginState.token}`, }, body: JSON.stringify(params), }) if (!response) { throw new Error('Network response was not ok') } const reader = response.body?.getReader() const decoder = new TextDecoder('utf-8') let buffer = '' while (true) { const { done, value } = await reader?.read() || {} if (done) break buffer += decoder.decode(value, { stream: true }) const parts = buffer.split('\n\n') buffer = parts.pop()! for (const part of parts) { if (!part.trim().startsWith('data:')) continue const payload = part.replace(/^data:\s*/, '').trim() try { const obj = JSON.parse(payload) if (obj?.event && obj.event === 'workflow_started') { onStart?.(obj?.data?.id || null, obj?.data?.created_at || 0) } if (obj?.event && obj.event === 'workflow_finished') { onComplete?.(obj?.data?.id || null, obj?.data?.finished_at || 0) return } if (obj?.event && obj.event === 'text_chunk') { let text_chunk = obj.data?.text as string if (text_chunk) { if (text_chunk.startsWith('<') && text_chunk.endsWith('>')) { const endTag = text_chunk.match(/<\/[^>]*>/) if (endTag) { text_chunk = text_chunk.replace(endTag[0], '\n' + endTag[0]) } } onTextChunk?.(text_chunk) } } } catch { // ignore } } } onComplete?.(null) }