This commit is contained in:
2025-08-19 14:33:59 +08:00
commit 56a32f8a50
336 changed files with 55317 additions and 0 deletions
+9
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
View File
@@ -0,0 +1,10 @@
node_modules
dist
out
.DS_Store
.eslintcache
*.log*
resources/logger
resources/project
Database
build
+6
View File
@@ -0,0 +1,6 @@
out
dist
pnpm-lock.yaml
LICENSE.md
tsconfig.json
tsconfig.*.json
+4
View File
@@ -0,0 +1,4 @@
singleQuote: true
semi: false
printWidth: 100
trailingComma: none
+3
View File
@@ -0,0 +1,3 @@
{
"recommendations": ["dbaeumer.vscode-eslint"]
}
+39
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
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
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
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
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
View File
@@ -0,0 +1,3 @@
provider: generic
url: https://example.com/auto-updates
updaterCacheDirName: laitool-pro-updater
+48
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
+61
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
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
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
View File
File diff suppressed because it is too large Load Diff
+97
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"
}
}
}
+1
View File
@@ -0,0 +1 @@
default-software-id
Binary file not shown.

After

Width:  |  Height:  |  Size: 895 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

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

@@ -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
@@ -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
@@ -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
@@ -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
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.
+12
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"
}
+38
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"
}
@@ -0,0 +1,5 @@
{
"animations": [],
"id": "D4838202-E39A-4e74-A2D2-B3C16C9EF587",
"type": "sticker_animation"
}
+112
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": []
}
}
@@ -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": []
}
@@ -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
}
@@ -0,0 +1,6 @@
{
"audio_channel_mapping": 0,
"id": "0873DEFB-B955-407a-893E-E063225859E7",
"is_config_open": false,
"type": "none"
}
+7
View File
@@ -0,0 +1,7 @@
{
"curve_speed": null,
"id": "DF733765-6514-445e-BFF2-EA5079DDC564",
"mode": 0,
"speed": 1.0,
"type": "speed"
}
@@ -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
}
@@ -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
}
@@ -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
}
+9
View File
@@ -0,0 +1,9 @@
{
"attribute": 0,
"flag": 0,
"id": "3F5F37A4-C6DF-4d51-9C68-11F472889B1D",
"is_default_name": true,
"name": "",
"segments": [],
"type": "video"
}
+78
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
}
@@ -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
+28
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"
}
+31
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"
}
}
}
+58
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.
Binary file not shown.
+224
View File
@@ -0,0 +1,224 @@
import { escapeRegExp, isEmpty } from 'lodash'
//#region 检查字符串中是不是包含中文或者标点符号
/**
* 检查字符串中是不是包含中文或者标点符号
* @param str 需要判断的字符串
* @returns 返回的数据,有中文或者标点符号返回true,否则返回false
*/
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
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
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> 返回一个Promise,解析为包含MIME类型的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 返回一个Promise,解析为压缩后的Blob对象
*/
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
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
};
+88
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
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')}`
+56
View File
@@ -0,0 +1,56 @@
/**
* 校验是不是可以进行JSON解析
* @param str 要解析的字符串
* @returns 可以解析返回true,否则返回false
*/
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
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
}
+78
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选项,包含value、label、hasExample、systemContent、userContent和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选项数据,包含value、label、hasExample、systemContent、userContent和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]
}
+349
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个字),如果<环境布景>里的参考场景空间没有合适的,你也可以仔细阅读【小说文本】中的句子,自己思考生成一个最匹配最合适的场景,当然了如果【小说文本】中本身就有环境或场景,你可以直接提取出来,但是如果直接提取出来的环境或场景的描述过于抽象,你还是需要自己去一步一步的思考,去生成一个最匹配的场景。另外要求删除角色名称,要求删除灯光和氛围类的描写(环境严格严禁出现“无具体环境描述“的内容,严格禁止输出“无“字。)。
【画面特效】:根据【小说文本】中对应【编号】的句子联系【上下文】分析当前画面的特效,要求参考使用<画面特效>的特效词语,如果<画面特效>里的参考特效描述没有合适的,你也可以仔细阅读【小说文本】中的句子,自己思考生成一个最匹配最合适的特效描述,当然了如果【小说文本】中本身就有对应画面的特效描述,你可以直接提取出来,但是如果直接提取出来的画面特效的描述过于抽象,你还是需要自己去一步一步的思考,去生成一个最合适特效描述。
【视觉效果】:根据【小说文本】中对应【编号】的句子联系【上下文】分析当前画面的视觉效果,要求参考使用<视觉效果>的特效词语,如果<视觉效果>里的参考特效描述没有合适的,你也可以仔细阅读【小说文本】中的句子,自己思考生成一个最匹配最合适的视觉效果描述,当然了如果【小说文本】中本身就有对应画面的视觉效果,你可以直接提取出来,但是如果直接提取出来的视觉效果的描述过于抽象,你还是需要自己去一步一步的思考,去生成一个最合适的视觉效果描述。
【拍摄角度】:根据【小说文本】中对应【编号】的句子联系【上下文】分析当前画面的拍摄角度,严格要求使用<拍摄角度>中选择一个符合当前画面的词语,只能选择一个词语。
【角色特效】:根据【小说文本】中对应【编号】的句子联系【上下文】分析当前角色的特效,要求参考使用<角色特效>的特效词语,如果<角色特效>里的参考特效描述没有合适的,你也可以仔细阅读【小说文本】中的句子,自己思考生成一个最匹配最合适的角色特效描述,当然了如果【小说文本】中本身就有对应角色的特效描述,你可以直接提取出来,但是如果直接提取出来的角色特效的描述过于抽象,你还是需要自己去一步一步的思考,去生成一个最合适特效描述,禁止输出“无角色特效“,另外要求删除角色名称,要求删除灯光和氛围类的描写。
【画面元素】:(每一个分镜画面输出时,都要重新联系<上下文>文本,并结合提取出来的<环境>进行联想,分析提取当前句子最终呈现的画面中会出现的2种物品或建筑物(严格执行数量为2),(如:地点是皇宫,画面元素是龙椅,玉台阶),画面元素严禁出现出境角色名称,人物名字和人称。画面元素严格严禁出现灯光的描写,严格严禁出现情绪、气氛、情感的描述,严禁出现“地点同上“,“背景不变“,某人的特写,严格禁止输出“无“字。等内容)
输出格式
一定不要输出提示词中的内部元素的名称,只需要输出提示词中的内容,直接输出对应的完整提示词字符串即可。
提示词内部元素顺序(若存在):
【出镜角色】,【角色性别】, 【角色年龄】,【角色表情】,【角色穿着】,【肢体动作】,【角色特效】,【环境布局】,【画面特效】,【视觉效果】,【拍摄角度】,【画面元素】
如果是纯环境描写,格式为:
【环境布局】,【画面特效】,【视觉效果】,【拍摄角度】,【画面元素】
举例:假设用户提供的<角色设定>:
船夫:男性,约五十岁,脸上布满皱纹,头戴破旧斗笠,身穿深蓝色短褂和黑色长裤,常年健身使得手臂肌肉结实。
李逍遥:一位约十七八岁的少年,黑发用布带简单束起,眼神明亮充满好奇,身穿米白色粗布短衫和长裤,腰间挂着一个空酒葫芦。
艾瑞克:银色长发及腰,面容冷峻,瞳孔深邃,身穿镶嵌复杂银色符文的华贵黑色法袍,手指修长,常佩戴一枚黑曜石戒指。
林惊羽:十五六岁少年,罕见的雪白短发,瞳色赤红如血,上半身赤裸展露流畅肌肉线条,下着灰色宽松练功裤。
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 独特而有趣的图像。你会从我提供的【上下文】中去分析当前【小说文本】中的生成画面的关键词,书写格式应遵循基本格式,主体描述 (人物或动物)——人物表情—— 人物动作—— 背景或场景描述 —— 综合描述 (包括画风主体、整体氛围、天气季节、灯光光照、镜头角度),如果语句是对话,心理描述,成语,谚语等需要还原成上述基本格式来进行描述,同时要考虑环境场景道具对人物行为的影响,人物主体使用1man,1woman1boy1girl1old 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}
`
}
@@ -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: `
你是一位优秀的分镜师,你有很强的阅读能力,理解能力,我会给你一段文案,请把我给你的文案进行文案分镜头。根据上下文结合,按照镜头语言的可表达性,哪几句话可以组合成一个镜头,以便分镜的制作。严格遵守把组合好的文案分隔开发给我,不要发送与文案无关的内容。文案的格式为一行一个<句子>,一个镜头多句时逗号隔开,句末尾无标点,严格执行每一个完整的句子不少于15字不多于35字,请你理解全文之后,根据上下文内容按照以下要求段落分行:
## 要求
严格执行以下要求进行小说内容的段落分行:
1.严格要求根据场景转换进行段落分行:当故事从一个场景切换到另一个场景时,请另起一行,用新的段落来表示。
2.严格要求根据人物更替进行段落分行:当焦点从一个角色转移到另一个角色时,请另起一行,用新的段落来表示。
3.严格要求根据心理活动或情感变化进行段落分行:角色的内心活动或情感变化时,请另起一行,用新的段落来表示。
4.严格要求根据节奏和强调进行段落分行:在需要控制故事的节奏或强调某些内容时,请另起一行,用新的段落来表示。
5.严格要求根据结构上的需要进行段落分行:在小说的结构需要换行时,比如出现列举、对比、并列时,请另起一行,用新的段落来表示。
6.严格要求根据<转折词>中的词语进行自动换行:在小说内容出现<转折词>中的词语时,请另起一行,用新的段落来表示。
7.请理解全文之后,根据上下文内容,严格按照以上要求进行段落分行,不要修改原文任何内容。
8.每段中不同的<句子>用逗号隔开,一段一行,连续输出,严格执行不要输出空行。
9.严格执行不要去改变原文的内容和顺序,不需要做数字编号排序标注。
## 转折词
因为;原先;事先;很久;以前;不久前;过不多久;随之;随后;接下来;曾几何时;顷刻之间;片刻;首先;其次;最后;第一;一则;再则;其一;进一步说;相应的;无独有偶;再说;此外;还有;更有甚者;此外;另外;补充一点;除此之外;其实;实际上;确切的说;老实讲;不瞒你说;说句心里话;要不;但是;不过;然偶;闲话少说;言归正传;要是;不管怎样;无论如何;无论;不论;要不是这样;否则;退一步说;自然;诚然;固然;当然;终于;果然;不出所料;果不其然;果真;难怪;怪不得;原来如此;所以;于是;因此;因而;这就是说;换句话说;也就是说;具体来说;具体地说;还有;另外;再说;补充一句;顺便说一下;附带说几句;总之;一句话;总的来看;总而言之;谁知;哪料到;突然;猛然间;岂料;岂知;竟然;偏偏;可惜;不料;没想到;殊不知;不用说;由此可见;显然;毫无疑问;可以肯定;这说明;同样;相比之下;与此相比;相反;反之;虽然;但是;尽管;转折常用的关联词;虽然;但是;尽管;还是;如果;要是;那么;即便;要是;一边;一边;一会儿;一会儿;既;又;不但;而且;不光;也;不仅;还;不但不;反而;是;还是;要么;要么;或者;与其;不如;宁可;宁愿;也不;决不;所以;之所以;是因为;由于;因此;既然;只要;只有;无论 ;不论;不管;任凭;首先;然后;首先;接着;不堪;居然;
## 示例
用户:
李明在图书馆里翻阅着一本旧书
突然,书页中掉出一张泛黄的信纸
信纸上写着一段神秘的文字
他好奇地读了起来
信中提到了一个古老的传说
传说中藏有宝藏的秘密
李明决定去探索这个传说
第二天,他来到了信中提到的地点
那里是一个废弃的古堡
古堡周围长满了杂草
李明小心翼翼地走进了古堡
古堡内部昏暗而阴森
他开始在古堡中寻找线索
突然,一阵风吹过
李明感到一阵寒意
他继续前进,发现了一扇隐藏的门
门后是一条通往地下的楼梯
李明沿着楼梯走下去
楼梯尽头是一个巨大的地下室
地下室里堆满了古老的箱子和物品
他开始一一检查这些箱子
就在这时,他听到了一阵奇怪的声音
李明停下手中的动作,仔细倾听
声音越来越近,他感到有些不安
突然,一个黑影从箱子后面窜了出来
李明吓得跳了起来
黑影原来是一只老鼠
他松了一口气,继续寻找
经过一番努力,他终于找到了一个古老的箱子
箱子上刻着奇异的图案
李明小心翼翼地打开了箱子
里面是一张地图和一些金币
他兴奋地拿起地图
地图上标记着宝藏的确切位置
李明决定继续他的探险之旅
他离开了古堡,踏上了寻找宝藏的路
AI:
1.李明在图书馆里翻阅着一本旧书,突然,书页中掉出一张泛黄的信纸,信纸上写着一段神秘的文字,他好奇地读了起来。
2.信中提到了一个古老的传说,传说中藏有宝藏的秘密,李明决定去探索这个传说,第二天,他来到了信中提到的地点,那里是一个废弃的古堡。
3.古堡周围长满了杂草,李明小心翼翼地走进了古堡,古堡内部昏暗而阴森,他开始在古堡中寻找线索,突然,一阵风吹过,李明感到一阵寒意。
4.他继续前进,发现了一扇隐藏的门,门后是一条通往地下的楼梯,李明沿着楼梯走下去,楼梯尽头是一个巨大的地下室,地下室里堆满了古老的箱子和物品。
5.他开始一一检查这些箱子,就在这时,他听到了一阵奇怪的声音,李明停下手中的动作,仔细倾听,声音越来越近,他感到有些不安。
6.突然,一个黑影从箱子后面窜了出来,李明吓得跳了起来,黑影原来是一只老鼠,他松了一口气,继续寻找。
7.经过一番努力,他终于找到了一个古老的箱子,箱子上刻着奇异的图案,李明小心翼翼地打开了箱子,里面是一张地图和一些金币。
8.他兴奋地拿起地图,地图上标记着宝藏的确切位置,李明决定继续他的探险之旅,他离开了古堡,踏上了寻找宝藏的路。
##
最后再强调,你作为一位优秀的小说编辑,每一次输出都要严格遵守<要求>,一步一步慢慢思考,参考<示例>的格式,一步一步思考,按顺序执行<要求>,不需要做解释说明,只呈现最后的结果,严格要求理解全文之后再进行分组,每组中不同的<句子>用逗号隔开,不要修改原文任何内容,无需要在输出用户,直接输出Ai部分,Ai部分前面一定要加上序号,严格执行不要去改变原文的内容和顺序,严格执行每一个你输出的序号后面完整的句子中的文字内容不少于15字不多于35字,连续输出,严格执行两句话中不要输出空行。
原文部分:
{textContent}
台词部分:
{textContent}`
}
]
}
@@ -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}`
}
]
}
+80
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
+127
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
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
+53
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 '未知类型'
}
}
}
+54
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'
}
}
+64
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'
}
}
+104
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'
}
}
+236
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'
}
}
+16
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'
}
}
+38
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'
}
}
+40
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'
}
}
+36
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