v1.2.2 - Fix network error on background, auto-retry streaming with reconnect
This commit is contained in:
539
node_modules/@nicepkg/gpt-runner-shared/dist/node.cjs
generated
vendored
Normal file
539
node_modules/@nicepkg/gpt-runner-shared/dist/node.cjs
generated
vendored
Normal file
@@ -0,0 +1,539 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
const index = require('./shared/gpt-runner-shared.79ccd90a.cjs');
|
||||
require('minimatch');
|
||||
require('debug');
|
||||
const axios = require('axios');
|
||||
const httpProxyAgent = require('http-proxy-agent');
|
||||
const httpsProxyAgent = require('https-proxy-agent');
|
||||
const node_child_process = require('node:child_process');
|
||||
const fs = require('node:fs');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
const getCacheDir = require('cachedir');
|
||||
const node_url = require('node:url');
|
||||
require('jsonc-parser');
|
||||
const launch = require('launch-editor');
|
||||
const nodeLocalstorage = require('@kvs/node-localstorage');
|
||||
const open = require('open');
|
||||
const fp = require('find-free-ports');
|
||||
const ip = require('ip');
|
||||
const undici = require('undici');
|
||||
require('web-streams-polyfill/polyfill');
|
||||
require('zod-to-json-schema');
|
||||
require('zod');
|
||||
|
||||
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
|
||||
|
||||
const axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
|
||||
const fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
||||
const os__default = /*#__PURE__*/_interopDefaultLegacy(os);
|
||||
const path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
||||
const getCacheDir__default = /*#__PURE__*/_interopDefaultLegacy(getCacheDir);
|
||||
const launch__default = /*#__PURE__*/_interopDefaultLegacy(launch);
|
||||
const open__default = /*#__PURE__*/_interopDefaultLegacy(open);
|
||||
const fp__default = /*#__PURE__*/_interopDefaultLegacy(fp);
|
||||
const ip__default = /*#__PURE__*/_interopDefaultLegacy(ip);
|
||||
|
||||
function initAxios() {
|
||||
const httpProxyUrl = process.env.HTTP_PROXY;
|
||||
const httpsProxyUrl = process.env.HTTPS_PROXY;
|
||||
if (httpProxyUrl) {
|
||||
const httpAgent = new httpProxyAgent.HttpProxyAgent(httpProxyUrl);
|
||||
axios__default.defaults.httpAgent = httpAgent;
|
||||
}
|
||||
if (httpsProxyUrl) {
|
||||
const httpsAgent = new httpsProxyAgent.HttpsProxyAgent(httpsProxyUrl);
|
||||
axios__default.defaults.httpsAgent = httpsAgent;
|
||||
}
|
||||
}
|
||||
let axiosInstance = null;
|
||||
function getAxiosInstance() {
|
||||
if (!axiosInstance) {
|
||||
initAxios();
|
||||
axiosInstance = axios__default.create();
|
||||
}
|
||||
return axiosInstance;
|
||||
}
|
||||
|
||||
class PathUtils {
|
||||
static getCurrentDirName(importMetaUrl, getDirname) {
|
||||
let dirname = "";
|
||||
try {
|
||||
dirname = getDirname();
|
||||
} catch {
|
||||
}
|
||||
if (!importMetaUrl)
|
||||
return index.toUnixPath(dirname);
|
||||
const __filename = node_url.fileURLToPath(importMetaUrl);
|
||||
const __dirname = path__default.dirname(__filename);
|
||||
return __dirname;
|
||||
}
|
||||
static join(...paths) {
|
||||
return index.toUnixPath(path__default.join(...paths));
|
||||
}
|
||||
static resolve(...paths) {
|
||||
return index.toUnixPath(path__default.resolve(...paths));
|
||||
}
|
||||
static relative(from, to) {
|
||||
return index.toUnixPath(path__default.relative(from, to));
|
||||
}
|
||||
static dirname(filePath) {
|
||||
return index.toUnixPath(path__default.dirname(filePath));
|
||||
}
|
||||
static extname(filePath) {
|
||||
if (!PathUtils.isFile(filePath))
|
||||
return "";
|
||||
return path__default.extname(filePath);
|
||||
}
|
||||
static isFile(filePath) {
|
||||
return fs__default.existsSync(filePath) && fs__default.statSync(filePath).isFile();
|
||||
}
|
||||
static isDirectory(filePath) {
|
||||
return fs__default.existsSync(filePath) && fs__default.statSync(filePath).isDirectory();
|
||||
}
|
||||
static includeExt(filePath, exts) {
|
||||
if (!exts || !Array.isArray(exts))
|
||||
return false;
|
||||
return exts.some((ext) => filePath.endsWith(ext));
|
||||
}
|
||||
static isExit(filePath) {
|
||||
return fs__default.existsSync(filePath);
|
||||
}
|
||||
static isAccessible(filePath, mode) {
|
||||
if (!PathUtils.isExit(filePath))
|
||||
return false;
|
||||
const modeMap = {
|
||||
F: fs__default.constants.F_OK,
|
||||
R: fs__default.constants.R_OK,
|
||||
W: fs__default.constants.W_OK,
|
||||
X: fs__default.constants.X_OK
|
||||
};
|
||||
const finalMode = modeMap[mode || "F"] || fs__default.constants.F_OK;
|
||||
try {
|
||||
fs__default.accessSync(filePath, finalMode);
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static getDirPath(filePath) {
|
||||
return path__default.dirname(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
async function getGlobalCacheDir(name) {
|
||||
const cacheDir = getCacheDir__default(name);
|
||||
await createCacheDir(cacheDir);
|
||||
return cacheDir;
|
||||
}
|
||||
async function createCacheDir(cacheDir) {
|
||||
if (await PathUtils.isAccessible(cacheDir, "W"))
|
||||
return;
|
||||
await fs__default.promises.mkdir(cacheDir, { recursive: true });
|
||||
}
|
||||
|
||||
const _BinaryDownloader = class {
|
||||
static async getBinaryPath() {
|
||||
const cacheDir = await getGlobalCacheDir("nicepkg-tunnel");
|
||||
const binaryPath = path__default.join(cacheDir, _BinaryDownloader.BINARY_FILENAME);
|
||||
return binaryPath;
|
||||
}
|
||||
static async downloadBinary() {
|
||||
const debug = new index.Debug("tunnel");
|
||||
const binaryPath = await _BinaryDownloader.getBinaryPath();
|
||||
if (!fs__default.existsSync(binaryPath)) {
|
||||
const binaryUrl = `https://cdn-media.huggingface.co/frpc-gradio-${_BinaryDownloader.VERSION}/${_BinaryDownloader.BINARY_NAME}${_BinaryDownloader.EXTENSION}`;
|
||||
debug.log(`Downloading ${binaryUrl} to ${binaryPath}...`);
|
||||
try {
|
||||
const axios = getAxiosInstance();
|
||||
const response = await axios.get(binaryUrl, {
|
||||
responseType: "arraybuffer"
|
||||
});
|
||||
await fs__default.promises.writeFile(binaryPath, response.data, "binary");
|
||||
fs__default.chmodSync(binaryPath, 493);
|
||||
debug.log(`Downloaded success ${binaryUrl} to ${binaryPath}`);
|
||||
} catch (err) {
|
||||
debug.error(`Failed to download ${binaryUrl}: ${err}`);
|
||||
if (err?.response?.status === 403) {
|
||||
throw new Error(
|
||||
`Cannot set up a share link as this platform is incompatible. Please create a GitHub issue with information about your platform: ${JSON.stringify(
|
||||
os__default.userInfo()
|
||||
)}`
|
||||
);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let BinaryDownloader = _BinaryDownloader;
|
||||
BinaryDownloader.VERSION = "0.2";
|
||||
BinaryDownloader.EXTENSION = os__default.platform() === "win32" ? ".exe" : "";
|
||||
BinaryDownloader.MACHINE = os__default.arch();
|
||||
BinaryDownloader.ARCH = _BinaryDownloader.MACHINE === "x64" ? "amd64" : _BinaryDownloader.MACHINE;
|
||||
BinaryDownloader.BINARY_NAME = `frpc_${os__default.type().toLowerCase()}_${_BinaryDownloader.ARCH.toLowerCase()}`;
|
||||
BinaryDownloader.BINARY_FILENAME = `${_BinaryDownloader.BINARY_NAME}_v${_BinaryDownloader.VERSION}`;
|
||||
|
||||
class TunnelProcess {
|
||||
constructor(command) {
|
||||
this.proc = null;
|
||||
this.command = command;
|
||||
}
|
||||
async start() {
|
||||
const binaryPath = await BinaryDownloader.getBinaryPath();
|
||||
await BinaryDownloader.downloadBinary();
|
||||
return this._startProcess(binaryPath);
|
||||
}
|
||||
kill() {
|
||||
if (this.proc !== null) {
|
||||
this.proc.kill("SIGTERM");
|
||||
this.proc = null;
|
||||
}
|
||||
}
|
||||
_startProcess(binary) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.proc = node_child_process.spawn(binary, this.command, {
|
||||
stdio: ["ignore", "pipe", "pipe"]
|
||||
});
|
||||
process.once("exit", () => this.kill());
|
||||
let output = "";
|
||||
this.proc.stdout.on("data", (data) => {
|
||||
output += data.toString();
|
||||
const match = output.match(/start proxy success: (.+)/);
|
||||
if (match) {
|
||||
resolve(match[1]);
|
||||
output = "";
|
||||
}
|
||||
});
|
||||
this.proc.stderr.on("data", (data) => {
|
||||
output += data.toString();
|
||||
});
|
||||
this.proc.on("error", (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class Tunnel {
|
||||
constructor(options) {
|
||||
this.GRADIO_API_SERVER_URL = "https://api.gradio.app/v2/tunnel-request";
|
||||
const {
|
||||
remoteHost,
|
||||
remotePort,
|
||||
localHost,
|
||||
localPort,
|
||||
shareToken
|
||||
} = options;
|
||||
this.url = null;
|
||||
this.remoteHost = remoteHost || "";
|
||||
this.remotePort = remotePort || 0;
|
||||
this.localHost = localHost || "localhost";
|
||||
this.localPort = localPort;
|
||||
this.shareToken = shareToken || "";
|
||||
}
|
||||
async initProcess() {
|
||||
if (!this.remoteHost || !this.remotePort) {
|
||||
try {
|
||||
const axios = getAxiosInstance();
|
||||
const res = await axios.get(this.GRADIO_API_SERVER_URL);
|
||||
const data = res.data;
|
||||
this.remoteHost = data[0].host;
|
||||
this.remotePort = data[0].port;
|
||||
} catch (err) {
|
||||
throw new Error(`Failed to fetch ${this.GRADIO_API_SERVER_URL}: ${index.getErrorMsg(err)}`);
|
||||
}
|
||||
}
|
||||
const command = [
|
||||
"http",
|
||||
"-n",
|
||||
this.shareToken,
|
||||
"-l",
|
||||
`${this.localPort}`,
|
||||
"-i",
|
||||
this.localHost,
|
||||
"--uc",
|
||||
"--sd",
|
||||
"random",
|
||||
"--ue",
|
||||
"--server_addr",
|
||||
`${this.remoteHost}:${this.remotePort}`,
|
||||
"--disable_log_color"
|
||||
];
|
||||
this.tunnelProcess = new TunnelProcess(command);
|
||||
}
|
||||
async startTunnel() {
|
||||
if (!this.tunnelProcess)
|
||||
await this.initProcess();
|
||||
this.url = await this.tunnelProcess.start();
|
||||
return this.url;
|
||||
}
|
||||
kill() {
|
||||
if (this.tunnelProcess) {
|
||||
console.log(
|
||||
`Killing tunnel ${this.localHost}:${this.localPort} <> ${this.url}`
|
||||
);
|
||||
this.tunnelProcess.kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function compareVersion(a, b) {
|
||||
const aParts = a.split(".");
|
||||
const bParts = b.split(".");
|
||||
const len = Math.max(aParts.length, bParts.length);
|
||||
const stringToNum = (str) => parseInt(str.match(/\d+/)?.[0] || "0") || 0;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const aPart = stringToNum(aParts[i]) || 0;
|
||||
const bPart = stringToNum(bParts[i]) || 0;
|
||||
if (aPart > bPart)
|
||||
return 1;
|
||||
if (aPart < bPart)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
function checkNodeVersion() {
|
||||
const currentNodeVersion = process.version;
|
||||
if (compareVersion(currentNodeVersion, index.MIN_NODE_VERSION) < 0)
|
||||
return `You are using Node ${currentNodeVersion}, but GPT-Runner requires Node ${index.MIN_NODE_VERSION}.
|
||||
Please upgrade your Node version in https://nodejs.org/en/download`;
|
||||
}
|
||||
function canUseNodeFetchWithoutCliFlag() {
|
||||
const currentNodeVersion = process.version;
|
||||
return compareVersion(currentNodeVersion, "18.0.0") > 0;
|
||||
}
|
||||
function getRunServerEnv() {
|
||||
if (!canUseNodeFetchWithoutCliFlag()) {
|
||||
return {
|
||||
NODE_OPTIONS: "--experimental-fetch",
|
||||
NODE_NO_WARNINGS: "1"
|
||||
};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
class FileUtils {
|
||||
static async readFile(params) {
|
||||
const { filePath, valid = true } = params;
|
||||
if (typeof filePath !== "string")
|
||||
return "";
|
||||
if (valid && !PathUtils.isFile(filePath))
|
||||
return "";
|
||||
if (!filePath)
|
||||
return "";
|
||||
return fs.promises.readFile(filePath, { encoding: "utf8" });
|
||||
}
|
||||
static async writeFile(params) {
|
||||
const { filePath, content, overwrite = true, valid = true } = params;
|
||||
if (valid) {
|
||||
if (!PathUtils.isAccessible(filePath, "W"))
|
||||
return;
|
||||
if (!PathUtils.isFile(filePath))
|
||||
return;
|
||||
}
|
||||
const dir = PathUtils.getDirPath(filePath);
|
||||
if (!PathUtils.isExit(dir))
|
||||
await fs.promises.mkdir(dir, { recursive: true });
|
||||
if (overwrite)
|
||||
await fs.promises.writeFile(filePath, content, { encoding: "utf8" });
|
||||
else
|
||||
await fs.promises.appendFile(filePath, content, { encoding: "utf8" });
|
||||
}
|
||||
static async deletePath(fullPath) {
|
||||
if (!PathUtils.isAccessible(fullPath, "W"))
|
||||
await fs.promises.rm(fullPath, { recursive: true });
|
||||
}
|
||||
static async ensurePath(params) {
|
||||
const { filePath } = params;
|
||||
if (!PathUtils.isAccessible(filePath, "W"))
|
||||
await fs.promises.mkdir(filePath, { recursive: true });
|
||||
}
|
||||
static async movePath(params) {
|
||||
const { oldPath, newPath } = params;
|
||||
if (PathUtils.isAccessible(oldPath, "W"))
|
||||
await fs.promises.rename(oldPath, newPath);
|
||||
}
|
||||
static async travelFiles(params) {
|
||||
const { isValidPath, callback } = params;
|
||||
const filePath = PathUtils.resolve(params.filePath);
|
||||
if (!PathUtils.isAccessible(filePath, "R"))
|
||||
return;
|
||||
const promises = [];
|
||||
if (PathUtils.isDirectory(filePath)) {
|
||||
const entries = await fs.promises.readdir(filePath);
|
||||
for (const entry of entries) {
|
||||
const fullPath = PathUtils.join(filePath, entry);
|
||||
if (!PathUtils.isAccessible(filePath, "R"))
|
||||
continue;
|
||||
const isValid = await isValidPath(fullPath);
|
||||
if (isValid)
|
||||
promises.push(FileUtils.travelFiles({ filePath: fullPath, isValidPath, callback }));
|
||||
}
|
||||
} else {
|
||||
const result = callback(filePath);
|
||||
if (result instanceof Promise)
|
||||
promises.push(result);
|
||||
}
|
||||
await Promise.allSettled(promises);
|
||||
}
|
||||
static async travelFilesByFilterPattern(params) {
|
||||
const { filePath, isValidPath, callback, exts = [], includes = null, excludes = null } = params;
|
||||
await FileUtils.travelFiles({
|
||||
filePath,
|
||||
isValidPath: async (filePath2) => {
|
||||
if (exts.length > 0 && PathUtils.isFile(filePath2) && !PathUtils.includeExt(filePath2, exts))
|
||||
return false;
|
||||
if (!index.createFilterByPattern(includes)(filePath2))
|
||||
return false;
|
||||
if (index.createFilterByPattern(excludes)(filePath2))
|
||||
return false;
|
||||
if (!isValidPath(filePath2))
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
callback
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function launchEditor(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { path, lineNum, columnNum = 0, editorName, onError } = params;
|
||||
const finalPath = lineNum && columnNum ? `${path}:${lineNum}:${columnNum}` : path;
|
||||
launch__default(finalPath, editorName, (error) => {
|
||||
if (error) {
|
||||
onError?.(error);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
async function launchEditorByPathAndContent(params) {
|
||||
const { path, matchContent, editorName, onError } = params;
|
||||
const content = await FileUtils.readFile({ filePath: path });
|
||||
let lineNum = 0;
|
||||
let columnNum = 0;
|
||||
if (matchContent) {
|
||||
const matchContentStartIndex = content.indexOf(matchContent);
|
||||
if (matchContentStartIndex !== -1) {
|
||||
const beforeMatchContent = content.slice(0, matchContentStartIndex);
|
||||
lineNum = beforeMatchContent.split("\n").length;
|
||||
columnNum = matchContentStartIndex - beforeMatchContent.lastIndexOf("\n");
|
||||
}
|
||||
}
|
||||
await launchEditor({ path, lineNum, columnNum, editorName, onError });
|
||||
return { lineNum, columnNum };
|
||||
}
|
||||
|
||||
async function getStorage(storageName) {
|
||||
const cacheFolder = await getGlobalCacheDir("gpt-runner-server");
|
||||
const storage = await nodeLocalstorage.kvsLocalStorage({
|
||||
name: storageName,
|
||||
storeFilePath: cacheFolder,
|
||||
version: 1
|
||||
});
|
||||
return {
|
||||
cacheDir: cacheFolder,
|
||||
storage
|
||||
};
|
||||
}
|
||||
|
||||
function openInBrowser(props) {
|
||||
const { url } = props;
|
||||
try {
|
||||
open__default(url);
|
||||
} catch (error) {
|
||||
throw new Error(`Server is started at ${url} but failed to open browser. ${error}`);
|
||||
}
|
||||
}
|
||||
async function getPort(props) {
|
||||
const { defaultPort, autoFreePort, excludePorts } = props;
|
||||
if (defaultPort) {
|
||||
if (!autoFreePort)
|
||||
return defaultPort;
|
||||
const canUseDefaultPort = await fp__default.isFreePort(defaultPort);
|
||||
if (canUseDefaultPort)
|
||||
return defaultPort;
|
||||
}
|
||||
const freePorts = await fp__default.findFreePorts(1, {
|
||||
startPort: 3001,
|
||||
endPort: 9999,
|
||||
isFree: async (port) => {
|
||||
if (excludePorts?.includes(port))
|
||||
return false;
|
||||
return fp__default.isFreePort(port);
|
||||
}
|
||||
});
|
||||
return freePorts[0];
|
||||
}
|
||||
function getLocalHostname() {
|
||||
return ip__default.address("public", "ipv4");
|
||||
}
|
||||
|
||||
function addNodejsPolyfill() {
|
||||
if (!canUseNodeFetchWithoutCliFlag()) {
|
||||
console.log("GPT Runner: add polyfill for fetch", process.version);
|
||||
globalThis.fetch = undici.fetch;
|
||||
globalThis.Headers = undici.Headers;
|
||||
globalThis.Request = undici.Request;
|
||||
globalThis.Response = undici.Response;
|
||||
}
|
||||
}
|
||||
|
||||
async function getDefaultProxyUrl() {
|
||||
let proxyUrl = "";
|
||||
try {
|
||||
const { storage } = await getStorage(index.ServerStorageName.SecretsConfig);
|
||||
const proxySecret = await storage.get(index.SecretStorageKey.Proxy);
|
||||
proxyUrl = proxySecret?.proxyUrl ?? "";
|
||||
} catch (error) {
|
||||
console.error("getDefaultProxyUrl error", error);
|
||||
}
|
||||
if (proxyUrl)
|
||||
return proxyUrl;
|
||||
["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY"].forEach((key) => {
|
||||
if (proxyUrl)
|
||||
return;
|
||||
const upperKey = key.toUpperCase();
|
||||
const lowerKey = key.toLowerCase();
|
||||
const upperKeyValue = process.env[upperKey] && process.env[upperKey] !== "undefined" ? process.env[upperKey] || "" : "";
|
||||
const lowerKeyValue = process.env[lowerKey] && process.env[lowerKey] !== "undefined" ? process.env[lowerKey] || "" : "";
|
||||
return proxyUrl = upperKeyValue || lowerKeyValue || "";
|
||||
});
|
||||
return proxyUrl;
|
||||
}
|
||||
|
||||
function sendSuccessResponse(res, options) {
|
||||
return res.status(options.status || 200).json(index.buildSuccessResponse(options));
|
||||
}
|
||||
function sendFailResponse(res, options) {
|
||||
return res.status(options.status || 400).json(index.buildFailResponse(options));
|
||||
}
|
||||
function verifyParamsByZod(params, schema) {
|
||||
index.verifyZod(schema, params);
|
||||
}
|
||||
|
||||
exports.FileUtils = FileUtils;
|
||||
exports.PathUtils = PathUtils;
|
||||
exports.Tunnel = Tunnel;
|
||||
exports.addNodejsPolyfill = addNodejsPolyfill;
|
||||
exports.canUseNodeFetchWithoutCliFlag = canUseNodeFetchWithoutCliFlag;
|
||||
exports.checkNodeVersion = checkNodeVersion;
|
||||
exports.compareVersion = compareVersion;
|
||||
exports.getDefaultProxyUrl = getDefaultProxyUrl;
|
||||
exports.getGlobalCacheDir = getGlobalCacheDir;
|
||||
exports.getLocalHostname = getLocalHostname;
|
||||
exports.getPort = getPort;
|
||||
exports.getRunServerEnv = getRunServerEnv;
|
||||
exports.getStorage = getStorage;
|
||||
exports.launchEditor = launchEditor;
|
||||
exports.launchEditorByPathAndContent = launchEditorByPathAndContent;
|
||||
exports.openInBrowser = openInBrowser;
|
||||
exports.sendFailResponse = sendFailResponse;
|
||||
exports.sendSuccessResponse = sendSuccessResponse;
|
||||
exports.verifyParamsByZod = verifyParamsByZod;
|
||||
Reference in New Issue
Block a user