This commit is contained in:
lq1405 2025-08-19 14:33:59 +08:00
commit 56a32f8a50
336 changed files with 55317 additions and 0 deletions

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
node_modules
dist
out
.DS_Store
.eslintcache
*.log*
resources/logger
resources/project
Database
build

6
.prettierignore Normal file
View File

@ -0,0 +1,6 @@
out
dist
pnpm-lock.yaml
LICENSE.md
tsconfig.json
tsconfig.*.json

4
.prettierrc.yaml Normal file
View File

@ -0,0 +1,4 @@
singleQuote: true
semi: false
printWidth: 100
trailingComma: none

3
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"recommendations": ["dbaeumer.vscode-eslint"]
}

39
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,39 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"cwd": "${workspaceRoot}",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
},
"runtimeArgs": ["--sourcemap"],
"env": {
"REMOTE_DEBUGGING_PORT": "9222"
}
},
{
"name": "Debug Renderer Process",
"port": 9222,
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}/src/renderer",
"timeout": 60000,
"presentation": {
"hidden": true
}
}
],
"compounds": [
{
"name": "Debug All",
"configurations": ["Debug Main Process", "Debug Renderer Process"],
"presentation": {
"order": 1
}
}
]
}

12
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,12 @@
{
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"vue3snippets.enable-compile-vue-file-on-did-save-code": false
}

34
README.md Normal file
View File

@ -0,0 +1,34 @@
# laitool-pro
An Electron application with Vue and TypeScript
## Recommended IDE Setup
- [VSCode](https://code.visualstudio.com/) + [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) + [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin)
## Project Setup
### Install
```bash
$ npm install
```
### Development
```bash
$ npm run dev
```
### Build
```bash
# For windows
$ npm run build:win
# For macOS
$ npm run build:mac
# For Linux
$ npm run build:linux
```

10
auto-imports.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
}

14
components.d.ts vendored Normal file
View File

@ -0,0 +1,14 @@
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
// biome-ignore lint: disable
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
}

3
dev-app-update.yml Normal file
View File

@ -0,0 +1,3 @@
provider: generic
url: https://example.com/auto-updates
updaterCacheDirName: laitool-pro-updater

48
electron-builder.yml Normal file
View File

@ -0,0 +1,48 @@
appId: com.electron.app
productName: laitool-pro
directories:
buildResources: build
files:
- '!**/.vscode/*'
- '!src/*'
- '!electron.vite.config.{js,ts,mjs,cjs}'
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
- '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
asarUnpack:
- resources/**
win:
executableName: LaiTool PRO
nsis:
oneClick: false
artifactName: ${name}-${version}-setup.${ext}
shortcutName: ${productName}
uninstallDisplayName: ${productName}
createDesktopShortcut: always
allowToChangeInstallationDirectory: true
createDesktopShortcut: true
createStartMenuShortcut: true
shortcutName: "南枫AI"
mac:
entitlementsInherit: build/entitlements.mac.plist
extendInfo:
- NSCameraUsageDescription: Application requests access to the device's camera.
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
notarize: false
dmg:
artifactName: ${name}-${version}.${ext}
linux:
target:
- AppImage
- snap
- deb
maintainer: electronjs.org
category: Utility
appImage:
artifactName: ${name}-${version}.${ext}
npmRebuild: false
publish:
provider: generic
url: https://example.com/auto-updates

View File

@ -0,0 +1,61 @@
// electron.vite.config.ts
import { resolve } from "path";
import { defineConfig, externalizeDepsPlugin, bytecodePlugin } from "electron-vite";
import vue from "@vitejs/plugin-vue";
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import tsconfigPaths from "vite-tsconfig-paths";
import { NaiveUiResolver } from "unplugin-vue-components/resolvers";
var electron_vite_config_default = defineConfig({
main: {
resolve: {
alias: {
"@": resolve("src"),
"@renderer": resolve("src/renderer/src")
}
},
plugins: [externalizeDepsPlugin(), bytecodePlugin(), tsconfigPaths()]
},
preload: {
plugins: [externalizeDepsPlugin(), bytecodePlugin()],
resolve: {
alias: {
"@": resolve("src"),
"@renderer": resolve("src/renderer/src")
}
}
},
renderer: {
resolve: {
alias: {
"@": resolve("src"),
"@renderer": resolve("src/renderer/src")
}
},
plugins: [
bytecodePlugin(),
vue({
template: {
compilerOptions: {
// 将webview标签标记为自定义元素
isCustomElement: (tag) => ["webview"].includes(tag)
}
}
}),
AutoImport({
imports: [
"vue",
{
"naive-ui": ["useDialog", "useMessage", "useNotification", "useLoadingBar"]
}
]
}),
Components({
resolvers: [NaiveUiResolver()]
})
]
}
});
export {
electron_vite_config_default as default
};

58
electron.vite.config.ts Normal file
View File

@ -0,0 +1,58 @@
import { resolve } from 'path'
import { defineConfig, externalizeDepsPlugin, bytecodePlugin } from 'electron-vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import tsconfigPaths from 'vite-tsconfig-paths'
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
main: {
resolve: {
alias: {
'@': resolve('src'),
'@renderer': resolve('src/renderer/src')
}
},
plugins: [externalizeDepsPlugin(), bytecodePlugin(), tsconfigPaths()]
},
preload: {
plugins: [externalizeDepsPlugin(), bytecodePlugin()],
resolve: {
alias: {
'@': resolve('src'),
'@renderer': resolve('src/renderer/src')
}
}
},
renderer: {
resolve: {
alias: {
'@': resolve('src'),
'@renderer': resolve('src/renderer/src')
}
},
plugins: [
bytecodePlugin(),
vue({
template: {
compilerOptions: {
// 将webview标签标记为自定义元素
isCustomElement: (tag) => ['webview'].includes(tag)
}
}
}),
AutoImport({
imports: [
'vue',
{
'naive-ui': ['useDialog', 'useMessage', 'useNotification', 'useLoadingBar']
}
]
}),
Components({
resolvers: [NaiveUiResolver()]
})
]
}
})

25
eslint.config.mjs Normal file
View File

@ -0,0 +1,25 @@
import tseslint from '@electron-toolkit/eslint-config-ts'
import eslintConfigPrettier from '@electron-toolkit/eslint-config-prettier'
import eslintPluginVue from 'eslint-plugin-vue'
export default tseslint.config(
{ ignores: ['**/node_modules', '**/dist', '**/out'] },
tseslint.configs.recommended,
eslintPluginVue.configs['flat/recommended'],
{
files: ['**/*.vue'],
languageOptions: {
parserOptions: {
parser: tseslint.parser
}
}
},
{
files: ['**/*.{ts,mts,tsx,vue}'],
rules: {
'vue/require-default-prop': 'off',
'vue/multi-word-component-names': 'off'
}
},
eslintConfigPrettier
)

9086
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

97
package.json Normal file
View File

@ -0,0 +1,97 @@
{
"name": "laitool-pro",
"version": "v3.4.3",
"description": "A desktop application for AI image generation and processing, built with Electron and Vue 3.",
"main": "./out/main/index.js",
"author": "xiangbei",
"homepage": "https://electron-vite.org",
"scripts": {
"format": "prettier --write .",
"lint": "eslint --cache .",
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
"typecheck:web": "vue-tsc --noEmit -p tsconfig.web.json --composite false",
"typecheck": "npm run typecheck:node && npm run typecheck:web",
"start": "electron-vite preview",
"dev": "electron-vite dev",
"build": "npm run typecheck && electron-vite build",
"postinstall": "electron-builder install-app-deps",
"build:unpack": "npm run build && electron-builder --dir",
"build:win": "npm run build && electron-builder --win",
"build:mac": "npm run build && electron-builder --mac",
"build:linux": "npm run build && electron-builder --linux"
},
"dependencies": {
"@alicloud/alimt20181012": "^1.3.0",
"@alicloud/openapi-client": "^0.4.14",
"@alicloud/tea-util": "^1.4.10",
"@electron-toolkit/preload": "^3.0.1",
"@electron-toolkit/utils": "^4.0.0",
"@vicons/ionicons5": "^0.13.0",
"@volcengine/openapi": "^1.30.1",
"axios": "^1.8.4",
"color-string": "^2.0.1",
"compressing": "^1.10.1",
"crypto-js": "^4.2.0",
"electron-updater": "^6.3.9",
"lodash": "^4.17.21",
"moment-timezone": "^0.5.48",
"music-metadata-browser": "^2.5.11",
"node-machine-id": "^1.1.12",
"pinia": "^3.0.1",
"realm": "^20.1.0",
"sharp": "^0.34.1",
"tencentcloud-sdk-nodejs": "^4.1.26",
"vite-tsconfig-paths": "^5.1.4",
"vue-router": "^4.5.0",
"wav-file-info": "^0.0.10",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0"
},
"devDependencies": {
"@electron-toolkit/eslint-config-prettier": "3.0.0",
"@electron-toolkit/eslint-config-ts": "^3.0.0",
"@electron-toolkit/tsconfig": "^1.0.1",
"@types/node": "^22.13.4",
"@vitejs/plugin-vue": "^5.2.1",
"electron": "^34.2.0",
"electron-builder": "^25.1.8",
"electron-vite": "^3.0.0",
"eslint": "^9.20.1",
"eslint-plugin-vue": "^9.32.0",
"naive-ui": "^2.41.0",
"prettier": "^3.5.1",
"typescript": "^5.7.3",
"unplugin-auto-import": "^19.1.2",
"unplugin-vue-components": "^28.4.1",
"vite": "^6.1.0",
"vue": "^3.5.13",
"vue-tsc": "^2.2.2"
},
"build": {
"asar": true,
"files": [
"out/**/*",
"!resources/"
],
"extraResources": [
"resources/package/exittool/**",
"resources/package/ffmpeg/**",
"resources/package/Improve/**",
"resources/image/style/**",
"resources/image/zhanwei.png",
"resources/scripts/model/**",
"resources/scripts/Lai.exe",
"resources/scripts/discordScript.js",
"resources/tmp/**",
"resources/icon.ico"
],
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true
},
"win": {
"target": "nsis",
"icon": "./resources/icon.ico"
}
}
}

View File

@ -0,0 +1 @@
default-software-id

BIN
resources/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 KiB

BIN
resources/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

BIN
resources/icon1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@ -0,0 +1,43 @@
7767517
41 42
Input input.1 0 1 data
Split splitncnn_input0 1 2 data input.1_splitncnn_0 input.1_splitncnn_1
Convolution Conv_0 1 1 input.1_splitncnn_1 54 0=64 1=3 4=1 5=1 6=1728
PReLU PRelu_1 1 1 54 56 0=64
Convolution Conv_2 1 1 56 57 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_3 1 1 57 59 0=64
Convolution Conv_4 1 1 59 60 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_5 1 1 60 62 0=64
Convolution Conv_6 1 1 62 63 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_7 1 1 63 65 0=64
Convolution Conv_8 1 1 65 66 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_9 1 1 66 68 0=64
Convolution Conv_10 1 1 68 69 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_11 1 1 69 71 0=64
Convolution Conv_12 1 1 71 72 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_13 1 1 72 74 0=64
Convolution Conv_14 1 1 74 75 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_15 1 1 75 77 0=64
Convolution Conv_16 1 1 77 78 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_17 1 1 78 80 0=64
Convolution Conv_18 1 1 80 81 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_19 1 1 81 83 0=64
Convolution Conv_20 1 1 83 84 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_21 1 1 84 86 0=64
Convolution Conv_22 1 1 86 87 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_23 1 1 87 89 0=64
Convolution Conv_24 1 1 89 90 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_25 1 1 90 92 0=64
Convolution Conv_26 1 1 92 93 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_27 1 1 93 95 0=64
Convolution Conv_28 1 1 95 96 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_29 1 1 96 98 0=64
Convolution Conv_30 1 1 98 99 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_31 1 1 99 101 0=64
Convolution Conv_32 1 1 101 102 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_33 1 1 102 104 0=64
Convolution Conv_34 1 1 104 105 0=48 1=3 4=1 5=1 6=27648
PixelShuffle DepthToSpace_35 1 1 105 106 0=4
Interp Resize_37 1 1 input.1_splitncnn_0 111 0=1 1=4.000000e+00 2=4.000000e+00
BinaryOp Add_38 2 1 106 111 112
Interp Resize_40 1 1 112 output 0=3 1=5.000000e-01 2=5.000000e-01

View File

@ -0,0 +1,43 @@
7767517
41 42
Input input.1 0 1 data
Split splitncnn_input0 1 2 data input.1_splitncnn_0 input.1_splitncnn_1
Convolution Conv_0 1 1 input.1_splitncnn_1 54 0=64 1=3 4=1 5=1 6=1728
PReLU PRelu_1 1 1 54 56 0=64
Convolution Conv_2 1 1 56 57 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_3 1 1 57 59 0=64
Convolution Conv_4 1 1 59 60 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_5 1 1 60 62 0=64
Convolution Conv_6 1 1 62 63 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_7 1 1 63 65 0=64
Convolution Conv_8 1 1 65 66 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_9 1 1 66 68 0=64
Convolution Conv_10 1 1 68 69 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_11 1 1 69 71 0=64
Convolution Conv_12 1 1 71 72 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_13 1 1 72 74 0=64
Convolution Conv_14 1 1 74 75 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_15 1 1 75 77 0=64
Convolution Conv_16 1 1 77 78 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_17 1 1 78 80 0=64
Convolution Conv_18 1 1 80 81 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_19 1 1 81 83 0=64
Convolution Conv_20 1 1 83 84 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_21 1 1 84 86 0=64
Convolution Conv_22 1 1 86 87 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_23 1 1 87 89 0=64
Convolution Conv_24 1 1 89 90 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_25 1 1 90 92 0=64
Convolution Conv_26 1 1 92 93 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_27 1 1 93 95 0=64
Convolution Conv_28 1 1 95 96 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_29 1 1 96 98 0=64
Convolution Conv_30 1 1 98 99 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_31 1 1 99 101 0=64
Convolution Conv_32 1 1 101 102 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_33 1 1 102 104 0=64
Convolution Conv_34 1 1 104 105 0=48 1=3 4=1 5=1 6=27648
PixelShuffle DepthToSpace_35 1 1 105 106 0=4
Interp Resize_37 1 1 input.1_splitncnn_0 111 0=1 1=4.000000e+00 2=4.000000e+00
BinaryOp Add_38 2 1 106 111 112
Interp Resize_40 1 1 112 output 0=3 1=7.500000e-01 2=7.500000e-01

View File

@ -0,0 +1,42 @@
7767517
40 41
Input input.1 0 1 data
Split splitncnn_input0 1 2 data input.1_splitncnn_0 input.1_splitncnn_1
Convolution Conv_0 1 1 input.1_splitncnn_1 54 0=64 1=3 4=1 5=1 6=1728
PReLU PRelu_1 1 1 54 56 0=64
Convolution Conv_2 1 1 56 57 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_3 1 1 57 59 0=64
Convolution Conv_4 1 1 59 60 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_5 1 1 60 62 0=64
Convolution Conv_6 1 1 62 63 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_7 1 1 63 65 0=64
Convolution Conv_8 1 1 65 66 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_9 1 1 66 68 0=64
Convolution Conv_10 1 1 68 69 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_11 1 1 69 71 0=64
Convolution Conv_12 1 1 71 72 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_13 1 1 72 74 0=64
Convolution Conv_14 1 1 74 75 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_15 1 1 75 77 0=64
Convolution Conv_16 1 1 77 78 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_17 1 1 78 80 0=64
Convolution Conv_18 1 1 80 81 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_19 1 1 81 83 0=64
Convolution Conv_20 1 1 83 84 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_21 1 1 84 86 0=64
Convolution Conv_22 1 1 86 87 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_23 1 1 87 89 0=64
Convolution Conv_24 1 1 89 90 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_25 1 1 90 92 0=64
Convolution Conv_26 1 1 92 93 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_27 1 1 93 95 0=64
Convolution Conv_28 1 1 95 96 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_29 1 1 96 98 0=64
Convolution Conv_30 1 1 98 99 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_31 1 1 99 101 0=64
Convolution Conv_32 1 1 101 102 0=64 1=3 4=1 5=1 6=36864
PReLU PRelu_33 1 1 102 104 0=64
Convolution Conv_34 1 1 104 105 0=48 1=3 4=1 5=1 6=27648
PixelShuffle DepthToSpace_35 1 1 105 106 0=4
Interp Resize_37 1 1 input.1_splitncnn_0 111 0=1 1=4.000000e+00 2=4.000000e+00
BinaryOp Add_38 2 1 106 111 output

View File

@ -0,0 +1,270 @@
7767517
268 473
Input input.1 0 1 data
Convolution Conv_0 1 1 data 193 0=64 1=3 4=1 5=1 6=1728
Split splitncnn_0 1 8 193 193_splitncnn_0 193_splitncnn_1 193_splitncnn_2 193_splitncnn_3 193_splitncnn_4 193_splitncnn_5 193_splitncnn_6 193_splitncnn_7
Convolution Conv_1 1 1 193_splitncnn_7 195 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_1 1 4 195 195_splitncnn_0 195_splitncnn_1 195_splitncnn_2 195_splitncnn_3
Concat Concat_3 2 1 193_splitncnn_6 195_splitncnn_3 196
Convolution Conv_4 1 1 196 198 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_2 1 3 198 198_splitncnn_0 198_splitncnn_1 198_splitncnn_2
Concat Concat_6 3 1 193_splitncnn_5 195_splitncnn_2 198_splitncnn_2 199
Convolution Conv_7 1 1 199 201 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_3 1 2 201 201_splitncnn_0 201_splitncnn_1
Concat Concat_9 4 1 193_splitncnn_4 195_splitncnn_1 198_splitncnn_1 201_splitncnn_1 202
Convolution Conv_10 1 1 202 204 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_12 5 1 193_splitncnn_3 195_splitncnn_0 198_splitncnn_0 201_splitncnn_0 204 205
Convolution Conv_13 1 1 205 206 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_16 2 1 206 193_splitncnn_2 209 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_4 1 6 209 209_splitncnn_0 209_splitncnn_1 209_splitncnn_2 209_splitncnn_3 209_splitncnn_4 209_splitncnn_5
Convolution Conv_17 1 1 209_splitncnn_5 211 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_5 1 4 211 211_splitncnn_0 211_splitncnn_1 211_splitncnn_2 211_splitncnn_3
Concat Concat_19 2 1 209_splitncnn_4 211_splitncnn_3 212
Convolution Conv_20 1 1 212 214 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_6 1 3 214 214_splitncnn_0 214_splitncnn_1 214_splitncnn_2
Concat Concat_22 3 1 209_splitncnn_3 211_splitncnn_2 214_splitncnn_2 215
Convolution Conv_23 1 1 215 217 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_7 1 2 217 217_splitncnn_0 217_splitncnn_1
Concat Concat_25 4 1 209_splitncnn_2 211_splitncnn_1 214_splitncnn_1 217_splitncnn_1 218
Convolution Conv_26 1 1 218 220 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_28 5 1 209_splitncnn_1 211_splitncnn_0 214_splitncnn_0 217_splitncnn_0 220 221
Convolution Conv_29 1 1 221 222 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_32 2 1 222 209_splitncnn_0 225 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_8 1 6 225 225_splitncnn_0 225_splitncnn_1 225_splitncnn_2 225_splitncnn_3 225_splitncnn_4 225_splitncnn_5
Convolution Conv_33 1 1 225_splitncnn_5 227 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_9 1 4 227 227_splitncnn_0 227_splitncnn_1 227_splitncnn_2 227_splitncnn_3
Concat Concat_35 2 1 225_splitncnn_4 227_splitncnn_3 228
Convolution Conv_36 1 1 228 230 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_10 1 3 230 230_splitncnn_0 230_splitncnn_1 230_splitncnn_2
Concat Concat_38 3 1 225_splitncnn_3 227_splitncnn_2 230_splitncnn_2 231
Convolution Conv_39 1 1 231 233 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_11 1 2 233 233_splitncnn_0 233_splitncnn_1
Concat Concat_41 4 1 225_splitncnn_2 227_splitncnn_1 230_splitncnn_1 233_splitncnn_1 234
Convolution Conv_42 1 1 234 236 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_44 5 1 225_splitncnn_1 227_splitncnn_0 230_splitncnn_0 233_splitncnn_0 236 237
Convolution Conv_45 1 1 237 238 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_48 2 1 238 225_splitncnn_0 241 0=1 -23301=2,2.000000e-01,1.000000e+00
Eltwise Add_51 2 1 241 193_splitncnn_1 244 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_12 1 7 244 244_splitncnn_0 244_splitncnn_1 244_splitncnn_2 244_splitncnn_3 244_splitncnn_4 244_splitncnn_5 244_splitncnn_6
Convolution Conv_52 1 1 244_splitncnn_6 246 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_13 1 4 246 246_splitncnn_0 246_splitncnn_1 246_splitncnn_2 246_splitncnn_3
Concat Concat_54 2 1 244_splitncnn_5 246_splitncnn_3 247
Convolution Conv_55 1 1 247 249 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_14 1 3 249 249_splitncnn_0 249_splitncnn_1 249_splitncnn_2
Concat Concat_57 3 1 244_splitncnn_4 246_splitncnn_2 249_splitncnn_2 250
Convolution Conv_58 1 1 250 252 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_15 1 2 252 252_splitncnn_0 252_splitncnn_1
Concat Concat_60 4 1 244_splitncnn_3 246_splitncnn_1 249_splitncnn_1 252_splitncnn_1 253
Convolution Conv_61 1 1 253 255 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_63 5 1 244_splitncnn_2 246_splitncnn_0 249_splitncnn_0 252_splitncnn_0 255 256
Convolution Conv_64 1 1 256 257 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_67 2 1 257 244_splitncnn_1 260 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_16 1 6 260 260_splitncnn_0 260_splitncnn_1 260_splitncnn_2 260_splitncnn_3 260_splitncnn_4 260_splitncnn_5
Convolution Conv_68 1 1 260_splitncnn_5 262 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_17 1 4 262 262_splitncnn_0 262_splitncnn_1 262_splitncnn_2 262_splitncnn_3
Concat Concat_70 2 1 260_splitncnn_4 262_splitncnn_3 263
Convolution Conv_71 1 1 263 265 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_18 1 3 265 265_splitncnn_0 265_splitncnn_1 265_splitncnn_2
Concat Concat_73 3 1 260_splitncnn_3 262_splitncnn_2 265_splitncnn_2 266
Convolution Conv_74 1 1 266 268 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_19 1 2 268 268_splitncnn_0 268_splitncnn_1
Concat Concat_76 4 1 260_splitncnn_2 262_splitncnn_1 265_splitncnn_1 268_splitncnn_1 269
Convolution Conv_77 1 1 269 271 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_79 5 1 260_splitncnn_1 262_splitncnn_0 265_splitncnn_0 268_splitncnn_0 271 272
Convolution Conv_80 1 1 272 273 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_83 2 1 273 260_splitncnn_0 276 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_20 1 6 276 276_splitncnn_0 276_splitncnn_1 276_splitncnn_2 276_splitncnn_3 276_splitncnn_4 276_splitncnn_5
Convolution Conv_84 1 1 276_splitncnn_5 278 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_21 1 4 278 278_splitncnn_0 278_splitncnn_1 278_splitncnn_2 278_splitncnn_3
Concat Concat_86 2 1 276_splitncnn_4 278_splitncnn_3 279
Convolution Conv_87 1 1 279 281 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_22 1 3 281 281_splitncnn_0 281_splitncnn_1 281_splitncnn_2
Concat Concat_89 3 1 276_splitncnn_3 278_splitncnn_2 281_splitncnn_2 282
Convolution Conv_90 1 1 282 284 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_23 1 2 284 284_splitncnn_0 284_splitncnn_1
Concat Concat_92 4 1 276_splitncnn_2 278_splitncnn_1 281_splitncnn_1 284_splitncnn_1 285
Convolution Conv_93 1 1 285 287 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_95 5 1 276_splitncnn_1 278_splitncnn_0 281_splitncnn_0 284_splitncnn_0 287 288
Convolution Conv_96 1 1 288 289 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_99 2 1 289 276_splitncnn_0 292 0=1 -23301=2,2.000000e-01,1.000000e+00
Eltwise Add_102 2 1 292 244_splitncnn_0 295 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_24 1 7 295 295_splitncnn_0 295_splitncnn_1 295_splitncnn_2 295_splitncnn_3 295_splitncnn_4 295_splitncnn_5 295_splitncnn_6
Convolution Conv_103 1 1 295_splitncnn_6 297 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_25 1 4 297 297_splitncnn_0 297_splitncnn_1 297_splitncnn_2 297_splitncnn_3
Concat Concat_105 2 1 295_splitncnn_5 297_splitncnn_3 298
Convolution Conv_106 1 1 298 300 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_26 1 3 300 300_splitncnn_0 300_splitncnn_1 300_splitncnn_2
Concat Concat_108 3 1 295_splitncnn_4 297_splitncnn_2 300_splitncnn_2 301
Convolution Conv_109 1 1 301 303 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_27 1 2 303 303_splitncnn_0 303_splitncnn_1
Concat Concat_111 4 1 295_splitncnn_3 297_splitncnn_1 300_splitncnn_1 303_splitncnn_1 304
Convolution Conv_112 1 1 304 306 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_114 5 1 295_splitncnn_2 297_splitncnn_0 300_splitncnn_0 303_splitncnn_0 306 307
Convolution Conv_115 1 1 307 308 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_118 2 1 308 295_splitncnn_1 311 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_28 1 6 311 311_splitncnn_0 311_splitncnn_1 311_splitncnn_2 311_splitncnn_3 311_splitncnn_4 311_splitncnn_5
Convolution Conv_119 1 1 311_splitncnn_5 313 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_29 1 4 313 313_splitncnn_0 313_splitncnn_1 313_splitncnn_2 313_splitncnn_3
Concat Concat_121 2 1 311_splitncnn_4 313_splitncnn_3 314
Convolution Conv_122 1 1 314 316 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_30 1 3 316 316_splitncnn_0 316_splitncnn_1 316_splitncnn_2
Concat Concat_124 3 1 311_splitncnn_3 313_splitncnn_2 316_splitncnn_2 317
Convolution Conv_125 1 1 317 319 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_31 1 2 319 319_splitncnn_0 319_splitncnn_1
Concat Concat_127 4 1 311_splitncnn_2 313_splitncnn_1 316_splitncnn_1 319_splitncnn_1 320
Convolution Conv_128 1 1 320 322 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_130 5 1 311_splitncnn_1 313_splitncnn_0 316_splitncnn_0 319_splitncnn_0 322 323
Convolution Conv_131 1 1 323 324 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_134 2 1 324 311_splitncnn_0 327 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_32 1 6 327 327_splitncnn_0 327_splitncnn_1 327_splitncnn_2 327_splitncnn_3 327_splitncnn_4 327_splitncnn_5
Convolution Conv_135 1 1 327_splitncnn_5 329 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_33 1 4 329 329_splitncnn_0 329_splitncnn_1 329_splitncnn_2 329_splitncnn_3
Concat Concat_137 2 1 327_splitncnn_4 329_splitncnn_3 330
Convolution Conv_138 1 1 330 332 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_34 1 3 332 332_splitncnn_0 332_splitncnn_1 332_splitncnn_2
Concat Concat_140 3 1 327_splitncnn_3 329_splitncnn_2 332_splitncnn_2 333
Convolution Conv_141 1 1 333 335 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_35 1 2 335 335_splitncnn_0 335_splitncnn_1
Concat Concat_143 4 1 327_splitncnn_2 329_splitncnn_1 332_splitncnn_1 335_splitncnn_1 336
Convolution Conv_144 1 1 336 338 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_146 5 1 327_splitncnn_1 329_splitncnn_0 332_splitncnn_0 335_splitncnn_0 338 339
Convolution Conv_147 1 1 339 340 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_150 2 1 340 327_splitncnn_0 343 0=1 -23301=2,2.000000e-01,1.000000e+00
Eltwise Add_153 2 1 343 295_splitncnn_0 346 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_36 1 7 346 346_splitncnn_0 346_splitncnn_1 346_splitncnn_2 346_splitncnn_3 346_splitncnn_4 346_splitncnn_5 346_splitncnn_6
Convolution Conv_154 1 1 346_splitncnn_6 348 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_37 1 4 348 348_splitncnn_0 348_splitncnn_1 348_splitncnn_2 348_splitncnn_3
Concat Concat_156 2 1 346_splitncnn_5 348_splitncnn_3 349
Convolution Conv_157 1 1 349 351 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_38 1 3 351 351_splitncnn_0 351_splitncnn_1 351_splitncnn_2
Concat Concat_159 3 1 346_splitncnn_4 348_splitncnn_2 351_splitncnn_2 352
Convolution Conv_160 1 1 352 354 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_39 1 2 354 354_splitncnn_0 354_splitncnn_1
Concat Concat_162 4 1 346_splitncnn_3 348_splitncnn_1 351_splitncnn_1 354_splitncnn_1 355
Convolution Conv_163 1 1 355 357 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_165 5 1 346_splitncnn_2 348_splitncnn_0 351_splitncnn_0 354_splitncnn_0 357 358
Convolution Conv_166 1 1 358 359 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_169 2 1 359 346_splitncnn_1 362 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_40 1 6 362 362_splitncnn_0 362_splitncnn_1 362_splitncnn_2 362_splitncnn_3 362_splitncnn_4 362_splitncnn_5
Convolution Conv_170 1 1 362_splitncnn_5 364 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_41 1 4 364 364_splitncnn_0 364_splitncnn_1 364_splitncnn_2 364_splitncnn_3
Concat Concat_172 2 1 362_splitncnn_4 364_splitncnn_3 365
Convolution Conv_173 1 1 365 367 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_42 1 3 367 367_splitncnn_0 367_splitncnn_1 367_splitncnn_2
Concat Concat_175 3 1 362_splitncnn_3 364_splitncnn_2 367_splitncnn_2 368
Convolution Conv_176 1 1 368 370 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_43 1 2 370 370_splitncnn_0 370_splitncnn_1
Concat Concat_178 4 1 362_splitncnn_2 364_splitncnn_1 367_splitncnn_1 370_splitncnn_1 371
Convolution Conv_179 1 1 371 373 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_181 5 1 362_splitncnn_1 364_splitncnn_0 367_splitncnn_0 370_splitncnn_0 373 374
Convolution Conv_182 1 1 374 375 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_185 2 1 375 362_splitncnn_0 378 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_44 1 6 378 378_splitncnn_0 378_splitncnn_1 378_splitncnn_2 378_splitncnn_3 378_splitncnn_4 378_splitncnn_5
Convolution Conv_186 1 1 378_splitncnn_5 380 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_45 1 4 380 380_splitncnn_0 380_splitncnn_1 380_splitncnn_2 380_splitncnn_3
Concat Concat_188 2 1 378_splitncnn_4 380_splitncnn_3 381
Convolution Conv_189 1 1 381 383 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_46 1 3 383 383_splitncnn_0 383_splitncnn_1 383_splitncnn_2
Concat Concat_191 3 1 378_splitncnn_3 380_splitncnn_2 383_splitncnn_2 384
Convolution Conv_192 1 1 384 386 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_47 1 2 386 386_splitncnn_0 386_splitncnn_1
Concat Concat_194 4 1 378_splitncnn_2 380_splitncnn_1 383_splitncnn_1 386_splitncnn_1 387
Convolution Conv_195 1 1 387 389 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_197 5 1 378_splitncnn_1 380_splitncnn_0 383_splitncnn_0 386_splitncnn_0 389 390
Convolution Conv_198 1 1 390 391 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_201 2 1 391 378_splitncnn_0 394 0=1 -23301=2,2.000000e-01,1.000000e+00
Eltwise Add_204 2 1 394 346_splitncnn_0 397 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_48 1 7 397 397_splitncnn_0 397_splitncnn_1 397_splitncnn_2 397_splitncnn_3 397_splitncnn_4 397_splitncnn_5 397_splitncnn_6
Convolution Conv_205 1 1 397_splitncnn_6 399 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_49 1 4 399 399_splitncnn_0 399_splitncnn_1 399_splitncnn_2 399_splitncnn_3
Concat Concat_207 2 1 397_splitncnn_5 399_splitncnn_3 400
Convolution Conv_208 1 1 400 402 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_50 1 3 402 402_splitncnn_0 402_splitncnn_1 402_splitncnn_2
Concat Concat_210 3 1 397_splitncnn_4 399_splitncnn_2 402_splitncnn_2 403
Convolution Conv_211 1 1 403 405 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_51 1 2 405 405_splitncnn_0 405_splitncnn_1
Concat Concat_213 4 1 397_splitncnn_3 399_splitncnn_1 402_splitncnn_1 405_splitncnn_1 406
Convolution Conv_214 1 1 406 408 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_216 5 1 397_splitncnn_2 399_splitncnn_0 402_splitncnn_0 405_splitncnn_0 408 409
Convolution Conv_217 1 1 409 410 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_220 2 1 410 397_splitncnn_1 413 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_52 1 6 413 413_splitncnn_0 413_splitncnn_1 413_splitncnn_2 413_splitncnn_3 413_splitncnn_4 413_splitncnn_5
Convolution Conv_221 1 1 413_splitncnn_5 415 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_53 1 4 415 415_splitncnn_0 415_splitncnn_1 415_splitncnn_2 415_splitncnn_3
Concat Concat_223 2 1 413_splitncnn_4 415_splitncnn_3 416
Convolution Conv_224 1 1 416 418 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_54 1 3 418 418_splitncnn_0 418_splitncnn_1 418_splitncnn_2
Concat Concat_226 3 1 413_splitncnn_3 415_splitncnn_2 418_splitncnn_2 419
Convolution Conv_227 1 1 419 421 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_55 1 2 421 421_splitncnn_0 421_splitncnn_1
Concat Concat_229 4 1 413_splitncnn_2 415_splitncnn_1 418_splitncnn_1 421_splitncnn_1 422
Convolution Conv_230 1 1 422 424 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_232 5 1 413_splitncnn_1 415_splitncnn_0 418_splitncnn_0 421_splitncnn_0 424 425
Convolution Conv_233 1 1 425 426 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_236 2 1 426 413_splitncnn_0 429 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_56 1 6 429 429_splitncnn_0 429_splitncnn_1 429_splitncnn_2 429_splitncnn_3 429_splitncnn_4 429_splitncnn_5
Convolution Conv_237 1 1 429_splitncnn_5 431 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_57 1 4 431 431_splitncnn_0 431_splitncnn_1 431_splitncnn_2 431_splitncnn_3
Concat Concat_239 2 1 429_splitncnn_4 431_splitncnn_3 432
Convolution Conv_240 1 1 432 434 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_58 1 3 434 434_splitncnn_0 434_splitncnn_1 434_splitncnn_2
Concat Concat_242 3 1 429_splitncnn_3 431_splitncnn_2 434_splitncnn_2 435
Convolution Conv_243 1 1 435 437 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_59 1 2 437 437_splitncnn_0 437_splitncnn_1
Concat Concat_245 4 1 429_splitncnn_2 431_splitncnn_1 434_splitncnn_1 437_splitncnn_1 438
Convolution Conv_246 1 1 438 440 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_248 5 1 429_splitncnn_1 431_splitncnn_0 434_splitncnn_0 437_splitncnn_0 440 441
Convolution Conv_249 1 1 441 442 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_252 2 1 442 429_splitncnn_0 445 0=1 -23301=2,2.000000e-01,1.000000e+00
Eltwise Add_255 2 1 445 397_splitncnn_0 448 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_60 1 7 448 448_splitncnn_0 448_splitncnn_1 448_splitncnn_2 448_splitncnn_3 448_splitncnn_4 448_splitncnn_5 448_splitncnn_6
Convolution Conv_256 1 1 448_splitncnn_6 450 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_61 1 4 450 450_splitncnn_0 450_splitncnn_1 450_splitncnn_2 450_splitncnn_3
Concat Concat_258 2 1 448_splitncnn_5 450_splitncnn_3 451
Convolution Conv_259 1 1 451 453 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_62 1 3 453 453_splitncnn_0 453_splitncnn_1 453_splitncnn_2
Concat Concat_261 3 1 448_splitncnn_4 450_splitncnn_2 453_splitncnn_2 454
Convolution Conv_262 1 1 454 456 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_63 1 2 456 456_splitncnn_0 456_splitncnn_1
Concat Concat_264 4 1 448_splitncnn_3 450_splitncnn_1 453_splitncnn_1 456_splitncnn_1 457
Convolution Conv_265 1 1 457 459 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_267 5 1 448_splitncnn_2 450_splitncnn_0 453_splitncnn_0 456_splitncnn_0 459 460
Convolution Conv_268 1 1 460 461 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_271 2 1 461 448_splitncnn_1 464 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_64 1 6 464 464_splitncnn_0 464_splitncnn_1 464_splitncnn_2 464_splitncnn_3 464_splitncnn_4 464_splitncnn_5
Convolution Conv_272 1 1 464_splitncnn_5 466 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_65 1 4 466 466_splitncnn_0 466_splitncnn_1 466_splitncnn_2 466_splitncnn_3
Concat Concat_274 2 1 464_splitncnn_4 466_splitncnn_3 467
Convolution Conv_275 1 1 467 469 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_66 1 3 469 469_splitncnn_0 469_splitncnn_1 469_splitncnn_2
Concat Concat_277 3 1 464_splitncnn_3 466_splitncnn_2 469_splitncnn_2 470
Convolution Conv_278 1 1 470 472 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_67 1 2 472 472_splitncnn_0 472_splitncnn_1
Concat Concat_280 4 1 464_splitncnn_2 466_splitncnn_1 469_splitncnn_1 472_splitncnn_1 473
Convolution Conv_281 1 1 473 475 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_283 5 1 464_splitncnn_1 466_splitncnn_0 469_splitncnn_0 472_splitncnn_0 475 476
Convolution Conv_284 1 1 476 477 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_287 2 1 477 464_splitncnn_0 480 0=1 -23301=2,2.000000e-01,1.000000e+00
Split splitncnn_68 1 6 480 480_splitncnn_0 480_splitncnn_1 480_splitncnn_2 480_splitncnn_3 480_splitncnn_4 480_splitncnn_5
Convolution Conv_288 1 1 480_splitncnn_5 482 0=32 1=3 4=1 5=1 6=18432 9=2 -23310=1,2.000000e-01
Split splitncnn_69 1 4 482 482_splitncnn_0 482_splitncnn_1 482_splitncnn_2 482_splitncnn_3
Concat Concat_290 2 1 480_splitncnn_4 482_splitncnn_3 483
Convolution Conv_291 1 1 483 485 0=32 1=3 4=1 5=1 6=27648 9=2 -23310=1,2.000000e-01
Split splitncnn_70 1 3 485 485_splitncnn_0 485_splitncnn_1 485_splitncnn_2
Concat Concat_293 3 1 480_splitncnn_3 482_splitncnn_2 485_splitncnn_2 486
Convolution Conv_294 1 1 486 488 0=32 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Split splitncnn_71 1 2 488 488_splitncnn_0 488_splitncnn_1
Concat Concat_296 4 1 480_splitncnn_2 482_splitncnn_1 485_splitncnn_1 488_splitncnn_1 489
Convolution Conv_297 1 1 489 491 0=32 1=3 4=1 5=1 6=46080 9=2 -23310=1,2.000000e-01
Concat Concat_299 5 1 480_splitncnn_1 482_splitncnn_0 485_splitncnn_0 488_splitncnn_0 491 492
Convolution Conv_300 1 1 492 493 0=64 1=3 4=1 5=1 6=110592
Eltwise Add_303 2 1 493 480_splitncnn_0 496 0=1 -23301=2,2.000000e-01,1.000000e+00
Eltwise Add_306 2 1 496 448_splitncnn_0 499 0=1 -23301=2,2.000000e-01,1.000000e+00
Convolution Conv_307 1 1 499 500 0=64 1=3 4=1 5=1 6=36864
BinaryOp Add_308 2 1 193_splitncnn_0 500 501
Interp Resize_310 1 1 501 506 0=1 1=2.000000e+00 2=2.000000e+00
Convolution Conv_311 1 1 506 508 0=64 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Interp Resize_314 1 1 508 513 0=1 1=2.000000e+00 2=2.000000e+00
Convolution Conv_315 1 1 513 515 0=64 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Convolution Conv_317 1 1 515 517 0=64 1=3 4=1 5=1 6=36864 9=2 -23310=1,2.000000e-01
Convolution Conv_319 1 1 517 output 0=3 1=3 4=1 5=1 6=1728

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,12 @@
{
"album_image": "",
"blur": 0.0,
"color": "",
"id": "11E13EB0-8293-4aad-AE6C-906B269D852C",
"image": "",
"image_id": "",
"image_name": "",
"source_platform": 0,
"team_id": "",
"type": "canvas_color"
}

View File

@ -0,0 +1,38 @@
{
"id": "01FEF79C-875B-4215-B35B-686620E4FC5F",
"keyframe_list": [
{
"curveType": "Line",
"graphID": "",
"left_control": {
"x": 0.0,
"y": 0.0
},
"right_control": {
"x": 0.0,
"y": 0.0
},
"time_offset": 0,
"values": [
1.0
]
},
{
"curveType": "Line",
"graphID": "",
"left_control": {
"x": 0.0,
"y": 0.0
},
"right_control": {
"x": 0.0,
"y": 0.0
},
"time_offset": 8550000,
"values": [
1.5
]
}
],
"property_type": "KFTypeScaleX"
}

View File

@ -0,0 +1,5 @@
{
"animations": [],
"id": "D4838202-E39A-4e74-A2D2-B3C16C9EF587",
"type": "sticker_animation"
}

View File

@ -0,0 +1,112 @@
{
"add_type": 0,
"alignment": 1,
"background_alpha": 1.0,
"background_color": "",
"background_height": 0.14,
"background_horizontal_offset": 0.0,
"background_round_radius": 0.0,
"background_style": 0,
"background_vertical_offset": 0.0,
"background_width": 0.14,
"bold_width": 0.0,
"border_alpha": 1.0,
"border_color": "",
"border_width": 0.08,
"caption_template_info": {
"category_id": "",
"category_name": "",
"effect_id": "",
"resource_id": "",
"resource_name": ""
},
"check_flag": 7,
"combo_info": {
"text_templates": []
},
"content": "{\"text\":\"251525234\"}",
"fixed_height": -1.0,
"fixed_width": -1.0,
"font_category_id": "",
"font_category_name": "",
"font_id": "",
"font_name": "",
"font_path": "",
"font_resource_id": "",
"font_size": 7,
"font_source_platform": 0,
"font_team_id": "",
"font_title": "none",
"font_url": "",
"fonts": [{
"category_id": "",
"category_name": "",
"effect_id": "6740435892441190919",
"file_uri": "",
"id": "",
"path": "",
"request_id": "",
"resource_id": "6740435892441190919",
"source_platform": 0,
"team_id": "",
"title": ""
}],
"force_apply_line_max_width": false,
"global_alpha": 1.0,
"group_id": "",
"has_shadow": false,
"id": "5B91D2ED-4A1A-40e5-87BE-0713ECDA74BA",
"initial_scale": 1.0,
"is_rich_text": false,
"italic_degree": 0,
"ktv_color": "",
"language": "",
"layer_weight": 1,
"letter_spacing": 0.0,
"line_feed": 1,
"line_max_width": 0.82,
"line_spacing": 0.02,
"name": "",
"original_size": [],
"preset_category": "",
"preset_category_id": "",
"preset_has_set_alignment": false,
"preset_id": "",
"preset_index": 0,
"preset_name": "",
"recognize_task_id": "",
"recognize_type": 0,
"relevance_segment": [],
"shadow_alpha": 0.8,
"shadow_angle": -45.0,
"shadow_color": "",
"shadow_distance": 8.0,
"shadow_point": {
"x": 1.0182337649086284,
"y": -1.0182337649086284
},
"shadow_smoothing": 1.0,
"shape_clip_x": false,
"shape_clip_y": false,
"style_name": "",
"sub_type": 0,
"subtitle_keywords": null,
"text_alpha": 1.0,
"text_color": "#FFFFFF",
"text_curve": null,
"text_preset_resource_id": "",
"text_size": 30,
"text_to_audio_ids": [],
"tts_auto_update": false,
"type": "subtitle",
"typesetting": 0,
"underline": false,
"underline_offset": 0.22,
"underline_width": 0.05,
"use_effect_default_color": false,
"words": {
"end_time": [],
"start_time": [],
"text": []
}
}

View File

@ -0,0 +1,35 @@
{
"app_id": 0,
"category_id": "",
"category_name": "",
"check_flag": 1,
"duration": 864600000,
"effect_id": "",
"formula_id": "",
"id": "B3C79950-E268-4ea8-80FF-D749FF93E4DE",
"intensifies_path": "",
"is_ai_clone_tone": false,
"is_ugc": false,
"local_material_id": "",
"music_id": "",
"name": "1705933173091_7a573b60-2af6-4b43-a3ef-46c715300468.wav",
"path": "D:/AI 推文/QQ/无辜领证/1705933173091_7a573b60-2af6-4b43-a3ef-46c715300468.wav",
"query": "",
"request_id": "",
"resource_id": "",
"search_id": "",
"source_platform": 0,
"team_id": "",
"text_id": "",
"tone_category_id": "",
"tone_category_name": "",
"tone_effect_id": "",
"tone_effect_name": "",
"tone_second_category_id": "",
"tone_second_category_name": "",
"tone_speaker": "",
"tone_type": "",
"type": "extract_music",
"video_id": "",
"wave_points": []
}

View File

@ -0,0 +1,20 @@
{
"ai_beats": {
"beat_speed_infos": [],
"beats_path": "",
"beats_url": "",
"melody_path": "",
"melody_percents": [
0.0
],
"melody_url": ""
},
"enable_ai_beats": false,
"gear": 404,
"gear_count": 0,
"id": "252D7F03-8B76-4774-AC5F-43FF9A7A0303",
"mode": 404,
"type": "beats",
"user_beats": [],
"user_delete_ai_beats": null
}

View File

@ -0,0 +1,6 @@
{
"audio_channel_mapping": 0,
"id": "0873DEFB-B955-407a-893E-E063225859E7",
"is_config_open": false,
"type": "none"
}

View File

@ -0,0 +1,7 @@
{
"curve_speed": null,
"id": "DF733765-6514-445e-BFF2-EA5079DDC564",
"mode": 0,
"speed": 1.0,
"type": "speed"
}

View File

@ -0,0 +1,63 @@
{
"cartoon": false,
"clip": {
"alpha": 1.0,
"flip": {
"horizontal": false,
"vertical": false
},
"rotation": 0.0,
"scale": {
"x": 1.0,
"y": 1.0
},
"transform": {
"x": 0.0,
"y": 0.0
}
},
"common_keyframes": [],
"enable_adjust": false,
"enable_color_curves": true,
"enable_color_match_adjust": false,
"enable_color_wheels": true,
"enable_lut": false,
"enable_smart_color_adjust": false,
"extra_material_refs": [
"D4838202-E39A-4e74-A2D2-B3C16C9EF587"
],
"group_id": "",
"hdr_settings": null,
"id": "F130A2DC-B22A-42ba-970D-38BDEE08F2AE",
"intensifies_audio": false,
"is_placeholder": false,
"is_tone_modify": false,
"keyframe_refs": [],
"last_nonzero_volume": 1.0,
"material_id": "5B91D2ED-4A1A-40e5-87BE-0713ECDA74BA",
"render_index": 14002,
"responsive_layout": {
"enable": false,
"horizontal_pos_layout": 0,
"size_layout": 0,
"target_follow": "",
"vertical_pos_layout": 0
},
"reverse": false,
"source_timerange": null,
"speed": 1.0,
"target_timerange": {
"duration": 3000000,
"start": 0
},
"template_id": "",
"template_scene": "default",
"track_attribute": 0,
"track_render_index": 0,
"uniform_scale": {
"on": true,
"value": 1.0
},
"visible": true,
"volumn": 1.0
}

View File

@ -0,0 +1,51 @@
{
"cartoon": false,
"clip": null,
"common_keyframes": [],
"enable_adjust": false,
"enable_color_curves": true,
"enable_color_match_adjust": false,
"enable_color_wheels": true,
"enable_lut": false,
"enable_smart_color_adjust": false,
"extra_material_refs": [
"45268E0D-9136-43e2-939E-5F2C23E3569A",
"252D7F03-8B76-4774-AC5F-43FF9A7A0303",
"2629569D-3A20-41ba-A41A-AD617BA9E404",
"8D5BF8F3-6AF8-4bb3-84B7-04E3A86CE300"
],
"group_id": "",
"hdr_settings": null,
"id": "A210B2A7-ED82-43c1-B159-9D849290593E",
"intensifies_audio": false,
"is_placeholder": false,
"is_tone_modify": false,
"keyframe_refs": [],
"last_nonzero_volume": 1.0,
"material_id": "B3C79950-E268-4ea8-80FF-D749FF93E4DE",
"render_index": 0,
"responsive_layout": {
"enable": false,
"horizontal_pos_layout": 0,
"size_layout": 0,
"target_follow": "",
"vertical_pos_layout": 0
},
"reverse": false,
"source_timerange": {
"duration": 864600000,
"start": 0
},
"speed": 1.0,
"target_timerange": {
"duration": 864600000,
"start": 0
},
"template_id": "",
"template_scene": "default",
"track_attribute": 0,
"track_render_index": 0,
"uniform_scale": null,
"visible": true,
"volumn": 1.0
}

View File

@ -0,0 +1,73 @@
{
"cartoon": false,
"clip": {
"alpha": 1.0,
"flip": {
"horizontal": false,
"vertical": false
},
"rotation": 0.0,
"scale": {
"x": 1.0,
"y": 1.0
},
"transform": {
"x": 0.0,
"y": 0.0
}
},
"common_keyframes": [],
"enable_adjust": true,
"enable_color_curves": true,
"enable_color_match_adjust": false,
"enable_color_wheels": true,
"enable_lut": true,
"enable_smart_color_adjust": false,
"extra_material_refs": [
"DF733765-6514-445e-BFF2-EA5079DDC564",
"11E13EB0-8293-4aad-AE6C-906B269D852C",
"0873DEFB-B955-407a-893E-E063225859E7",
"4DD7DFFE-CFD9-4e0b-8890-56C7450677EA"
],
"group_id": "",
"hdr_settings": {
"intensity": 1.0,
"mode": 1,
"nits": 1000
},
"id": "2B8043D9-1EEB-48da-A136-B38F3816611E",
"intensifies_audio": false,
"is_placeholder": false,
"is_tone_modify": false,
"keyframe_refs": [],
"last_nonzero_volume": 1.0,
"material_id": "7BE6192E-90BC-421f-AE0D-2323D81008D8",
"render_index": 0,
"responsive_layout": {
"enable": false,
"horizontal_pos_layout": 0,
"size_layout": 0,
"target_follow": "",
"vertical_pos_layout": 0
},
"reverse": false,
"source_timerange": {
"duration": 5000000,
"start": 0
},
"speed": 1.0,
"target_timerange": {
"duration": 5000000,
"start": 0
},
"template_id": "",
"template_scene": "default",
"track_attribute": 0,
"track_render_index": 0,
"uniform_scale": {
"on": true,
"value": 1.0
},
"visible": true,
"volumn": 1.0
}

View File

@ -0,0 +1,9 @@
{
"attribute": 0,
"flag": 0,
"id": "3F5F37A4-C6DF-4d51-9C68-11F472889B1D",
"is_default_name": true,
"name": "",
"segments": [],
"type": "video"
}

View File

@ -0,0 +1,78 @@
{
"aigc_type": "none",
"audio_fade": null,
"cartoon_path": "",
"category_id": "",
"category_name": "",
"check_flag": 63487,
"crop": {
"lower_left_x": 0.0,
"lower_left_y": 1.0,
"lower_right_x": 1.0,
"lower_right_y": 1.0,
"upper_left_x": 0.0,
"upper_left_y": 0.0,
"upper_right_x": 1.0,
"upper_right_y": 0.0
},
"crop_ratio": "free",
"crop_scale": 1.0,
"duration": 10800000000,
"extra_type_option": 0,
"formula_id": "",
"freeze": null,
"gameplay": null,
"has_audio": false,
"height": 1000,
"id": "7BE6192E-90BC-421f-AE0D-2323D81008D8",
"intensifies_audio_path": "",
"intensifies_path": "",
"is_ai_generate_content": false,
"is_unified_beauty_mode": false,
"local_id": "",
"local_material_id": "",
"material_id": "",
"material_name": "00001.png",
"material_url": "",
"matting": {
"flag": 0,
"has_use_quick_brush": false,
"has_use_quick_eraser": false,
"interactiveTime": [],
"path": "",
"strokes": []
},
"media_path": "",
"object_locked": null,
"origin_material_id": "",
"path": "D:/AI 推文/番茄小说/如画室友/03/tmp/input_crop/00001.png",
"picture_from": "none",
"picture_set_category_id": "",
"picture_set_category_name": "",
"request_id": "",
"reverse_intensifies_path": "",
"reverse_path": "",
"smart_motion": null,
"source": 0,
"source_platform": 0,
"stable": {
"matrix_path": "",
"stable_level": 0,
"time_range": {
"duration": 0,
"start": 0
}
},
"team_id": "",
"type": "photo",
"video_algorithm": {
"algorithms": [],
"deflicker": null,
"motion_blur_config": null,
"noise_reduction": null,
"path": "",
"quality_enhance": null,
"time_range": null
},
"width": 1000
}

View File

@ -0,0 +1,7 @@
{
"choice": 0,
"id": "4DD7DFFE-CFD9-4e0b-8890-56C7450677EA",
"production_path": "",
"time_range": null,
"type": "vocal_separation"
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,28 @@
{
"draft_path": "你的剪映草稿地址",
"project_path": "你的项目文件地址(存放图片视频等数据的文件夹)",
"project_name": "你的项目名字",
"gpt_business": "b44c6f24-59e4-4a71-b2c7-3df0c4e35e65",
"gpt_model": "gpt-3.5-turbo",
"task_number": 1,
"translation_business": "https://fanyi-api.baidu.com/api/trans/vip/translate",
"translation_app_id": "1234",
"translation_secret": "2234",
"translation_auto": true,
"theme": "light",
"gpt_auto_inference": "storyFirst",
"webui_api_url": "你的SD地址后面要加/",
"gpt_count": 8,
"customize_gpt_prompt": "a93b693e-bb3f-406d-9730-cba43a6585a2",
"character_select_model": "drop",
"image_generate_category": "mj",
"window_wh_bm_remember": false,
"window_wh_bm": {
"x": 1699,
"y": 230,
"width": 1936,
"height": 1048
},
"space_image": "C:\\Users\\27698\\Desktop\\LAITool\\resources\\image\\zhanwei.png",
"gpt_key": "gptkey"
}

View File

@ -0,0 +1,31 @@
{
"interactive_mode": "auto",
"webui_api_url": "",
"type": "img2img",
"seed": -1,
"resize": {
"scale": 1.0
},
"crop": 1,
"inpaint": false,
"mask_mode": "transparent-background-fast",
"mask_bg_mode": "#ffffff",
"tag": {
"enable": true,
"mode": ""
},
"overlay": true,
"workspace": {
"input": "input",
"output": "output",
"tmp": {
"parent": "tmp",
"input_crop": "input_crop",
"output_crop": "output_crop",
"input_tag": "input_crop",
"input_mask": "input_mask",
"input_crop_mask": "input_crop_mask",
"crop_info": "crop_info.txt"
}
}
}

View File

@ -0,0 +1,58 @@
{
"workspace": "C:\\Users\\27698\\Desktop\\测试",
"setting": {
"type": "txt2img",
"resize": {
"scale": 1
},
"crop": 1,
"webui_api_url": "",
"seed": -1,
"inpaint": false,
"mask_mode": "transparent-background",
"mask_bg_mode": "#ffffff",
"overlay": true,
"batch_size": 4
},
"tag": {
"enable": true,
"mode": "action",
"actions": [
"closed eyes",
"closed mouth",
"from behind",
"smile",
"looking at viewer",
"side",
"upper body",
"covering mouth",
"covering face"
],
"badPrompt": "chinese_text,japanese_text,korean_text,dark_skin,dark-skinned_male,yukata,kimono,large_tsukioka_kogane,collarbone,artist_name,open_clothes,bare_shoulders,subtitled,off_shoulder,hair_bun,single_hair_bun,hakama_skirt,hakama,black_hakama,katana,breasts,blush,hanfu,closed_mouth,closed_eyes,underwear,cleavage,bra,realistic,earrings,torii,strapless"
},
"webui": {
"prompt": "",
"negative_prompt": "",
"denoising_strength": 1,
"cfg_scale": 5,
"sampler_name": "DPM++ 2M Karras",
"steps": 15,
"width": 800,
"height": 800,
"adetailer": true,
"batch_size": 1
},
"config": {
"setting": "img_base.json"
},
"adetailer": [
{
"ad_confidence": 0.7,
"ad_model": "face_yolov8n.pt"
},
{
"ad_confidence": 0.7,
"ad_model": "hand_yolov8n.pt"
}
]
}

File diff suppressed because one or more lines are too long

Binary file not shown.

BIN
resources/tmp/temp.7z Normal file

Binary file not shown.

224
src/define/Tools/common.ts Normal file
View File

@ -0,0 +1,224 @@
import { escapeRegExp, isEmpty } from 'lodash'
//#region 检查字符串中是不是包含中文或者标点符号
/**
*
* @param str
* @returns truefalse
*/
export function ContainsChineseOrPunctuation(str: string): boolean {
return /[\u4e00-\u9fa5]|[\u3000-\u301e\u2013\u2014\u2018\u2019\u201c\u201d\u2026\u203b\uff08\uff09\uff1a\uff1b\uff1f\uff01\uff0c\u3001\uff0e\u3002\uff1f\uff01\u2018\u2019\u201c\u201d]/.test(
str
)
}
//#endregion
//#region 通用的失败重试函数
/**
*
* @param fn
* @param retries
* @param delay
* @returns
*/
export async function RetryWithBackoff<T>(
fn: () => Promise<T>,
retries: number = 5,
delay: number = 2000
): Promise<T> {
let attempts = 0
while (attempts < retries) {
try {
return await fn()
} catch (error: any) {
attempts++
// 这边记下日志吧
global.logger.error(
fn.name + '_RetryWithBackoff',
`${attempts} 请求失败,开始下一次重试,失败信息如下:` + error.toString()
)
if (attempts >= retries) {
throw new Error(`失败次数超过 ${retries} 错误信息如下: ${error.message}`)
}
await new Promise((resolve) => setTimeout(resolve, delay))
}
}
throw new Error('所有重试失败') // 理论上不会到达这里
}
//#endregion
//#region 并发执行任务(控制同时执行的任务数)
/**
*
* @param tasks
* @param concurrentCount
* @returns
*/
export async function ExecuteConcurrently(
tasks: Array<() => Promise<any>>,
concurrentCount: number
): Promise<any[]> {
let activeTasks: Array<Promise<any>> = []
let results: Array<Promise<any>> = []
while (tasks.length > 0) {
if (activeTasks.length < concurrentCount) {
let task: any = tasks.shift()
let promise = task()
.then((result) => {
activeTasks = activeTasks.filter((t) => t !== promise)
return result
})
.catch((error) => {
// 抛出任务,停止所有的任务
tasks.length = 0
throw error
})
activeTasks.push(promise)
results.push(promise)
} else {
await Promise.race(activeTasks)
}
}
return Promise.all(results)
}
//#endregion
//#region 替换主字符串中的子字符串
/**
*
* @param mainString
* @param substringArray
* @returns
*/
export function ReplaceSubstrings(
mainString: string,
substringArray: string[],
replacement: string = ' '
): string {
// 按长度降序排序子字符串数组,以确保较长的子字符串先被替换
substringArray.sort((a, b) => b.length - a.length)
// 对每个子字符串进行替换
for (const substring of substringArray) {
// 创建一个正则表达式,用于全局匹配子字符串
const regex = new RegExp(escapeRegExp(substring), 'g')
// 将匹配到的子字符串替换为等长的空格
mainString = mainString.replace(regex, replacement)
}
return mainString
}
//#endregion
//#region 获取url的基础地址
/**
* url的基础地址
* @param url url地址
* @returns
*/
export function GetBaseUrl(url: string): string {
if (isEmpty(url)) {
throw new Error('url不能为空')
}
// 判断是不是一个合法的url
if (!url.startsWith('http')) {
throw new Error('一个合法的url请求地址')
}
const parsedUrl = new URL(url)
return `${parsedUrl.protocol}//${parsedUrl.host}`
}
//#endregion
//#region 通用的下载完网络图片
/**
*
* @param url
* @param localPath
* @returns
*/
export async function DownloadFile(url: string, localPath?: string): Promise<void> {
if (typeof window !== 'undefined' && window.document) {
// 浏览器环境
const response = await fetch(url)
if (!response.body) {
throw new Error('浏览器不支持流式下载')
}
const reader = response.body.getReader()
// const contentLength = +response.headers.get('Content-Length')!
let receivedLength = 0
const chunks: any[] = []
while (true) {
const { done, value } = await reader.read()
if (done) break
chunks.push(value)
receivedLength += value.length
// 可以在这里更新进度,比如:
// console.log(`已接收 ${receivedLength} / ${contentLength}`);
}
const blob = new Blob(chunks)
const link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = localPath || 'downloaded_file'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(link.href)
} else {
// Node.js 环境
const fs = require('fs')
const { pipeline } = require('stream')
const { promisify } = require('util')
const path = require('path')
const https = require('https')
const http = require('http')
const urlObj = new URL(url)
const filePath = localPath || path.basename(url)
const protocol = urlObj.protocol === 'https:' ? https : http
const streamPipeline = promisify(pipeline)
const response = await new Promise((resolve, reject) => {
protocol
.get(url, (res) => {
if (res.statusCode === 200) {
resolve(res)
} else {
reject(new Error(`请求失败,状态码:${res.statusCode}`))
}
})
.on('error', reject)
})
await streamPipeline(response, fs.createWriteStream(filePath))
}
}
//#endregion
//#region 通用文件操作可以在node和浏览器环境中使用
/**
* basename
* @param filePath
* @returns
*/
export function GetFileBasename(filePath: string): string {
if (isEmpty(filePath)) {
throw new Error('filePath is empty, must be a valid file path')
}
const baseName = filePath.split('/').pop()?.split('\\').pop() ?? ''
if (isEmpty(baseName)) {
throw new Error('filePath is empty, must be a valid file path')
}
return baseName
}
//#endregion

353
src/define/Tools/file.ts Normal file
View File

@ -0,0 +1,353 @@
import fs from 'fs'
import { isEmpty } from 'lodash'
import path from 'path'
import util from 'util'
import { exec } from 'child_process'
const execAsync = util.promisify(exec)
const fspromises = fs.promises
/**
*
* @param {*} path
* @returns true表示存在false表示不存在
*/
export async function CheckFileOrDirExist(filePath) {
try {
let newFilePath = path.resolve(filePath)
await fspromises.access(newFilePath)
return true // 文件或目录存在
} catch (error) {
return false // 文件或目录不存在
}
}
// 检查文件夹是不是存在,不存在的话,创建
export async function CheckFolderExistsOrCreate(folderPath) {
try {
if (!(await CheckFileOrDirExist(folderPath))) {
await fspromises.mkdir(folderPath, { recursive: true })
}
} catch (error) {
throw error
}
}
/**
*
* @param {*} rootPath
* @param {*} subPath
* @returns
*/
export function JoinPath(rootPath: string, subPath: string | null): string | undefined {
// 判断第二个地址是不是存在不存在返回null存在返回拼接后的地址
if (subPath && !isEmpty(subPath)) {
return path.resolve(rootPath, subPath)
} else {
return undefined
}
}
/**
*
* @param {*} folderPath
* @param {*} isDeleteOut false
*/
export async function DeleteFolderAllFile(
folderPath: string,
isDeleteOut: boolean = false
): Promise<void> {
try {
let folderIsExist = await CheckFileOrDirExist(folderPath)
if (!folderIsExist) {
throw new Error('目的文件夹不存在,' + folderPath)
}
// 开始删除
let files = await fspromises.readdir(folderPath)
for (const file of files) {
const curPath = path.join(folderPath, file)
const stat = await fspromises.stat(curPath)
if (stat.isDirectory()) {
// 判断是不是文件夹
await DeleteFolderAllFile(curPath) // 递归删除文件夹内容
await fspromises.rmdir(curPath) // 删除空文件夹
} else {
// 删除文件
await fspromises.unlink(curPath)
}
}
// 判断是不是要删除最外部的文件夹
if (isDeleteOut) {
await fspromises.rmdir(folderPath)
}
} catch (error) {
throw error
}
}
/**
*
* @param {*} source
* @param {*} target
* @param {*} checkParent false
*/
export async function CopyFileOrFolder(source, target, checkParent = false) {
try {
// 判断源文件或文件夹是不是存在
if (!(await CheckFileOrDirExist(source))) {
throw new Error(`源文件或文件夹不存在: ${source}`)
}
// 判断父文件夹是否存在,不存在创建
const parent_path = path.dirname(target)
let parentIsExist = await CheckFileOrDirExist(parent_path)
if (!parentIsExist) {
if (checkParent) {
throw new Error(`目的文件或文件夹的父文件夹不存在: ${parent_path}`)
} else {
await fspromises.mkdir(parent_path, { recursive: true })
}
}
// 判断是不是文件夹
const isDirectory = await IsDirectory(source)
// 复制文件夹的逻辑
async function copyDirectory(source, target) {
// 创建目标文件夹
await fspromises.mkdir(target, { recursive: true })
let entries = await fspromises.readdir(source, { withFileTypes: true })
for (let entry of entries) {
let srcPath = path.join(source, entry.name)
let tgtPath = path.join(target, entry.name)
if (entry.isDirectory()) {
await copyDirectory(srcPath, tgtPath)
} else {
await fspromises.copyFile(srcPath, tgtPath)
}
}
}
if (isDirectory) {
// 创建目标文件夹
await copyDirectory(source, target)
} else {
// 复制文件
await fspromises.copyFile(source, target)
}
} catch (error) {
throw error
}
}
/** *
* @param {*} path
* @returns true false
*/
export async function IsDirectory(path) {
try {
const stat = await fspromises.stat(path)
return stat.isDirectory()
} catch (error) {
throw new Error(`获取文件夹信息失败: ${path}`)
}
}
/**
*
* @param {*} source_path /
* @param {*} target_path /
*/
export async function BackupFileOrFolder(source_path: string, target_path: string): Promise<void> {
try {
// 判断父文件夹是否存在,不存在创建
const parent_path = path.dirname(target_path)
if (!(await CheckFileOrDirExist(parent_path))) {
await fspromises.mkdir(parent_path, { recursive: true })
}
// 判断是不是文件夹
const isDirectory = await IsDirectory(source_path)
if (isDirectory) {
// 复制文件夹
await fspromises.rename(source_path, target_path)
} else {
// 复制文件
await fspromises.copyFile(source_path, target_path)
}
} catch (error) {
throw error
}
}
/**
*
* @param {*} folderPath
* @param {*} extensions
* @returns
*/
export async function GetFilesWithExtensions(
folderPath: string,
extensions: string[]
): Promise<string[]> {
try {
// 判断当前是不是文件夹
if (!(await IsDirectory(folderPath))) {
throw new Error('输入的不是有效的文件夹地址')
}
let entries = await fspromises.readdir(folderPath, { withFileTypes: true })
let files = [] as any
// 使用Promise.all来并行处理所有的stat调用
const fileStats = await Promise.all(
entries.map(async (entry) => {
const entryPath = path.join(folderPath, entry.name)
if (entry.isFile()) {
return {
name: entry.name,
path: entryPath,
isFile: true
}
} else {
return {
isFile: false
}
}
})
)
// 过滤出文件并且满足扩展名要求的文件
files = fileStats.filter(
(fileStat) =>
fileStat.isFile && extensions.includes(path.extname(fileStat.name ?? '').toLowerCase())
)
// 对files数组进行排序基于文件名
files.sort((a: any, b: any) => a.name.localeCompare(b.name))
// 返回文件名数组(完整的)
return files.map((fileStat) => path.join(folderPath, fileStat.name))
} catch (error) {
throw error
}
}
/**
*
* @param filePath
* @returns kb单位
*/
export async function GetFileSize(filePath: string): Promise<number> {
try {
if (!(await CheckFileOrDirExist(filePath))) {
throw new Error('获取文件大小,指定的文件不存在')
}
const stats = await fspromises.stat(filePath)
return stats.size / 1024
} catch (error) {
throw error
}
}
/**
*
* @param folderPath
* @returns
*/
export async function GetSubdirectoriesWithInfo(folderPath: string): Promise<Array<{name: string, fullPath: string, ctime: Date}>> {
try {
const filesAndDirectories = await fs.promises.readdir(folderPath, { withFileTypes: true })
// 过滤出文件夹
const directories = filesAndDirectories.filter((dirent) => dirent.isDirectory())
// 并行获取所有文件夹的状态信息
const directoryStatsPromises = directories.map((dirent) =>
fs.promises.stat(path.join(folderPath, dirent.name))
)
const directoryStats = await Promise.all(directoryStatsPromises)
// 将目录信息和状态对象组合
const directoriesWithInfo = directories.map((dirent, index) => ({
name: dirent.name,
fullPath: path.join(folderPath, dirent.name),
ctime: directoryStats[index].ctime
}))
// 按创建时间排序,最新的在前
directoriesWithInfo.sort((a, b) => b.ctime.getTime() - a.ctime.getTime())
return directoriesWithInfo
} catch (error) {
throw error
}
}
/**
* exif信息删除
* @param {*} exiftoolPath exiftool的地址
* @param {*} source
* @param {*} target
*/
export async function DeleteFileExifData(exiftoolPath: string, source: string, target: string) {
try {
if (await CheckFileOrDirExist(target)) {
await fspromises.unlink(target)
}
let script = `"${exiftoolPath}" -all= -overwrite_original "${source}" -o "${target}"`
await execAsync(script, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' })
} catch (error) {
throw error
}
}
/**
*
*
* URL下载图片文件
*
*
* @param {string} imageUrl - URL地址
* @param {string} localPath -
* @returns {Promise<string>}
* @throws {Error}
*
* @example
* // 下载图片到指定路径
* try {
* const savedPath = await DownloadImageFromUrl(
* 'https://example.com/image.jpg',
* 'd:/images/downloaded.jpg'
* );
* console.log('图片已保存至:', savedPath);
* } catch (error) {
* console.error('下载图片失败:', error.message);
* }
*/
export async function DownloadImageFromUrl(imageUrl: string, localPath: string): Promise<string> {
try {
// 确保目标文件夹存在
const dirPath = path.dirname(localPath)
await CheckFolderExistsOrCreate(dirPath)
// 使用fetch获取图片数据
const response = await fetch(imageUrl)
if (!response.ok) {
throw new Error(`下载失败HTTP状态码: ${response.status}`)
}
// 获取图片的二进制数据
const arrayBuffer = await response.arrayBuffer()
const buffer = Buffer.from(arrayBuffer)
// 将图片数据写入本地文件
await fspromises.writeFile(localPath, buffer)
return localPath
} catch (error) {
if (error instanceof Error) {
throw new Error(`下载图片失败: ${error.message}`)
} else {
throw new Error('下载图片时发生未知错误')
}
}
}

388
src/define/Tools/image.ts Normal file
View File

@ -0,0 +1,388 @@
import path from 'path'
import sharp from 'sharp'
import { CheckFileOrDirExist, CheckFolderExistsOrCreate } from './file'
import fs from 'fs'
import https from 'https'
/**
* (base64或buffer)
* @param {*} image_path
* @param {*} width
* @param {*} height
* @param {*} type
* @returns (base64或buffer)
*/
export async function ResizeImage(
image_path: string,
width: number | sharp.ResizeOptions,
height: number,
type: string
) {
try {
// 检查 type 参数
if (type !== 'base64' && type !== 'buffer') {
throw new Error('type 参数必须是 "base64" 或 "buffer"')
}
// 判断是不是图片文件
if (!image_path.match(/\.(jpg|jpeg|png)$/)) {
throw new Error('输入的文件地址不是图片文件地址')
}
// 判断文件是否存在
if (!(await CheckFileOrDirExist(image_path))) {
throw new Error('文件不存在')
}
// 修改图片尺寸
const image = sharp(image_path)
image.resize(width, height)
let data = await image.toBuffer()
if (type === 'base64') {
return data.toString('base64')
} else {
return data
}
} catch (error) {
throw error
}
}
/**
*
* @param {*} image_path
* @returns width和height属性
*/
export async function GetImageSize(image_path: string) {
try {
// 判断文件是否存在
if (!(await CheckFileOrDirExist(image_path))) {
throw new Error('文件不存在')
}
// 判断是不是图片文件
if (!image_path.match(/\.(jpg|jpeg|png)$/)) {
throw new Error('输入的文件地址不是图片文件地址')
}
// 获取图片的宽高
const metadata = await sharp(image_path).metadata()
return {
width: metadata.width,
height: metadata.height
}
} catch (error) {
throw error
}
}
/**
* MIME类型
* @param filePath
* @returns MIME类型字符串
*/
export function GetMimeType(filePath: string): string {
const extension = path.extname(filePath).toLowerCase()
const mimeTypes: { [key: string]: string } = {
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.png': 'image/png',
'.gif': 'image/gif',
'.webp': 'image/webp'
// 添加更多文件类型和对应的MIME类型
}
return mimeTypes[extension] || 'application/octet-stream'
}
/**
* base64字符串中获取图片类型和对应文件后缀
* @param base64String - base64编码的图片数据
* @returns
*/
export function GetImageTypeFromBase64(base64String: string): string {
// 默认后缀
let extension = '.png'
// 检查是否是base64格式的数据URI
if (typeof base64String !== 'string' || !base64String.startsWith('data:image/')) {
return extension // 不是有效的图片base64返回默认后缀
}
try {
// 提取MIME类型
const matches = base64String.match(/^data:image\/([a-zA-Z0-9+.-]+);base64,/)
if (matches && matches.length > 1) {
const mimeSubtype = matches[1].toLowerCase()
// 映射MIME子类型到文件后缀
switch (mimeSubtype) {
case 'jpeg':
case 'jpg':
extension = '.jpg'
break
case 'png':
extension = '.png'
break
case 'gif':
extension = '.gif'
break
case 'webp':
extension = '.webp'
break
case 'svg+xml':
extension = '.svg'
break
case 'bmp':
extension = '.bmp'
break
case 'tiff':
extension = '.tiff'
break
default:
// 其他不常见格式使用MIME子类型作为后缀
extension = `.${mimeSubtype}`
}
}
} catch (error) {
console.error('解析base64图片类型时出错:', error)
}
return extension
}
/**
* MIME类型的base64字符串
* @param url URL
* @returns Promise<string> PromiseMIME类型的base64字符串
*/
export function GetImageBase64(url: string): Promise<string> {
if (!url) {
return Promise.reject('URL不能为空')
}
if (url.startsWith('http://') || url.startsWith('https://')) {
return new Promise((resolve, reject) => {
https
.get(url, (response) => {
const mimeType = response.headers['content-type'] || 'application/octet-stream'
const data: any[] = []
response.on('data', (chunk) => data.push(chunk))
response.on('end', () => {
const buffer = Buffer.concat(data)
const base64Data = `data:${mimeType};base64,${buffer.toString('base64')}`
resolve(base64Data)
})
})
.on('error', (err) => reject(err))
})
} else {
return new Promise((resolve, reject) => {
fs.readFile(url, (err, data) => {
if (err) {
reject(err)
} else {
const mimeType = GetMimeType(url)
const base64Data = `data:${mimeType};base64,${data.toString('base64')}`
resolve(base64Data)
}
})
})
}
}
/**
*
* @param base64 Blob对象
* @param maxSizeInBytes
* @returns PromiseBlob对象
*/
export async function CompressImageToSize(
filePath: string,
maxSizeInBytes: number
): Promise<Buffer> {
let quality = 100 // 初始质量设置
let outputBuffer
const image = sharp(filePath)
// 输出图片的大小
// 迭代压缩过程
while (true) {
outputBuffer = await image.jpeg({ quality }).toBuffer()
if (outputBuffer.length <= maxSizeInBytes || quality === 20) {
break
}
quality -= 5 // 每次迭代降低质量
}
return outputBuffer
}
/**
*
*
* @param inputPath
* @param outputPath
* @param regions x, y, width, height属性
* @param markColor { r: 255, g: 255, b: 255 }
* @param backColor { r: 0, g: 0, b: 0 }
*/
export async function ProcessImage(
inputPath: string,
outputPath: string,
regions: { width: any; height: any; x: any; y: any; imageWidth?: any; imageHeight?: any }[],
markColor: { r: number; g: number; b: number } = { r: 255, g: 255, b: 255 },
backColor: { r: number; g: number; b: number } = { r: 0, g: 0, b: 0 }
): Promise<void> {
try {
// 读取图片并进行处理
const image = sharp(inputPath)
// 获取图片的元数据
const { width, height } = await image.metadata()
if (!width || !height) {
throw new Error('获取图片的宽高失败')
}
const whiteBackground = await sharp()
.composite([
{
input: {
create: {
width,
height,
channels: 3,
background: backColor
}
}
}
])
.png()
.toBuffer()
// 创建多个白色的矩形,并进行合成
const composites = await Promise.all(
regions.map(async (region) => {
// let rateW = 0
let rateY = 0
let rate = 0
if (region.imageWidth != null && region.imageHeight != null) {
rateY = height / region.imageHeight
// rateW = width / region.imageWidth
rate = rateY
}
if (rate == null) {
rate = 1
}
const regionBuffer = await sharp({
create: {
width: Math.ceil(region.width * rate),
height: Math.ceil(region.height * rate),
channels: 3, // RGB channels
background: markColor // 标记颜色
}
})
.png()
.toBuffer()
return {
input: regionBuffer,
left: Math.ceil(region.x * rate),
top: Math.ceil(region.y * rate)
}
})
)
// 在背景上叠加所有的矩形区域
await sharp(whiteBackground).composite(composites).toFile(outputPath)
} catch (err) {
throw err
}
}
/**
* base64写到本地文件
* @param base64 base64字符串
* @param outFilePath
*/
export async function Base64ToFile(base64: string, outFilePath: string): Promise<void> {
try {
let base64Data = base64.replace(/^data:image\/\w+;base64,/, '')
let dataBuffer = Buffer.from(base64Data, 'base64')
let out_folder = path.dirname(outFilePath)
await CheckFolderExistsOrCreate(out_folder)
await fs.promises.writeFile(outFilePath, dataBuffer)
// await this.tools.writeArrayToFile(dataBuffer, out_file);
} catch (error: any) {
throw new Error('将base64转换为文件失败失败信息如下' + error.toString())
}
}
/**
* 2×2
*
* @param inputPath
* @param reName
* @param outputDir
* @returns {Promise<string[]>}
*/
export async function ImageSplit(
inputPath: string,
reName: string,
outputDir: string
): Promise<string[]> {
try {
// 确保输出目录存在
await CheckFolderExistsOrCreate(outputDir)
// 获取图片元数据
const metadata = await sharp(inputPath).metadata()
if (!metadata.height || !metadata.width) {
throw new Error('获取图片的宽高失败')
}
// 计算每个分块的宽高使用Math.floor确保不超出边界
const smallWidth = Math.floor(metadata.width / 2)
const smallHeight = Math.floor(metadata.height / 2)
// 计算最后一列和最后一行可能的额外宽度/高度(处理奇数像素)
const rightWidth = metadata.width - smallWidth
const bottomHeight = metadata.height - smallHeight
const timestamp = new Date().getTime()
const imgs: string[] = []
for (let i = 0; i < 4; i++) {
// 确定当前分块的位置和尺寸
const isRightColumn = i % 2 !== 0
const isBottomRow = i >= 2
const xOffset = isRightColumn ? smallWidth : 0
const yOffset = isBottomRow ? smallHeight : 0
// 使用实际宽高,确保右边和底部区块使用正确尺寸
const blockWidth = isRightColumn ? rightWidth : smallWidth
const blockHeight = isBottomRow ? bottomHeight : smallHeight
const outFile = path.join(outputDir, `${reName}_${timestamp}_${i}.png`)
// 提取并保存分块
await sharp(inputPath)
.extract({
left: xOffset,
top: yOffset,
width: blockWidth,
height: blockHeight
})
.toFile(outFile)
imgs.push(outFile)
}
return imgs
} catch (err) {
throw err
}
}

13
src/define/Tools/index.ts Normal file
View File

@ -0,0 +1,13 @@
import * as image from './image';
import * as common from './common';
import * as file from './file'
import * as validate from './validate';
import * as write from './write';
export {
image,
common,
file,
validate,
write
};

View File

@ -0,0 +1,88 @@
// const winston = require('winston');
import winston from 'winston'
import path from 'path'
import DailyRotateFile from 'winston-daily-rotate-file'
import moment from 'moment-timezone'
import { define } from '../define'
import { DEFINE_STRING } from '../ipcDefineString'
import { LoggerLevel } from '../enum/logger'
export class Logger {
log_folder: string
logger: winston.Logger
constructor() {
this.log_folder = define.log_folder
this.logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp({
format: () => moment().tz('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss')
}),
winston.format.printf(
(info) =>
`${new Date().toLocaleString()} [${info.level.toUpperCase()}] [${info.service}] ${info.message}`
)
),
transports: [
new DailyRotateFile({
filename: path.resolve(this.log_folder, `LAITool-%DATE%.log`),
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '10m',
maxFiles: '14d'
})
]
})
if (process.env.NODE_ENV !== 'production') {
this.logger.add(
new winston.transports.Console({
format: winston.format.simple()
})
)
}
}
sendLoggerToRenderer(level: LoggerLevel, message: string) {
// console.log(global)
global.wins[0].webContents.send(DEFINE_STRING.LOGGER.ADD_LOGGER, {
level: level,
message: message
})
}
/**
* info级别的日志
* @param {*} service service
* @param {*} message
*/
info(service, message) {
this.logger.info(message, { service })
this.sendLoggerToRenderer(LoggerLevel.Info, `${message}`)
}
/**
* error级别的日志
* @param {*} service service
* @param {*} message
*/
error(service, message) {
this.logger.error(message, { service })
this.sendLoggerToRenderer(LoggerLevel.Error, `${message}`)
}
/**
* warn级别的日志
* @param {*} service service
* @param {*} message
*/
warn(service, message) {
this.logger.warn(message, { service })
this.sendLoggerToRenderer(LoggerLevel.Warn, `${message}`)
}
success(service, message) {
this.logger.info(message, { service })
this.sendLoggerToRenderer(LoggerLevel.Success, `${message}`)
}
}

62
src/define/Tools/time.ts Normal file
View File

@ -0,0 +1,62 @@
/**
* number
* 00:00:03.867 --3867
* @param {*} timeString
* @returns
*/
export function TimeStringToMilliseconds(timeString) {
// 分割字符串获取小时、分钟、秒和毫秒
const parts = timeString.split(/[:.]/)
const hours = parseInt(parts[0], 10)
const minutes = parseInt(parts[1], 10)
const seconds = parseInt(parts[2], 10)
const milliseconds = parseInt(parts[3], 10)
// 将小时、分钟、秒转换为毫秒并计算总和
return hours * 3600000 + minutes * 60000 + seconds * 1000 + milliseconds
}
/**
*
* 85233 -- '00:01:25.233'
* @param {*} milliseconds
* @returns
*/
export function MillisecondsToTimeString(milliseconds) {
let totalSeconds = milliseconds / 1000
const hours = Math.floor(totalSeconds / 3600)
totalSeconds %= 3600
const minutes = Math.floor(totalSeconds / 60)
const seconds = Math.floor(totalSeconds % 60)
const ms = milliseconds % 1000
// 将小时、分钟、秒格式化为两位数,毫秒格式化为三位数
const hoursFormatted = hours.toString().padStart(2, '0')
const minutesFormatted = minutes.toString().padStart(2, '0')
const secondsFormatted = seconds.toString().padStart(2, '0')
const msFormatted = ms.toString().padStart(3, '0')
let timeString = `${hoursFormatted}:${minutesFormatted}:${secondsFormatted}.${msFormatted}`
// 使用正则表达式检测并删除多余的小数点
// 此正则表达式查找除了第一个小数点之外的所有小数点,并将它们替换为空字符串
timeString = timeString.replace(/(\.\d+)\./g, '$1')
return timeString
}
/**
* Promise
* @param time
* @returns viod
*/
export async function TimeDelay(time: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, time))
}
/**
* yyyy-mm-dd hh:mm:ss
* @param now
* @returns
*/
export const formattedDate = (now: Date) =>
`${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`

View File

@ -0,0 +1,56 @@
/**
* JSON解析
* @param str
* @returns truefalse
*/
export function ValidateJson(str: string): boolean {
try {
JSON.parse(str)
return true
} catch (e) {
return false
}
}
/**
* JSON字符串
* @description
* @param str
* @returns
*/
export function ValidateJsonAndParse<T>(str: string): T {
try {
if (str == null) {
throw new Error('数据不能为空')
}
let res = JSON.parse(str) as T
return res
} catch (e) {
throw new Error('数据解析失败,请检查数据格式')
}
}
interface ValidationErrorItem {
message?: string
[key: string]: any
}
interface ValidationErrors {
[key: string]: ValidationErrorItem[] | any
message?: string
}
/**
*
* @param errors
* @returns
*/
export function ValidateErrorString(errors: ValidationErrors): string {
const errorMessages = Object.values(errors)
.map((err) => {
return err[0]?.message || '验证错误'
})
.join(' ')
let res = '请修正以下错误: ' + (errorMessages || errors.message)
return res
}

129
src/define/Tools/write.ts Normal file
View File

@ -0,0 +1,129 @@
import { isEmpty } from 'lodash'
/**
*
*
* @param text -
* @param simpleSplitChar - 使
* @param specialSplitChat - 使
* @returns
*/
export function FormatWord(
text: string,
simpleSplitChar?: string,
specialSplitChat?: string[]
): string[] {
const defaultSimpleSplitChar = '。,“”‘’!?【】《》()…—:;.,\'\'""!?[]<>()...-:;'
const defaultSpecialSplitChat = [
'.',
'*',
'?',
'+',
'^',
'$',
'[',
']',
'(',
')',
'{',
'}',
'|',
'\\'
]
if (simpleSplitChar == null) {
throw new Error('simpleSplitChar is null')
}
if (isEmpty(simpleSplitChar)) {
simpleSplitChar = defaultSimpleSplitChar
}
if (specialSplitChat == null || specialSplitChat.length === 0) {
specialSplitChat = defaultSpecialSplitChat
}
Array.from(simpleSplitChar).forEach((item) => {
let regex: RegExp
if (defaultSpecialSplitChat.includes(item)) {
regex = new RegExp('\\' + item, 'g')
} else {
regex = new RegExp(item, 'g')
}
text = text.replace(regex, '\n')
})
let wordArr = text.split('\n')
wordArr = wordArr.filter((item) => item != '' && item != null)
return wordArr
}
/**
* word数组进行重新分组
*
* @param words - word数组
* @param maxChars -
* @returns maxChars
*
* @example
* ```typescript
* const words = ['短句', '中等', '这是长句子', '短', '也是中等']
* const result = groupWordsByCharCount(words, 6)
* // 结果: [['短句', '中等'], ['这是长句子', '短'], ['也是中等']]
* // 解释按顺序处理:
* // 第1组: '短句'(2) + '中等'(2) = 4字符 ✓
* // 第2组: '这是长句子'(5) + '短'(1) = 6字符 ✓
* // 第3组: '也是中等'(4字符) ✓
* ```
*/
export function groupWordsByCharCount(words: string[], maxChars: number): string[][] {
if (!Array.isArray(words) || words.length === 0) {
return []
}
if (maxChars <= 0) {
throw new Error('maxChars must be greater than 0')
}
const result: string[][] = []
let currentGroup: string[] = []
let currentCharCount = 0
for (const word of words) {
const wordLength = word.length
// 如果单个word就超过了最大字符数单独放一组
if (wordLength > maxChars) {
// 如果当前组不为空,先添加到结果中
if (currentGroup.length > 0) {
result.push([...currentGroup])
currentGroup = []
currentCharCount = 0
}
// 将超长的word单独作为一组
result.push([word])
// 注意这里不需要continue让它继续到下一个word
continue
}
// 检查加入当前word后是否会超过限制
if (currentCharCount + wordLength > maxChars) {
// 如果会超过,先将当前组添加到结果中
if (currentGroup.length > 0) {
result.push([...currentGroup])
}
// 开始新的一组将当前word加入
currentGroup = [word]
currentCharCount = wordLength
} else {
// 如果不会超过,加入当前组
currentGroup.push(word)
currentCharCount += wordLength
}
}
// 处理最后一组
if (currentGroup.length > 0) {
result.push(currentGroup)
}
return result
}

View File

@ -0,0 +1,78 @@
import { aiPrompts } from './aiPrompt'
export type AiInferenceModelModel = {
value: string // AI选项值
label: string // AI选项标签
hasExample: boolean // 是否有示例
mustCharacter: boolean // 是否必须包含角色
systemContent: string // 系统内容
userContent: string // 用户内容
allAndExampleContent: string | null // 所有和示例内容
}
/**
* AI选项数据
* @description AI选项valuelabelhasExamplesystemContentuserContent和allAndExampleContent等属性
*/
export const aiOptionsData: AiInferenceModelModel[] = [
{
value: 'NanFengStoryboardMasterScenePrompt',
label: '【NanFeng】场景提示大师上下文-不包含人物)',
hasExample: false,
mustCharacter: false,
systemContent: aiPrompts.NanFengStoryboardMasterScenePromptSystemContent,
userContent: aiPrompts.NanFengStoryboardMasterScenePromptUserContent,
allAndExampleContent: null
},
{
value: 'NanFengStoryboardMasterSpecialEffects',
label: '【NanFeng】分镜大师-特效增强版(上下文-角色分析-人物固定)',
hasExample: false,
mustCharacter: true,
systemContent: aiPrompts.NanFengStoryboardMasterSpecialEffectsSystemContent,
userContent: aiPrompts.NanFengStoryboardMasterSpecialEffectsUserContent,
allAndExampleContent: null
},
{
value: 'NanFengStoryboardMasterSDEnglish',
label: '【NanFeng】分镜大师-SD英文版上下文-SD-英文提示词)',
hasExample: false,
mustCharacter: false,
systemContent: aiPrompts.NanFengStoryboardMasterSDEnglishSystemContent,
userContent: aiPrompts.NanFengStoryboardMasterSDEnglishUserContent,
allAndExampleContent: null
},
{
value: 'NanFengStoryboardMasterSingleFrame',
label: '【NanFeng】分镜大师-单帧分镜提示词(上下文-单帧-人物推理)',
hasExample: false,
mustCharacter: false,
systemContent: aiPrompts.NanFengStoryboardMasterSingleFrameSystemContent,
userContent: aiPrompts.NanFengStoryboardMasterSingleFrameUserContent,
allAndExampleContent: null
},
{
value: 'NanFengStoryboardMasterSingleFrameWithCharacter',
label: '【NanFeng】分镜大师-单帧分镜提示词(上下文-单帧-角色分析-人物固定)',
hasExample: false,
mustCharacter: true,
systemContent: aiPrompts.NanFengStoryboardMasterSingleFrameWithCharacterSystemContent,
userContent: aiPrompts.NanFengStoryboardMasterSingleFrameWithCharacterUserContent,
allAndExampleContent: null
}
]
/**
* AI选项数据
* @description AI选项数据valuelabelhasExamplesystemContentuserContent和allAndExampleContent等属性
* @param id AI选项ID
* @returns AI选项数据
* @throws {Error} AI选项
*/
export function GetAIPromptOptionByValue(value: string) {
let aiOptionIndex = aiOptionsData.findIndex((item) => item.value == value)
if (aiOptionIndex == -1) {
throw new Error('没有找到对应的AI选项请先检查配置')
}
return aiOptionsData[aiOptionIndex]
}

View File

@ -0,0 +1,349 @@
export const aiPrompts = {
/** 南枫角色提取-系统 */
NanFengCharacterSystemContent: `你是一个专业小说角色提取描述师`,
/** 南枫人物提取-用户输入 */
NanFengCharacterUserContent: `
1.
2.
1..30 穿
2..28穿T恤
3..28穿
4..26穿
5..30穿西
6..32穿绿穿
1..30 穿
2..28穿T恤
/,
"调皮""面露""害羞""羞涩""顽皮""卧室""床上""浴巾""淋浴喷头""性感""呼叫器”、""、""、""、""以及和""
穿
相貌特征:台词序号.角色名称.角色描述
{textContent}
`,
/** 南枫场景提取-系统 */
NanFengSceneSystemContent: `你是一个专业小说场景提取描述师`,
/** 南枫场景提取-用户输入 */
NanFengSceneUserContent: `
1.
2. :
,
1..
2..
3..线
4..耀
1..
2..
/,
"调皮""面露""害羞""羞涩""顽皮""卧室""床上""浴巾""淋浴喷头""性感""呼叫器”、""、""、""、""以及和""
:
..
{textContent}
`,
/** 南枫分镜助手特效增强版-系统 */
NanFengStoryboardMasterSpecialEffectsSystemContent: `
Role: 来推laitools分镜描述词大师
<Input Requirements>:
小说信息: 需要转换的小说文本的上下文
小说文本: 需要转换为漫画分镜描述的原始文本
角色设定: 包含主要角色的完整描述性短语或句子AI
<Background>: 穿
:
<角色设定><角色设定> <角色设定>穿穿使
<表情词库>
穿<角色设定>穿穿<角色设定>穿 穿
<肢体动作>
使<环境布景>15<环境布景>
使<画面特效><画面特效>
使<视觉效果><视觉效果>
使<拍摄角度>
使<角色特效><角色特效>
<上下文><环境>22
, 穿
<角色设定>
穿使
穿
穿
线
AI :
穿使
穿
穿
湿
线
线
PS
<角色设定>
##
,怀
##
姿姿退退姿
##
宿广殿绿绿
##
穿耀
##
##
耀穿耀耀耀
##
穿穿
Profile: 你是一位专业的小说转漫画分镜描述师<角色设定><小说信息>
Skills: 文本分析
Goals: 将用户提供的带编号小说文本逐句<角色设定><角色设定><Background> "提示词"
Constrains: 分镜描述需忠实原文使<角色设定> "提示词"
OutputFormat: 只输出纯文本提示词字符串
Workflow:
1.<角色设定>
2.<Background>
<角色设定>
穿
3.
4.
5.
`,
/** 南枫分镜助手特效增强版-用户输入 */
NanFengStoryboardMasterSpecialEffectsUserContent: `
:
{contextContent}
{textContent}
{characterContent}
## Initialization
Initialization: 请提供带编号的小说文本和包含每个角色完整描述的<角色设定> "提示词"
`,
/** 南枫分镜助手场景提示词-系统 */
NanFengStoryboardMasterScenePromptSystemContent: `
AI
1.
2.MJ提示词
:
包含:人物表情++++++
<表情词库>
<肢体动作>
使使<环境布景>
使<构图>
使<景别>
使<方向>
使<高度>
MJ提示词,MJ提示词MJ提示词用中文输出
S形构图线
西
广
Examples
Example1
,
AI输出
殿
Example2
AI输出
Initialization
<Pico><Rules><Examples><Rules>MJ提示词
`,
/** 南枫分镜助手场景提示词-用户输入 */
NanFengStoryboardMasterScenePromptUserContent: `
{contextContent}
{textContent}
`,
/** 南枫分镜助手SD英文提示词-系统 */
NanFengStoryboardMasterSDEnglishSystemContent: `
Stable diffusion人工智能程序的提示生成器 AI 使1man1woman1boy1girl1old woman1old man等的词去描述
`,
/** 南枫分镜助手SD英文提示词-用户输入 */
NanFengStoryboardMasterSDEnglishUserContent: `
{contextContent}
{textContent}
`,
/** 南枫分镜助手单帧分镜提示词-系统 */
NanFengStoryboardMasterSingleFrameSystemContent: `
AI
:
1.
2.
3./,
4."调皮""面露""害羞""羞涩""顽皮""卧室""床上""浴巾""淋浴喷头""性感""呼叫器”、""、""、""、""以及和""
Examples
:
AI输出:
绿2.
:
怀
AI输出:
:
AI输出:
:
AI输出:
:
AI输出:
Initialization
"地点同上""背景不变"
"无""无"
`,
/** 南枫分镜助手单帧分镜提示词-用户输入 */
NanFengStoryboardMasterSingleFrameUserContent: `
{contextContent}
{textContent}
`,
/** 南枫分镜助手单帧分镜助手,带角色分析和上下文-系统 */
NanFengStoryboardMasterSingleFrameWithCharacterSystemContent: `
AI
:
<Background>:
'我''你' 穿穿使
<表情词库>
<肢体动作>
<位置地点>"地点同上""画面元素不变"
##
怀
##
姿姿退退姿
- Profile: 你是一位专业的小说转漫画分镜描述师
- Skills: 文本分析
- Goals: 将用户提供的小说文本逐句拆分<Background>
- Constrains: 分镜描述需忠实原文
- Workflow:
1.
2.<Background>
3.<Background>20
4./,
5."调皮""面露""害羞""羞涩""顽皮""卧室""床上""浴巾""淋浴喷头""性感""呼叫器”、""、""、""、""、""、""以及和""
Examples
:
1.
2.SSS级禁咒师
3.怀
4.
5.
6.
AI输出:
1.绿
2.20
3.
4.
5.
6.
Initialization
"地点同上""背景不变"
"无""无"
`,
/** 南枫分镜助手单帧分镜助手,带角色分析和上下文-用户输入 */
NanFengStoryboardMasterSingleFrameWithCharacterUserContent: `
{contextContent}
{characterContent}
{textContent}
`
}

View File

@ -0,0 +1,97 @@
export const AIWordMergeLong: OpenAIRequest.Request = {
model: 'deepseek-chat',
stream: false,
temperature: 0.3,
messages: [
{
role: 'system',
content:
'你是一位优秀的分镜师,你有很强的阅读能力,理解能力,我会给你一段文案,请把我给你的文案进行文案分镜头。根据上下文结合,按照镜头语言的可表达性,哪几句话可以组合成一个镜头,以便分镜的制作。严格遵守把组合好的文案分隔开发给我,不要发送与文案无关的内容。文案的格式为一行一个<句子>一个镜头多句时逗号隔开句末尾无标点严格执行每一个完整的句子不少于15字不多于35字请你理解全文之后根据上下文内容按照以下要求段落分行'
},
{
role: 'user',
content: `
便<句子>1535
##
1.
2.
3.
4.
5.
6.<转折词><转折词>
7.
8.<句子>
9.
##
退便便
##
:
线
沿
AI:
1.
2.
3.线
4.沿
5.
6.
7.
8.
##
<要求><示例><要求><句子>Ai部分Ai部分前面一定要加上序号1535
{textContent}
{textContent}`
}
]
}

View File

@ -0,0 +1,108 @@
export const AIWordMergeShort = {
model: 'deepseek-chat',
stream: false,
temperature: 0.3,
messages: [
{
role: 'system',
content:
'你是一位优秀的分镜师,你有很强的阅读能力,理解能力,我会给你一段文案,请把我给你的文案进行文案分镜头。根据上下文结合,按照镜头语言的可表达性,哪几句话可以组合成一个镜头,以便分镜的制作。严格遵守把组合好的文案分隔开发给我,不要发送与文案无关的内容。文案的格式为一行一个<句子>一个镜头多句时逗号隔开句末尾无标点严格执行每一个完整的句子不少于15字不多于35字请你理解全文之后根据上下文内容按照以下要求段落分行'
},
{
role: 'user',
content: `你是一位优秀的分镜师,你有很强的阅读能力,理解能力,我会给你一段文案,请把我给你的文案进行文案分镜头。根据上下文结合,按照镜头语言的可表达性,哪几句话可以组合成一个镜头,以便分镜的制作。严格遵守把组合好的文案分隔开发给我,不要发送与文案无关的内容。文案的格式为一行一个<句子>一个镜头多句时逗号隔开句末尾无标点严格执行每一个完整的句子不少于15字不多于35字请你理解全文之后根据上下文内容按照以下要求段落分行
##
1.
2.
3.
4.
5.
6. <转折词><转折词>
7.
8. <句子>
9.
##
退便便
##
:
线
沿
AI:
1.
2.
3.
4.
5.
6.
7. 线
8.
9.
10. 沿
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
##
<要求><示例><要求><句子>Ai部分Ai部分前面一定要加上序号1535
##
{textContent}
##
{textContent}`
}
]
}

View File

@ -0,0 +1,80 @@
export const apiDefineData = [
{
label: 'LAI API - 香港',
value: 'b44c6f24-59e4-4a71-b2c7-3df0c4e35e65',
id: 'b44c6f24-59e4-4a71-b2c7-3df0c4e35e65',
gpt_url: 'https://api.laitool.cc/v1/chat/completions',
mj_url: {
imagine: 'https://api.laitool.cc/mj/submit/imagine',
describe: 'https://api.laitool.cc/mj/submit/describe',
update_file: 'https://api.laitool.cc/mj/submit/upload-discord-images',
once_get_task: 'https://api.laitool.cc/mj/task/${id}/fetch'
},
d3_url: {
image: 'https://api.laitool.cc/v1/images/generations'
},
buy_url: 'https://api.laitool.cc/register?aff=RCSW'
},
{
label: 'LAI API - 美国',
value: '2b443f53-ba12-42b3-a57c-e4df92685c73',
id: '2b443f53-ba12-42b3-a57c-e4df92685c73',
gpt_url: 'https://laitool.net/v1/chat/completions',
mj_url: {
imagine: 'https://laitool.net/mj/submit/imagine',
describe: 'https://laitool.net/mj/submit/describe',
update_file: 'https://laitool.net/mj/submit/upload-discord-images',
once_get_task: 'https://laitool.net/mj/task/${id}/fetch'
},
d3_url: {
image: 'https://laitool.net/v1/images/generations'
},
buy_url: 'https://laitool.net/register?aff=RCSW'
}
]
/**
* ID获取API配置
* @description ID获取API配置
* @param id API ID
* @returns
*/
export function GetApiDefineDataById(id: string) {
let mj_api_url_index = apiDefineData.findIndex((item) => item.value == id)
if (mj_api_url_index == -1) {
throw new Error('没有找到对应的API的配置请先检查配置')
}
return apiDefineData[mj_api_url_index]
}
/**
* API
* @param type
* @returns
*/
export function getAPIOptions(type: string) {
switch (type) {
case 'mj':
let options = apiDefineData
.filter((item) => item.mj_url != null)
.map((item) => {
return {
label: item.label,
value: item.value
}
})
return options
case 'gpt':
let gptOptions = apiDefineData
.filter((item) => item.gpt_url != null)
.map((item) => {
return {
label: item.label,
value: item.value
}
})
return gptOptions
default:
return []
}
}

View File

View File

@ -0,0 +1,127 @@
//#region 出图方式
import { PromptMergeType } from '../enum/bookEnum'
import { TaskModal } from '../model/task'
// 出图方式
export enum ImageCategory {
/** Midjourney 图像生成平台 */
Midjourney = 'mj',
/** Stable Diffusion 图像生成平台 */
Stable_Diffusion = 'sd',
/** ComfyUI 图像生成框架 */
Comfy_UI = 'comfyui',
/** DALL-E 图像生成模型 */
DALL_E_3 = 'd3',
/** FLUX API 图像生成服务 */
Flux_API = 'flux-api',
/** FLUX FORGE 图像生成工具 */
Flux_Forge = 'flux-forge'
}
/**
*
*
* 便
* Midjourney和Stable Diffusion对提示词有不同的格式要求
*
* @param {ImageCategory} imageCategory - MidjourneyStable Diffusion等
* @returns {PromptMergeType}
* - MJ_MERGE: 适用于Midjourney的提示词格式
* - SD_MERGE: 适用于Stable DiffusionComfyUIDALL-E 3FLUX相关平台的提示词格式
*
* @example
* // 获取Midjourney的提示词合并类型
* const mjMergeType = getMergePromptType(ImageCategory.Midjourney);
* // 返回 PromptMergeType.MJ_MERGE
*
* // 获取Stable Diffusion的提示词合并类型
* const sdMergeType = getMergePromptType(ImageCategory.Stable_Diffusion);
* // 返回 PromptMergeType.SD_MERGE
*/
export function getMergePromptType(imageCategory: ImageCategory): PromptMergeType {
switch (imageCategory) {
case ImageCategory.Midjourney:
return PromptMergeType.MJ_MERGE
case ImageCategory.Stable_Diffusion:
return PromptMergeType.SD_MERGE
case ImageCategory.Comfy_UI:
return PromptMergeType.SD_MERGE
case ImageCategory.DALL_E_3:
return PromptMergeType.SD_MERGE
case ImageCategory.Flux_API:
return PromptMergeType.SD_MERGE
case ImageCategory.Flux_Forge:
return PromptMergeType.SD_MERGE
default:
return PromptMergeType.MJ_MERGE
}
}
/**
*
* @returns label和value的选项数组
*/
export function getImageCategoryOptions(): Array<{ label: string; value: string }> {
return [
{ label: 'Midjourney', value: ImageCategory.Midjourney },
{ label: 'Stable Diffusion', value: ImageCategory.Stable_Diffusion },
{ label: 'ComfyUI', value: ImageCategory.Comfy_UI },
{ label: 'DALL-E', value: ImageCategory.DALL_E_3 },
{ label: 'FLUX API', value: ImageCategory.Flux_API },
{ label: 'FLUX FORGE', value: ImageCategory.Flux_Forge }
]
}
/**
*
* @param value
* @returns
*/
export function getImageCategoryLabel(value: string): TaskModal.TaskStatus {
const options = getImageCategoryOptions()
const option = options.find((option) => option.value === value)
if (option) {
return {
status: option.value,
label: option.label,
type: 'success'
} as TaskModal.TaskStatus
} else {
return {
status: 'UNKNOWN',
label: 'UNKNOWN',
type: 'warning'
}
}
}
//#endregion
//#region 图转视频方式
export enum ImageToVideoCategory {
/** runway 生成视频 */
RUNWAY = 'runway',
/** luma 生成视频 */
LUMA = 'luma',
/** 可灵生成视频 */
KLING = 'kling',
/** Pika 生成视频 */
PIKA = 'pika'
}
/**
*
* @returns label和value的选项数组
*/
export function getImageToVideoCategoryOptions(): Array<{ label: string; value: string }> {
return [
{ label: 'Runway', value: ImageToVideoCategory.RUNWAY },
{ label: 'Luma', value: ImageToVideoCategory.LUMA },
{ label: '可灵', value: ImageToVideoCategory.KLING },
{ label: 'Pika', value: ImageToVideoCategory.PIKA }
]
}
//#endregion

213
src/define/data/mjData.ts Normal file
View File

@ -0,0 +1,213 @@
//#region MJ 出图方式
/**
* MJ API
*/
export enum ImageGenerateMode {
/** API 模式 */
MJ_API = 'mj_api',
//本地MJ
LOCAL_MJ = 'local_mj',
// 代理MJ
REMOTE_MJ = 'remote_mj',
// 浏览器模式
BROWSER_MJ = 'browser_mj',
// 本地 SD
LOCAL_SD = 'local_sd',
// ComfyUI
ComfyUI = 'comfyui',
// flux-api
FLUX_API = 'flux-api',
// flxu-forge
FLUX_FORGE = 'flux-forge',
// 导入
IMPORT = 'import'
}
/**
*
* @description
* @returns
*/
export function getImageGenerateModeOptions(): Array<{ label: string; value: string }> {
return [{ label: 'API模式', value: ImageGenerateMode.MJ_API }]
}
//#endregion
//#region 生图机器人
export enum MJRobotType {
// MJ
MJ = 'mj',
// niji
NIJI = 'niji'
}
/**
* MJ的机器人列表
* @returns
*/
export function getMJRobotOptions() {
return [
{
label: 'MJ',
value: MJRobotType.MJ
},
{
label: 'NIJI',
value: MJRobotType.NIJI
}
]
}
//#endregion
//#region 机器人出图模型
/**
*
*/
export function getMJRobotModelOptions(mjRobot?: MJRobotType) {
let allRobotModel = [
{
label: 'MJ V7.0',
text: 'v 7',
type: MJRobotType.MJ,
value: '0d33ae62-e0a8-4429-89e4-304bfd20cd6f'
},
{
label: 'MJ V6.1',
text: 'v 6.1',
type: MJRobotType.MJ,
value: 'f799de81-91da-413f-89fd-58b2ff8174db'
},
{
label: 'MJ V6.0',
text: 'v 6',
type: MJRobotType.MJ,
value: '3e6473ab-9a64-4574-9a38-f5c75af552b6'
},
{
label: 'MJ V5.2',
text: 'v 5.2',
type: MJRobotType.MJ,
value: '27a0d30e-f46c-4684-96c8-d91334deb94f'
},
{
label: 'MJ V5.1',
text: 'v 5.1',
type: MJRobotType.MJ,
value: 'e1226715-e969-44c4-b18b-f2ad5dae5d2f'
},
{
label: 'MJ V5.0',
text: 'v 5',
type: MJRobotType.MJ,
value: 'afb7bea1-4eda-46ea-8165-34701b4566bf'
},
{
label: 'MJ V4.0',
text: 'v 4',
type: MJRobotType.MJ,
value: 'd05b8497-7f4a-4890-8fac-89f1803984d2'
},
{
label: 'NIJI V6',
text: 'niji 6',
type: MJRobotType.NIJI,
value: '99377cad-c103-4cee-a958-86a104879328'
},
{
label: 'NIJI V5',
text: 'niji 5',
type: MJRobotType.NIJI,
value: '53cec077-9885-4635-ab18-e021066b2c4c'
},
{
label: 'NIJI V4',
text: 'niji 4',
type: MJRobotType.NIJI,
value: '6a7199fe-6e0d-40a9-9772-b5eb3d2e2e66'
}
]
switch (mjRobot) {
case MJRobotType.MJ:
return allRobotModel.filter((item) => item.type == MJRobotType.MJ)
case MJRobotType.NIJI:
return allRobotModel.filter((item) => item.type == MJRobotType.NIJI)
default:
return allRobotModel
}
}
//#endregion
//#region MJ 出图比例
/**
* MJ出图的比例Options
* @returns
*/
export function getMJImageScaleOptions() {
return [
{
label: '1:1',
value: '3e2772f2-041c-49c6-ba13-d0ed120310b8'
},
{
label: '4:3',
value: 'fcef555c-1958-4082-88fe-434782aa8151'
},
{
label: '3:4',
value: '13f71d53-73a3-4c9b-9c1e-6e7e939aee73'
},
{
label: '16:9',
value: 'bf33ce1a-15cd-4901-b38e-89543cf14a1f'
},
{
label: '9:16',
value: 'fd4641e2-97f4-4a86-8616-4965e05f3348'
}
]
}
//#endregion
//#region 出图速率
export enum MJSpeed {
// 快速
FAST = 'FAST',
// 休闲
RELAX = 'RELAXED'
}
/**
* MJ的速度Options
* @returns
*/
export function getMJSpeedOptions() {
return [
{
label: '快速',
value: MJSpeed.FAST
},
{
label: '慢速',
value: MJSpeed.RELAX
}
]
}
//#endregion

View File

@ -0,0 +1,53 @@
/**
*
*/
export enum PresetCategory {
/** 角色 */
Character = 'character',
/** 场景 */
Scene = 'scene',
/** 风格 */
Style = 'style',
/** 其他 */
Other = 'other'
}
/**
*
* @returns label和value的选项数组
*/
export function getPresetCategoryOptions(): Array<{ label: string; value: string }> {
return [
{ label: '风格预设', value: PresetCategory.Style },
{ label: '人物预设', value: PresetCategory.Character },
{ label: '场景预设', value: PresetCategory.Scene }
]
}
/**
*
* @param value
* @returns
*/
export function getPresetCategoryLabel(value: string): string {
const option = getPresetCategoryOptions().find((item) => item.value === value)
return option ? option.label : '未知类型'
}
/**
*
* @param value
* @returns '未知类型'
*/
export function getPromptSortLabel(value: string): string {
const option = getPresetCategoryOptions().find((item) => item.value === value)
if (option) {
return option.label
} else {
if (value == 'prompt') {
return '提示词'
} else {
return '未知类型'
}
}
}

View File

@ -0,0 +1,54 @@
interface ISoftwareData {
/** 软件版本号 */
version: string
/** 发布日期 */
date: string
/** 更新说明列表 */
notes: string[]
/** 系统信息 */
systemInfo: {
/** 快速开始 */
quickStart: string
/** 使用文档 */
documentationUrl: string
/** 更新文档 */
updateUrl: string
/** 软件文档 */
softwareUrl: string
/** WIKI */
wikiUrl: string
}
}
export const SoftwareData: ISoftwareData = {
version: 'V3.4.2',
date: '2025-08-08',
notes: [
'1. 新增图/文转视频菜单界面,专注实现图/文转视频(目前只集成了 MJ VIDEO',
' • 全新的界面排列,小说列表和批次任务更加分明',
' • 添加转视频进度,在主界面即可看到转视频的比例',
' • 单独的界面去处理图转视频,避免表格数据过多繁琐',
' • 新增分页显示,界面加载更快,也可切换不分页',
' • 单独操作面板,参数修改处理更加清晰,支持多种模式显示',
' • 批量设置转视频配置,可以批量修改分类',
' • 友好的选择视频界面',
'2. 重写软件导出剪映,修复若干草稿导出问题',
' • 修复导出剪映文案和图片对齐问题,解决时长越长越明显的对不上问题',
' • 修复导出草稿关键帧部分问题',
' • 导出的文案通过分镜自动导入不再需要手动选择SRT',
'3. 美化生成草稿界面弹窗,优化部分逻辑',
' • 删除选择SRT文件SRT根据聚合推文中导入的SRT自动生成草稿',
' • 只需选择配音文件即可配音文件和导入的SRT请自行对应',
' • 背景音乐不在内部设置自行选择文件夹或者是MP3、WAV文件',
' • 背景音乐选择文件夹则读取文件夹,随机获取一个',
' • 背景音乐选择指定的音乐文件则使用选择的'
],
systemInfo: {
quickStart: '快速开始',
documentationUrl: 'https://rvgyir5wk1c.feishu.cn/wiki/WdaWwAfDdiLOnjkywIgcaQoKnog',
updateUrl: 'https://pvwu1oahp5m.feishu.cn/docx/CAjGdTDlboJ3nVx0cQccOuNHnvd',
softwareUrl: 'https://pvwu1oahp5m.feishu.cn/docx/FONZdfnrOoLlMrxXHV0czJ3jnkd',
wikiUrl:
'https://rvgyir5wk1c.feishu.cn/wiki/space/7481893355360190492?ccm_open_type=lark_wiki_spaceLink&open_tab_from=wiki_home'
}
}

View File

@ -0,0 +1,64 @@
// @ts-ignore
import Realm from 'realm'
import { BookType } from '@/define/enum/bookEnum'
export class BookModel extends Realm.Object<BookModel> {
id!: string
no!: number
name!: string
bookFolderPath!: string
imageFolder!: string | undefined
type!: BookType
oldVideoPath!: string | undefined
srtPath!: string | undefined
audioPath!: string | undefined
draftDepend?: string // 草稿依赖
draftSrtStyle!: string | undefined // 草稿字幕样式
backgroundMusic!: string | undefined // 背景音乐ID
friendlyReminder!: string | undefined // 友情提示
updateTime!: Date
createTime!: Date
version!: string
imageStyle!: string[] | undefined // 软件内置的样式
autoAnalyzeCharacter!: string | undefined // 自动分析角色设置
customizeImageStyle!: string[] | undefined // 自定义的样式
videoConfig!: string | undefined // 合成视频设置
prefixPrompt!: string | undefined // 前缀
suffixPrompt!: string | undefined // 后缀
subtitlePosition!: string | undefined // 字幕位置
watermarkPosition!: string | undefined // 水印位置一个json数组字符串
imageType!: string | undefined // 出图类型
static schema: Realm.ObjectSchema = {
name: 'Book',
properties: {
id: 'string',
no: 'int',
name: 'string',
bookFolderPath: 'string',
type: 'string',
oldVideoPath: 'string?',
srtPath: 'string?',
audioPath: 'string?',
draftDepend: 'string?',
draftSrtStyle: 'string?',
backgroundMusic: 'string?',
friendlyReminder: 'string?',
imageFolder: 'string?',
updateTime: 'date',
createTime: 'date',
version: 'string',
imageStyle: 'string?[]',
autoAnalyzeCharacter: 'string?',
customizeImageStyle: 'string?[]',
videoConfig: 'string?',
prefixPrompt: 'string?',
suffixPrompt: 'string?',
subtitlePosition: 'string?',
watermarkPosition: 'string?',
imageType: 'string?'
},
// 主键为_id
primaryKey: 'id'
}
}

View File

@ -0,0 +1,104 @@
import { ImageCategory } from '@/define/data/imageData'
import { BookTaskStatus } from '@/define/enum/bookEnum'
import Realm, { ObjectSchema } from 'realm'
export class ImageDefineModel extends Realm.Object<ImageDefineModel> {
label!: string
key!: string
value!: string
children!: string
type!: string
prompt!: string
image_url!: string
cref_cw!: number
lora!: string
chinese_prompt!: string
lora_weight!: number
show_image!: string
isShow!: true
static schema: ObjectSchema = {
name: 'ImageDefine',
properties: {
label: 'string',
key: 'string',
value: 'string',
children: 'string',
type: 'string',
prompt: 'string',
image_url: 'string',
cref_cw: 'int',
lora: 'string',
chinese_prompt: 'string',
lora_weight: 'int',
show_image: 'string',
isShow: 'bool'
},
primaryKey: 'key'
}
}
export class BookTaskModel extends Realm.Object<BookTaskModel> {
id!: string
no!: number
bookId!: string
name!: string
generateVideoPath!: string | null
srtPath!: string | null
draftDepend?: string // 草稿依赖
audioPath!: string | null
draftSrtStyle!: string | null // 草稿字幕样式
backgroundMusic!: string | null // 背景音乐ID
friendlyReminder!: string | null // 友情提示
imageFolder!: string | null
imageStyle!: string | null // 软件内置的样式
cacheImageList!: string[] | null // 缓存的图片列表
autoAnalyzeCharacter!: string | null // 自动分析角色设置
customizeImageStyle!: string[] | null // 自定义的样式
videoConfig!: string | null // 合成视频设置
prefixPrompt!: string | null // 前缀
suffixPrompt!: string | null // 后缀
styleList!: string[] | null
status!: BookTaskStatus
errorMsg!: string | null
isAuto!: boolean // 是否自动
openVideoGenerate!: boolean | null // 是否开启视频生成
updateTime!: Date
createTime!: Date
imageCategory!: ImageCategory // 图片出图方式
subImageFolder!: string[] | null // 出图的子文件夹
static schema: ObjectSchema = {
name: 'BookTask',
properties: {
id: 'string',
bookId: { type: 'string', indexed: true },
no: 'int',
name: 'string',
generateVideoPath: 'string?',
srtPath: 'string?',
draftDepend: 'string?',
audioPath: 'string?',
draftSrtStyle: 'string?',
backgroundMusic: 'string?',
friendlyReminder: 'string?',
imageFolder: 'string?',
subImageFolder: 'string?[]',
cacheImageList: 'string?[]',
imageStyle: 'string?[]',
autoAnalyzeCharacter: 'string?',
customizeImageStyle: 'string?[]',
videoConfig: 'string?',
prefixPrompt: 'string?',
suffixPrompt: 'string?',
status: 'string',
openVideoGenerate: 'bool?',
errorMsg: 'string?',
isAuto: 'bool',
updateTime: 'date',
createTime: 'date',
imageCategory: 'string'
},
// 主键为_id
primaryKey: 'id'
}
}

View File

@ -0,0 +1,236 @@
import Realm, { ObjectSchema } from 'realm'
import { BookTaskStatus, MJAction } from '@/define/enum/bookEnum'
import { MJImageType } from '@/define/enum/mjEnum'
export class Subtitle extends Realm.Object<Subtitle> {
startTime!: number
endTime!: number
srtValue!: string
id!: string
static schema = {
name: 'Subtitle',
properties: {
startTime: 'int',
endTime: 'int',
srtValue: 'string',
id: 'string'
},
primaryKey: 'id'
}
}
export class MJMessage extends Realm.Object<MJMessage> {
id!: string
mjApiUrl!: string | null
progress!: number
category!: MJImageType
imageClick!: string | null // 图片点击(显示的小的)
imageShow!: string | null // 图片实际的地址
messageId!: string // 消息ID可以是MJ中的也可以是API中的
action!: MJAction // 动作(生图,反推之类)
status!: string // 状态
message!: string | null // 消息
static schema: ObjectSchema = {
name: 'MJMessage',
properties: {
id: 'string',
mjApiUrl: 'string?',
progress: 'int',
category: 'string',
imageClick: 'string?',
imageShow: 'string?',
messageId: 'string',
action: 'string',
status: 'string',
message: 'string?'
},
primaryKey: 'id'
}
}
export class VideoMessage extends Realm.Object<VideoMessage> {
id!: string
msg!: string | null
videoType!: string
prompt!: string | null
style!: string | null
imageUrl!: string | null
model!: string | null
bookTaskDetailId!: string
status!: string | null
videoUrl!: string | null
taskId!: string | null
runwayOptions!: string | null // 生成视频的一些设置
lumaOptions!: string | null // 生成视频的一些设置
klingOptions!: string | null // 生成视频的一些设置
messageData!: string | null
static schema: ObjectSchema = {
name: 'VideoMessage',
properties: {
id: 'string',
msg: 'string?',
videoType: 'string',
bookTaskDetailId: 'string?',
prompt: 'string?',
style: 'string?',
imageUrl: 'string?',
model: 'string?',
status: 'string?',
videoUrl: 'string?',
taskId: 'string?',
runwayOptions: 'string?',
lumaOptions: 'string?',
klingOptions: 'string?',
messageData: 'string?'
},
primaryKey: 'id'
}
}
export class WebuiConfig extends Realm.Object<WebuiConfig> {
sampler_name!: string // 采样器名称
negative_prompt!: string // 负面提示
batch_size!: number // 批次大小
steps!: number // 步数
cfg_scale!: number // 提示词相关性
denoising_strength!: number // 降噪强度
width!: number // 宽度
height!: number // 高度
seed!: number // 种子
init_images!: string // 初始图片(垫图的图片地址)
id!: string
static schema: ObjectSchema = {
name: 'WebuiConfig',
properties: {
sampler_name: 'string',
negative_prompt: 'string',
batch_size: 'int',
steps: 'int',
cfg_scale: 'int',
denoising_strength: 'int',
width: 'int',
height: 'int',
seed: 'int',
init_images: 'string',
id: 'string'
},
primaryKey: 'id'
}
}
export class SDConfig extends Realm.Object<SDConfig> {
checkpoints!: string // 大模型
api!: string // api地址
model!: string // 生图方式
webuiConfig!: WebuiConfig
id!: string
static schema: ObjectSchema = {
name: 'SDConfig',
properties: {
checkpoints: 'string',
api: 'string',
model: 'string',
webuiConfig: 'WebuiConfig',
id: 'string'
},
primaryKey: 'id'
}
}
// 放反推的提示词的对象
export class ReversePrompt extends Realm.Object<ReversePrompt> {
id!: string
bookTaskDetailId!: string
prompt!: string
promptCN!: string
isSelect!: boolean
static schema: ObjectSchema = {
name: 'ReversePrompt',
properties: {
id: 'string',
bookTaskDetailId: 'string',
prompt: 'string',
promptCN: 'string',
isSelect: 'bool'
},
primaryKey: 'id'
}
}
export class BookTaskDetailModel extends Realm.Object<BookTaskDetailModel> {
id!: string
no!: number
name!: string
bookId!: string
bookTaskId!: string
videoPath!: string | null // 视频地址
generateVideoPath!: string | null // 生成视频地址
audioPath!: string | null // 音频地址
word!: string | null // 文案
oldImage!: string | null // 旧图片用于SD的图生图
afterGpt!: string | null // GPT生成的文案
startTime!: number | null // 开始时间
endTime!: number | null // 结束时间
timeLimit!: string | null // 事件实现0 -- 3000
subValue!: string | null // 包含的字幕数据
characterTags!: string[] | null // 角色标签
sceneTags!: string[] | null // 场景标签
styleTags!: string[] | null // 风格标签
promptSort!: string | null // 提示词排序
gptPrompt!: string | null // GPT提示词
mjMessage!: MJMessage | null // MJ消息
videoMessage!: VideoMessage | null // 视频消息
outImagePath!: string | null // 输出图片地址
subImagePath!: string[] | null // 子图片地址
imageLock!: boolean // 图片锁
prompt!: string | null // 提示
adetailer!: boolean // 是否开启修脸
sdConifg!: SDConfig | null // SD配置
reversePrompt!: ReversePrompt[] | null // 反推的提示词(数组)
subtitlePosition!: string | null // 字幕位置
status!: BookTaskStatus
createTime!: Date
updateTime!: Date
static schema: ObjectSchema = {
name: 'BookTaskDetail',
properties: {
id: 'string',
no: 'int',
name: 'string',
bookId: { type: 'string', indexed: true },
bookTaskId: { type: 'string', indexed: true },
videoPath: 'string?',
generateVideoPath: 'string?', // 生成视频地址
audioPath: 'string?',
word: 'string?',
oldImage: 'string?',
afterGpt: 'string?',
startTime: 'int?',
endTime: 'int?',
timeLimit: 'string?',
subValue: 'string?',
reversePrompt: { type: 'list', objectType: 'ReversePrompt' },
characterTags: { type: 'list', objectType: 'string' },
sceneTags: 'string[]',
styleTags: 'string[]',
promptSort: 'string?',
gptPrompt: 'string?',
mjMessage: 'MJMessage?',
videoMessage: 'VideoMessage?',
outImagePath: 'string?',
subImagePath: 'string[]',
imageLock: 'bool',
prompt: 'string?',
adetailer: 'bool',
sdConifg: 'SDConfig?',
subtitlePosition: 'string?',
status: 'string',
createTime: 'date',
updateTime: 'date'
},
// 主键为_id
primaryKey: 'id'
}
}

View File

@ -0,0 +1,16 @@
import Realm, { ObjectSchema } from 'realm'
export class OptionModel extends Realm.Object<OptionModel> {
key!: string;
value!: string;
type!: string;
static schema: ObjectSchema = {
name: 'Option',
properties: {
key: 'string',
value: 'string',
type: 'string'
},
primaryKey: 'key'
}
}

View File

@ -0,0 +1,38 @@
import Realm, { ObjectSchema } from 'realm'
export class PresetModel extends Realm.Object<PresetModel> {
id!: string
label!: string
type!: string
showImage?: string[]
prompt!: string
chinesePrompt?: string[]
imageUrl?: string
srefSw?: number
crefCw?: number
lora?: string
loraWeight?: number
isShow!: boolean
aliases?: string[]
createTime!: Date
static schema: ObjectSchema = {
name: 'Preset',
properties: {
id: 'string',
label: 'string',
type: 'string',
showImage: 'string?[]',
imageUrl: 'string?',
prompt: 'string',
chinesePrompt: 'string?',
srefSw: 'int?',
crefCw: 'int?',
lora: 'string?',
loraWeight: 'int?',
isShow: 'bool',
aliases: 'string?[]',
createTime: 'date'
},
primaryKey: 'id'
}
}

View File

@ -0,0 +1,40 @@
import Realm, { ObjectSchema } from 'realm'
import { BookBackTaskStatus, BookBackTaskType, TaskExecuteType } from '@/define/enum/bookEnum'
export class TaskListModel extends Realm.Object<TaskListModel> {
id!: string
bookId!: string
bookTaskId!: string
bookTaskDetailId!: string
name!: string // 任务名称,小说名+批次名+分镜名
type!: BookBackTaskType
status!: BookBackTaskStatus
errorMessage!: string | null
executeType!: TaskExecuteType // 任务执行类型,手动还是自动
createTime!: Date
updateTime!: Date
startTime!: number
endTime!: number
messageName?: string
static schema: ObjectSchema = {
name: 'TaskList',
properties: {
id: 'string',
bookId: { type: 'string', indexed: true },
bookTaskId: { type: 'string', indexed: true },
bookTaskDetailId: { type: 'string', indexed: true },
name: 'string',
type: 'string',
status: 'string',
errorMessage: 'string?',
executeType: { type: 'string', default: TaskExecuteType.AUTO },
createTime: 'date',
updateTime: 'date',
startTime: 'int',
endTime: 'int',
messageName: 'string?'
},
primaryKey: 'id'
}
}

View File

@ -0,0 +1,36 @@
// 定义抽象基类
import Realm from 'realm'
export abstract class BaseService {
protected realm: Realm | null = null
// 抽象类的构造函数应该是protected以防止外部直接实例化
protected constructor() {
// 构造函数逻辑使用someValue进行初始化
}
// 定义抽象方法,子类必须实现,打开数据库连接
abstract open(dbPath: string): void
// 关闭数据库连接
close(): void {
// 关闭数据库的连接,防止内存溢出
// 实现关闭数据库连接的逻辑
if (this.realm != null) {
console.log('Closing database connection')
this.realm.close()
this.realm = null // 清理引用,确保垃圾回收
}
}
transaction(func: () => unknown): void {
if (this.realm != null) {
// 判断当前的relam是不是在一个事务中
if (this.realm.isInTransaction) {
func()
} else {
this.realm.write(() => {
func()
})
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More