diff --git a/package.json b/package.json index d56b6b1..ce59fc4 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/resources/scripts/db/book.realm.lock b/resources/scripts/db/book.realm.lock index bb9e84c..7e8318d 100644 Binary files a/resources/scripts/db/book.realm.lock and b/resources/scripts/db/book.realm.lock differ diff --git a/resources/scripts/db/software.realm.lock b/resources/scripts/db/software.realm.lock index fe9b9e5..221955b 100644 Binary files a/resources/scripts/db/software.realm.lock and b/resources/scripts/db/software.realm.lock differ diff --git a/src/define/data/softawareData.ts b/src/define/data/softawareData.ts index ebc064c..4c399e5 100644 --- a/src/define/data/softawareData.ts +++ b/src/define/data/softawareData.ts @@ -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提示词专家-全能优化版" ] - -} \ No newline at end of file +} diff --git a/src/define/gptDefine.js b/src/define/gptDefine.js index 96033b7..c10344b 100644 --- a/src/define/gptDefine.js +++ b/src/define/gptDefine.js @@ -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 + + 作为角色 ,每一次输出都要严格遵守,一步一步思考,按顺序执行 ,使用默认 ,下面是小说文本:`, + 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', diff --git a/src/main/Service/MJ/mj.ts b/src/main/Service/MJ/mj.ts index 6c3121f..deb6ed5 100644 --- a/src/main/Service/MJ/mj.ts +++ b/src/main/Service/MJ/mj.ts @@ -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生成图片相关 /** * 单个生成图片,将任务添加到队列中 diff --git a/src/renderer/src/common/image.ts b/src/renderer/src/common/image.ts new file mode 100644 index 0000000..e9b75e0 --- /dev/null +++ b/src/renderer/src/common/image.ts @@ -0,0 +1,56 @@ +import { isEmpty } from "lodash" + +// 通过加载图片的方式检查文件是否存在 +export function checkImageExists(imagePath: string): Promise { + return new Promise((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) + } + }) +} \ No newline at end of file diff --git a/src/renderer/src/components/Book/MJReverse/MonitorStatus.vue b/src/renderer/src/components/Book/MJReverse/MonitorStatus.vue index cc202fe..f11c003 100644 --- a/src/renderer/src/components/Book/MJReverse/MonitorStatus.vue +++ b/src/renderer/src/components/Book/MJReverse/MonitorStatus.vue @@ -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) {