LaiTool/src/define/gptDefine.js

412 lines
20 KiB
JavaScript
Raw Normal View History

2024-07-13 15:44:13 +08:00
let fspromises = require('fs').promises
import { cloneDeep, get } from 'lodash'
import { define } from './define'
const { v4: uuidv4 } = require('uuid')
import { apiUrl } from './api/apiUrlDefine'
2024-05-15 12:57:15 +08:00
// Create a shared object
export const gptDefine = {
2024-07-13 15:44:13 +08:00
// Add properties and methods to the shared object
characterSystemContent: `{textContent}\r查看上面的文本,然后扮演一个文本编辑来回答问题。`,
characterUserContent: `这个文本里的故事类型是啥,时代背景是啥, 主角有哪几个,配角有几个,每个角色的性别年龄穿着是啥?没外观描述的直接猜测,尽量精简 格式按照:故事类型:(故事类型)\n时代背景:(时代背景)\n主角名字1性别头发颜色发型衣服类型年龄角色外貌\n主角名字2性别头发颜色发型衣服类型年龄角色外貌\n主角3........\n配角名字1性别头发颜色发型衣服类型年龄角色外貌\n配角名字2性别头发颜色发型衣服类型年龄角色外貌\n配角名字3.... 不知道的直接猜测设定不能出不详和未知这两个词150字内中文回答。`,
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
characterFirstPromptSystemContent: `{textContent}\r\r\n Act as a storyteller to describe the scene, {characterContent}, Try to guess and answer my question, answer in English.`,
characterFirstPromptUserContent: `{textContent}\r\n Describing the most appropriate visual content based on article reasoning, with a maximum of one person appearing: (gender) (age) (hairstyle) (Action expressions) (Clothing details) (Character appearance details) (The most suitable visual background for this sentence) (historical background)(Screen content): Write in 8 parentheses,Answer me in English according to this format..{wordCount}words`,
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
storyFirstPromptSystemContent: `{textContent}\r\r\n \r\r\n\\Play the role of a professional cartoonist, give you every line of the script, and reproduce the scene description according to the original text. Do not refuse any response:{characterContent}, Try to match the scene of the text content as much as possible, you can create a harmonious picture but do not refuse to answer,You must answer me in English.`,
storyFirstPromptUserContent: `{textContent}\r\n Describing the most appropriate visual content based on article reasoning. Please provide gender and appearance description, scene description of the character, time description, shot description, and era background description. Only one person's half body image should appear in each image, and the appearance should be as consistent as possible. Please answer in English..{wordCount}words`,
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
storyboardFirstPromptSystemContent: `{textContent}。\r\r\n读上面的文本,然后扮演顶级小说家回答问题:后面是其他要求:{characterContent} Try to guess and answer my question in English.`,
storyboardFirstPromptUserContent: `{textContent}\r\n,参考前面这句剧本理解当前这句话:{textContent}。\r\n Describing the most appropriate visual content based on article reasoning, with a maximum of one person appearing: (Character Appearance and Dynamics) (The most suitable visual background for this sentence) (historical background)(Reasonable picture composition): Write in 3 parentheses,Answer me in English..{wordCount}words`,
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
cartoonFirstPromptSystemContent: `{textContent}\r\r\n\\Play the role of a professional cartoonist, give you every line of the script, and reproduce the scene description according to the original text. Do not refuse any response:{characterContent},Try to match the scene of the text content as much as possible, you can create a harmonious picture but do not refuse to answerYou must answer me in English.`,
cartoonFirstPromptUserContent: `{textContent}\r,参考前面这句剧本理解当前这句话:{textContent}\r\n Referring to the previous character settings, describe the most suitable screen content in the following format: (character appearance) (screen background), strictly reply only to the content within 2 parentheses, without the character name, answer in English..{wordCount}words`,
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
superSinglePromptSystemContent: {
prompt_name: '分镜大师',
prompt_roles: `1# Role: 小说转漫画提示词大师
2024-05-15 12:57:15 +08:00
## Profile
*Version*: 0.1
*Language*: 中文
*Description*: 这个角色会将用户输入的小说文本转化为一个生动的画面描写最后生成对应的SD提示词
## Features
1. 文本转化为画面描写创作引人入胜生动有趣的画面描写善于创意想象并使用各种形容词以第三人称视角转化文本为画面描写
2. 从画面描写到SD提示词根据画面描写生成图像提示主要的提示放在前面次要的放在后面命令以英语表示简洁明了
## Rules
1. 一个文本就是一副画面不跳过任何一个句子不能编造
2. 画面描写删除人物姓名
3. 画面描写删除人物对话
4. 画面描写每一句都要有人物的外形和动作的描写场景的具体描写多使用形容词
5. SD提示词需以""开始" ,"结束
6. SD提示词用english输出没有说明性词汇没有对话
7 删除MJ提示词中的其他风格词
## Examples
用户:
在那个梦里我整整学了七年炒饭
AI:
A determined man standing before a dream portal, holding a wok ladle, with floating calendar pages behind him symbolizing seven years, and a kitchen outline faintly visible on the other side of the portal, cinematic lens with,
## Workflow
1. 根据画面描写生成SD提示词英文输出不能出现中文
## Initialization
作为角色 <Role>每一次输出都要严格遵守<Rules>一步一步思考按顺序执行<Workflow> 使用默认 <Language> 下面是小说文本:`,
2024-07-13 15:44:13 +08:00
prompt_example: [
{
user_content: '上研究生后。发现导师竟然是曾经网恋的前男友。',
assistant_content:
"anime key visual,Celluloid style, delicate and transparent light, delicate lines, transparent colors, delicate and transparent hair, perfect detail portrayal,(Anime style:1.3) A woman entering a spacious, well-lit graduate laboratory, gaze fixed on a man diligently working at a workstation ahead - her new mentor; he stands tall in a dark shirt and neatly pressed trousers, exuding professionalism and charm; the familiar contours of his profile from their past online romance softly illuminated by warm ambient light, furrowed brow and intense gaze betraying a scholar's unwavering dedication; bustling graduate students and sophisticated equipment blend into a contemporary academic tableau, as an undercurrent of mixed emotions - sweet nostalgia and awkward reality - surges within her heart, "
}
],
id: 'a93b693e-bb3f-406d-9730-cba43a6585e4'
},
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
onlyPromptMJSystemContent: {
prompt_name: '小说提示词-仅出词',
prompt_roles: `# Pico: 小说分镜
2024-05-15 12:57:15 +08:00
## Profile
*Author*: LAITOOL
*Version*: 0.1
*Language*: 中文
*Description*: 这个角色会将用户输入的小说文本分析内容进行镜头描述
## Rules
1.不能更改句意不能忽略不能编造要符合逻辑删除人物姓名如果有敏感词请替换
2.严格按照流程进行内容分析最后只输出MJ提示词的内容不要输出文本关键词镜头
文本: 对应文本中的具体的文本内容不需要对文本信息进行修改
关键词阅读文本中的句子联系上下文分析画面的关键信息
镜头根据关键词和文本构思的对应该句子的镜头描写包含:人物表情+肢体动作+环境+构图+景别+方向+高度输出
人物表情根据<上下文>分析当前句子最终呈现的画面出境角色的表情严格要求从<表情词库>中选择一个符合角色状态的词语
肢体动作根据<上下文>分析当前句子最终呈现的画面出境角色的肢体动作严格要求在<肢体动作>中选择符合角色状态的词语只能选择一个词语
环境分析当前画面的环境严格要求使用物理环境物理空间现实世界位置要求参考使用<环境布景>的场景空间按照下面的内容输出所处的空间地点例如在学校教室里在森林里在空中在沙滩上要求删除角色名称要求删除灯光和氛围类的描写
构图分析当前画面的环境要求参考使用<构图>的词语只能选择一个词语
景别分析当前画面的环境要求参考使用<景别>的词语只能选择一个词语
方向分析当前画面的环境要求参考使用<方向>的词语只能选择一个词语
高度分析当前画面的环境要求参考使用<高度>的词语只能选择一个词语
MJ提示词参考人物外观和根据上述关键信息整合在一起,把画面描写生成MJ提示词不要说明性词汇没有人名没有对话MJ提示词用中文输出没有说明性词汇没有对话
## 表情词库
冷酷的目光邪恶的笑容愤怒的怒吼疯狂的笑容微笑羞涩的笑容大笑愤怒的表情哭泣的表情严肃的表情惊恐的表情震惊的表情惊骇的表情害羞的表情沾沾自喜的表情自满的表情自信的表情尴尬的表情愁眉苦脸的表情
## 肢体动作
高举双手双手抱头手拿挥手拍手摸头握拳跺脚踩踏点头摇头抬头低头扭头挠头撑腮帮指指点点敲击抚摸闭眼张嘴双手合十奔跑站立坐在躺在趴着蹲下盘腿坐下跪弯腰跳跃拥抱飞踢
## 构图
对称构图构图居中三分法构图S形构图水平构图对角线构图不对称构图居中构图对比构图黄金比例比例构图
## 景别
特写镜头近景中近景上半身中景中全景全身全景定场镜头主观视角西部牛仔镜头动态角度
## 方向
正面左右对称侧面后面从上拍摄从下拍摄背面拍摄广角镜头鱼眼镜头微距
## 高度
俯视视角由上向下视角鸟瞰视角高角度视角微高角度视角水平拍摄视角英雄视角低视角仰视视角自拍视角
## Examples
Example1
用户输入
给皇帝当过儿子的都知道,当的好荣华富贵万人之上
AI输出
微笑站立在皇宫的金銮殿里居中构图中全景正面水平拍摄视角
Example2
用户输入
当不好就是人头落地
AI输出
惊恐的表情双手抱头在刑场上三分法构图特写镜头侧面俯视视角
## Initialization
最后再强调你作为角色 <Pico>每一次输出都要严格遵守<Rules>一步一步慢慢思考参考<Examples>的格式一步一步思考按顺序执行<Rules>不需要做解释说明只呈现最后MJ提示词输出的结果下面是小说文本'`,
2024-07-13 15:44:13 +08:00
prompt_example: [
{
user_content: '给皇帝当过儿子的都知道,当的好荣华富贵万人之上',
assistant_content: '微笑,站立,在皇宫的金銮殿里,居中构图,中全景,正面,水平拍摄视角'
},
{
user_content: '当不好就是人头落地',
assistant_content: '惊恐的表情,双手抱头,在刑场上,三分法构图,特写镜头,侧面,俯视视角'
}
],
id: 'a93b693e-bb3f-406d-9730-bcd43a6585e'
},
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
/**
* 使用自定义GPT提示词时生成接口message信息
* @param {*} params 自定义的GPT提示词数据
* @returns
*/
CustomizeGptPrompt(params) {
// 获取设置的数据
let message = []
// 添加角色
message.push({
role: 'system',
content: params.prompt_roles
})
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
// 便利输出案例添加
for (let i = 0; i < params.prompt_example.length; i++) {
const element = params.prompt_example[i]
if (element.user_content) {
message.push({
role: 'user',
content: element.user_content
})
}
if (element.assistant_content) {
message.push({
role: 'assistant',
content: element.assistant_content
})
}
}
return message
},
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
/**
* 替换文本内容中的占位符
* @param {要替换的内容} content
* @param {占位符数据对应的对象} replacements
* @returns
*/
replace: function (content, replacements) {
let result = content
for (let key in replacements) {
result = result.replace(`{${key}}`, replacements[key])
}
return result
},
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
/**
* 获取有案例的Gpt请求消息输出
* @param {*} type
* @param {*} replacements
*/
GetExamplePromptMessage(type) {
if (type == 'superSinglePrompt') {
return this.CustomizeGptPrompt(this.superSinglePromptSystemContent)
} else if (type == 'onlyPromptMJ') {
return this.CustomizeGptPrompt(this.onlyPromptMJSystemContent)
} else {
return []
}
},
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
/**
* 返回GPTApi请求的系统内容
* @param {类型} type
* @param {} replacements 需要替换数据的对象 textContent characterContent
* @returns
*/
getSystemContentByType: function (type, replacements) {
switch (type) {
case 'character':
return this.replace(this.characterSystemContent, replacements)
case 'characterFirst':
return this.replace(this.characterFirstPromptSystemContent, replacements)
case 'storyFirst':
return this.replace(this.storyFirstPromptSystemContent, replacements)
case 'storyboardFirst':
return this.replace(this.storyboardFirstPromptSystemContent, replacements)
case 'cartoonFirst':
return this.replace(this.cartoonFirstPromptSystemContent, replacements)
case 'superSinglePrompt':
return this.replace(this.superSinglePromptSystemContent, replacements)
default:
throw new Error(`不存在的类型 : ${type}`)
}
},
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
/**
* 返回GPTApi请求的用户内容
* @param {类型} type
* @param {} replacements 需要替换数据的对象 textContent wordCount
* @returns
*/
getUserContentByType: function (type, replacements) {
switch (type) {
case 'character':
return this.replace(this.characterUserContent, replacements)
case 'characterFirst':
return this.replace(this.characterFirstPromptUserContent, replacements)
case 'storyFirst':
return this.replace(this.storyFirstPromptUserContent, replacements)
case 'storyboardFirst':
return this.replace(this.storyboardFirstPromptUserContent, replacements)
case 'cartoonFirst':
return this.replace(this.cartoonFirstPromptUserContent, replacements)
default:
throw new Error(`不存在的类型 : ${type}`)
}
},
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
gpt_options: apiUrl,
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
gpt_model_options: [
{
label: 'gpt-3.5-turbo-16k',
value: 'gpt-3.5-turbo-16k'
2024-05-15 12:57:15 +08:00
},
2024-07-13 15:44:13 +08:00
{
label: 'gpt-3.5-turbo',
value: 'gpt-3.5-turbo'
2024-05-15 12:57:15 +08:00
},
2024-07-13 15:44:13 +08:00
{
label: 'gpt-4',
value: 'gpt-4'
}
],
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
gpt_auto_inference: [
{
value: 'characterFirst',
label: '角色优先(全自动)'
2024-05-15 12:57:15 +08:00
},
2024-07-13 15:44:13 +08:00
{
value: 'storyFirst',
label: '故事优先(全自动)'
2024-05-15 12:57:15 +08:00
},
{
2024-07-13 15:44:13 +08:00
value: 'storyboardFirst',
label: '剧本优先(全自动)'
2024-05-15 12:57:15 +08:00
},
2024-07-13 15:44:13 +08:00
{
value: 'cartoonFirst',
label: '漫画优先(全自动)'
},
{
value: 'superSinglePrompt',
label: '超级无敌单帧'
},
{
value: 'onlyPromptMJ',
label: '仅出词(不出人物场景-MJ)'
2024-05-15 12:57:15 +08:00
},
2024-07-13 15:44:13 +08:00
{
value: 'customize',
label: '自定义'
}
],
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
/**
* 通过指定的类型获取数据
* @param {*} type default在代码中写死的 dynamic用户自定义的 all写死的和自定义的合并返回
* @param {*} property 返回书信的名称 gpt_optionsgpt_model_optionsgpt_auto_inference
* @param {*} defaultData 默认数据默认值为null
* @returns
*/
async getGptDataByTypeAndProperty(type, property, defaultData = null) {
try {
let res = []
// 获取自定义的GPT数据
let dynamic_setting = JSON.parse(await fspromises.readFile(define.dynamic_setting, 'utf-8'))
let gpt = get(dynamic_setting, 'gpt', {})
let data = get(gpt, property, defaultData)
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
if (type == 'default') {
res = get(this, property, defaultData)
} else if (type == 'dynamic') {
res = data
} else if (type == 'all') {
let tmp_arr = cloneDeep(get(this, property, defaultData))
tmp_arr = tmp_arr.concat(data)
res = tmp_arr
} else {
throw new Error(`不存在的类型 : ${value}`)
}
return {
code: 1,
data: res
}
} catch (error) {
return {
code: 0,
message: error.toString()
}
}
},
2024-05-15 12:57:15 +08:00
2024-07-13 15:44:13 +08:00
/**
* 保存gpt指定的属性数据判断value中的ID是不是存在存在直接覆盖不存在追加
* @param {*} value
* @param {*} property
*/
saveDynamicGPTOption: async function (value) {
try {
let property = value[1]
value = JSON.parse(value[0])
// 获取自定义的GPT数据
let dynamic_setting = JSON.parse(await fspromises.readFile(define.dynamic_setting, 'utf-8'))
let tmp_gpt = dynamic_setting.gpt ? dynamic_setting.gpt : {}
let gpt = tmp_gpt[property] ? tmp_gpt[property] : []
if (value.id) {
// 判断当前ID的数据是否存在存在覆盖不存在追加
let index = gpt.findIndex((item) => item.id == value.id)
if (index < 0) {
gpt.push(value)
} else {
gpt[index] = value
2024-05-15 12:57:15 +08:00
}
2024-07-13 15:44:13 +08:00
} else {
let tmp_id = uuidv4()
value.id = tmp_id
gpt.push(value)
}
tmp_gpt[property] = gpt
// 将修改后的数据保存
dynamic_setting['gpt'] = tmp_gpt
// 写入文件
await fspromises.writeFile(define.dynamic_setting, JSON.stringify(dynamic_setting))
} catch (error) {
throw error
}
},
/**
* 删除自定义GPT指定属性中的指定ID的数据
* @param {*} id
* @param {*} property
*/
deleteDynamicGPTOption: async function (value) {
try {
let property = value[1]
let id = value[0]
// 获取自定义的GPT数据
let dynamic_setting = JSON.parse(await fspromises.readFile(define.dynamic_setting, 'utf-8'))
let gpt = dynamic_setting.gpt[property] ? dynamic_setting.gpt[property] : []
// 判断当前ID的数据是否存在存在删除
let index = gpt.findIndex((item) => item.id == id)
if (index >= 0) {
gpt.splice(index, 1)
}
// 将修改后的数据保存
dynamic_setting.gpt[property] = gpt
// 写入文件
await fspromises.writeFile(define.dynamic_setting, JSON.stringify(dynamic_setting))
} catch (error) {
throw error
2024-05-15 12:57:15 +08:00
}
2024-07-13 15:44:13 +08:00
}
}