IntelliClass_FE/utils/http.ts
HoshinoSuzumi 20471bfbe3
Some checks failed
CI / lint (push) Failing after 59s
CI / test (push) Failing after 47s
feat: 完成 AIGC Conversation 组件
2025-04-26 21:54:10 +08:00

117 lines
3.0 KiB
TypeScript

import type { NitroFetchOptions, NitroFetchRequest } from 'nitropack'
import { FetchError } from 'ofetch'
/**
* 封装 HTTP 请求
* @param url 请求的路径
* @param options 请求选项
* @returns 返回请求结果
*
* @throws {FetchError} 请求失败时抛出错误
*/
export const http = async <T>(
url: string,
options?: NitroFetchOptions<NitroFetchRequest>,
) => {
const loginState = useLoginState()
const runtimeConfig = useRuntimeConfig()
const baseURL = runtimeConfig.public.baseURL as string
try {
const data = await $fetch<T>(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 <ReqT>(
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)
}