217 lines
8.9 KiB
JavaScript
217 lines
8.9 KiB
JavaScript
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 Object,headers,默认:{}
|
||
* @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();
|
||
}
|
||
}
|
||
});
|
||
})
|
||
} |