Commit c0bbf709 authored by 周成波's avatar 周成波

大改了一波

parent 53878490
......@@ -8,7 +8,6 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
ElButton: typeof import('element-plus/es')['ElButton']
ElCol: typeof import('element-plus/es')['ElCol']
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
......@@ -20,7 +19,6 @@ declare module 'vue' {
ElOption: typeof import('element-plus/es')['ElOption']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSlider: typeof import('element-plus/es')['ElSlider']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
......
......@@ -48,6 +48,13 @@ export const useManyValues = () => {
deformed,bad anatomy,disfigured,poorly drawn face,lowres,mutated,extra limb,ugly,poorly drawn hands,missing limb,floating limbs,
disconnected limbs,malformed hands,out of focus,long neck,long body,gape,`;
const llms = {
tyqw_online: {'api': 'tyqw', 'name':'线上通义千问'},
baichuan: {'api': 'langchain', 'name':'本地baichuan2-7b'},
qwen_local: {'api': 'langchain', 'name':'本地Qwen-7B-Chat'},
chatgpt: {'api': 'gpt', 'name':'chatgpt'},
};
const horizontal_data = {
task_id: "20240209114425596",
chatgpt_prompt: `生成一个50字的小故事`,
......@@ -60,7 +67,7 @@ export const useManyValues = () => {
const vertical_data = {
task_id: "20240220181602687",
chatgpt_prompt: `生成一个50字的科幻小故事,阿凡达系列`,
chatgpt_answer: ``,
chatgpt_answer: `在奇幻的熊猫王国,阿宝——不再是功夫大师,而化身为西游世界里的神秘旅者。一日,阿宝巧遇唐僧师徒四人,他们正被一只诡异黑影困扰,经书被盗,疑云密布。画面中,阿宝手持九齿钉耙,取代八戒成为护法,勇闯妖洞。峰回路转,黑影竟是被封印的悟空分身,误入歧途。阿宝凭借智慧与武力,解开误会,反转剧情,助悟空分身归于本体,携手抵御真正邪魔,恢复取经历程的和平景象。`,
chatgpt_answer_roles: [],
adapt_result_json: [],
final_video: ``,
......@@ -181,7 +188,7 @@ export const useManyValues = () => {
gender: 'Male',
label: '男,台湾腔',
},
]
];
const voices_en = [
{
......@@ -189,7 +196,7 @@ export const useManyValues = () => {
gender: 'Male',
label: '男,美式磁性',
},
]
];
const bgm = [
{
......@@ -224,12 +231,36 @@ export const useManyValues = () => {
value: '大自然',
label: '大自然',
},
]
];
const role_attribute_options = [
{
value: '人',
label: '人',
},
{
value: '动物',
label: '动物',
},
{
value: '物品',
label: '物品',
},
{
value: '其他生物',
label: '其他生物',
},
{
value: '未知',
label: '未知',
},
];
return {
screen: screen,
sd_prompt_prefix: sd_prompt_prefix,
sd_negative_prompt_prefix: sd_negative_prompt_prefix,
llms: llms,
horizontal_data: horizontal_data,
vertical_data: vertical_data,
if_need_subtitle: if_need_subtitle,
......@@ -239,5 +270,6 @@ export const useManyValues = () => {
voices_en: voices_en,
bgm: bgm,
bgm_volume_marks: bgm_volume_marks,
role_attribute_options: role_attribute_options,
}
}
<script setup lang="ts">
import { onMounted, reactive, ref } from "vue";
import { Sunny, UploadFilled } from "@element-plus/icons-vue";
import { ElMessage, genFileId,
type UploadInstance,
type UploadProps,
type UploadRawFile } from "element-plus";
import text2videoService from "@/api/service/text2videoService";
import utils from "@/utils/utils";
import { useManyValues } from './compositions/useManyValues'
const debug = ref(import.meta.env.MODE === 'production' ? false : true);
const loading = ref(false);
const dialogVisible = ref(false);
const dialogData = ref("");
const default_data = useManyValues();
const form = reactive({
screen: default_data.screen,
if_need_subtitle: default_data.if_need_subtitle,
chatgpt_prompt: "",
chatgpt_answer: "",
chatgpt_answer_roles: <Wm.RolesItem[]>[],
all_roles: "",
adapt_result_json: <Wm.ScriptsItem[]>[],
task_id: "",
final_video: "",
});
const sd_prompt_prefix = default_data.sd_prompt_prefix;
const sd_negative_prompt_prefix = default_data.sd_negative_prompt_prefix;
const tyqw = {'api': 'tyqw', 'name':'通义千问线上'};
const baichuan = {'api': 'langchain', 'name':'baichuan2-7b'};
const qwen = {'api': 'langchain', 'name':'Qwen-7B-Chat'};
const gpt = {'api': 'gpt', 'name':'chatgpt'};
const wenan_llm = tyqw.api
const wenan_llm_name = tyqw.name
const role_llm = tyqw.api
const role_llm_name = tyqw.name
const role_keywords_llm = qwen.api
const role_keywords_llm_name = qwen.name
const tuili_llm = qwen.api
const tuili_llm_name = qwen.name
const fanyi_llm = qwen.api
const fanyi_llm_name = qwen.name
const voice_rate = ref(-15)
const voice_volume = ref(0)
const voice = ref("zh-CN-YunjianNeural")
const bgm = ref("解忧曲")
const bgm_volume = ref(0.3)
const pwdCheckDialogVisible = ref(false);
const pwdCheckValue = ref("")
const sub_font_color = ref("#FFFF00")
const sub_font_size = ref(30)
const sub_position = ref(0.3)
onMounted(() => {
// 初始化示例数据
onChangeScreen(form.screen);
// 初始化密码框
if (debug.value == true) {
pwdCheckDialogVisible.value = false;
} else {
pwdCheckDialogVisible.value = true;
}
});
const delay = (ms: any) => new Promise(res => setTimeout(res, ms));
const onSubmitGpt = () => {
text2videoService
.submitLLM(form.chatgpt_prompt, wenan_llm)
.then((result: string) => {
console.log(form.chatgpt_prompt);
console.log(result);
form.chatgpt_answer = result;
})
.catch((error: any) => {
// console.error(error);
ElMessage({
message: error,
type: "error",
});
});
};
const onAdaptRoles = async () => {
if (!form.chatgpt_answer || form.chatgpt_answer.length == 0) {
ElMessage({
message: "文案不能为空",
type: "error",
});
return;
}
loading.value = true;
// 推理角色
form.chatgpt_answer_roles = [];
try {
const adapt_restrict = `
指令:
请理解这个故事,给出这个故事中的所有角色,多个角色以逗号分隔`;
const roles = await text2videoService.submitLLM("故事:\n" + form.chatgpt_answer + "\n" + adapt_restrict, role_llm);
form.all_roles = roles.replace(/。|(|)/g, '').replace(/、/g, ',')
console.log(form.all_roles)
const roles_arr = form.all_roles.split(/[,,]/);
console.log(roles_arr)
async function processRoles() {
for (const one_role of roles_arr) {
await delay(100);
const adapt_keyword_restrict = `
指令:
请理解这个故事,给出这个角色“${one_role.trim()}”的关键词(性别(可以发挥想象进行补充,但一定要有),年龄(可以发挥想象进行补充,但一定要有),
肤色(可以发挥想象进行补充,但一定要有),衣服(可以发挥想象进行补充,但一定要有),发型(可以发挥想象进行补充,但一定要有),
发色(可以发挥想象进行补充,但一定要有),脸色(可以发挥想象进行补充,但一定要有),五官特点(可以发挥想象进行补充,但一定要有))。
要求:
关键词以逗号分隔。
只要返回关键词,不需要其他的说明文字。`;
let keywords = await text2videoService.submitLLM("故事:\n" + form.chatgpt_answer + "\n" + adapt_keyword_restrict, role_keywords_llm);
keywords = keywords.replace(/。/g, '').replace(/、/g, ',')
// await delay(100);
// const adapt_attribute_restrict = `
// 指令:
// 请理解这个故事,从“人,动物,物品,其他生物,未知”中选择这个角色“${one_role.trim()}”的属性。只能在所给选项中选择,并且只需要返回选择的结果,不需要其他的说明文字。`;
// let attribute = await text2videoService.submitLLM("故事:\n" + form.chatgpt_answer + "\n" + adapt_attribute_restrict, role_keywords_llm);
// attribute = attribute.replace(/。/g, '').replace(/、/g, ',')
form.chatgpt_answer_roles.push({
"角色": one_role.trim(),
"角色关键词": keywords.trim()+",穿着衣服",
// "属性": attribute.trim(),
"属性": "",
"角色英文关键词": "",
});
}
}
try {
await processRoles();
console.log(form.chatgpt_answer_roles)
} catch (error) {
ElMessage({
message: String(error),
type: "error"
});
} finally {
loading.value = false; // 最终关闭loading(无论成功或失败)
}
} catch (error) {
ElMessage({
message: String(error),
type: "error",
});
} finally {
// 最终关闭loading(无论成功或失败)
loading.value = false;
}
};
const onAdapt = async () => {
if (!form.chatgpt_answer || form.chatgpt_answer.length == 0) {
ElMessage({
message: "文案不能为空",
type: "error",
});
return;
}
loading.value = true;
form.task_id = utils.genDateTimeStr();
console.log(form.task_id)
// 按标点拆分成分镜
const sentences = utils.splitText(form.chatgpt_answer);
console.log(sentences.length)
// 分镜
form.adapt_result_json = []
for (let i = 0; i < sentences.length; i++) {
form.adapt_result_json.push({
"编号": (i + 1).toString(),
"场景描述": sentences[i].trim(),
"场景关键词": "",
"角色": "",
"角色关键词": "",
"画面描述词": "",
"本镜配图": "src/assets/loading.gif",
"local_image_path": "",
});
}
console.log(form.adapt_result_json)
async function processScenes() {
for (const item of form.adapt_result_json) {
await onAdaptOne(item);
// await delay(100);
// await onDrawOne(item);
onDrawOne(item);
}
}
try {
await processScenes();
ElMessage({
message: "all scene ok",
type: "success"
});
console.log(form.adapt_result_json);
} catch (error) {
ElMessage({
message: String(error),
type: "error"
});
} finally {
loading.value = false; // 最终关闭loading(无论成功或失败)
}
};
const onAdaptOne = async (item: any) => {
if (!item.场景描述) {
ElMessage({
message: "分镜场景描述不能为空",
type: "error",
});
return;
}
// 推理关键词
try {
const adapt_restrict = `
指令:
请理解这个故事,给出这个场景“${item.场景描述}”的关键词(年代(可以发挥想象进行补充,但一定要有),空间(可以发挥想象进行补充,但一定要有),
时间段(可以发挥想象进行补充,但一定要有),地理环境(可以发挥想象进行补充,但一定要有),天气(可以发挥想象进行补充,但一定要有),
物品(可以发挥想象进行补充,但一定要有),人物(可以发挥想象进行补充,但一定要有),镜头角度(可以发挥想象进行补充,但一定要有))。
要求:
关键词以逗号分隔。
只要返回关键词,不需要其他的说明文字。`;
const keywords = await text2videoService.submitLLM("故事:\n" + form.chatgpt_answer + "\n" + adapt_restrict, tuili_llm);
// console.log(keywords)
item.场景关键词 = keywords;
if (form.chatgpt_answer_roles.length === 0) {
// 总角色为空
item.角色 = '';
item.角色关键词 = '';
} else {
// 总角色不为空
const adapt_role_restrict = `
指令:
请理解这个故事,针对其中的这个场景:“${item.场景描述}”,从所有角色中选择本场景的角色,多个角色以逗号分隔。`;
const item_roles = await text2videoService.submitLLM("故事:\n" + form.chatgpt_answer + "\n所有角色:\n"+ form.all_roles +"\n" + adapt_role_restrict, tuili_llm);
// console.log(role_keywords)
item.角色 = item_roles;
let role_kws = ""
const item_roles_arr = item_roles.split(/[,,、]/);
item_roles_arr.forEach( one_item_role => {
let temp_role_kws = ""
// 人工匹配角色关键词,先找想同的
for (const i of form.chatgpt_answer_roles) {
if (i["角色"].trim() == one_item_role.trim()) {
temp_role_kws = `【${i["角色"]}${i["角色关键词"]}】`;
// 找到就ok
break;
}
}
// 如果找不到相同的,则模糊匹配
if (! temp_role_kws) {
for (const i of form.chatgpt_answer_roles) {
if (i["角色"].includes(one_item_role.trim()) || one_item_role.includes(i["角色"].trim())) {
temp_role_kws = `【${i["角色"]}${i["角色关键词"]}】`;
// 匹配到一个就ok
break;
}
}
}
role_kws = `${role_kws}${temp_role_kws}`;
})
item.角色关键词 = role_kws;
}
} catch (error) {
ElMessage({
message: String(error),
type: "error",
});
}
};
const onDrawOne = async (item: any) => {
if (!item.场景描述 && !item.场景关键词) {
ElMessage({
message: "场景描述和场景关键词不能都为空",
type: "error",
});
return;
}
// 翻译+画图
if (!form.task_id) {
form.task_id = utils.genDateTimeStr();
console.log(form.task_id)
}
try {
item.本镜配图 = "src/assets/loading.gif";
let temp_prompt = ""
if (item.场景描述) {temp_prompt = temp_prompt + `场景描述为:${item.场景描述}\n`};
if (item.场景关键词) {temp_prompt = temp_prompt + `场景关键词为:${item.场景关键词}\n`};
if (item.角色) {temp_prompt = temp_prompt + `场景中的角色有:${item.角色}\n`};
if (item.角色关键词) {temp_prompt = temp_prompt + `角色关键词为:${item.角色关键词}\n`};
const sd_describe = await text2videoService.submitLLM(
`${temp_prompt}
指令:
请理解以上内容,并返回一段英文的描述。`, fanyi_llm
);
item.画面描述词 = sd_describe;
const sd_prompt = item.画面描述词 + "," + sd_prompt_prefix;
let width = "960";
let height = "540";
if (form.screen == "竖屏") {
width = "540";
height = "960";
}
// console.log(sd_prompt);
// console.log(sd_negative_prompt_prefix);
const sampler_index = "DPM++ SDE Karras";
const seed = "-1";
const steps = "6";
const cfg_scale = "2";
const sd_img = await text2videoService.submitSD(form.task_id, item.编号, sd_prompt, sd_negative_prompt_prefix, width, height, sampler_index, seed, steps, cfg_scale);
item.本镜配图 = sd_img.domain_image_path+"?v="+utils.genDateTimeStr();
item.local_image_path = sd_img.local_image_path;
} catch (error) {
ElMessage({
message: String(error),
type: "error",
});
item.本镜配图 = ""
}
};
const onGenVideo = () => {
if (!form.adapt_result_json || form.adapt_result_json.length == 0 ) {
ElMessage({
message: "必要信息不能为空,请重新执行",
type: "error",
});
return;
}
let is_all_ok = true;
form.adapt_result_json.map(item => {
if (item.编号 == "" || item.场景描述 == "" || item.local_image_path == "") {
ElMessage({
message: `分镜 ${item.编号} 的必要信息为空,请重新执行`,
type: "error",
});
is_all_ok = false;
}
});
if (!is_all_ok) return;
console.log(form.adapt_result_json);
const video_param_detail = form.adapt_result_json.map(item => {
return {
idx: item.编号,
text: item.场景描述,
img_path: item.local_image_path
};
});
let para_rate = `${voice_rate.value}%`;
let para_volume = `${voice_volume.value}%`;
if(voice_rate.value >= 0){para_rate = `+${para_rate}`}
if(voice_volume.value >= 0){para_volume = `+${para_volume}`}
const video_param = {
task_id: form.task_id,
if_need_subtitle: form.if_need_subtitle,
lang: "zh",
task_info: video_param_detail,
rate: para_rate,
volume: para_volume,
voice: voice.value,
bgm: bgm.value,
bgm_volume: bgm_volume.value,
sub_font_size: String(sub_font_size.value),
sub_font_color: sub_font_color.value,
sub_position: String(1 - sub_position.value),
}
text2videoService
.submitGenVideo(video_param)
.then((result: string) => {
console.log(result);
form.final_video = "";
form.final_video = result+"?v="+utils.genDateTimeStr();
})
.catch((error: any) => {
// console.error(error);
ElMessage({
message: error,
type: "error",
});
});
};
const clean_demo = () => {
form.chatgpt_prompt = "";
form.chatgpt_answer = "";
form.chatgpt_answer_roles = <Wm.RolesItem[]>[];
form.adapt_result_json = <Wm.ScriptsItem[]>[];
form.task_id = "";
form.final_video = "";
}
const clean_roles = () => {
form.chatgpt_answer_roles = <Wm.RolesItem[]>[];
}
const onChangeScreen = (val: string) => {
if (debug.value == true) {
if (val == "横屏") {
form.task_id = default_data.horizontal_data.task_id;
form.chatgpt_prompt = default_data.horizontal_data.chatgpt_prompt;
form.chatgpt_answer = default_data.horizontal_data.chatgpt_answer;
form.chatgpt_answer_roles = default_data.horizontal_data.chatgpt_answer_roles;
form.adapt_result_json = default_data.horizontal_data.adapt_result_json;
form.final_video = default_data.horizontal_data.final_video;
} else {
form.task_id = default_data.vertical_data.task_id;
form.chatgpt_prompt = default_data.vertical_data.chatgpt_prompt;
form.chatgpt_answer = default_data.vertical_data.chatgpt_answer;
form.chatgpt_answer_roles = default_data.vertical_data.chatgpt_answer_roles;
form.adapt_result_json = default_data.vertical_data.adapt_result_json;
form.final_video = default_data.vertical_data.final_video;
}
}
}
const showsdprompt = (item: any) => {
// alert(item.画面描述词)
dialogData.value = item.画面描述词+ "," +sd_prompt_prefix+'===== negative ====='+sd_negative_prompt_prefix;
dialogVisible.value = true; // 打开对话框
}
const upload = ref<UploadInstance>()
const actionUrl = ref(
import.meta.env.MODE === 'production'
? '/file'
: import.meta.env.VITE_APP_BASE_API + '/file'
)
const handleUploadSuccess = (val: Wm.UploadResult) => {
if (val.code == 0){
// console.log(val)
const id = parseInt(val.message) - 1;
form.adapt_result_json[id].本镜配图 = val.data[0].url+"?v="+utils.genDateTimeStr();
form.adapt_result_json[id].local_image_path = val.data[0].path;
ElMessage({
message: '上传成功',
type: 'success'
})
} else {
ElMessage({
message: '上传失败',
type: 'error'
})
}
}
const handleExceed: UploadProps['onExceed'] = (files) => {
upload.value!.clearFiles()
const file = files[0] as UploadRawFile
file.uid = genFileId()
upload.value!.handleStart(file)
upload.value!.submit()
}
const onPwdCheckDialog = () => {
text2videoService
.submitPwdCheck(pwdCheckValue.value)
.then((result: string) => {
if (result == "success") {
pwdCheckDialogVisible.value = false;
} else {
ElMessage({
message: result,
type: "error",
});
}
})
.catch((error: any) => {
ElMessage({
message: error,
type: "error",
});
});
}
const onDeleteOne = (item: any) => {
try {
let delete_no = item.编号;
// 删除记录
form.adapt_result_json = form.adapt_result_json.filter(item => item.编号 !== delete_no);
// 重新对记录进行编号
form.adapt_result_json = form.adapt_result_json.map((item, index) => {
return {...item, 编号: (index + 1).toString()};
});
} catch (error) {
ElMessage({
message: String(error),
type: "error",
});
}
};
</script>
<template>
<main class="home-container">
<!-- 标题 -->
<el-divider content-position="left">text2video</el-divider>
<el-form :model="form" label-width="114px" v-loading="loading">
<el-form-item>
<div>
<el-radio-group v-model="form.screen" @change="onChangeScreen">
<el-radio label="横屏" size="large" border/>
<el-radio label="竖屏" size="large" border/>
</el-radio-group>
</div>
</el-form-item>
<el-form-item>
<el-button type="success" @click="clean_demo">清除所有数据</el-button>
</el-form-item>
<!-- Prompt到文案 -->
<el-form-item label="Prompt">
<el-input v-model="form.chatgpt_prompt" :autosize="true" type="textarea" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmitGpt">生成文案({{wenan_llm_name}}</el-button>
</el-form-item>
<el-form-item label="文案">
<el-input v-model="form.chatgpt_answer" :autosize="true" type="textarea" />
</el-form-item>
<!-- 角色 -->
<el-form-item>
<el-button type="primary" @click="onAdaptRoles">推理角色({{role_llm_name}})、推理角色关键词({{role_keywords_llm_name}}</el-button>
<el-button plain @click="clean_roles">清空总角色列表</el-button>
</el-form-item>
<el-form-item label="角色">
<el-table :data="form.chatgpt_answer_roles" border style="width: 100%; z-index: calc(var(--el-table-index) -1)">
<el-table-column prop="角色" label="角色" width="300">
<template v-slot="scope">
<el-input v-model="scope.row.角色" :autosize="true" type="textarea"></el-input>
</template>
</el-table-column>
<el-table-column prop="属性" label="属性" width="300">
<template v-slot="scope">
<el-select v-model="scope.row.属性" filterable allow-create :reserve-keyword="false">
<el-option
v-for="item in default_data.role_attribute_options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
</el-table-column>
<el-table-column prop="角色关键词" label="角色关键词">
<template v-slot="scope">
<el-input v-model="scope.row.角色关键词" :autosize="true" type="textarea"></el-input>
</template>
</el-table-column>
</el-table>
</el-form-item>
<!-- 分镜 -->
<el-form-item>
<el-button type="primary" @click="onAdapt">分镜、推理场景关键词({{tuili_llm_name}})、英文描述({{fanyi_llm_name}})、绘图</el-button>
</el-form-item>
<el-form-item label="分镜">
<el-table :data="form.adapt_result_json" border style="width: 100%; z-index: calc(var(--el-table-index) -1)">
<el-table-column prop="编号" label="编号" width="60" />
<el-table-column prop="场景描述" label="场景描述">
<template v-slot="scope">
<el-input v-model="scope.row.场景描述" :autosize="true" type="textarea"></el-input>
</template>
</el-table-column>
<el-table-column prop="场景关键词" label="场景关键词">
<template v-slot="scope">
<el-input v-model="scope.row.场景关键词" :autosize="true" type="textarea"></el-input>
</template>
</el-table-column>
<el-table-column prop="角色" label="角色">
<template v-slot="scope">
<el-input v-model="scope.row.角色" :autosize="true" type="textarea"></el-input>
</template>
</el-table-column>
<el-table-column prop="角色关键词" label="角色关键词">
<template v-slot="scope">
<el-input v-model="scope.row.角色关键词" :autosize="true" type="textarea"></el-input>
</template>
</el-table-column>
<el-table-column prop="本镜配图" label="本镜配图" width="300">
<template v-slot="scope">
<div>
<el-image :src="scope.row.本镜配图" :zoom-rate="1.2" :max-scale="1.5" :min-scale="0.5"
:preview-src-list="[scope.row.本镜配图]" fit="cover" :hide-on-click-modal="true"
/>
</div>
</template>
</el-table-column>
<el-table-column width="120" label="操作" align="center">
<!--
<template v-slot:header>
<el-button type="danger" size="default" @click="">批量绘制所有图片</el-button>
</template>
-->
<template v-slot="scope">
<div style="margin: 10px 0"><el-button type="primary" size="default" @click="onAdaptOne(scope.row)">推理关键词</el-button></div>
<div style="margin: 10px 0"><el-button type="primary" size="default" @click="onDrawOne(scope.row)">翻译、绘图</el-button></div>
<el-upload
class="upload-demo"
ref="upload"
list-type="picture"
:show-file-list="false"
:limit="1"
:action="actionUrl"
:on-success="handleUploadSuccess"
:on-exceed="handleExceed"
:data="{item_id: scope.row.编号}"
>
<el-button type="primary">上传图片</el-button>
</el-upload>
<div style="margin: 10px 0"><el-button plain @click="showsdprompt(scope.row)">debug</el-button></div>
<el-dialog
v-model=dialogVisible
width="80%"
>
<p>{{ dialogData }}</p>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="dialogVisible = false">ok</el-button>
</div>
</template>
</el-dialog>
<div style="margin: 10px 0"><el-button type="danger" size="default" @click="onDeleteOne(scope.row)">删除本镜</el-button></div>
</template>
</el-table-column>
</el-table>
</el-form-item>
<!-- 生成视频 -->
<el-form-item label="设置">
<span style="margin: 0 20px">TTS语速:</span>
<el-slider v-model="voice_rate" show-input :min="-50" :max="50" :marks="default_data.marks" style="width: 900px" />
</el-form-item>
<el-form-item>
<span style="margin: 0 20px">TTS音量:</span>
<el-slider v-model="voice_volume" show-input :min="-80" :max="80" :marks="default_data.marks" style="width: 900px" />
</el-form-item>
<el-form-item>
<span style="margin: 20px 20px 0 20px">TTS语音:</span>
<el-select v-model="voice" placeholder="Select" style="width: 400px; margin-top: 20px;">
<el-option
v-for="item in default_data.voices"
:key="item.value"
:label="item.value"
:value="item.value"
>
<span style="float: left">{{ item.value }}</span>
<span
style="
float: right;
color: var(--el-text-color-secondary);
font-size: 13px;
"
>{{ item.label }}</span>
</el-option>
</el-select>
<audio :src="'src/assets/edge-tts-voices/' + voice + '.mp3'" controls style="height: 30px; margin: 20px 0 0 10px;"></audio>
</el-form-item>
<el-form-item>
<span style="margin: 0 20px">背景音乐:</span>
<el-select v-model="bgm" placeholder="无" style="width: 400px;">
<el-option
v-for="item in default_data.bgm"
:key="item.value"
:label="item.value"
:value="item.value"
>
<span style="float: left">{{ item.label }}</span>
<span
style="
float: right;
color: var(--el-text-color-secondary);
font-size: 13px;
"
>{{ item.value }}</span>
</el-option>
</el-select>
<audio :src="'src/assets/bgm/' + bgm + '.mp3'" controls style="height: 30px; margin-left:10px;"></audio>
</el-form-item>
<el-form-item>
<span style="margin: 0 20px">背景音量:</span>
<el-slider v-model="bgm_volume" show-input :step="0.1" :min="0" :max="2" :marks="default_data.bgm_volume_marks" style="width: 600px" />
</el-form-item>
<el-form-item>
<span style="margin: 20px 20px">字幕:</span>
<el-switch v-model="form.if_need_subtitle" active-value="true" inactive-value="false"/>
<div v-if="JSON.parse(form.if_need_subtitle.toLowerCase())">
<span style="margin-left:30px;">字体颜色:</span>
<el-color-picker v-model="sub_font_color"/>
<span style="margin-left:30px;">字体大小:</span>
<el-input-number v-model="sub_font_size" :min="1" :max="50" controls-position="right" />
<span style="margin-left:30px;">在屏幕上的位置:</span>
<el-slider v-model="sub_position" :step="0.1" :min="0" :max="1" show-input vertical height="100px" />
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onGenVideo">生成视频</el-button>
</el-form-item>
<el-form-item>
<video :src="form.final_video" controls></video>
</el-form-item>
</el-form>
<!-- 授权密码框 -->
<el-dialog
v-model=pwdCheckDialogVisible
title="请输入密码"
width="20%"
:close-on-click-modal="false"
:close-on-press-escape="false"
:show-close="false"
>
<el-form :model="form">
<el-form-item label="密码">
<el-input v-model="pwdCheckValue" autocomplete="off" type="password" show-password />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="onPwdCheckDialog()">ok</el-button>
</div>
</template>
</el-dialog>
</main>
</template>
<style lang="scss" scoped>
.home-container {
width: 100%;
}
</style>
<style lang="scss">
.home-container {
.el-table .el-table__cell {
z-index: calc(var(--el-table-index) -1);
}
}
</style>
<script setup lang="ts">
import { onMounted, reactive, ref } from "vue";
import { onMounted, reactive, ref, nextTick } from "vue";
import { Sunny, UploadFilled } from "@element-plus/icons-vue";
import { ElMessage, genFileId,
type UploadInstance,
......@@ -28,23 +28,14 @@ const form = reactive({
const sd_prompt_prefix = default_data.sd_prompt_prefix;
const sd_negative_prompt_prefix = default_data.sd_negative_prompt_prefix;
const tyqw = {'api': 'tyqw', 'name':'通义千问线上'};
const baichuan = {'api': 'langchain', 'name':'baichuan2-7b'};
const qwen = {'api': 'langchain', 'name':'Qwen-7B-Chat'};
const gpt = {'api': 'gpt', 'name':'chatgpt'};
const wenan_llm = qwen.api
const wenan_llm_name = qwen.name
const role_llm = tyqw.api
const role_llm_name = tyqw.name
const role_keywords_llm = qwen.api
const role_keywords_llm_name = qwen.name
const tuili_llm = qwen.api
const tuili_llm_name = qwen.name
const fanyi_llm = qwen.api
const fanyi_llm_name = qwen.name
const voice_rate = ref(-15)
const wen_an_llm = default_data.llms.tyqw_online;
const role_llm = default_data.llms.tyqw_online;
const role_keywords_llm = default_data.llms.qwen_local;
const tuili_llm = default_data.llms.qwen_local;
const tuili_keyword_llm = default_data.llms.tyqw_online;
const fanyi_llm = default_data.llms.qwen_local;
const voice_rate = ref(-10)
const voice_volume = ref(0)
const voice = ref("zh-CN-YunjianNeural")
const bgm = ref("解忧曲")
......@@ -52,8 +43,8 @@ const bgm_volume = ref(0.3)
const pwdCheckDialogVisible = ref(false);
const pwdCheckValue = ref("")
const sub_font_color = ref("#FFFF00")
const sub_font_size = ref(30)
const sub_position = ref(0.2)
const sub_font_size = ref(25)
const sub_position = ref(0.4)
onMounted(() => {
......@@ -71,7 +62,7 @@ const delay = (ms: any) => new Promise(res => setTimeout(res, ms));
const onSubmitGpt = () => {
text2videoService
.submitLLM(form.chatgpt_prompt, wenan_llm)
.submitLLM(form.chatgpt_prompt, wen_an_llm.api)
.then((result: string) => {
console.log(form.chatgpt_prompt);
console.log(result);
......@@ -94,36 +85,75 @@ const onAdaptRoles = async () => {
});
return;
}
loading.value = true;
// 推理角色
form.chatgpt_answer_roles = [];
try {
const adapt_restrict = `
指令:
请理解这个故事,给出这个故事中的所有角色,多个角色以逗号分隔`;
const roles = await text2videoService.submitLLM("故事:\n" + form.chatgpt_answer + "\n" + adapt_restrict, role_llm);
form.all_roles = roles.replace(/。/g, '').replace(/、/g, ',')
console.log(form.all_roles)
const roles_arr = form.all_roles.split(/[,,]/);
console.log(roles_arr)
const adapt_restrict = `请理解这个故事:“${form.chatgpt_answer}”,给出这个故事中的所有角色,多个角色以逗号分隔。\n要求:只返回角色名称即可,不要添加其他的内容。`;
let roles = await text2videoService.submitLLM(adapt_restrict, role_llm.api);
form.all_roles = roles.replace(/。|(|)/g, '').replace(/、/g, ',');
console.log(form.all_roles);
const roles_arr = form.all_roles.split(/[,,]/);
console.log(roles_arr);
// 推理属性
const attribute_options = default_data.role_attribute_options.map(option => option.value);
for (const one_role of roles_arr) {
// const adapt_attribute_restrict = `根据这个故事:“${form.chatgpt_answer}”,你认为这个角色:“${one_role}”是“${String(attribute_options)}”中的哪一种?请返回选择的结果。\n要求:只返回选择的结果即可,不要添加其他的内容。`;
const adapt_attribute_restrict = `你认为这个角色:“${one_role}”是“${String(attribute_options)}”中的哪一种?请返回选择的结果。\n要求:只返回选择的结果即可,不要添加其他的内容。`;
let attribute = await text2videoService.submitLLM(adapt_attribute_restrict, role_keywords_llm.api);
form.chatgpt_answer_roles.push({
"角色": one_role.trim(),
"角色关键词": "",
"角色英文关键词": "",
"属性": attribute,
});
}
console.log(form.chatgpt_answer_roles)
};
const onAdaptRolesKeywords = async () => {
if (!form.chatgpt_answer_roles || form.chatgpt_answer_roles.length == 0) {
ElMessage({
message: "总角色不能为空",
type: "error",
});
return;
}
for (const one_role of form.chatgpt_answer_roles) {
if (!one_role.属性) {
ElMessage({
message: `请选择 ${one_role.角色} 的属性`,
type: "error",
});
return;
}
}
loading.value = true;
// 推理角色关键词
try {
async function processRoles() {
for (const one_role of roles_arr) {
for (const one_role of form.chatgpt_answer_roles) {
await delay(100);
const adapt_keyword_restrict = `
指令:
请理解这个故事,给出这个角色“${one_role.trim()}”的关键词(性别(可以发挥想象进行补充,但一定要有),年龄(可以发挥想象进行补充,但一定要有),
肤色(可以发挥想象进行补充,但一定要有),衣服(可以发挥想象进行补充,但一定要有),发型(可以发挥想象进行补充,但一定要有),
发色(可以发挥想象进行补充,但一定要有),脸色(可以发挥想象进行补充,但一定要有),五官特点(可以发挥想象进行补充,但一定要有))。
要求:
关键词以逗号分隔。
只要返回关键词,不需要其他的说明文字。`;
let keywords = await text2videoService.submitLLM("故事:\n" + form.chatgpt_answer + "\n" + adapt_keyword_restrict, role_keywords_llm);
keywords = keywords.replace(/。/g, '').replace(/、/g, ',')
form.chatgpt_answer_roles.push({
"角色": one_role.trim(),
"角色关键词": keywords.trim()+",穿着衣服"
});
let adapt_keyword_restrict = `请理解这个故事:“${form.chatgpt_answer}”,给出其中这个角色“${one_role.角色}”的关键词,以逗号分隔。包括但不限于:`;
let temp_restrict = "";
if (one_role.属性.includes("人")) {
temp_restrict = `性别(可以发挥想象进行补充,但一定要有), 年龄(可以发挥想象进行补充,但一定要有),
肤色(可以发挥想象进行补充,但一定要有), 衣服(可以发挥想象进行补充,但一定要有), 发型(可以发挥想象进行补充,但一定要有),
发色(可以发挥想象进行补充,但一定要有), 脸色(可以发挥想象进行补充,但一定要有), 五官特点(可以发挥想象进行补充,但一定要有)`;
} else {
temp_restrict = `体型(可以发挥想象进行补充,但一定要有), 颜色(可以发挥想象进行补充,但一定要有),
四肢(可以发挥想象进行补充,但一定要有), 五官特点(可以发挥想象进行补充,但一定要有),
身体(皮毛,羽毛,鳞片,肤色等,可以发挥想象进行补充,没有就不提供)`;
}
adapt_keyword_restrict = adapt_keyword_restrict + temp_restrict + "。回答限制在30个字左右。";
let keywords = await text2videoService.submitLLM(adapt_keyword_restrict, role_keywords_llm.api);
keywords = keywords.replace(/。/g, '').replace(/、/g, ',');
one_role.角色关键词 = keywords;
await delay(100);
const adapt_attribute_restrict_en = `你现在扮演专业的英语翻译的角色。请将这段文字“${keywords}”翻译为英语。\n要求:只返回英语即可,不要返回其他内容。`;
let keywords_en = await text2videoService.submitLLM(adapt_attribute_restrict_en, role_keywords_llm.api);
keywords_en = keywords_en.replace(/"/g, '');
one_role.角色英文关键词 = keywords_en;
}
}
try {
......@@ -134,8 +164,6 @@ const onAdaptRoles = async () => {
message: String(error),
type: "error"
});
} finally {
loading.value = false; // 最终关闭loading(无论成功或失败)
}
} catch (error) {
ElMessage({
......@@ -148,6 +176,7 @@ const onAdaptRoles = async () => {
}
};
const onAdapt = async () => {
if (!form.chatgpt_answer || form.chatgpt_answer.length == 0) {
ElMessage({
......@@ -156,7 +185,6 @@ const onAdapt = async () => {
});
return;
}
loading.value = true;
form.task_id = utils.genDateTimeStr();
console.log(form.task_id)
// 按标点拆分成分镜
......@@ -172,21 +200,28 @@ const onAdapt = async () => {
"角色": "",
"角色关键词": "",
"画面描述词": "",
"本镜配图": "src/assets/loading.gif",
"本镜配图": "src/assets/waiting.png",
"local_image_path": "",
});
}
console.log(form.adapt_result_json)
}
const onAdaptScene = async () => {
if (!form.adapt_result_json || form.adapt_result_json.length == 0) {
ElMessage({
message: "分镜不能为空",
type: "error",
});
return;
}
loading.value = true;
async function processScenes() {
for (const item of form.adapt_result_json) {
await onAdaptOne(item);
// await delay(100);
// await onDrawOne(item);
onDrawOne(item);
await onAdaptOneScene(item);
}
}
try {
await processScenes();
ElMessage({
......@@ -202,42 +237,82 @@ const onAdapt = async () => {
} finally {
loading.value = false; // 最终关闭loading(无论成功或失败)
}
};
const onAdaptOne = async (item: any) => {
const onAdaptOneScene = async (item: any) => {
if (!item.场景描述) {
ElMessage({
message: "分镜场景描述不能为空",
message: `分镜 ${item.编号} 场景描述不能为空`,
type: "error",
});
return;
}
// 推理关键词
// 推理场景
try {
const adapt_restrict = `
指令:
请理解这个故事,给出这个场景“${item.场景描述}”的关键词(年代(可以发挥想象进行补充,但一定要有),空间(可以发挥想象进行补充,但一定要有),
时间段(可以发挥想象进行补充,但一定要有),地理环境(可以发挥想象进行补充,但一定要有),天气(可以发挥想象进行补充,但一定要有),
物品(可以发挥想象进行补充,但一定要有),人物(可以发挥想象进行补充,但一定要有),镜头角度(可以发挥想象进行补充,但一定要有))。
要求:
关键词以逗号分隔。
只要返回关键词,不需要其他的说明文字。`;
const keywords = await text2videoService.submitLLM("故事:\n" + form.chatgpt_answer + "\n" + adapt_restrict, tuili_llm);
const adapt_restrict = `你现在扮演专业的英语翻译的角色。请将这段文字“${item.场景描述}”翻译为英语。\n要求:只返回英语即可,不要返回其他内容。`;
const keywords = await text2videoService.submitLLM(adapt_restrict, tuili_llm.api);
// console.log(keywords)
item.场景关键词 = keywords;
} catch (error) {
ElMessage({
message: String(error),
type: "error",
});
}
};
const onAdaptSceneRoles = async () => {
if (!form.adapt_result_json || form.adapt_result_json.length == 0) {
ElMessage({
message: "分镜不能为空",
type: "error",
});
return;
}
loading.value = true;
async function processScenes() {
for (const item of form.adapt_result_json) {
await onAdaptOneSceneRoles(item);
}
}
try {
await processScenes();
console.log(form.adapt_result_json);
} catch (error) {
ElMessage({
message: String(error),
type: "error"
});
} finally {
loading.value = false; // 最终关闭loading(无论成功或失败)
}
};
const onAdaptOneSceneRoles = async (item: any) => {
if (!item.场景描述) {
ElMessage({
message: `分镜 ${item.编号} 场景描述不能为空`,
type: "error",
});
return;
}
// 推理角色
try {
if (form.chatgpt_answer_roles.length === 0) {
// 总角色为空
item.角色 = '';
item.角色关键词 = '';
} else {
// 总角色不为空
const adapt_role_restrict = `
指令:
请理解这个故事,针对其中的这个场景:“${item.场景描述}”,从所有角色中选择本场景的角色,多个角色以逗号分隔。`;
const item_roles = await text2videoService.submitLLM("故事:\n" + form.chatgpt_answer + "\n所有角色:\n"+ form.all_roles +"\n" + adapt_role_restrict, tuili_llm);
// console.log(role_keywords)
item.角色 = item_roles;
// const adapt_role_restrict = `请理解这个故事:“${form.chatgpt_answer}”,针对其中的这个场景:“${item.场景描述}”,从所有角色:“${form.all_roles}”中选择本场景的角色,多个角色以逗号分隔。`;
const adapt_role_restrict = `整个故事(“${form.chatgpt_answer}),\n\n本章节(${item.场景描述}),\n\n角色列表(${form.all_roles}),\n\n你是程序员,请返回给本章节出现的角色,注意,不要发挥想象,必须从角色列表中选出本章节出现过的角色,如果多个用逗号隔开。`;
const item_roles = await text2videoService.submitLLM(adapt_role_restrict, tuili_keyword_llm.api);
// console.log(adapt_role_restrict)
// console.log(item_roles)
item.角色 = item_roles.trim();
let role_kws = ""
const item_roles_arr = item_roles.split(/[,,、]/);
item_roles_arr.forEach( one_item_role => {
......@@ -245,7 +320,7 @@ const onAdaptOne = async (item: any) => {
// 人工匹配角色关键词,先找想同的
for (const i of form.chatgpt_answer_roles) {
if (i["角色"].trim() == one_item_role.trim()) {
temp_role_kws = `${i["角色"]}${i["角色关键词"]}`;
temp_role_kws = `[${i["角色英文关键词"]}]`;
// 找到就ok
break;
}
......@@ -254,7 +329,7 @@ const onAdaptOne = async (item: any) => {
if (! temp_role_kws) {
for (const i of form.chatgpt_answer_roles) {
if (i["角色"].includes(one_item_role.trim()) || one_item_role.includes(i["角色"].trim())) {
temp_role_kws = `${i["角色"]}${i["角色关键词"]}`;
temp_role_kws = `[${i["角色英文关键词"]}]`;
// 匹配到一个就ok
break;
}
......@@ -272,10 +347,26 @@ const onAdaptOne = async (item: any) => {
}
};
const onDraw = async () => {
if (!form.adapt_result_json || form.adapt_result_json.length == 0) {
ElMessage({
message: "分镜不能为空",
type: "error",
});
return;
}
for (const item of form.adapt_result_json) {
onDrawOne(item);
}
};
const onDrawOne = async (item: any) => {
if (!item.场景描述 && !item.场景关键词) {
item.本镜配图 = "src/assets/loading.gif";
if (!item.场景关键词 && !item.角色关键词) {
ElMessage({
message: "场景描述和场景关键词不能都为空",
message: "英文描述不能为空",
type: "error",
});
return;
......@@ -286,18 +377,19 @@ const onDrawOne = async (item: any) => {
console.log(form.task_id)
}
try {
item.本镜配图 = "src/assets/loading.gif";
let temp_prompt = ""
if (item.场景描述) {temp_prompt = temp_prompt + `场景描述为:${item.场景描述}\n`};
if (item.场景关键词) {temp_prompt = temp_prompt + `场景关键词为:${item.场景关键词}\n`};
if (item.角色) {temp_prompt = temp_prompt + `场景中的角色有:${item.角色}\n`};
if (item.角色关键词) {temp_prompt = temp_prompt + `角色关键词为:${item.角色关键词}\n`};
const sd_describe = await text2videoService.submitLLM(
`${temp_prompt}
指令:
请理解以上内容,并返回一段英文的描述。`, fanyi_llm
);
item.画面描述词 = sd_describe;
// let temp_prompt = ""
// if (item.场景描述) {temp_prompt = temp_prompt + `场景描述为:${item.场景描述}\n`};
// if (item.场景关键词) {temp_prompt = temp_prompt + `场景关键词为:${item.场景关键词}\n`};
// if (item.角色) {temp_prompt = temp_prompt + `场景中的角色有:${item.角色}\n`};
// if (item.角色关键词) {temp_prompt = temp_prompt + `角色关键词为:${item.角色关键词}\n`};
// const sd_describe = await text2videoService.submitLLM(
// `${temp_prompt}
// 指令:
// 请理解以上内容,并返回一段英文的描述。`, fanyi_llm.api
// );
// item.画面描述词 = sd_describe;
item.画面描述词 = item.场景关键词 + "," + item.角色关键词;
const sd_prompt = item.画面描述词 + "," + sd_prompt_prefix;
let width = "960";
let height = "540";
......@@ -323,6 +415,7 @@ const onDrawOne = async (item: any) => {
}
};
const onGenVideo = () => {
if (!form.adapt_result_json || form.adapt_result_json.length == 0 ) {
ElMessage({
......@@ -396,6 +489,9 @@ const clean_demo = () => {
const clean_roles = () => {
form.chatgpt_answer_roles = <Wm.RolesItem[]>[];
}
const clean_scenes = () => {
form.adapt_result_json = <Wm.ScriptsItem[]>[];
}
const onChangeScreen = (val: string) => {
if (debug.value == true) {
......@@ -419,7 +515,7 @@ const onChangeScreen = (val: string) => {
const showsdprompt = (item: any) => {
// alert(item.画面描述词)
dialogData.value = item.画面描述词+ "," +sd_prompt_prefix+'===== negative ====='+sd_negative_prompt_prefix;
dialogData.value = `${item.场景关键词},${item.角色关键词},${sd_prompt_prefix}===== 反向提示词 =====${sd_negative_prompt_prefix}`;
dialogVisible.value = true; // 打开对话框
}
......@@ -478,6 +574,23 @@ const onPwdCheckDialog = () => {
});
}
const onDeleteOne = (item: any) => {
try {
let delete_no = item.编号;
// 删除记录
form.adapt_result_json = form.adapt_result_json.filter(item => item.编号 !== delete_no);
// 重新对记录进行编号
form.adapt_result_json = form.adapt_result_json.map((item, index) => {
return {...item, 编号: (index + 1).toString()};
});
} catch (error) {
ElMessage({
message: String(error),
type: "error",
});
}
};
</script>
<template>
......@@ -501,33 +614,55 @@ const onPwdCheckDialog = () => {
<el-input v-model="form.chatgpt_prompt" :autosize="true" type="textarea" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmitGpt">生成文案({{wenan_llm_name}}</el-button>
<el-button type="primary" @click="onSubmitGpt">生成文案({{wen_an_llm.name}}</el-button>
</el-form-item>
<el-form-item label="文案">
<el-input v-model="form.chatgpt_answer" :autosize="true" type="textarea" />
</el-form-item>
<!-- 角色 -->
<el-form-item>
<el-button type="primary" @click="onAdaptRoles">推理角色({{role_llm_name}})、推理角色关键词({{role_keywords_llm_name}}</el-button>
<el-button type="primary" @click="onAdaptRoles">推理角色({{role_llm.name}}</el-button>
<el-button type="primary" @click="onAdaptRolesKeywords">推理关键词({{role_keywords_llm.name}}</el-button>
<el-button plain @click="clean_roles">清空总角色列表</el-button>
</el-form-item>
<el-form-item label="角色">
<el-table :data="form.chatgpt_answer_roles" border style="width: 100%; z-index: calc(var(--el-table-index) -1)">
<el-table-column prop="角色" label="角色">
<el-table-column prop="角色" label="角色" width="300">
<template v-slot="scope">
<el-input v-model="scope.row.角色" :autosize="true" type="textarea"></el-input>
</template>
</el-table-column>
<el-table-column prop="属性" label="属性" width="300">
<template v-slot="scope">
<el-select v-model="scope.row.属性" filterable allow-create :reserve-keyword="false">
<el-option
v-for="item in default_data.role_attribute_options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
</el-table-column>
<el-table-column prop="角色关键词" label="角色关键词">
<template v-slot="scope">
<el-input v-model="scope.row.角色关键词" :autosize="true" type="textarea"></el-input>
</template>
</el-table-column>
<el-table-column prop="角色英文关键词" label="角色英文关键词">
<template v-slot="scope">
<el-input v-model="scope.row.角色英文关键词" :autosize="true" type="textarea"></el-input>
</template>
</el-table-column>
</el-table>
</el-form-item>
<!-- 分镜 -->
<el-form-item>
<el-button type="primary" @click="onAdapt">分镜、推理场景关键词({{tuili_llm_name}})、英文描述({{fanyi_llm_name}})、绘图</el-button>
<el-button type="primary" @click="onAdapt">分镜</el-button>
<el-button type="primary" @click="onAdaptScene">推理场景({{tuili_llm.name}})</el-button>
<el-button type="primary" @click="onAdaptSceneRoles">推理场景角色({{tuili_keyword_llm.name}})</el-button>
<el-button type="primary" @click="onDraw">绘图</el-button>
<el-button plain @click="clean_scenes">清空分镜列表</el-button>
</el-form-item>
<el-form-item label="分镜">
<el-table :data="form.adapt_result_json" border style="width: 100%; z-index: calc(var(--el-table-index) -1)">
......@@ -537,7 +672,7 @@ const onPwdCheckDialog = () => {
<el-input v-model="scope.row.场景描述" :autosize="true" type="textarea"></el-input>
</template>
</el-table-column>
<el-table-column prop="场景关键词" label="场景关键词">
<el-table-column prop="场景关键词" label="场景英文描述">
<template v-slot="scope">
<el-input v-model="scope.row.场景关键词" :autosize="true" type="textarea"></el-input>
</template>
......@@ -568,8 +703,9 @@ const onPwdCheckDialog = () => {
</template>
-->
<template v-slot="scope">
<div style="margin: 10px 0"><el-button type="primary" size="default" @click="onAdaptOne(scope.row)">推理关键词</el-button></div>
<div style="margin: 10px 0"><el-button type="primary" size="default" @click="onDrawOne(scope.row)">翻译、绘图</el-button></div>
<div style="margin: 10px 0"><el-button type="primary" size="small" @click="onAdaptOneScene(scope.row)">推理场景</el-button></div>
<div style="margin: 10px 0"><el-button type="primary" size="small" @click="onAdaptOneSceneRoles(scope.row)">推理角色</el-button></div>
<div style="margin: 10px 0"><el-button type="primary" size="small" @click="onDrawOne(scope.row)">绘图</el-button></div>
<el-upload
class="upload-demo"
ref="upload"
......@@ -581,9 +717,9 @@ const onPwdCheckDialog = () => {
:on-exceed="handleExceed"
:data="{item_id: scope.row.编号}"
>
<el-button type="primary">上传图片</el-button>
<el-button type="primary" size="small">上传图片</el-button>
</el-upload>
<div style="margin: 10px 0"><el-button plain @click="showsdprompt(scope.row)">debug</el-button></div>
<div style="margin: 10px 0"><el-button plain size="small" @click="showsdprompt(scope.row)">debug</el-button></div>
<el-dialog
v-model=dialogVisible
width="80%"
......@@ -595,6 +731,7 @@ const onPwdCheckDialog = () => {
</div>
</template>
</el-dialog>
<!-- <div style="margin: 10px 0"><el-button type="danger" size="small" @click="onDeleteOne(scope.row)">删除本镜</el-button></div> -->
</template>
</el-table-column>
</el-table>
......@@ -652,7 +789,7 @@ const onPwdCheckDialog = () => {
</el-form-item>
<el-form-item>
<span style="margin: 0 20px">背景音量:</span>
<el-slider v-model="bgm_volume" show-input step="0.1" :min="0" :max="2" :marks="default_data.bgm_volume_marks" style="width: 600px" />
<el-slider v-model="bgm_volume" show-input :step="0.1" :min="0" :max="2" :marks="default_data.bgm_volume_marks" style="width: 600px" />
</el-form-item>
<el-form-item>
<span style="margin: 20px 20px">字幕:</span>
......@@ -663,7 +800,7 @@ const onPwdCheckDialog = () => {
<span style="margin-left:30px;">字体大小:</span>
<el-input-number v-model="sub_font_size" :min="1" :max="50" controls-position="right" />
<span style="margin-left:30px;">在屏幕上的位置:</span>
<el-slider v-model="sub_position" step="0.1" :min="0" :max="1" show-input vertical height="100px" />
<el-slider v-model="sub_position" :step="0.1" :min="0" :max="1" show-input vertical height="100px" />
</div>
</el-form-item>
<el-form-item>
......@@ -674,7 +811,7 @@ const onPwdCheckDialog = () => {
</el-form-item>
</el-form>
<!-- 授权密码框 -->
<el-dialog
<el-dialog
v-model=pwdCheckDialogVisible
title="请输入密码"
width="20%"
......@@ -684,7 +821,7 @@ const onPwdCheckDialog = () => {
>
<el-form :model="form">
<el-form-item label="密码">
<el-input v-model="pwdCheckValue" autocomplete="off" type="password" show-password />
<el-input v-model="pwdCheckValue" autocomplete="off" type="password" show-password @keyup.enter="onPwdCheckDialog()" />
</el-form-item>
</el-form>
<template #footer>
......
......@@ -52,8 +52,8 @@ const bgm_volume = ref(0.3)
const pwdCheckDialogVisible = ref(false);
const pwdCheckValue = ref("")
const sub_font_color = ref("#FFFF00")
const sub_font_size = ref(30)
const sub_position = ref(0.2)
const sub_font_size = ref(25)
const sub_position = ref(0.4)
onMounted(() => {
......@@ -122,7 +122,9 @@ const onAdaptRoles = async () => {
keywords = keywords.replace(/。/g, '').replace(/、/g, ',')
form.chatgpt_answer_roles.push({
"角色": one_role.trim(),
"角色关键词": keywords.trim()+",dressed"
"角色关键词": keywords.trim()+",dressed",
"角色英文关键词": "",
"属性": "",
});
}
}
......@@ -645,7 +647,7 @@ const onPwdCheckDialog = () => {
</el-form-item>
<el-form-item>
<span style="margin: 0 20px">背景音量:</span>
<el-slider v-model="bgm_volume" show-input step="0.1" :min="0" :max="2" :marks="default_data.bgm_volume_marks" style="width: 600px" />
<el-slider v-model="bgm_volume" show-input :step="0.1" :min="0" :max="2" :marks="default_data.bgm_volume_marks" style="width: 600px" />
</el-form-item>
<el-form-item>
<span style="margin: 20px 20px">字幕:</span>
......@@ -656,7 +658,7 @@ const onPwdCheckDialog = () => {
<span style="margin-left:30px;">字体大小:</span>
<el-input-number v-model="sub_font_size" :min="1" :max="50" controls-position="right" />
<span style="margin-left:30px;">在屏幕上的位置:</span>
<el-slider v-model="sub_position" step="0.1" :min="0" :max="1" show-input vertical height="100px" />
<el-slider v-model="sub_position" :step="0.1" :min="0" :max="1" show-input vertical height="100px" />
</div>
</el-form-item>
<el-form-item>
......@@ -677,7 +679,7 @@ const onPwdCheckDialog = () => {
>
<el-form :model="form">
<el-form-item label="密码">
<el-input v-model="pwdCheckValue" autocomplete="off" type="password" show-password />
<el-input v-model="pwdCheckValue" autocomplete="off" type="password" show-password @keyup.enter="onPwdCheckDialog()" />
</el-form-item>
</el-form>
<template #footer>
......
......@@ -24,6 +24,8 @@ declare namespace Wm {
interface RolesItem {
"角色": string,
"角色关键词": string,
"角色英文关键词": string,
"属性": string,
}
interface UploadResult {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment