142 lines
4.3 KiB
JavaScript
142 lines
4.3 KiB
JavaScript
"use strict";
|
||
const common_vendor = require("../../common/vendor.js");
|
||
function joinApiUrl(base, path) {
|
||
const b = String(base || "").replace(/\/+$/, "");
|
||
const p = String(path || "").replace(/^\/+/, "");
|
||
return p ? `${b}/${p}` : b;
|
||
}
|
||
function appendQuery(url, data) {
|
||
if (!data || typeof data !== "object")
|
||
return url;
|
||
const keys = Object.keys(data);
|
||
if (!keys.length)
|
||
return url;
|
||
const qs = keys.map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(data[k] ?? "")}`).join("&");
|
||
return url + (url.includes("?") ? "&" : "?") + qs;
|
||
}
|
||
function decodeChunkData(data) {
|
||
if (typeof data === "string")
|
||
return data;
|
||
if (!data)
|
||
return "";
|
||
if (typeof TextDecoder !== "undefined" && data instanceof ArrayBuffer) {
|
||
return new TextDecoder("utf-8").decode(new Uint8Array(data));
|
||
}
|
||
if (data instanceof ArrayBuffer) {
|
||
const bytes = new Uint8Array(data);
|
||
let str = "";
|
||
for (let i = 0; i < bytes.length; i++)
|
||
str += String.fromCharCode(bytes[i]);
|
||
try {
|
||
return decodeURIComponent(escape(str));
|
||
} catch (e) {
|
||
return str;
|
||
}
|
||
}
|
||
return "";
|
||
}
|
||
function consumeSseBuffer(buffer, onEvent) {
|
||
let rest = buffer;
|
||
let idx = rest.indexOf("\n\n");
|
||
while (idx !== -1) {
|
||
const block = rest.slice(0, idx);
|
||
rest = rest.slice(idx + 2);
|
||
let event = "message";
|
||
let dataLine = "";
|
||
block.split("\n").forEach((line) => {
|
||
if (line.startsWith("event:"))
|
||
event = line.slice(6).trim();
|
||
else if (line.startsWith("data:"))
|
||
dataLine += line.slice(5).trim();
|
||
});
|
||
if (dataLine) {
|
||
try {
|
||
onEvent(event, JSON.parse(dataLine));
|
||
} catch (e) {
|
||
onEvent(event, dataLine);
|
||
}
|
||
}
|
||
idx = rest.indexOf("\n\n");
|
||
}
|
||
return rest;
|
||
}
|
||
function parsePartialDietPlainText(text) {
|
||
const out = {};
|
||
if (!text)
|
||
return out;
|
||
const lineRe = /^(早餐|喝的|午餐|晚餐|提示|少碰)[::]\s*(.*)$/gm;
|
||
let match;
|
||
while ((match = lineRe.exec(text)) !== null) {
|
||
const key = { "早餐": "breakfast", "喝的": "drinks", "午餐": "lunch", "晚餐": "dinner", "提示": "tips", "少碰": "avoid" }[match[1]];
|
||
const val = (match[2] || "").trim();
|
||
if (key === "avoid") {
|
||
out.avoid = val.split(/[、,,;;\s]+/).map((s) => s.trim()).filter(Boolean);
|
||
} else {
|
||
out[key] = val;
|
||
}
|
||
}
|
||
const tail = text.match(/(?:^|\n)(早餐|喝的|午餐|晚餐|提示|少碰)[::]\s*([^\n]*)$/);
|
||
if (tail) {
|
||
const key = { "早餐": "breakfast", "喝的": "drinks", "午餐": "lunch", "晚餐": "dinner", "提示": "tips", "少碰": "avoid" }[tail[1]];
|
||
const val = (tail[2] || "").trim();
|
||
if (key === "avoid") {
|
||
if (val)
|
||
out.avoid = val.split(/[、,,;;\s]+/).map((s) => s.trim()).filter(Boolean);
|
||
} else {
|
||
out[key] = val;
|
||
}
|
||
}
|
||
return out;
|
||
}
|
||
function requestAiStream(opts) {
|
||
const {
|
||
baseUrl,
|
||
url,
|
||
method = "GET",
|
||
data = {},
|
||
onEvent,
|
||
fallback
|
||
} = opts;
|
||
return new Promise((resolve, reject) => {
|
||
const token = common_vendor.index.getStorageSync("token") || "";
|
||
let sseBuffer = "";
|
||
let requestUrl = joinApiUrl(baseUrl, url);
|
||
if (method === "GET") {
|
||
requestUrl = appendQuery(requestUrl, data);
|
||
}
|
||
const task = common_vendor.wx$1.request({
|
||
url: requestUrl,
|
||
method,
|
||
data: method === "POST" ? data : {},
|
||
enableChunked: true,
|
||
timeout: 6e4,
|
||
header: {
|
||
token,
|
||
"content-type": "application/x-www-form-urlencoded",
|
||
"Cache-Control": "no-cache"
|
||
},
|
||
success: (res) => {
|
||
if (res && res.data) {
|
||
sseBuffer += decodeChunkData(res.data);
|
||
sseBuffer = consumeSseBuffer(sseBuffer, onEvent);
|
||
}
|
||
resolve(res);
|
||
},
|
||
fail: (err) => reject(err)
|
||
});
|
||
if (task && typeof task.onChunkReceived === "function") {
|
||
task.onChunkReceived((res) => {
|
||
sseBuffer += decodeChunkData(res.data);
|
||
sseBuffer = consumeSseBuffer(sseBuffer, onEvent);
|
||
});
|
||
} else if (typeof fallback === "function") {
|
||
fallback().then(resolve).catch(reject);
|
||
} else {
|
||
reject(new Error("当前环境不支持流式请求"));
|
||
}
|
||
});
|
||
}
|
||
exports.parsePartialDietPlainText = parsePartialDietPlainText;
|
||
exports.requestAiStream = requestAiStream;
|
||
//# sourceMappingURL=../../../.sourcemap/mp-weixin/tongji/utils/aiStreamRequest.js.map
|