Files
ks-app-employment-service/utils/streamRequest.js
2025-10-13 16:01:49 +08:00

217 lines
8.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import config from "@/config.js"
import useUserStore from '@/stores/useUserStore';
/**
* @param url String请求的地址默认none
* @param data Object请求的参数默认{}
* @returns promise
**/
export default function StreamRequest(url, data = {}, onDataReceived, onError, onComplete) {
const userStore = useUserStore();
const Authorization = userStore.token ? encodeURIComponent(userStore.token) : '';
const headers = {
"Authorization": Authorization,
"Accept": "text/event-stream",
"Content-Type": "application/json;charset=UTF-8"
};
return new Promise(async (resolve, reject) => {
try {
const response = await fetch(config.StreamBaseURl + url, {
method: "POST",
headers,
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`HTTP 错误: ${response.status}`);
}
const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8");
let buffer = "";
let retryCount = 0;
const maxRetries = 3;
while (true) {
const {
done,
value
} = await reader.read();
if (done) {
console.log("📡 Stream reading completed");
break;
}
buffer += decoder.decode(value, {
stream: true
});
let lines = buffer.split("\n");
buffer = lines.pop(); // 可能是不完整的 JSON 片段,留待下次解析
console.log(`📦 Processing ${lines.length} lines, buffer length: ${buffer.length}`);
for (let line of lines) {
if (line.startsWith("data: ")) {
const jsonData = line.slice(6).trim();
if (jsonData === "[DONE]") {
onComplete && onComplete();
resolve();
return;
}
try {
// 检查JSON数据是否完整
if (jsonData && jsonData.trim() && jsonData !== "[DONE]") {
const parsedData = JSON.parse(jsonData);
// 处理标准的choices格式
if (parsedData?.choices?.[0]?.delta?.content) {
const content = parsedData.choices[0].delta.content;
if (content) {
onDataReceived && onDataReceived(content);
}
}
// 处理reasoning_content
else if (parsedData?.choices?.[0]?.delta?.reasoning_content) {
const content = parsedData.choices[0].delta.reasoning_content;
if (content) {
onDataReceived && onDataReceived(content);
}
}
// 处理tool响应
else if (parsedData?.tool?.response) {
const content = parsedData.tool.response;
if (content) {
onDataReceived && onDataReceived(content);
}
}
// 处理其他格式的数据如jobs_array_number, durationSeconds等
else {
console.log("📦 收到非内容数据:", Object.keys(parsedData));
}
}
} catch (e) {
console.error("JSON 解析失败:", e.message, "原始数据长度:", jsonData.length, "数据预览:", jsonData.substring(0, 100) + "...");
// 不抛出错误,继续处理下一个数据块
}
}
}
}
// 处理剩余的缓冲区数据
if (buffer.trim()) {
console.log("📦 Processing remaining buffer:", buffer.substring(0, 100) + "...");
const lines = buffer.split("\n");
for (let line of lines) {
if (line.startsWith("data: ")) {
const jsonData = line.slice(6).trim();
if (jsonData && jsonData !== "[DONE]") {
try {
const parsedData = JSON.parse(jsonData);
// 处理标准的choices格式
if (parsedData?.choices?.[0]?.delta?.content) {
const content = parsedData.choices[0].delta.content;
if (content) {
onDataReceived && onDataReceived(content);
}
}
// 处理reasoning_content
else if (parsedData?.choices?.[0]?.delta?.reasoning_content) {
const content = parsedData.choices[0].delta.reasoning_content;
if (content) {
onDataReceived && onDataReceived(content);
}
}
// 处理tool响应
else if (parsedData?.tool?.response) {
const content = parsedData.tool.response;
if (content) {
onDataReceived && onDataReceived(content);
}
}
} catch (e) {
console.warn("处理剩余数据时JSON解析失败:", e.message);
}
}
}
}
}
onComplete && onComplete();
resolve();
} catch (error) {
console.error("Stream 请求失败:", error);
onError && onError(error);
reject(error);
}
});
}
/**
* @param url String请求的地址默认none
* @param data Object请求的参数默认{}
* @param method String请求的方式默认GET
* @param loading Boolean是否需要loading 默认false
* @param header Objectheaders默认{}
* @returns promise
**/
export function chatRequest(url, data = {}, method = 'GET', loading = false, headers = {}) {
if (loading) {
uni.showLoading({
title: '请稍后',
mask: true
})
}
let Authorization = ''
if (useUserStore().token) {
Authorization = `${useUserStore().token}`
}
const header = headers || {};
header["Authorization"] = encodeURIComponent(Authorization);
return new Promise((resolve, reject) => {
uni.request({
url: config.StreamBaseURl + url,
method: method,
data: data,
header,
success: resData => {
// 响应拦截
if (resData.statusCode === 200) {
const {
code,
msg
} = resData.data
if (code === 200) {
resolve(resData.data)
return
}
uni.showToast({
title: msg,
icon: 'none'
})
}
if (resData.data?.code === 401 || resData.data?.code === 402) {
useUserStore().logOut()
}
const err = new Error('请求出现异常,请联系工作人员')
err.error = resData
reject(err)
},
fail: (err) => {
reject(err)
},
complete: () => {
if (loading) {
uni.hideLoading();
}
}
});
})
}