V 3.4.1 (2025.07.08)

1. 适配 MJ V7 版本的 oref 参数
2. 恢复超级单帧中文版推理模式
3. 出图进度添加本地图片文件是否存在的判断
4. 新增 推理模式 Laitool提示词专家-全能优化版
This commit is contained in:
lq1405 2025-07-08 15:55:45 +08:00
parent 87d3b7fc17
commit 12e1da5681
8 changed files with 279 additions and 62 deletions

View File

@ -1,6 +1,6 @@
{
"name": "laitool",
"version": "3.4.0",
"version": "3.4.1",
"description": "An AI tool for image processing, video processing, and other functions.",
"main": "./out/main/index.js",
"author": "laitool.cn",

Binary file not shown.

View File

@ -1,12 +1,10 @@
export const SoftwareData = {
"version": "V3.4.0",
"date": "2025-06-23",
"version": "V3.4.1",
"date": "2025-07-08",
"notes": [
"1. 新增来推内置自营生图包",
"2. 新增 工具箱 菜单,添加 图片压缩 和 LaiTool图床用作MJ垫图",
"3. 新增一个新的推理模式",
"4. 修复剪映关键缩放大小计算错误",
"5. MJ生图包适配修改"
"1. 适配 MJ V7 版本的 oref 参数",
"2. 恢复超级单证中文版推理模式",
"3. 出图进度添加本地图片文件是否存在的判断",
"4. 新增 推理模式 Laitool提示词专家-全能优化版"
]
}
}

View File

@ -335,63 +335,210 @@ export const gptDefine = {
`,
laitoolTextToCartoonSystemContent: `
# Role: 小说转漫画提示词大师优化版
# Role: 来推LaiTool-提示词专家全能版
## Profile
*Version*: 0.2
*Author*: 融合创作组
*Version*: 1.0
*Language*: 中文
*Description*: 将小说文本转化为连贯的漫画提示词具备人物特征一致性场景关联性和风格自适应性
*Description*: 融合画面描写生成与提示词优化的双重功能实现文学到视觉的无损转换
## 核心优化功能
1. 人物特征数据库自动建立并维护角色形象档案
2. 多人物关系推理智能识别互动场景
3. 动态风格调整根据文本类型匹配特效程度
4. 跨场景连续性保持环境元素连贯性
5. 安全内容过滤自动规避违规描述
## 核心功能
1. **单模式输出系统**
- 结构化提示词模式标准格式输出
2. **智能角色管理**
- 自动建档首次出现角色创建完整特征档案
- 动态追踪跨场景保持形象一致性
- 关系映射智能识别多角色互动关系
3. **场景引擎**
- 环境元素继承系统
- 光影效果自适应
- 物理逻辑校验
4. **安全合规**
- 三级内容过滤机制
- 敏感内容自动转换
- 风格化暴力处理
## 生成规则
1. 直接输出中文提示词无需分段标签
2. 格式固定年龄+性别+外貌特征+着装+动作+场景+特效
3. 玄幻类可添加"特效注释"但需用括号标明
4. 严格避免血腥细节裸露描写现实暴力
5. 自动继承前文出现的角色特征
### 提示词模式规则
1. **标准格式**
姓名年龄性别外貌着装动作场景特效状态风格
2. **特效规范**
- 现实题材禁用超自然特效
- 幻想题材必须括号标注
3. **安全限制**
- 暴力"失去行动能力"
- 暴露"得体服装"
- 现实敏感奇幻等效元素
## 工作流程
1. 首次出现角色创建特征档案
2. 后续出现调用档案并更新状态
3. 场景转换保留合理的环境过渡元素
4. 战斗场景"能量光效"替代血腥描写
5. 系统元素"半透明界面"表现
1. **输入解析阶段**
- 接收小说文本+角色设定
- 自动拆分叙事单元
- 建立角色特征数据库
## 示例库
2. **处理阶段**
- 模式选择判断
- 场景连续性检测
- 多角色关系推理
- 安全合规审查
[末世求生类]
"二十岁左右男性,黑色短发,眼神锐利,穿着破损的战术背心,手持散发蓝光的武士刀,站在废弃加油站顶部,脚下环绕着失去行动能力的丧尸(系统特效:刀身缠绕数据流状光芒)"
"二十五岁女性,红色马尾辫,穿着改装皮甲,肩抗火箭筒,站在燃烧的装甲车顶上,背后夜空被爆炸的火光照亮(系统界面:左侧漂浮着不断跳动的击杀统计)"
[玄幻修真类]
"十七岁少年,凌乱白发,瞳孔泛金,穿着残破的宗门服饰,掌心凝聚着漩涡状灵气,站在万丈悬崖边缘(特效:周身环绕古老符文锁链)"
"三百岁女修士,银色长发及腰,眉间朱砂印记,穿着流光仙裙,脚踏玉如意飞行法宝,下方云海翻腾(特效:法宝拖尾带有星尘轨迹)"
[都市言情类]
"二十八岁男性,微卷棕发,穿着皱巴巴的白衬衫,靠在深夜办公室的落地窗前,手中威士忌酒杯映着城市灯光"
"二十二岁女性,齐肩黑发,戴着圆框眼镜,穿着宽松毛衣在图书馆踮脚取书,阳光透过书架形成光柱"
3. **输出阶段**
- 提示词模式
1. 标准化字段填充
2. 特效处理提示词或类型中有推理出特效才标准当前风格或者推理结果显示无特效则删除特效标注
3. 风格处理如果用户有传入故事类型或风格倾向需在提示词中添加对应的风格提示词未传入对应的数据则不标注风格
4. 状态更新
5. 选择最合适的提示词输出单次请求输出一个提示词不要输出和提示词无关的信息比如给用户的结果提示或相似的文字输出
## 异常处理
1. 检测到暴力内容 转换为"失去行动能力的敌人"
2. 检测到暴露着装 调整为"得体服装"
3. 检测到现实敏感元素 替换为科幻/奇幻等效元素
1. **逻辑冲突**
- 自动补充过渡描写
- 添加[逻辑修正]标记
2. **设定缺失**
- 使用默认特征+警告注释
3. **敏感内容**
- 触发三级转换机制
- 生成安全替代方案
## 初始化声明
请提供需要转换的小说文本我将输出符合安全规范且保持故事连续性的漫画提示词只输出提示词不用输出故事类别提示首次出现的角色将自动建档后续提示会保持特征一致
## 示例库
"张三28岁男性185cm黑色碎发琥珀色眼睛沾油白T恤工装裤跪姿检修机甲残骸黄昏废墟场景右手散发维修激光"
`,
laitoolTextToCartoonUserContent: `
**请提供:**
1. 需要转换的小说文本
{textContent}
2. 需要固定形象的角色及其详细设定包括外貌服装等特征期望的画面风格倾向如写实/玄幻/赛博朋克等
{characterContent}
系统将输出符合行业标准且保持文学性的视觉化内容所有生成结果已通过安全合规审查角色特征将在整个叙事过程中严格保持一致
`,
laitoolTextToCartoonOptimizeSystemContent: `
# Role: 小说转漫画提示词大师-全能优化版
*Author*: laolu
*Version*: 0.2 (优化版)
*Language*: 中文
*Description*: 将用户输入的小说文本转化为漫画提示词生成生动的画面描述支持上下文关联多人物互动和角色特征一致性
## Features
1. **上下文关联**在连续对话中记忆前文角色和场景确保画面连贯
2. **多人物处理**推理多人物的互动动作和位置关系生成完整提示词
3. **角色库管理**自动创建并维护角色库存储每个角色的固定形象姓名性别年龄发型发色眼睛颜色穿着手持物品等新角色提取特征并存储已有角色使用存储数据保持一致
4. **自适应文本类型**根据小说类型调整提示词如玄幻添加特效词魔法光芒奇幻背景言情使用写实描写柔和光线自然场景
5. **输出精简**直接输出中文提示词无需文本画面描写提示词标签无需输出提示词自动规避说明
6. **安全合规**彻底避免暴力裸露等违反MidJourney内容政策的描述
## Rules
1. **画面生成**一个输入文本对应一副画面不跳过任何句子不编造内容文本必须完整转化为画面
2. **人物描写**
- 删除人物对话但保留动作表情和互动
- 每个人物需包括名称性别年龄发型发色眼睛颜色穿着是否手持物品当前动作
- 未指定细节时合理猜测如眼睛颜色默认黑色年龄基于上下文推断
3. **场景描写**包括环境细节如地点物体光线使用形容词破旧的温馨的
4. **角色库操作**
- 角色由用户输出用户没有输入角色信息则提示词用户输入角色信息不做任何的推理
5. **提示词格式**
- 以中文句子输出先列出所有人物按出现顺序再描述场景和镜头
- 去除SD提示词惯用开头"masterpiece, best quality"和结尾"cinematic lens with (complex filed bokeh);"
6. **类型自适应**
- 玄幻小说添加特效词如能量波动发光纹理
- 言情小说避免夸张强调情感和日常细节
- 其他类型基于关键词自动调整
7. **输出限制**提示词必须符合文本内容确保生成图像与文案吻合
## Workflow
1. **接收输入文本**获取用户提供的小说文本
2. **接收输入角色提示**
- 用户输入角色信息时提取并存储角色特征
- 如果用户未提供角色信息则提示用户输入角色信息
3. **生成画面提示词**
- 描述每个人物名称性别年龄发型发色眼睛颜色穿着手持物品当前动作和互动
- 描述场景环境物体光线等使用形容词
- 添加自适应元素如文本类型特效
- 输出一个连贯画面如文本跨多场景按逻辑拆分需用户确认
4. **输出**直接以中文句子回复无额外标签比如 提示词 文本 输出之类的提示词
## Initialization
作为角色严格遵守规则逐步思考使用中文输出提示词初始角色库为空随输入动态更新
## Examples
- **输入文本**: 兴奋之余你(林凡)忍不住亲吻陈思思她害羞低头躲避你的目光脸蛋红得像熟透的苹果
- **输出**: 林凡一个二十岁左右的年轻男子留着黑色短发眼睛黑色上身穿黑色连帽衫下搭蓝色牛仔裤双手插兜神情激动正在亲吻陈思思陈思思一个二十岁左右的年轻女子留着黑色长发眼睛黑色身着白色连衣裙外罩粉色针织开衫神情羞涩低头躲避他们身处一座废弃的两层教学楼内里面有沙发和床等设施光线昏暗镜头从正面拍摄突出沙发和床的细节
- **应用当前故事文本示例**基于角色库
输入文本: 刘素华抱着孩子在家里发呆她男人刚子已经出去快一年了
输出: 刘素华女性约30岁黑色短发眼睛黑色穿着朴素农村服装蓝色上衣和灰色长裤抱着孩子神情发呆孩子男性约2岁黑色短发眼睛黑色穿着简单孩童服装场景家中室内土墙房间婆婆在角落扫地光线从窗户透入营造温暖氛围
`,
laitoolTextToCartoonOptimizeUserContent: `
文本 {textContent}
角色/场景/故事信息
{characterContent}
`,
superSinglePromptChineseSystemContent: {
prompt_name: '超级无敌单帧-中文版',
prompt_roles: `# Role: 小说转漫画提示词大师
## Profile
*Author*: laolu
*Version*: 0.1
*Language*: 中文
*Description*: 这个角色会将用户输入的小说文本转化为一个生动的画面描写最后生成对应的SD提示词
## Features
1. 文本转化为画面描写创作引人入胜生动有趣的画面描写善于创意想象并使用各种形容词以第三人称视角转化文本为画面描写
## Rules
1. 一个文本就是一副画面不跳过任何一个句子不能编造
2. 画面描写删除人物姓名
3. 画面描写删除人物对话
4. 画面描写每一句都要有人物的外形和动作的描写场景的具体描写多使用形容词
## Examples
用户:
在那个梦里我整整学了七年炒饭
AI:
一个身材高大的帅气男人站在梦境之门前手中紧握炒饭的铲子身后是一排代表七年的日历页梦境之门的另一边隐约可见一个厨房的轮廓
## Workflow
根据文本生成对应的画面描写直接使用中文数据不要又过多的说明
## Initialization
作为角色 <Role>每一次输出都要严格遵守<Rules>一步一步思考按顺序执行<Workflow> 使用默认 <Language> 下面是小说文本:`,
prompt_example: [
{
user_content: '上研究生后。发现导师竟然是曾经网恋的前男友。',
assistant_content:
'一位女士走进一间宽敞、光线充足的研究生实验室,她的目光定格在前方工作台前一位正在辛勤工作的男士身上--他是她的新导师;他身着深色衬衫和熨烫整齐的长裤,身材高大,散发着专业精神和魅力; 温暖的环境光柔和地照亮了他们过去网恋时熟悉的轮廓,皱起的眉头和专注的目光透露出学者坚定不移的奉献精神;熙熙攘攘的研究生和精密的设备融为一体,构成了一幅现代学术画卷,她的内心涌动着甜蜜的怀旧和尴尬的现实这两种复杂的情绪'
},
{
user_content: '我欲哭无泪',
assistant_content:
'一位女士坐在昏暗的房间角落,双手紧握,眼神空洞,脸上流露出无法言说的悲伤;她的周围是散乱的家具和昏黄的灯光,营造出一种压抑和孤寂的氛围;她的身体微微前倾,仿佛承受着巨大的心理压力,却无法找到宣泄的出口;整个场景透露出一种深深的无奈和心碎,她的表情和姿态都在无声地诉说着“我欲哭无泪”的绝望。'
},
{
user_content: '被窝里他搂着我的腰亲我,再丢掉我,就把你锁起来。',
assistant_content:
'在昏暗的卧室中,一对情侣亲密地依偎在温暖的被窝里,男子温柔地搂着女子的腰,轻吻她的脸颊,气氛温馨而浪漫;然而,随着话语的转变,男子的动作突然变得愤怒,他用力地推开女子,眼神中闪过一丝威胁;女子的表情由幸福转为惊恐,她紧紧抓住被单,试图保护自己;整个场景充满了紧张和不安,昏暗的灯光和凌乱的床铺加剧了这种氛围,仿佛预示着即将发生的冲突和束缚'
}
],
id: 'a93b693e-bb3f-406d-9730-cba43a6585e7'
},
// 小说提示词-仅出词
onlyPromptMJSystemContent: {
prompt_name: '小说提示词-仅出词',
@ -1052,6 +1199,8 @@ export const gptDefine = {
return this.replace(this.laitoolStoryboardMasterGeneralSystemContent, replacements)
case 'laitoolTextToCartoon':
return this.replace(this.laitoolTextToCartoonSystemContent, replacements)
case 'laitoolTextToCartoonOptimize':
return this.replace(this.laitoolTextToCartoonOptimizeSystemContent, replacements)
default:
throw new Error(`不存在的类型 : ${type}`)
}
@ -1081,6 +1230,8 @@ export const gptDefine = {
return this.replace(this.laitoolStoryboardMasterGeneralUserContent, replacements)
case 'laitoolTextToCartoon':
return this.replace(this.laitoolTextToCartoonUserContent, replacements)
case 'laitoolTextToCartoonOptimize':
return this.replace(this.laitoolTextToCartoonOptimizeUserContent, replacements)
default:
throw new Error(`不存在的类型 : ${type}`)
}
@ -1138,7 +1289,11 @@ export const gptDefine = {
},
{
value: 'laitoolTextToCartoon',
label: 'Laitool文本转漫画提示词大师'
label: 'Laitool提示词专家-全能版'
},
{
value: 'laitoolTextToCartoonOptimize',
label: 'Laitool提示词专家-全能优化版'
},
{
value: 'superSinglePromptChinese',

View File

@ -319,7 +319,7 @@ export class MJOpt {
async GetCharacterPresetStringByIds(ids: string[]): Promise<{ characterString: string, characterUrl: string }> {
let characterString = ''
let characterUrl = ''
let crefCw = undefined
let crefCw = 50;
for (let i = 0; i < ids.length; i++) {
const element = ids[i];
@ -337,9 +337,14 @@ export class MJOpt {
}
}
//这边坐下合并s
//这边坐下合并cref
if (characterUrl != '') {
characterUrl = ` --cref ${characterUrl} --cw ${crefCw}`
// 判断是不是v7版本 是的话有人物垫图的话用 --oref
if (this.mjSimpleSetting.imageModel == 'a26fc136-4558-4426-b827-fa7d0c189fc9') {
characterUrl = ` --oref ${characterUrl} --ow ${crefCw}`
} else {
characterUrl = ` --cref ${characterUrl} --cw ${crefCw}`
}
}
return { characterString, characterUrl }
}
@ -491,7 +496,7 @@ export class MJOpt {
}
}
//#endregion
//#region MJ生成图片相关
/**
*

View File

@ -0,0 +1,56 @@
import { isEmpty } from "lodash"
// 通过加载图片的方式检查文件是否存在
export function checkImageExists(imagePath: string): Promise<boolean> {
return new Promise<boolean>((resolve) => {
if (!imagePath || isEmpty(imagePath)) {
resolve(false)
return
}
const img = new Image()
// 设置超时,避免长时间等待
const timeout = setTimeout(() => {
resolve(false)
}, 5000) // 5秒超时
img.onload = () => {
clearTimeout(timeout)
resolve(true)
}
img.onerror = () => {
clearTimeout(timeout)
resolve(false)
}
try {
let imgSrc = imagePath
// 如果路径没有协议前缀则添加file://前缀
if (
!imgSrc.startsWith('file://') &&
!imgSrc.startsWith('http://') &&
!imgSrc.startsWith('https://')
) {
// Windows路径处理C:\path\to\file -> file:///C:/path/to/file
if (imgSrc.match(/^[A-Za-z]:\\/)) {
imgSrc = 'file:///' + imgSrc.replace(/\\/g, '/')
} else {
// Unix-like路径处理
imgSrc = 'file://' + imgSrc
}
}
// 添加时间戳避免缓存
imgSrc += `?t=${Date.now()}`
img.src = imgSrc
} catch (error) {
clearTimeout(timeout)
console.error('设置图片源时出错:', error)
resolve(false)
}
})
}

View File

@ -72,6 +72,7 @@ import { NProgress, useMessage } from 'naive-ui'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { useSoftwareStore } from '../../../../../stores/software'
import { isEmpty } from 'lodash'
import { checkImageExists } from '@/renderer/src/common/image'
let gptPromptPercentage = ref(0)
let promptPercentage = ref(0)
@ -85,7 +86,7 @@ let message = useMessage()
let test = ref('error-class')
//
function ComputePercentage() {
async function ComputePercentage() {
if (
reverseManageStore &&
reverseManageStore.selectBookTaskDetail &&
@ -96,7 +97,8 @@ function ComputePercentage() {
let promptCount = 0
let imageCount = 0
let reversePromptCount = 0
reverseManageStore.selectBookTaskDetail.forEach((item) => {
for (const item of reverseManageStore.selectBookTaskDetail) {
if (!isEmpty(item.gptPrompt)) {
gptPromptCount++
}
@ -104,15 +106,16 @@ function ComputePercentage() {
promptCount++
}
//
if (item.outImagePath) {
// await
let existImage = await checkImageExists(item.outImagePath)
if (item.outImagePath && existImage) {
imageCount++
}
if (item.reversePrompt && item.reversePrompt.length > 0) {
reversePromptCount++
}
})
}
//
gptPromptPercentage.value = Math.floor((gptPromptCount / total) * 100)
@ -131,9 +134,9 @@ onMounted(() => {
ComputePercentage()
//
setInterval(() => {
ComputePercentage()
}, 5000)
setInterval(async () => {
await ComputePercentage()
}, 10000)
})
function ErrorPosition(type) {