Upload 38 files
Browse files- package.json +4 -4
- src/api/controllers/chat.ts +19 -0
- src/api/controllers/core.ts +20 -7
package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"name": "hailuo-free-api",
|
| 3 |
-
"version": "0.0.
|
| 4 |
"description": "HailuoAI Free API Server",
|
| 5 |
"type": "module",
|
| 6 |
"main": "dist/index.js",
|
|
@@ -13,8 +13,8 @@
|
|
| 13 |
"dist/"
|
| 14 |
],
|
| 15 |
"scripts": {
|
| 16 |
-
"dev": "tsup src/index.ts --format cjs,esm --sourcemap --dts --publicDir public --watch --onSuccess \"node dist/index.js\"",
|
| 17 |
-
"start": "node dist/index.js",
|
| 18 |
"build": "tsup src/index.ts --format cjs,esm --sourcemap --dts --clean --publicDir public"
|
| 19 |
},
|
| 20 |
"author": "Vinlic",
|
|
@@ -53,4 +53,4 @@
|
|
| 53 |
"tsup": "^8.0.2",
|
| 54 |
"typescript": "^5.3.3"
|
| 55 |
}
|
| 56 |
-
}
|
|
|
|
| 1 |
{
|
| 2 |
"name": "hailuo-free-api",
|
| 3 |
+
"version": "0.0.16",
|
| 4 |
"description": "HailuoAI Free API Server",
|
| 5 |
"type": "module",
|
| 6 |
"main": "dist/index.js",
|
|
|
|
| 13 |
"dist/"
|
| 14 |
],
|
| 15 |
"scripts": {
|
| 16 |
+
"dev": "tsup src/index.ts --format cjs,esm --sourcemap --dts --publicDir public --watch --onSuccess \"node --enable-source-maps --no-node-snapshot dist/index.js\"",
|
| 17 |
+
"start": "node --enable-source-maps --no-node-snapshot dist/index.js",
|
| 18 |
"build": "tsup src/index.ts --format cjs,esm --sourcemap --dts --clean --publicDir public"
|
| 19 |
},
|
| 20 |
"author": "Vinlic",
|
|
|
|
| 53 |
"tsup": "^8.0.2",
|
| 54 |
"typescript": "^5.3.3"
|
| 55 |
}
|
| 56 |
+
}
|
src/api/controllers/chat.ts
CHANGED
|
@@ -422,6 +422,8 @@ async function receiveStream(
|
|
| 422 |
if (_.isError(result))
|
| 423 |
throw new Error(`Stream response invalid: ${event.data}`);
|
| 424 |
const { type, statusInfo, data: _data } = result;
|
|
|
|
|
|
|
| 425 |
const { code, message } = statusInfo || {};
|
| 426 |
if (code !== 0 && type != 3)
|
| 427 |
throw new Error(`Stream response error: ${message}`);
|
|
@@ -501,6 +503,23 @@ function createTransStream(model: string, stream: any, endCallback?: Function) {
|
|
| 501 |
if (_.isError(result))
|
| 502 |
throw new Error(`Stream response invalid: ${event.data}`);
|
| 503 |
const { type, statusInfo, data: _data } = result;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 504 |
const { code, message } = statusInfo || {};
|
| 505 |
if (code !== 0 && type != 3)
|
| 506 |
throw new Error(`Stream response error: ${message}`);
|
|
|
|
| 422 |
if (_.isError(result))
|
| 423 |
throw new Error(`Stream response invalid: ${event.data}`);
|
| 424 |
const { type, statusInfo, data: _data } = result;
|
| 425 |
+
if (type == 8)
|
| 426 |
+
return;
|
| 427 |
const { code, message } = statusInfo || {};
|
| 428 |
if (code !== 0 && type != 3)
|
| 429 |
throw new Error(`Stream response error: ${message}`);
|
|
|
|
| 503 |
if (_.isError(result))
|
| 504 |
throw new Error(`Stream response invalid: ${event.data}`);
|
| 505 |
const { type, statusInfo, data: _data } = result;
|
| 506 |
+
if (type == 8) {
|
| 507 |
+
const data = `data: ${JSON.stringify({
|
| 508 |
+
id: convId,
|
| 509 |
+
model,
|
| 510 |
+
object: "chat.completion.chunk",
|
| 511 |
+
choices: [
|
| 512 |
+
{
|
| 513 |
+
index: 0,
|
| 514 |
+
delta: { content: "" },
|
| 515 |
+
finish_reason: "stop",
|
| 516 |
+
},
|
| 517 |
+
],
|
| 518 |
+
created,
|
| 519 |
+
})}\n\n`;
|
| 520 |
+
!transStream.closed && transStream.write(data);
|
| 521 |
+
return transStream.end("data: [DONE]\n\n");
|
| 522 |
+
}
|
| 523 |
const { code, message } = statusInfo || {};
|
| 524 |
if (code !== 0 && type != 3)
|
| 525 |
throw new Error(`Stream response error: ${message}`);
|
src/api/controllers/core.ts
CHANGED
|
@@ -24,30 +24,34 @@ const FAKE_HEADERS = {
|
|
| 24 |
Pragma: "no-cache",
|
| 25 |
Priority: "u=1, i",
|
| 26 |
"Sec-Ch-Ua":
|
| 27 |
-
'"
|
| 28 |
"Sec-Ch-Ua-Mobile": "?0",
|
| 29 |
"Sec-Ch-Ua-Platform": '"Windows"',
|
|
|
|
|
|
|
|
|
|
| 30 |
"User-Agent":
|
| 31 |
-
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
| 32 |
};
|
| 33 |
// 伪装数据
|
| 34 |
const FAKE_USER_DATA = {
|
| 35 |
device_platform: "web",
|
| 36 |
app_id: "3001",
|
|
|
|
| 37 |
uuid: null,
|
| 38 |
device_id: null,
|
| 39 |
-
version_code: "21200",
|
| 40 |
os_name: "Windows",
|
| 41 |
browser_name: "chrome",
|
| 42 |
-
server_version: "101",
|
| 43 |
device_memory: 8,
|
| 44 |
-
cpu_core_num:
|
| 45 |
browser_language: "zh-CN",
|
| 46 |
browser_platform: "Win32",
|
| 47 |
-
screen_width:
|
| 48 |
-
screen_height:
|
| 49 |
unix: null,
|
| 50 |
};
|
|
|
|
|
|
|
| 51 |
// 文件最大大小
|
| 52 |
const FILE_MAX_SIZE = 100 * 1024 * 1024;
|
| 53 |
// 设备信息映射
|
|
@@ -78,6 +82,9 @@ async function requestDeviceInfo(token: string) {
|
|
| 78 |
token,
|
| 79 |
{
|
| 80 |
userId,
|
|
|
|
|
|
|
|
|
|
| 81 |
}
|
| 82 |
);
|
| 83 |
const { deviceIDStr } = checkResult(result);
|
|
@@ -315,6 +322,7 @@ async function request(
|
|
| 315 |
const yy = util.md5(
|
| 316 |
`${encodeURIComponent(fullUri)}_${dataJson}${util.md5(unix)}ooui`
|
| 317 |
);
|
|
|
|
| 318 |
return await axios.request({
|
| 319 |
method,
|
| 320 |
url: `https://hailuoai.com${fullUri}`,
|
|
@@ -326,6 +334,8 @@ async function request(
|
|
| 326 |
Referer: "https://hailuoai.com/",
|
| 327 |
Token: token,
|
| 328 |
...FAKE_HEADERS,
|
|
|
|
|
|
|
| 329 |
...(options.headers || {}),
|
| 330 |
Yy: yy,
|
| 331 |
},
|
|
@@ -391,6 +401,7 @@ async function requestStream(
|
|
| 391 |
session.on("error", reject);
|
| 392 |
});
|
| 393 |
|
|
|
|
| 394 |
const stream = session.request({
|
| 395 |
":method": method,
|
| 396 |
":path": `${uri}?${queryStr}`,
|
|
@@ -398,6 +409,8 @@ async function requestStream(
|
|
| 398 |
Referer: "https://hailuoai.com/",
|
| 399 |
Token: token,
|
| 400 |
...FAKE_HEADERS,
|
|
|
|
|
|
|
| 401 |
...(options.headers || {}),
|
| 402 |
Yy: yy,
|
| 403 |
...data.getHeaders(),
|
|
|
|
| 24 |
Pragma: "no-cache",
|
| 25 |
Priority: "u=1, i",
|
| 26 |
"Sec-Ch-Ua":
|
| 27 |
+
'"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
|
| 28 |
"Sec-Ch-Ua-Mobile": "?0",
|
| 29 |
"Sec-Ch-Ua-Platform": '"Windows"',
|
| 30 |
+
"Sec-Fetch-Dest": "empty",
|
| 31 |
+
"Sec-Fetch-Mode": "cors",
|
| 32 |
+
"Sec-Fetch-Site": "same-origin",
|
| 33 |
"User-Agent":
|
| 34 |
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
|
| 35 |
};
|
| 36 |
// 伪装数据
|
| 37 |
const FAKE_USER_DATA = {
|
| 38 |
device_platform: "web",
|
| 39 |
app_id: "3001",
|
| 40 |
+
version_code: "22200",
|
| 41 |
uuid: null,
|
| 42 |
device_id: null,
|
|
|
|
| 43 |
os_name: "Windows",
|
| 44 |
browser_name: "chrome",
|
|
|
|
| 45 |
device_memory: 8,
|
| 46 |
+
cpu_core_num: 12,
|
| 47 |
browser_language: "zh-CN",
|
| 48 |
browser_platform: "Win32",
|
| 49 |
+
screen_width: 1920,
|
| 50 |
+
screen_height: 1080,
|
| 51 |
unix: null,
|
| 52 |
};
|
| 53 |
+
const SENTRY_RELEASE = "CI7N-1MjJnx5pru-bzzhR";
|
| 54 |
+
const SENTRY_PUBLIC_KEY = "6cf106db5c7b7262eae7cc6b411c776a";
|
| 55 |
// 文件最大大小
|
| 56 |
const FILE_MAX_SIZE = 100 * 1024 * 1024;
|
| 57 |
// 设备信息映射
|
|
|
|
| 82 |
token,
|
| 83 |
{
|
| 84 |
userId,
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
params: FAKE_USER_DATA
|
| 88 |
}
|
| 89 |
);
|
| 90 |
const { deviceIDStr } = checkResult(result);
|
|
|
|
| 322 |
const yy = util.md5(
|
| 323 |
`${encodeURIComponent(fullUri)}_${dataJson}${util.md5(unix)}ooui`
|
| 324 |
);
|
| 325 |
+
const traceId = util.uuid(false);
|
| 326 |
return await axios.request({
|
| 327 |
method,
|
| 328 |
url: `https://hailuoai.com${fullUri}`,
|
|
|
|
| 334 |
Referer: "https://hailuoai.com/",
|
| 335 |
Token: token,
|
| 336 |
...FAKE_HEADERS,
|
| 337 |
+
"Baggage": `sentry-environment=production,sentry-release=${SENTRY_RELEASE},sentry-public_key=${SENTRY_PUBLIC_KEY},sentry-trace_id=${traceId},sentry-sample_rate=1,sentry-sampled=true`,
|
| 338 |
+
"Sentry-Trace": `${traceId}-${util.uuid(false).substring(16)}-1`,
|
| 339 |
...(options.headers || {}),
|
| 340 |
Yy: yy,
|
| 341 |
},
|
|
|
|
| 401 |
session.on("error", reject);
|
| 402 |
});
|
| 403 |
|
| 404 |
+
const traceId = util.uuid(false);
|
| 405 |
const stream = session.request({
|
| 406 |
":method": method,
|
| 407 |
":path": `${uri}?${queryStr}`,
|
|
|
|
| 409 |
Referer: "https://hailuoai.com/",
|
| 410 |
Token: token,
|
| 411 |
...FAKE_HEADERS,
|
| 412 |
+
"Baggage": `sentry-environment=production,sentry-release=${SENTRY_RELEASE},sentry-public_key=${SENTRY_PUBLIC_KEY},sentry-trace_id=${traceId},sentry-sample_rate=1,sentry-sampled=true`,
|
| 413 |
+
"Sentry-Trace": `${traceId}-${util.uuid(false).substring(16)}-1`,
|
| 414 |
...(options.headers || {}),
|
| 415 |
Yy: yy,
|
| 416 |
...data.getHeaders(),
|