Merge branch '108' of https://github.com/HBAI-Ltd/Toonflow-app into 108
# Conflicts: # src/router.ts
This commit is contained in:
commit
9ae2933d43
2
.gitignore
vendored
2
.gitignore
vendored
@ -36,6 +36,8 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
build/*
|
||||
|
||||
data/serve/
|
||||
|
||||
upload/*
|
||||
uploads/*
|
||||
|
||||
|
||||
93
data/web/css.worker-BvV5MPou.js
Normal file
93
data/web/css.worker-BvV5MPou.js
Normal file
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
470
data/web/html.worker-BLJhxQJQ.js
Normal file
470
data/web/html.worker-BLJhxQJQ.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
58
data/web/json.worker-usMZ-FED.js
Normal file
58
data/web/json.worker-usMZ-FED.js
Normal file
File diff suppressed because one or more lines are too long
67731
data/web/ts.worker-DGHjMaqB.js
Normal file
67731
data/web/ts.worker-DGHjMaqB.js
Normal file
File diff suppressed because one or more lines are too long
@ -58,6 +58,7 @@ RUN apk add --no-cache nginx supervisor && \
|
||||
|
||||
# 复制后端文件
|
||||
COPY --from=builder /app/build ./build
|
||||
COPY --from=builder /app/data/serve ./data/serve
|
||||
COPY --from=builder /app/package.json ./
|
||||
COPY --from=builder /app/yarn.lock ./
|
||||
|
||||
@ -100,7 +101,7 @@ stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:app]
|
||||
command=pm2-runtime start build/app.js --name app
|
||||
command=pm2-runtime start data/serve/app.js --name app
|
||||
directory=/app
|
||||
autostart=true
|
||||
autorestart=true
|
||||
|
||||
@ -32,6 +32,7 @@ RUN apk add --no-cache nginx supervisor && \
|
||||
|
||||
# 复制后端文件
|
||||
COPY --from=builder /app/build ./build
|
||||
COPY --from=builder /app/data/serve ./data/serve
|
||||
COPY --from=builder /app/package.json ./
|
||||
COPY --from=builder /app/yarn.lock ./
|
||||
|
||||
@ -74,7 +75,7 @@ stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:app]
|
||||
command=pm2-runtime start build/app.js --name app
|
||||
command=pm2-runtime start data/serve/app.js --name app
|
||||
directory=/app
|
||||
autostart=true
|
||||
autorestart=true
|
||||
|
||||
@ -22,6 +22,15 @@ files:
|
||||
|
||||
asar: true
|
||||
|
||||
extraResources:
|
||||
- from: data
|
||||
to: data
|
||||
filter:
|
||||
- "**/*"
|
||||
- "!db2.sqlite"
|
||||
- "!logs/**"
|
||||
- "!oss/**"
|
||||
|
||||
win:
|
||||
target:
|
||||
- target: nsis
|
||||
@ -72,4 +81,4 @@ linux:
|
||||
category: Development
|
||||
artifactName: ${productName}-${version}-${os}-${arch}.${ext}
|
||||
|
||||
publish: null
|
||||
publish: null
|
||||
8246
package-lock.json
generated
Normal file
8246
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "toonflow-app",
|
||||
"version": "1.0.7",
|
||||
"name": "toonflow",
|
||||
"version": "1.0.8",
|
||||
"description": "Toonflow 是一款 AI 短剧漫剧工具,能够利用 AI 技术将小说自动转化为剧本,并结合 AI 生成的图片和视频,实现高效的短剧创作。",
|
||||
"author": "HBAI-Ltd <ltlctools@outlook.com>",
|
||||
"homepage": "https://github.com/HBAI-Ltd/Toonflow-app#readme",
|
||||
@ -20,6 +20,7 @@
|
||||
"scripts": {
|
||||
"dev": "nodemon --inspect --exec tsx src/app.ts",
|
||||
"dev:gui": "electronmon -r tsx scripts/main.ts",
|
||||
"dev:gui-vite": "cross-env VITE_DEV=1 electronmon -r tsx scripts/main.ts",
|
||||
"lint": "tsc --noEmit",
|
||||
"build": "cross-env NODE_ENV=prod tsx scripts/build.ts",
|
||||
"pack": "electron-builder --dir",
|
||||
@ -27,7 +28,7 @@
|
||||
"dist:win": "yarn build && electron-builder --win",
|
||||
"dist:mac": "yarn build && electron-builder --mac",
|
||||
"dist:linux": "yarn build && electron-builder --linux",
|
||||
"test": "cross-env NODE_ENV=prod node build/app.js",
|
||||
"test": "cross-env NODE_ENV=prod node data/serve/app.js",
|
||||
"docker:build": "docker-compose -f docker/docker-compose.yml up -d --build",
|
||||
"docker:local": "docker-compose -f docker/docker-compose.local.yml up -d --build",
|
||||
"debug:ai": "npx @ai-sdk/devtools",
|
||||
@ -46,7 +47,7 @@
|
||||
"ai": "^6.0.67",
|
||||
"axios": "^1.13.2",
|
||||
"axios-retry": "^4.5.0",
|
||||
"better-sqlite3": "^12.6.2",
|
||||
"better-sqlite3": "^12.8.0",
|
||||
"compressing": "^2.1.0",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^17.2.3",
|
||||
@ -58,14 +59,13 @@
|
||||
"is-path-inside": "^4.0.0",
|
||||
"js-md5": "^0.8.3",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"knex": "^3.1.0",
|
||||
"knex": "^3.2.5",
|
||||
"lodash": "^4.17.23",
|
||||
"morgan": "^1.10.1",
|
||||
"qwen-ai-provider-v5": "^2.1.0",
|
||||
"serialize-error": "^13.0.1",
|
||||
"sharp": "^0.34.5",
|
||||
"socket.io": "^4.8.3",
|
||||
"sqlite3": "^5.1.7",
|
||||
"sucrase": "^3.35.1",
|
||||
"uuid": "^13.0.0",
|
||||
"vm2": "^3.10.5",
|
||||
@ -89,4 +89,4 @@
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,6 +22,7 @@ if (!fs.existsSync(envFile)) {
|
||||
const external = [
|
||||
"electron",
|
||||
"@huggingface/transformers",
|
||||
"onnxruntime-node",
|
||||
"vm2",
|
||||
"sqlite3",
|
||||
"better-sqlite3",
|
||||
@ -41,7 +42,7 @@ const appBuildConfig: esbuild.BuildOptions = {
|
||||
minify: false,
|
||||
format: "cjs",
|
||||
allowOverwrite: true,
|
||||
outfile: `build/app.js`,
|
||||
outfile: `data/serve/app.js`,
|
||||
platform: "node",
|
||||
target: "esnext",
|
||||
tsconfig: "./tsconfig.json",
|
||||
|
||||
121
scripts/main.ts
121
scripts/main.ts
@ -1,11 +1,80 @@
|
||||
import { app, BrowserWindow } from "electron";
|
||||
import path from "path";
|
||||
import startServe, { closeServe } from "src/app";
|
||||
import { number } from "zod";
|
||||
import fs from "fs";
|
||||
import Module from "module";
|
||||
|
||||
// 默认端口配置
|
||||
const defaultPort = 10588;
|
||||
|
||||
/**
|
||||
* 将 extraResources 中的 data 目录复制到用户数据目录(跳过已存在的文件,保留用户修改)
|
||||
*/
|
||||
function initializeData(): void {
|
||||
const srcDir = path.join(process.resourcesPath, "data");
|
||||
const destDir = path.join(app.getPath("userData"), "data");
|
||||
if (fs.existsSync(destDir)) return;
|
||||
copyDirRecursive(srcDir, destDir);
|
||||
}
|
||||
|
||||
function copyDirRecursive(src: string, dest: string): void {
|
||||
if (!fs.existsSync(src)) return;
|
||||
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
|
||||
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
||||
const srcPath = path.join(src, entry.name);
|
||||
const destPath = path.join(dest, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
copyDirRecursive(srcPath, destPath);
|
||||
} else if (!fs.existsSync(destPath)) {
|
||||
fs.copyFileSync(srcPath, destPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//获取全部依赖路径,优先从 unpacked 加载原生模块,其他模块从 asar 加载
|
||||
function getNodeModulesPaths(): string[] {
|
||||
const paths: string[] = [];
|
||||
if (app.isPackaged) {
|
||||
// external 依赖(原生模块)在 unpacked 目录
|
||||
const unpackedNodeModules = path.join(process.resourcesPath, "app.asar.unpacked", "node_modules");
|
||||
if (fs.existsSync(unpackedNodeModules)) {
|
||||
paths.push(unpackedNodeModules);
|
||||
}
|
||||
// 普通依赖在 asar 内
|
||||
const asarNodeModules = path.join(process.resourcesPath, "app.asar", "node_modules");
|
||||
paths.push(asarNodeModules);
|
||||
} else {
|
||||
paths.push(path.join(process.cwd(), "node_modules"));
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
//动态加载
|
||||
function requireWithCustomPaths(modulePath: string): any {
|
||||
const appNodeModulesPaths = getNodeModulesPaths();
|
||||
// 保存原始方法
|
||||
const originalNodeModulePaths = (Module as any)._nodeModulePaths;
|
||||
// 临时修改模块路径解析
|
||||
(Module as any)._nodeModulePaths = function (from: string): string[] {
|
||||
const paths = originalNodeModulePaths.call(this, from);
|
||||
// 将主程序的 node_modules 添加到前面
|
||||
for (let i = appNodeModulesPaths.length - 1; i >= 0; i--) {
|
||||
const p = appNodeModulesPaths[i];
|
||||
if (!paths.includes(p)) {
|
||||
paths.unshift(p);
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
};
|
||||
try {
|
||||
// 清除缓存确保加载最新
|
||||
delete require.cache[require.resolve(modulePath)];
|
||||
return require(modulePath);
|
||||
} finally {
|
||||
// 恢复原始方法
|
||||
(Module as any)._nodeModulePaths = originalNodeModulePaths;
|
||||
}
|
||||
}
|
||||
|
||||
function createMainWindow(port: any): void {
|
||||
const win = new BrowserWindow({
|
||||
width: 900,
|
||||
@ -13,29 +82,37 @@ function createMainWindow(port: any): void {
|
||||
show: true,
|
||||
autoHideMenuBar: true,
|
||||
});
|
||||
// 开发环境和生产环境使用不同的路径
|
||||
win.webContents.on("did-start-loading", () => {
|
||||
void win.webContents.executeJavaScript(`window.$electron = true; window.$port = ${port};`);
|
||||
});
|
||||
const isDev = process.env.NODE_ENV === "dev" || !app.isPackaged;
|
||||
const htmlPath = isDev
|
||||
? path.join(process.cwd(), "scripts", "web", "index.html")
|
||||
: path.join(app.getAppPath(), "scripts", "web", "index.html");
|
||||
|
||||
// 使用实际端口构建地址
|
||||
const baseUrl = `http://localhost:${port}`;
|
||||
const wsBaseUrl = `ws://localhost:${port}`;
|
||||
|
||||
// 构建带有 query 参数的 URL
|
||||
const url = new URL(`file://${htmlPath}`);
|
||||
url.searchParams.set("baseUrl", baseUrl);
|
||||
url.searchParams.set("wsBaseUrl", wsBaseUrl);
|
||||
|
||||
console.log("%c Line:30 🥓 url", "background:#33a5ff", url.toString());
|
||||
|
||||
void win.loadURL(url.toString());
|
||||
if (process.env.VITE_DEV) {
|
||||
void win.loadURL("http://localhost:50188");
|
||||
} else {
|
||||
const htmlPath = isDev ? path.join(process.cwd(), "data", "web", "index.html") : path.join(app.getPath("userData"), "data", "web", "index.html");
|
||||
void win.loadFile(htmlPath);
|
||||
}
|
||||
}
|
||||
|
||||
let closeServeFn: (() => Promise<void>) | undefined;
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
try {
|
||||
const port = await startServe(false);
|
||||
createMainWindow(10588);
|
||||
let servePath: string;
|
||||
if (app.isPackaged) {
|
||||
// 生产环境:从 extraResources 初始化数据到用户目录,然后从用户目录加载后端服务
|
||||
initializeData();
|
||||
servePath = path.join(app.getPath("userData"), "data", "serve", "app.js");
|
||||
} else {
|
||||
// 开发环境:直接加载源码(tsx 通过 -r tsx 注册了 require 钩子)
|
||||
servePath = path.join(process.cwd(), "src", "app.ts");
|
||||
}
|
||||
// 使用自定义路径加载模块
|
||||
const mod = requireWithCustomPaths(servePath);
|
||||
closeServeFn = mod.closeServe;
|
||||
const port = await mod.default(true);
|
||||
console.log("%c Line:112 🍇 port", "background:#2eafb0", port);
|
||||
createMainWindow(port);
|
||||
} catch (err) {
|
||||
console.error("[服务启动失败]:", err);
|
||||
// 如果服务启动失败,使用默认端口创建窗口
|
||||
@ -55,5 +132,5 @@ app.on("activate", () => {
|
||||
});
|
||||
|
||||
app.on("before-quit", async (event) => {
|
||||
await closeServe();
|
||||
if (closeServeFn) await closeServeFn();
|
||||
});
|
||||
|
||||
@ -17,6 +17,7 @@ const app = express();
|
||||
const server = http.createServer(app);
|
||||
|
||||
export default async function startServe(randomPort: Boolean = false) {
|
||||
console.log("%c Line:20 🍰 randomPort", "background:#b03734", randomPort);
|
||||
const io = new Server(server, { cors: { origin: "*" } });
|
||||
socketInit(io);
|
||||
|
||||
|
||||
36
src/err.ts
36
src/err.ts
@ -1,30 +1,30 @@
|
||||
import { serializeError } from "serialize-error";
|
||||
|
||||
// 处理未捕获的 Promise 拒绝
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
console.error('[未处理的 Promise 拒绝]');
|
||||
process.on("unhandledRejection", (reason, promise) => {
|
||||
console.error("[未处理的 Promise 拒绝]");
|
||||
if (reason instanceof Error) {
|
||||
console.error('错误名称:', reason.name);
|
||||
console.error('错误消息:', reason.message);
|
||||
console.error('堆栈信息:', reason.stack);
|
||||
console.error('序列化详情:', JSON.stringify(serializeError(reason), null, 2));
|
||||
console.error("错误名称:", reason.name);
|
||||
console.error("错误消息:", reason.message);
|
||||
console.error("堆栈信息:", reason.stack);
|
||||
console.error("序列化详情:", JSON.stringify(serializeError(reason), null, 2));
|
||||
} else {
|
||||
console.error('原因:', reason);
|
||||
console.error('类型:', typeof reason);
|
||||
console.error("原因:", reason);
|
||||
console.error("类型:", typeof reason);
|
||||
try {
|
||||
console.error('JSON:', JSON.stringify(reason, null, 2));
|
||||
} catch {
|
||||
console.error('(无法序列化)');
|
||||
console.error("JSON:", JSON.stringify(reason, null, 2));
|
||||
} catch {
|
||||
console.error("(无法序列化)");
|
||||
}
|
||||
}
|
||||
console.error('Promise:', promise);
|
||||
console.error("Promise:", promise);
|
||||
});
|
||||
|
||||
// 处理未捕获的异常
|
||||
process.on('uncaughtException', (error) => {
|
||||
console.error('[未捕获的异常]');
|
||||
console.error('错误名称:', error.name);
|
||||
console.error('错误消息:', error.message);
|
||||
console.error('堆栈信息:', error.stack);
|
||||
console.error('序列化详情:', JSON.stringify(serializeError(error), null, 2));
|
||||
process.on("uncaughtException", (error) => {
|
||||
console.error("[未捕获的异常]");
|
||||
console.error("错误名称:", error.name);
|
||||
console.error("错误消息:", error.message);
|
||||
console.error("堆栈信息:", error.stack);
|
||||
console.error("序列化详情:", JSON.stringify(serializeError(error), null, 2));
|
||||
});
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// @routes-hash 27c3b6ded51fc0de03bec6512e84485b
|
||||
// @routes-hash 074af9af2c664d3497c2c676a3423399
|
||||
import { Express } from "express";
|
||||
|
||||
import route1 from "./routes/agents/clearMemory";
|
||||
@ -40,10 +40,10 @@ import route36 from "./routes/novel/updateNovel";
|
||||
import route37 from "./routes/other/deleteAllData";
|
||||
import route38 from "./routes/other/getCaptcha";
|
||||
import route39 from "./routes/production/assets/getAssetsData";
|
||||
import route40 from "./routes/production/editImage/generateStoryboardImage";
|
||||
import route41 from "./routes/production/editImage/getStoryboardFlow";
|
||||
import route42 from "./routes/production/editImage/saveStoryboardFlow";
|
||||
import route43 from "./routes/production/editImage/updateStoryboardFlow";
|
||||
import route40 from "./routes/production/editStoryboard/generateStoryboardImage";
|
||||
import route41 from "./routes/production/editStoryboard/getStoryboardFlow";
|
||||
import route42 from "./routes/production/editStoryboard/saveStoryboardFlow";
|
||||
import route43 from "./routes/production/editStoryboard/updateStoryboardFlow";
|
||||
import route44 from "./routes/production/exportImage";
|
||||
import route45 from "./routes/production/getFlowData";
|
||||
import route46 from "./routes/production/getProductionData";
|
||||
@ -70,20 +70,21 @@ import route66 from "./routes/setting/agentDeploy/agentSetKey";
|
||||
import route67 from "./routes/setting/agentDeploy/deployAgentModel";
|
||||
import route68 from "./routes/setting/agentDeploy/getAgentDeploy";
|
||||
import route69 from "./routes/setting/dbConfig/clearData";
|
||||
import route70 from "./routes/setting/getTextModel";
|
||||
import route71 from "./routes/setting/loginConfig/getUser";
|
||||
import route72 from "./routes/setting/loginConfig/updateUserPwd";
|
||||
import route73 from "./routes/setting/memoryConfig/getMemory";
|
||||
import route74 from "./routes/setting/memoryConfig/sureMemory";
|
||||
import route75 from "./routes/setting/vendorConfig/addVendor";
|
||||
import route76 from "./routes/setting/vendorConfig/deleteVendor";
|
||||
import route77 from "./routes/setting/vendorConfig/getVendorList";
|
||||
import route78 from "./routes/setting/vendorConfig/modelTest";
|
||||
import route79 from "./routes/setting/vendorConfig/updateVendor";
|
||||
import route80 from "./routes/task/getTaskApi";
|
||||
import route81 from "./routes/task/getTaskCategories";
|
||||
import route82 from "./routes/task/taskDetails";
|
||||
import route83 from "./routes/test/test";
|
||||
import route70 from "./routes/setting/fileManagement/openFolder";
|
||||
import route71 from "./routes/setting/getTextModel";
|
||||
import route72 from "./routes/setting/loginConfig/getUser";
|
||||
import route73 from "./routes/setting/loginConfig/updateUserPwd";
|
||||
import route74 from "./routes/setting/memoryConfig/getMemory";
|
||||
import route75 from "./routes/setting/memoryConfig/sureMemory";
|
||||
import route76 from "./routes/setting/vendorConfig/addVendor";
|
||||
import route77 from "./routes/setting/vendorConfig/deleteVendor";
|
||||
import route78 from "./routes/setting/vendorConfig/getVendorList";
|
||||
import route79 from "./routes/setting/vendorConfig/modelTest";
|
||||
import route80 from "./routes/setting/vendorConfig/updateVendor";
|
||||
import route81 from "./routes/task/getTaskApi";
|
||||
import route82 from "./routes/task/getTaskCategories";
|
||||
import route83 from "./routes/task/taskDetails";
|
||||
import route84 from "./routes/test/test";
|
||||
|
||||
export default async (app: Express) => {
|
||||
app.use("/api/agents/clearMemory", route1);
|
||||
@ -125,10 +126,10 @@ export default async (app: Express) => {
|
||||
app.use("/api/other/deleteAllData", route37);
|
||||
app.use("/api/other/getCaptcha", route38);
|
||||
app.use("/api/production/assets/getAssetsData", route39);
|
||||
app.use("/api/production/editImage/generateStoryboardImage", route40);
|
||||
app.use("/api/production/editImage/getStoryboardFlow", route41);
|
||||
app.use("/api/production/editImage/saveStoryboardFlow", route42);
|
||||
app.use("/api/production/editImage/updateStoryboardFlow", route43);
|
||||
app.use("/api/production/editStoryboard/generateStoryboardImage", route40);
|
||||
app.use("/api/production/editStoryboard/getStoryboardFlow", route41);
|
||||
app.use("/api/production/editStoryboard/saveStoryboardFlow", route42);
|
||||
app.use("/api/production/editStoryboard/updateStoryboardFlow", route43);
|
||||
app.use("/api/production/exportImage", route44);
|
||||
app.use("/api/production/getFlowData", route45);
|
||||
app.use("/api/production/getProductionData", route46);
|
||||
@ -155,18 +156,19 @@ export default async (app: Express) => {
|
||||
app.use("/api/setting/agentDeploy/deployAgentModel", route67);
|
||||
app.use("/api/setting/agentDeploy/getAgentDeploy", route68);
|
||||
app.use("/api/setting/dbConfig/clearData", route69);
|
||||
app.use("/api/setting/getTextModel", route70);
|
||||
app.use("/api/setting/loginConfig/getUser", route71);
|
||||
app.use("/api/setting/loginConfig/updateUserPwd", route72);
|
||||
app.use("/api/setting/memoryConfig/getMemory", route73);
|
||||
app.use("/api/setting/memoryConfig/sureMemory", route74);
|
||||
app.use("/api/setting/vendorConfig/addVendor", route75);
|
||||
app.use("/api/setting/vendorConfig/deleteVendor", route76);
|
||||
app.use("/api/setting/vendorConfig/getVendorList", route77);
|
||||
app.use("/api/setting/vendorConfig/modelTest", route78);
|
||||
app.use("/api/setting/vendorConfig/updateVendor", route79);
|
||||
app.use("/api/task/getTaskApi", route80);
|
||||
app.use("/api/task/getTaskCategories", route81);
|
||||
app.use("/api/task/taskDetails", route82);
|
||||
app.use("/api/test/test", route83);
|
||||
app.use("/api/setting/fileManagement/openFolder", route70);
|
||||
app.use("/api/setting/getTextModel", route71);
|
||||
app.use("/api/setting/loginConfig/getUser", route72);
|
||||
app.use("/api/setting/loginConfig/updateUserPwd", route73);
|
||||
app.use("/api/setting/memoryConfig/getMemory", route74);
|
||||
app.use("/api/setting/memoryConfig/sureMemory", route75);
|
||||
app.use("/api/setting/vendorConfig/addVendor", route76);
|
||||
app.use("/api/setting/vendorConfig/deleteVendor", route77);
|
||||
app.use("/api/setting/vendorConfig/getVendorList", route78);
|
||||
app.use("/api/setting/vendorConfig/modelTest", route79);
|
||||
app.use("/api/setting/vendorConfig/updateVendor", route80);
|
||||
app.use("/api/task/getTaskApi", route81);
|
||||
app.use("/api/task/getTaskCategories", route82);
|
||||
app.use("/api/task/taskDetails", route83);
|
||||
app.use("/api/test/test", route84);
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ export default router.post(
|
||||
}
|
||||
//连接旧数据库
|
||||
db2 = knex({
|
||||
client: "sqlite3",
|
||||
client: "better-sqlite3",
|
||||
connection: {
|
||||
filename: db2Path,
|
||||
},
|
||||
|
||||
32
src/routes/setting/fileManagement/openFolder.ts
Normal file
32
src/routes/setting/fileManagement/openFolder.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import express from "express";
|
||||
import { z } from "zod";
|
||||
import { exec } from "child_process";
|
||||
import { success, error } from "@/lib/responseFormat";
|
||||
import { validateFields } from "@/middleware/middleware";
|
||||
import { isEletron } from "@/utils/getPath";
|
||||
import u from "@/utils";
|
||||
import path from "path";
|
||||
const router = express.Router();
|
||||
|
||||
export default router.post(
|
||||
"/",
|
||||
validateFields({
|
||||
path: z.string(),
|
||||
}),
|
||||
async (req, res) => {
|
||||
if (!isEletron()) {
|
||||
return res.status(400).send(error("仅支持客户端打开文件夹"));
|
||||
}
|
||||
const { path: folderPath } = req.body;
|
||||
const platform = process.platform;
|
||||
const target = u.getPath(folderPath);
|
||||
console.log("%c Line:23 🎂 target", "background:#fca650", target);
|
||||
const cmd = platform === "win32" ? `explorer "${target}"` : platform === "darwin" ? `open "${target}"` : `xdg-open "${target}"`;
|
||||
exec(cmd, (err) => {
|
||||
if (err) {
|
||||
return res.status(200).send(error(err.message));
|
||||
}
|
||||
res.status(200).send(success("打开文件夹成功"));
|
||||
});
|
||||
},
|
||||
);
|
||||
@ -1,3 +1,4 @@
|
||||
import * as ONNX_WEB from "onnxruntime-web";
|
||||
import { pipeline, env as transformersEnv, FeatureExtractionPipeline } from "@huggingface/transformers";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
|
||||
@ -26,7 +26,7 @@ if (!fs.existsSync(dbPath)) {
|
||||
}
|
||||
|
||||
const db = knex({
|
||||
client: "sqlite3",
|
||||
client: "better-sqlite3",
|
||||
connection: {
|
||||
filename: dbPath,
|
||||
},
|
||||
|
||||
@ -1,20 +1,35 @@
|
||||
import path from "path";
|
||||
import isPathInside from "is-path-inside";
|
||||
|
||||
export default (fileName?: string[] | string) => {
|
||||
let dbPath: string;
|
||||
let basePath: string;
|
||||
if (typeof process.versions?.electron !== "undefined") {
|
||||
const { app } = require("electron");
|
||||
const userDataDir: string = app.getPath("userData");
|
||||
dbPath = path.join(userDataDir, "data");
|
||||
basePath = path.join(userDataDir, "data");
|
||||
} else {
|
||||
dbPath = path.join(process.cwd(), "data");
|
||||
basePath = path.join(process.cwd(), "data");
|
||||
}
|
||||
if (fileName) {
|
||||
let dbPath: string;
|
||||
if (Array.isArray(fileName)) {
|
||||
dbPath = path.join(dbPath, ...fileName);
|
||||
dbPath = path.resolve(basePath, ...fileName);
|
||||
} else {
|
||||
dbPath = path.join(dbPath, fileName);
|
||||
dbPath = path.resolve(basePath, fileName);
|
||||
}
|
||||
if (!isPathInside(dbPath, basePath) && dbPath !== basePath) {
|
||||
throw new Error("路径逃逸错误,路径必须在数据目录内");
|
||||
}
|
||||
return dbPath;
|
||||
}
|
||||
return dbPath;
|
||||
return basePath;
|
||||
};
|
||||
|
||||
export function isEletron() {
|
||||
if (typeof process.versions?.electron !== "undefined") {
|
||||
const { app } = require("electron");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user