LaiTool V3.0.1-preview.7

This commit is contained in:
2024-08-18 16:22:19 +08:00
parent 07f99708da
commit 223678f761
78 changed files with 2827 additions and 917 deletions
+14 -14
View File
@@ -1,19 +1,19 @@
<template>
<n-config-provider
:hljs="hljs"
:theme="softwareStore.softWare.theme == 'dark' ? darkTheme : null"
>
<n-message-provider>
<n-dialog-provider>
<n-notification-provider>
<n-spin style="z-index: 1000;" :show="softwareStore.spin.spinning">
<n-spin style="z-index: 1000 !important;" :show="softwareStore.spin.spinning">
<template #description> {{ softwareStore.spin.tip }} </template>
<n-config-provider
:hljs="hljs"
:theme="softwareStore.softWare.theme == 'dark' ? darkTheme : null"
>
<n-message-provider>
<n-dialog-provider>
<n-notification-provider>
<RouterView></RouterView>
<template #description> {{ softwareStore.spin.tip }} </template>
</n-spin>
</n-notification-provider>
</n-dialog-provider>
</n-message-provider>
</n-config-provider>
</n-notification-provider>
</n-dialog-provider>
</n-message-provider>
</n-config-provider>
</n-spin>
</template>
<script>
@@ -7,21 +7,13 @@
@click="EditBook"
>编辑</n-button
>
<n-button
:size="softwareStore.softWare.reverse_data_table_size"
strong
secondary
style="margin-left: 5px"
type="info"
>任务</n-button
>
<n-button
:size="softwareStore.softWare.reverse_data_table_size"
strong
secondary
style="margin-left: 5px"
type="warning"
@click="EditBook"
@click="ResetBookData"
>重置</n-button
>
<n-button
@@ -30,58 +22,108 @@
strong
secondary
type="error"
@click="DeleteBookData"
>删除
</n-button>
</template>
<script>
import { ref, onMounted, defineComponent, h, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NButton, useDialog } from 'naive-ui'
<script setup>
import { ref, h, toRaw } from 'vue'
import { useMessage, useDialog, NButton } from 'naive-ui'
import { useReverseManageStore } from '../../../../../stores/reverseManage.ts'
import { useSoftwareStore } from '../../../../../stores/software'
import { BookType } from '../../../../../define/enum/bookEnum'
import AddBook from '../Components/AddBook.vue'
export default defineComponent({
components: {
NButton
},
props: ['book'],
setup(props) {
let message = useMessage()
let dialog = useDialog()
let book = ref(props.book)
let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore()
onMounted(async () => {})
/**
* 编辑小说数据
*/
async function EditBook(e) {
e.stopPropagation()
// 修改选中的数据
reverseManageStore.SetSelectBook(toRaw(book.value))
// 一个弹窗添加数据
let dialogWidth = 600
// ImportWordAndSrt
dialog.create({
showIcon: false,
closeOnEsc: false,
title: '编辑小说',
content: () => h(AddBook, { type: 'edit' }),
style: `width : ${dialogWidth}px;`,
maskClosable: false
})
}
return {
book,
reverseManageStore,
softwareStore,
EditBook
}
}
let props = defineProps({
book: undefined
})
let message = useMessage()
let dialog = useDialog()
let book = ref(props.book)
let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore()
/**
* 编辑小说数据
*/
async function EditBook(e) {
e.stopPropagation()
// 修改选中的数据
reverseManageStore.SetSelectBook(toRaw(book.value))
// 一个弹窗添加数据
let dialogWidth = 600
// ImportWordAndSrt
dialog.create({
showIcon: false,
closeOnEsc: false,
title: '编辑小说',
content: () => h(AddBook, { type: 'edit' }),
style: `width : ${dialogWidth}px;`,
maskClosable: false
})
}
async function ResetBookData(e) {
e.stopPropagation()
message.info('重置小说数据 ' + book.value.id)
let da = dialog.warning({
title: '重置小说数据警告',
content:
'是否重置小说数据,重置后数据将恢复至新建状态,所有的批次数据和文件数据都会被删除,请确认是否继续!',
positiveText: '确认',
negativeText: '取消',
onPositiveClick: async () => {
da?.destroy()
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在重置小说数据。。。'
let res = await window.book.ResetBookData(book.value.id)
softwareStore.spin.spinning = false
if (res.code == 0) {
message.error(res.message)
return
}
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在重新加载小说批次任务数据。。。'
// 这边修改还是在哪里修改啊// 加载任务列表
let bookTaskRes = await reverseManageStore.GetBookTaskDataFromDB({
bookId: book.value.id
})
softwareStore.spin.spinning = false
if (bookTaskRes.code == 0) {
message.error(bookTaskRes.message)
return
}
message.success('重置小说数据成功')
}
})
}
async function DeleteBookData(e) {
e.stopPropagation()
message.info('删除小说数据 ' + book.value.id)
let da = dialog.warning({
title: '删除小说数据警告',
content:
'是否删除小说数据,删除后数据将被永久删除,所有的批次数据和文件数据都会被删除,请确认是否继续!',
positiveText: '确认',
negativeText: '取消',
onPositiveClick: async () => {
da?.destroy()
debugger
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在删除小说数据。。。'
let res = await window.book.DeleteBookData(book.value.id)
softwareStore.spin.spinning = false
if (res.code == 0) {
message.error(res.message)
return
}
debugger
// 这边直接把数据删除了就行
reverseManageStore.bookData = reverseManageStore.bookData.filter(
(item) => item.id != book.value.id
)
message.success('删除小说数据成功')
}
})
}
</script>
@@ -34,14 +34,11 @@
</template>
<script>
import { ref, onMounted, defineComponent, h, onUnmounted, toRaw, watch } from 'vue'
import { ref, onMounted, defineComponent, h } from 'vue'
import { useMessage, NButton, useDialog } from 'naive-ui'
import { useReverseManageStore } from '../../../../../stores/reverseManage.ts'
import { useSoftwareStore } from '../../../../../stores/software'
import { BookType, OperateBookType } from '../../../../../define/enum/bookEnum'
import AddBook from '../Components/AddBook.vue'
import { DEFINE_STRING } from '../../../../../define/define_string'
import { ResponseMessageType } from '../../../../../define/enum/softwareEnum'
import ManageBookTaskGenerateInformation from './ManageBookTaskGenerateInformation.vue'
export default defineComponent({
@@ -51,9 +48,11 @@ export default defineComponent({
props: ['bookTask'],
setup(props) {
debugger
let message = useMessage()
let dialog = useDialog()
let bookTask = ref(props.bookTask)
console.log('bookTask', bookTask.value)
let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore()
@@ -172,6 +171,7 @@ export default defineComponent({
*/
async function ClipDraft(e) {
e.stopPropagation()
debugger
dialog.info({
closeOnEsc: false,
title: '生成草稿前检查',
@@ -186,7 +186,7 @@ export default defineComponent({
*/
async function GenerateVideo(e) {
e.stopPropagation()
alert('合成视频')
message.error('该功能暂不可用')
}
return {
@@ -32,6 +32,7 @@ export default defineComponent({
props: ['initData', 'index'],
setup(props) {
let data = ref(props.initData)
console.log('subValue', data.value)
onMounted(async () => {})
let show = computed(() => {
debugger
@@ -1,5 +1,5 @@
<template>
<div style="position: absolute; top: 0">
<div>
<n-dropdown trigger="hover" :options="reverseOptions" @select="ReverseSelect">
<n-button size="tiny" :color="softwareStore.SoftColor.BROWN_YELLOW" @click="AddReversePrompt">
单句反推
@@ -15,7 +15,6 @@
英文 2 中文
</n-button>
</n-dropdown>
<n-button
style="margin-left: 5px"
size="tiny"
@@ -35,6 +34,7 @@ import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { TranslateType } from '../../../../../define/enum/translate'
import { ContainsChineseOrPunctuation } from '../../../../../define/Tools/common'
import ReSelectReversePrompt from '../MJReverse/ReSelectReversePrompt.vue'
import { OperateBookType } from '../../../../../define/enum/bookEnum'
import { isEmpty } from 'lodash'
export default defineComponent({
@@ -53,7 +53,11 @@ export default defineComponent({
* 单句反推提示词
*/
async function AddReversePrompt() {
let res = await window.book.AddReversePrompt([data.value.id], null)
let res = await window.book.AddReversePrompt(
data.value.id,
OperateBookType.BOOKTASKDETAIL,
null
)
if (res.code == 0) {
message.error(res.message)
} else {
@@ -63,7 +67,8 @@ export default defineComponent({
async function AddNextReversePrompt() {
let res = await window.book.AddReversePrompt(
[data.value.id],
data.value.id,
OperateBookType.UNDERBOOKTASK,
reverseManageStore.selectBook.type
)
if (res.code == 0) {
@@ -84,6 +89,7 @@ export default defineComponent({
if (res.code == 0) {
message.error(res.message)
} else {
reverseManageStore.selectBookTaskDetail[props.index].gptPrompt = undefined
reverseManageStore.selectBookTaskDetail[props.index].reversePrompt = undefined
message.success('删除反推数据成功')
}
@@ -110,16 +116,16 @@ export default defineComponent({
// 处理翻译英文的数据
function TranslateOneParams(from, to) {
let translateData = []
// if (!isEmpty(data.value.prompt)) {
// translateData.push({
// text: item.prompt,
// from: from,
// to: to,
// type: TranslateType.PROMPT_TRANSLATE,
// isSplit: false, // 该参数设置为true时,会将文本按照标点符号分割成多个句子进行翻译
// bookTaskDetailId: data.value.id
// })
// } else {
if (!isEmpty(data.value.gptPrompt)) {
translateData.push({
text: data.value.gptPrompt,
from: from,
to: to,
type: TranslateType.GPT_PROMPT_TRANSLATE,
isSplit: false, // 该参数设置为true时,会将文本按照标点符号分割成多个句子进行翻译
bookTaskDetailId: data.value.id
})
} else {
let reversePrompt = data.value.reversePrompt
if (reversePrompt) {
reversePrompt.forEach((item) => {
@@ -143,7 +149,7 @@ export default defineComponent({
translateData.push(temp_obj)
})
}
// }
}
return translateData
}
@@ -152,27 +158,39 @@ export default defineComponent({
let translateData = []
for (let i = index.value; i < reverseManageStore.selectBookTaskDetail.length; i++) {
const element = reverseManageStore.selectBookTaskDetail[i]
let reversePrompt = element.reversePrompt
if (reversePrompt) {
reversePrompt.forEach((item) => {
if (from == 'zh' && to == 'en') {
// 判断是不是有中文
if (!ContainsChineseOrPunctuation(item.promptCN ? item.promptCN : item.prompt)) {
return
}
}
let temp_obj = {
text: item.prompt,
from: from,
to: to,
type: TranslateType.REVERSE_PROMPT_TRANSLATE,
isSplit: false, // 该参数设置为true时,会将文本按照标点符号分割成多个句子进行翻译
bookTaskDetailId: element.id,
reversePromptId: item.id
}
translateData.push(temp_obj)
// 这边判断GPT提示词是不是存在,存在的话翻译GPT提示词
if (!isEmpty(data.value.gptPrompt)) {
translateData.push({
text: element.gptPrompt,
from: from,
to: to,
type: TranslateType.GPT_PROMPT_TRANSLATE,
isSplit: false, // 该参数设置为true时,会将文本按照标点符号分割成多个句子进行翻译
bookTaskDetailId: element.id
})
} else {
let reversePrompt = element.reversePrompt
if (reversePrompt) {
reversePrompt.forEach((item) => {
if (from == 'zh' && to == 'en') {
// 判断是不是有中文
if (!ContainsChineseOrPunctuation(item.promptCN ? item.promptCN : item.prompt)) {
return
}
}
let temp_obj = {
text: item.prompt,
from: from,
to: to,
type: TranslateType.REVERSE_PROMPT_TRANSLATE,
isSplit: false, // 该参数设置为true时,会将文本按照标点符号分割成多个句子进行翻译
bookTaskDetailId: element.id,
reversePromptId: item.id
}
translateData.push(temp_obj)
})
}
}
}
return translateData
@@ -30,7 +30,7 @@ import { useSoftwareStore } from '../../../../../stores/software'
import DynamicTagsSelect from '../../Components/DynamicTagsSelect.vue'
import { usePromptStore } from '../../../../../stores/prompt'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { BookImageCategory, BookType, MergeType } from '../../../../../define/enum/bookEnum'
import { BookImageCategory, OperateBookType } from '../../../../../define/enum/bookEnum'
export default defineComponent({
components: { NDropdown, NPopover, NIcon, NButton, Construct },
@@ -110,20 +110,15 @@ export default defineComponent({
}
}
// 开始进行合并,调用不同的合并模式
let res = undefined
// 合并之前,要确认保存
softwareStore.spin.spinning = true
softwareStore.spin.tip = '合并命令中。。。'
if (type == 'mj_merge') {
res = await window.mj.MergePrompt(reverseManageStore.selectBookTask.id, MergeType.BOOKTASK)
} else if (type == 'sd_merge') {
res = await window.sd.MergePrompt(reverseManageStore.selectBookTask.id, MergeType.BOOKTASK)
} else {
message.error('未知的合并模式')
softwareStore.spin.spinning = false
return
}
let res = await window.book.MergePrompt(
reverseManageStore.selectBookTask.id,
type,
OperateBookType.BOOKTASK
)
// 这边对返回的数据进行处理
if (res.code == 0) {
@@ -1,5 +1,5 @@
<template>
<div style="position: absolute; top: 0">
<div>
<n-dropdown trigger="hover" :options="mergeOptions" @select="MergePrompt">
<n-button
size="tiny"
@@ -37,7 +37,6 @@
</n-button>
</div>
<n-input
style="margin-top: 5px"
type="textarea"
size="tiny"
@input="InputDebounced"
@@ -51,7 +50,7 @@ import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, h } from 'v
import { useMessage, useDialog, NInput, NButton, NDropdown } from 'naive-ui'
import { useSoftwareStore } from '../../../../../stores/software'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { MergeType, OperateBookType } from '../../../../../define/enum/bookEnum'
import { OperateBookType } from '../../../../../define/enum/bookEnum'
import { BookImageCategory } from '../../../../../define/enum/bookEnum'
import { debounce } from 'lodash'
import InputDialogContent from '../../Original/Components/InputDialogContent.vue'
@@ -81,25 +80,14 @@ export default defineComponent({
}
}
// 开始进行合并,调用不同的合并模式
let res = undefined
// 合并之前,要确认保存
softwareStore.spin.spinning = true
softwareStore.spin.tip = '合并命令中。。。'
if (type == 'mj_merge') {
res = await window.mj.MergePrompt(data.value.id, MergeType.BOOKTASKDETAIL)
} else if (type == 'sd_merge') {
res = await window.sd.MergePrompt(data.value.id, MergeType.BOOKTASKDETAIL)
} else {
message.error('未知的合并模式')
softwareStore.spin.spinning = false
return
}
let res = await window.book.MergePrompt(data.value.id, type, OperateBookType.BOOKTASKDETAIL)
softwareStore.spin.spinning = false
// 这边对返回的数据进行处理
if (res.code == 0) {
message.error(res.message)
softwareStore.spin.spinning = false
return
}
for (let i = 0; i < res.data.length; i++) {
@@ -110,7 +98,6 @@ export default defineComponent({
reverseManageStore.selectBookTaskDetail[selectBookDetailIndex].prompt = element.prompt
}
message.success(res.message)
softwareStore.spin.spinning = false
}
// 单个出图
@@ -169,7 +156,7 @@ export default defineComponent({
// 处理数据。获取当前的所有的数据
let dialogWidth = 400
let dialogHeight = 150
dialog.create({
let da = dialog.create({
title: '添加图片链接/本地地址',
showIcon: false,
closeOnEsc: false,
@@ -182,9 +169,12 @@ export default defineComponent({
style: `width : ${dialogWidth}px; min-height : ${dialogHeight}px`,
maskClosable: false,
onClose: async () => {
da?.destroy()
let row_image_url = image_url_ref.value.data
alert(row_image_url)
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在下载图片/分割图片中。。。'
let res = await window.book.DownloadImageUrlAndSplit(data.value.id, row_image_url)
softwareStore.spin.spinning = false
if (res.code == 0) {
message.error(res.message)
return
@@ -192,24 +182,6 @@ export default defineComponent({
data.value.outImagePath = res.data.outImagePath
data.value.subImagePath = res.data.subImagePath
message.success(res.message)
// 下载指定的图片地址并且分割
// await window.mj.DownloadImageUrlAndSplit(
// JSON.stringify([toRaw(row.value), row_image_url]),
// (value) => {
// if (value.code == 0) {
// message.error(value.message)
// return
// }
// // 更新当前的数据
// row.value.outImagePath = value.data.outImagePath
// row.value.subImagePath = value.data.subImagePath
// row.value.mj_message = value.data.mj_message ? value.data.mj_message : {}
// row.value.mj_message.image_click = value.data.image_click
// row.value.mj_message.image_path = value.data.image_path
// row.value.mj_message.progress = 100
// }
// )
}
})
}
@@ -0,0 +1,70 @@
<template>
<div class="artplayer-app" style="height: 100%">
<Artplayer ref="art" id="art-player" @get-instance="getInstance" :option="option" :style="palyarStyle" />
<div style="margin-top: 20px; display: flex; justify-content: center">
<n-button :loading="loading" type="info" @click="ReplaceFrame"> 替换为当前帧 </n-button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useMessage, useDialog, NButton } from 'naive-ui'
import Artplayer from '../../Components/Artplayer.vue'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { useSoftwareStore } from '../../../../../stores/software'
let message = useMessage()
let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore()
let props = defineProps({
videoPath: undefined,
type: undefined,
id: undefined
})
let videoPath = ref(props.videoPath)
let id = ref(props.id)
let art = ref(null)
let loading = ref(false)
function getInstance(art) {}
async function ReplaceFrame() {
let artInstance = art.value.instance
message.success(artInstance.currentTime)
let currentTime = artInstance.currentTime
loading.value = true
let res = await window.book.ReplaceVideoCurrentFrame(id.value, currentTime * 1000)
loading.value = false
if (res.code == 0) {
message.error(res.message)
} else {
// 将返回的数据写回
let index = reverseManageStore.selectBookTaskDetail.findIndex((item) => item.id == id.value)
if (index < 0) {
return
}
reverseManageStore.selectBookTaskDetail[index].oldImage = res.data
message.success('替换视频帧成功')
}
}
function test() {}
let palyarStyle = {
width: '600px',
height: '600px',
margin: '0 auto'
}
let option = {
container: '.artplayer-app',
id: id.value,
url: videoPath.value,
playbackRate: true,
aspectRatio: true,
mutex: true,
setting: true,
hotkey: true,
autoSize: true,
fullscreen: true
}
</script>
@@ -134,10 +134,12 @@ export default defineComponent({
code.value = code.value + '\n' + value.data
return
}
// 修改进度
softwareStore.spin.tip = `正在提取文案,当前进度 ${value.data.progress.current} / ${value.data.progress.total} 。。。`
let index = reverseManageStore.selectBookTaskDetail.findIndex((item) => item.id == value.id)
if (index >= 0) {
reverseManageStore.selectBookTaskDetail[index].word = value.data
reverseManageStore.selectBookTaskDetail[index].afterGpt = value.data
reverseManageStore.selectBookTaskDetail[index].word = value.data.content
reverseManageStore.selectBookTaskDetail[index].afterGpt = value.data.content
}
})
@@ -251,18 +253,39 @@ export default defineComponent({
return
}
let copywriting_res = await window.book.GetCopywriting(reverseManageStore.selectBook.id)
if (copywriting_res.code == 0) {
message.error(copywriting_res.message)
let subtitleSettingRes = await window.write.GetSubtitleSetting()
if (subtitleSettingRes.code == 0) {
message.error(subtitleSettingRes.message)
return
}
message.success('获取文案成功')
let da = dialog.warning({
title: '开始提取文案提示',
content: `即将进行文案提取,当前的文案提取模式为 ${subtitleSettingRes.data.selectModel} ,是否继续?`,
positiveText: '继续',
negativeText: '取消',
onPositiveClick: async () => {
da?.destroy()
softwareStore.spin.spinning = true
softwareStore.spin.tip = `正在使用 ${subtitleSettingRes.data.selectModel} 提取文案,正在准备中。。。`
let copywriting_res = await window.book.GetCopywriting(
reverseManageStore.selectBook.id,
reverseManageStore.selectBookTask.id,
OperateBookType.BOOKTASK
)
softwareStore.spin.spinning = false
if (copywriting_res.code == 0) {
message.error(copywriting_res.message)
return
}
// dialog.success({})
message.success('获取全部文案成功')
}
})
}
// 开始去除水印
async function RemoveWatermark() {
// softwareStore.spin.spinning = true
// softwareStore.spin.tip = '正在去除水印中'
if (isEmpty(reverseManageStore.selectBookTask.id)) {
window.api.showGlobalMessageDialog({
code: 0,
@@ -270,12 +293,23 @@ export default defineComponent({
})
return
}
let res_frame = await window.book.RemoveWatermark(
reverseManageStore.selectBookTask.id,
OperateBookType.BOOKTASK
)
softwareStore.spin.spinning = false
window.api.showGlobalMessageDialog(res_frame)
let da = dialog.warning({
title: '去除水印提示',
content: '即将去除全部水印,是否继续?',
positiveText: '继续',
negativeText: '取消',
onPositiveClick: async () => {
da?.destroy()
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在去除水印中。。。'
let res_frame = await window.book.RemoveWatermark(
reverseManageStore.selectBookTask.id,
OperateBookType.BOOKTASK
)
softwareStore.spin.spinning = false
window.api.showGlobalMessageDialog(res_frame)
}
})
}
// 获取文案信息设置
@@ -297,6 +331,28 @@ export default defineComponent({
})
}
// 导出文案
async function ExportCopywriting() {
debugger
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在导出文案中...'
let res = await window.book.ExportCopywriting(reverseManageStore.selectBookTask.id)
if (res.code == 0) {
message.error(res.message)
} else {
dialog.success({
title: '导出文案成功',
content: '导出文案成功,是否打开导出的字幕文件',
positiveText: '打开',
negativeText: '取消',
onPositiveClick: () => {
window.system.OpenFile(res.data)
}
})
}
softwareStore.spin.spinning = false
}
/**
* 获取水印位置
*/
@@ -329,6 +385,9 @@ export default defineComponent({
case 'recognizing_setting': // 文案位置设置
await GetCopywritingSetting()
break
case 'export_recognizing': // 导出文案
await ExportCopywriting()
break
case 'watermark_position': // 水印位置设置
await GetWatermarkPosition()
break
@@ -376,7 +435,6 @@ export default defineComponent({
* @param type 反推类型
*/
async function ImageReversePrompt(type = undefined) {
debugger
if (isEmpty(reverseManageStore.selectBookTask.id)) {
window.api.showGlobalMessageDialog({
code: 0,
@@ -384,32 +442,36 @@ export default defineComponent({
})
return
}
dialog.warning({
title: '反推提示',
content: `即将进行反推操作,反推方式为 ${
type ? type : reverseManageStore.selectBook.type
} ,是否继续?`,
positiveText: '继续',
negativeText: '取消',
onPositiveClick: async () => {
if (!type) {
let bookType = reverseManageStore.selectBook.type
type = bookType
}
if (!type) {
let bookType = reverseManageStore.selectBook.type
type = bookType
}
if (type != BookType.MJ_REVERSE && type != BookType.SD_REVERSE) {
message.error(`该类型 ${bookType} 的小说不支持反推`)
return
}
let reverseIds = []
// 开始获取需要反推的数据
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
const element = reverseManageStore.selectBookTaskDetail[i]
if (!element.reversePrompt || element.reversePrompt.length <= 0) {
reverseIds.push(element.id)
if (type != BookType.MJ_REVERSE && type != BookType.SD_REVERSE) {
message.error(`该类型 ${bookType} 的小说不支持反推`)
return
}
// 开始添加
let res = await window.book.AddReversePrompt(
reverseManageStore.selectBookTask.id,
OperateBookType.BOOKTASK,
type
)
if (res.code == 0) {
message.error(res.message)
} else {
message.success('添加所有反推任务成功')
}
}
}
// 开始添加
let res = await window.book.AddReversePrompt(reverseIds, type)
if (res.code == 0) {
message.error(res.message)
} else {
message.success('添加所有反推任务成功')
}
})
}
/**
@@ -417,13 +479,16 @@ export default defineComponent({
*/
async function RemoveReverseData(id) {
let deleteIds = []
// 删除全部的
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
const element = reverseManageStore.selectBookTaskDetail[i]
if (element.reversePrompt && element.reversePrompt.length > 0) {
deleteIds.push(element.id)
if (id == undefined) {
// 删除全部的
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
const element = reverseManageStore.selectBookTaskDetail[i]
if (element.reversePrompt && element.reversePrompt.length > 0) {
deleteIds.push(element.id)
}
}
} else {
deleteIds.push(id)
}
let res = await window.book.RemoveReverseData(deleteIds)
@@ -643,6 +708,10 @@ export default defineComponent({
label: '提取文案位置',
key: 'recognizing_setting'
},
{
label: '导出文案',
key: 'export_recognizing'
},
{
label: '停止提取',
key: 'stop_recognizing'
@@ -665,7 +734,8 @@ export default defineComponent({
},
{
label: 'SD反推',
key: 'sd_reverse'
key: 'sd_reverse',
disabled: reverseManageStore.selectBook.type != BookType.SD_REVERSE
},
{
label: '清除反推数据',
@@ -1,28 +1,107 @@
<template>
<div style="position: absolute; top: 0">
<!-- <n-button size="tiny">123</n-button> -->
<div style="margin-bottom: 2px">
<n-button :color="softwareStore.SoftColor.BROWN_YELLOW" size="tiny" @click="OpenGetVideoFrame"
>抽帧</n-button
>
<n-button
style="margin-left: 2px"
:color="softwareStore.SoftColor.BROWN_YELLOW"
size="tiny"
@click="GetVideoSubtitle"
>文案</n-button
>
<n-button
style="margin-left: 2px"
:color="softwareStore.SoftColor.BROWN_YELLOW"
size="tiny"
@click="RemoveImageWatermark"
>水印</n-button
>
</div>
<n-image v-if="data.oldImage" width="110" :src="data.oldImage"> </n-image>
<video v-else-if="data.data.videoPath" width="110" controls>
<n-image v-if="data.oldImage" width="112" :src="data.oldImage"> </n-image>
<video v-else-if="data.videoPath" width="110" controls>
<source :src="data.videoPath" type="video/mp4" />
</video>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage, NImage, NButton } from 'naive-ui'
<script setup>
import { ref, onMounted, h } from 'vue'
import { useMessage, useDialog, NImage, NButton } from 'naive-ui'
import { useSoftwareStore } from '../../../../../stores/software'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { OperateBookType } from '../../../../../define/enum/bookEnum'
import GetVideoFrame from './GetVideoFrame.vue'
let message = useMessage()
let dialog = useDialog()
let softwareStore = useSoftwareStore()
let reverseManageStore = useReverseManageStore()
export default defineComponent({
components: { NImage, NButton },
props: ['initData', 'index'],
setup(props) {
let message = useMessage()
let data = ref(props.initData)
onMounted(async () => {})
return {
data
}
}
let props = defineProps({
initData: undefined,
index: undefined
})
let data = ref(props.initData)
let index = ref(props.index)
onMounted(async () => {})
// 重新对当前视频进行抽帧
async function OpenGetVideoFrame() {
// 判断的分镜中的视频是否存在
if (!data.value.videoPath) {
message.error('当前分镜没有视频')
return
}
dialog.create({
title: '获取视频的帧',
style: 'width : 800px;',
content: () =>
h(GetVideoFrame, {
videoPath: data.value.videoPath,
id: data.value.id,
type: OperateBookType.BOOKTASKDETAIL
})
})
}
// 获取当前视频的片段的文案
async function GetVideoSubtitle() {
// alert(data.value.id)
softwareStore.spin.spinning = true
softwareStore.spin.tip = `获取分镜 ${data.value.name} 文案中。。。`
let res = await window.book.GetCopywriting(
reverseManageStore.selectBook.id,
data.value.id,
OperateBookType.BOOKTASKDETAIL
)
softwareStore.spin.spinning = false
if (res.code == 0) {
message.error(res.message)
} else {
// 修改指定的数据
reverseManageStore.selectBookTaskDetail[index.value].afterGpt = res.data
reverseManageStore.selectBookTaskDetail[index.value].word = res.data
message.success('获取视频文案成功')
}
}
// 去除当前分镜文案的水印
async function RemoveImageWatermark() {
softwareStore.spin.spinning = true
softwareStore.spin.tip = `去除分镜 ${data.value.name} 水印中。。。`
let res = await window.book.RemoveWatermark(data.value.id, OperateBookType.BOOKTASKDETAIL)
softwareStore.spin.spinning = false
if (res.code == 0) {
message.error(res.message)
} else {
// 修改指定的数据
let index = reverseManageStore.selectBookTaskDetail.findIndex(
(item) => item.id == data.value.id
)
if (index < 0) {
return
}
reverseManageStore.selectBookTaskDetail[index].oldImage = res.data
message.success(`${data.value.name} 去除水印成功`)
}
}
</script>
@@ -48,7 +48,7 @@
</n-form-item>
<n-form-item path="backgroundMusic">
<n-button :disabled="type == 'book'" type="info" @click="UseBookVideoDataToBookTask">{{
type == 'bookTsk' ? '应用主小说相关数据' : '当前就是用的主小说的数据'
type == bookTask ? '应用主小说相关数据' : '当前就是用的主小说的数据'
}}</n-button>
<n-button type="info" style="margin-left: 10px" @click="SaveVideoData">保存数据</n-button>
</n-form-item>
@@ -73,6 +73,7 @@ export default defineComponent({
props: ['bookTask', 'type'],
setup(props) {
let bookTask = ref(props.bookTask)
debugger
let type = ref(props.type)
let backgroundMusicOptions = ref([])
let message = useMessage()
@@ -1,5 +1,5 @@
<template>
<div style="margin-bottom: 7px">
<div>
<DatatableGptPromptButton :initData="data" :index="index" />
</div>
<div v-if="data.gptPrompt">
@@ -15,11 +15,22 @@
>
</n-input>
</div>
<div v-else class="show-gpt-prompt">
<div v-else-if="data.reversePrompt && data.reversePrompt.length > 0" class="show-gpt-prompt">
<div v-for="(item, index) in showReversePrompt" :key="index" style="margin-bottom: 5px">
<n-input v-model:value="item.prompt" type="text" size="tiny"> </n-input>
</div>
</div>
<n-input
v-else
type="textarea"
size="tiny"
v-model:value="data.gptPrompt"
:autosize="{
minRows: 6,
maxRows: 6
}"
@input="InputDebounced"
></n-input>
</template>
<script>
@@ -42,7 +53,7 @@ export default defineComponent({
let showReversePrompt = computed(() => {
debugger
let res = []
for (let i = 0; i < data.value.reversePrompt.length; i++) {
for (let i = 0; i < data.value.reversePrompt?.length; i++) {
let item = data.value.reversePrompt[i]
let res_obj = {
...item
@@ -106,6 +106,7 @@ export default defineComponent({
return h(DatatableHeaderImage)
},
width: 300,
className: 'space-row',
render(row, index) {
return h(DataTableShowGenerateImage, {
image_generate_category: 'mj',
@@ -126,7 +127,6 @@ export default defineComponent({
let div = document.getElementsByClassName('space-row')
for (let i = 0; i < div.length; i++) {
div[i].style.padding = '0px 5px'
div[i].style.position = 'relative'
}
}, 100)
@@ -6,7 +6,7 @@
<n-data-table
:columns="columns"
:size="softwareStore.softWare.reverse_data_table_size"
:data="data"
:data="reverseManageStore.bookData"
:pagination="pagination"
:bordered="false"
:remote="true"
@@ -39,7 +39,6 @@ export default defineComponent({
let message = useMessage()
let softwareStore = useSoftwareStore()
let reverseManageStore = useReverseManageStore()
let data = computed(() => reverseManageStore.GetBookData())
let maxHeight = ref(0)
//
const paginationReactive = (() => {
@@ -161,7 +160,7 @@ export default defineComponent({
{
title: '操作',
key: 'action',
width: 310,
width: 240,
fixed: 'right',
render: (row) => {
return h(BookListAction, { book: row })
@@ -185,7 +184,6 @@ export default defineComponent({
return {
softwareStore,
reverseManageStore,
data,
pagination,
maxHeight,
columns: createColumns(),
@@ -66,11 +66,14 @@ export default defineComponent({
//
switch (value.type) {
case ResponseMessageType.MJ_REVERSE:
case ResponseMessageType.MJ_REVERSE: // MJ
MJReverseResponse(value)
break
case ResponseMessageType.PROMPT_TRANSLATE:
PromptTranslateResponse(value)
case ResponseMessageType.REVERSE_PROMPT_TRANSLATE: //
ReversePromptTranslateResponse(value)
break
case ResponseMessageType.GPT_PROMPT_TRANSLATE: // GPT
GptPromptTranslateResponse(value)
break
case ResponseMessageType.MJ_IMAGE:
MJImageResponse(value)
@@ -111,7 +114,7 @@ export default defineComponent({
* prompt: string //
* promptCN: string //
*/
function PromptTranslateResponse(value) {
function ReversePromptTranslateResponse(value) {
if (!value.data) {
return
}
@@ -143,15 +146,32 @@ export default defineComponent({
}
}
function GptPromptTranslateResponse(value) {
console.log('GptPromptTranslateResponse', value)
if (!value.data) {
return
}
let index = reverseManageStore.selectBookTaskDetail.findIndex(
(item) => item.id == value.data.bookTaskDetailId
)
if (index < 0) {
return
}
reverseManageStore.selectBookTaskDetail[index].gptPrompt = value.data.prompt
}
/**
* MJ反推返回数据
*/
function MJReverseResponse(value) {
console.log('MJReverseResponse', value)
if (value.data && value.data.progress == 100) {
debugger
let dataIndex = reverseManageStore.selectBookTaskDetail.findIndex(
(item) => item.id == value.data.id
)
if (dataIndex >= 0) {
reverseManageStore.selectBookTaskDetail[dataIndex].gptPrompt = undefined
reverseManageStore.selectBookTaskDetail[dataIndex].reversePrompt = JSON.parse(
value.data.prompt
)
@@ -32,7 +32,7 @@
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, h } from 'vue'
import { useMessage, useDialog, NButton, NDataTable, NIcon } from 'naive-ui'
import { useMessage, useDialog, NButton, NDataTable, NIcon, NWatermark } from 'naive-ui'
import { useReverseManageStore } from '../../../../stores/reverseManage'
import { useSoftwareStore } from '../../../../stores/software'
import { AddSharp } from '@vicons/ionicons5'
@@ -46,7 +46,8 @@ export default defineComponent({
components: {
NButton,
NDataTable,
BookTaskListAction
BookTaskListAction,
NWatermark
},
setup() {
@@ -103,6 +104,7 @@ export default defineComponent({
width: 215,
fixed: 'right',
render(row, index) {
debugger
return h(BookTaskListAction, {
bookTask: row
})
@@ -89,7 +89,11 @@ export default defineComponent({
let message = useMessage()
let type = ref(props.type)
let row = ref(props.row)
let translate_options = ref([{ label: '翻译中文', key: 'chinese' }])
let translate_options = ref([
{ label: '翻译中文', key: 'chinese' },
{ label: '下翻译 英文 2 中文', key: 'down_english_chinese' },
{ label: '下翻译 中文 2 英文', key: 'down_chinese_english' }
])
//
watch(
@@ -142,7 +146,6 @@ export default defineComponent({
message.error('当前翻译的数据里面没有中文')
}
} else if (key == 'chinese') {
let t = [[toRaw(row.value)], 'en', 'zh', false, false]
await window.mj.TranslateReturnNowTask(JSON.stringify(t), (value) => {
if (value.code == 0) {
@@ -151,6 +154,14 @@ export default defineComponent({
}
message.success('添加翻译任务成功')
})
} else if (key == 'down_english_chinese') {
//
props.func.translateAll(key, props.index)
} else if (key == 'down_chinese_english') {
//
props.func.translateAll(key, props.index)
} else {
message.error('未知的翻译类型')
}
}
@@ -81,8 +81,8 @@
class="g-image-class generate-image-show"
:src="outImagePath ? outImagePath : space_image"
fit="cover"
width="120"
height="120"
:width="120"
:height="120"
lazy
/>
<n-button
@@ -107,7 +107,7 @@
subImage="true"
class="g-image-class"
draggable="true"
:width="width"
:width="56"
style="margin: 1px"
v-for="(image, index) in images"
:key="image.id"
@@ -330,7 +330,7 @@ export default defineComponent({
return
}
let lock = !data.value.imageLock
if (
reverseManageStore.selectBookTaskDetail &&
reverseManageStore.selectBookTaskDetail.length > 0
@@ -250,6 +250,7 @@ export default defineComponent({
row: row,
index: index,
func: {
translateAll: TranslateAll,
nextGptPrompt: NextGptPrompt,
singlePrompt: SinglePrompt
}
@@ -848,8 +849,9 @@ export default defineComponent({
* 翻译传入的数据
* @param {*} key 翻译的类型
*/
async function TranslateAll(key) {
async function TranslateAll(key, index = -1) {
//
debugger
if (key == 'english') {
let tmp_d = []
for (let i = 0; i < data.value.length; i++) {
@@ -877,6 +879,45 @@ export default defineComponent({
}
message.success('添加翻译任务成功')
})
} else if (key == 'down_english_chinese') {
//
// ,
let tempData = []
for (let i = 0; i < data.value.length; i++) {
const element = cloneDeep(data.value[i])
if (index <= i) {
tempData.push(element)
}
}
let t = [tempData, 'en', 'zh', false, false]
await window.mj.TranslateReturnNowTask(JSON.stringify(t), (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
message.success('添加翻译任务成功')
})
} else if (key == 'down_chinese_english') {
//
//
let tempData = []
for (let i = 0; i < data.value.length; i++) {
const element = cloneDeep(data.value[i])
if (index <= i) {
tempData.push(element)
}
}
let t = [tempData, 'zh', 'en', false, false]
await window.mj.TranslateReturnNowTask(JSON.stringify(t), (value) => {
if (value.code == 0) {
message.error(value.message)
return
}
message.success('添加翻译任务成功')
})
} else {
message.error('未知的翻译类型')
}
}
@@ -74,7 +74,6 @@ export default defineComponent({
for (let i = 0; i < data.value.length; i++) {
const item = data.value[i]
await window.api.GetPromptJson(item.name, (value) => {
console.log(value)
if (value.code == 0 && promptError) {
message.error(value.message)
promptError = false
@@ -35,8 +35,8 @@
v-model:value="mjSetting.imageScale"
></n-select>
</n-form-item>
<n-form-item label="命令后缀" style="width: 160px; margin-left: 10px" path="image_suffix">
<n-input v-model:value="image_suffix" placeholder="请输入后缀命令"></n-input>
<n-form-item label="命令后缀" style="width: 160px; margin-left: 10px" path="imageSuffix">
<n-input v-model:value="mjSetting.imageSuffix" placeholder="请输入后缀命令"></n-input>
</n-form-item>
<n-form-item label="生图任务量" style="width: 100px; margin-left: 10px" path="taskCount">
<n-input-number
@@ -91,7 +91,7 @@
<n-input
type="password"
placeholder="请输入密钥"
show-password-on="mousedown"
show-password-on="mousedown"
v-model:value="mjSetting.apiSetting.apiKey"
></n-input>
</n-form-item>
@@ -272,7 +272,7 @@ export default defineComponent({
let request_model_options = ref([])
let mj_api_options = ref([])
let image_suffix = computed(() => {
let computedSuffix = () => {
let text = image_model_options.value.findIndex((item) => {
return item.value == mjSetting.value.imageModel
})
@@ -285,7 +285,7 @@ export default defineComponent({
let dd = ` --${image_model_options.value[text].text} --ar ${image_scale_options.value[sc].text}`
mjSetting.value.imageSuffix = dd
return dd
})
}
//
async function InitData() {
@@ -419,7 +419,7 @@ export default defineComponent({
message.error('请检查必填字段')
return
}
mjSetting.value.imageSuffix = image_suffix.value
// mjSetting.value.imageSuffix = image_suffix.value
//
let request_model = mjSetting.value.requestModel
@@ -500,6 +500,9 @@ export default defineComponent({
mjSetting.value.imageModel =
image_model_options.value.length > 0 ? image_model_options.value[0].value : null
}
//
mjSetting.value.imageSuffix = computedSuffix()
}
/**
@@ -546,7 +549,6 @@ export default defineComponent({
image_scale_options,
image_model_options,
UpdateSelectRobot,
image_suffix,
request_model_options,
mj_api_options,
mj_speed_options,
@@ -1,18 +1,182 @@
<template>
<div>识别文案设置</div>
<div style="display: flex; align-items: center; margin-bottom: 10px; margin-top: 10px">
<div>选择识别字幕的方式</div>
<n-select
style="margin-left: 10px; width: 200px"
:options="subtitleOptions"
v-model:value="subtitleSetting.selectModel"
placeholder="选择识别文案方式"
/>
<n-button style="margin-left: 10px" :type="urlDisabled ? 'warning' : 'info'" @click="UnBlock">{{
urlDisabled ? '解锁' : '上锁'
}}</n-button>
<n-button style="margin-left: 10px" type="info" @click="ResetSubtitleSetting"
>重置数据</n-button
>
<n-button style="margin-left: 10px" type="info" @click="SaveSubtitleSetting">保存</n-button>
</div>
<div>
<n-card title="本地OCR | 本地Whisper">
<span class="url_class" @click="OpenTeach('local_ocr')" style="margin-left: 5px"
>本地OCR安装教程</span
>
<span class="url_class" @click="OpenTeach('local_whisper')" style="margin-left: 25px"
>本地Whisper安装教程</span
>
</n-card>
<n-card title="LAI Whisper" style="margin-top: 5px">
<n-form
ref="formRef"
label-placement="left"
inline
:label-width="auto"
:model="formValue"
:rules="rules"
:size="size"
>
<n-form-item label="API URL" path="subtitleSetting.laiWhisper.url">
<n-input
:disabled="urlDisabled"
style="width: 220px"
v-model:value="subtitleSetting.laiWhisper.url"
></n-input>
</n-form-item>
<n-form-item label="API KEY" path="subtitleSetting.laiWhisper.apiKey">
<n-input
type="password"
style="width: 220px"
show-password-on="mousedown"
v-model:value="subtitleSetting.laiWhisper.apiKey"
></n-input>
</n-form-item>
<n-form-item label="prompt" path="subtitleSetting.laiWhisper.prompt">
<n-input
type="text"
style="width: 220px"
placeholder="请输入识别文案的提示"
v-model:value="subtitleSetting.laiWhisper.prompt"
></n-input>
</n-form-item>
<n-form-item path="subtitleSetting.laiWhisper.syncGPTAPIKey">
<n-button type="info" @click="SyncGptSetting">同步GPT设置</n-button>
</n-form-item>
</n-form>
</n-card>
</div>
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue'
import { useMessage } from 'naive-ui'
export default defineComponent({
components: {},
setup() {
onMounted(async () => {})
return {}
<script setup>
import { onMounted, ref, toRaw } from 'vue'
import { useMessage, useDialog, NCard, NSelect, NForm, NFormItem, NInput, NButton } from 'naive-ui'
import { GetSubtitleType } from '../../../../define/enum/waterMarkAndSubtitle'
import { SyncGptKeyType } from '../../../../define/enum/softwareEnum'
let message = useMessage()
let dialog = useDialog()
let urlDisabled = ref(true)
let subtitleSetting = ref({
selectModel: GetSubtitleType.LAI_WHISPER,
laiWhisper: {
url: 'https://api.laitool.cc/',
apiKey: '你的LAI API KEY',
syncGPTAPIKey: false
}
})
onMounted(async () => {
let res = await window.write.GetSubtitleSetting()
if (res.code == 0) {
message.error(res.message)
} else {
subtitleSetting.value = res.data
}
})
// GPTAPI KEY
async function SyncGptSetting() {
dialog.warning({
title: '同步提示',
content:
'该功能会将通用设置中的GPT Key直接复制到这边,请确定在GPT中用的是LAI API,不然后续对应的操作可能会出现报错,是否继续操作?',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
//
let res = await window.gpt.SyncGptKey(SyncGptKeyType.SUBTITLE_SETTING)
if (res.code == 0) {
message.error(res.message)
} else {
subtitleSetting.value.laiWhisper.apiKey = res.data
message.success('获取全局GPT Key成功')
}
}
})
}
//
function UnBlock() {
urlDisabled.value = !urlDisabled.value
}
//
async function ResetSubtitleSetting() {
dialog.warning({
title: '重置识别文案设置',
content: '注意,该操作不可逆,是否重置识别文案设置?',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
let res = await window.write.ResetSubtitleSetting()
if (res.code == 0) {
message.error(res.message)
} else {
subtitleSetting.value = res.data
message.success('重置字幕设置成功')
}
}
})
}
//
async function SaveSubtitleSetting() {
//
let res = await window.write.SaveSubtitleSetting(toRaw(subtitleSetting.value))
if (res.code == 0) {
message.error(res.message)
} else {
message.success('保存提取文案设置成功')
}
}
//
function OpenTeach(type) {
switch (type) {
case 'local_ocr':
window.api.OpenUrl(
'https://rvgyir5wk1c.feishu.cn/docx/RSj1dIJvpooKCGxHxhgcDhsqnSh?from=from_copylink'
)
break
case 'local_whisper':
window.api.OpenUrl(
'https://pvwu1oahp5m.feishu.cn/docx/VrBVd2KUDosmNfxat3OceWuInjd?from=from_copylink'
)
default:
break
}
}
let subtitleOptions = ref([
{ label: '本地OCR', value: GetSubtitleType.LOCAL_OCR },
{ label: '本地Whisper', value: GetSubtitleType.LOCAL_WHISPER },
{ label: 'LAI Whisper', value: GetSubtitleType.LAI_WHISPER }
])
</script>
<style>
.url_class {
color: blue;
}
.url_class:hover {
color: brown;
cursor: pointer;
}
</style>
@@ -39,8 +39,14 @@
</n-form-item>
<n-form-item label="APP ID/应用ID">
<n-input
:type="item.name == 'laitool' ? 'text' : 'password'"
:show-password-on="mousedown"
v-if="item.name == 'laitool'"
type="text"
v-model:value="item.translation_app_id"
/>
<n-input
v-else
type="password"
show-password-on="mousedown"
v-model:value="item.translation_app_id"
/>
</n-form-item>
@@ -93,6 +99,7 @@ export default defineComponent({
return
}
translateSetting.value = translateSettingRes.data
console.log(translateSetting.value)
})
function GetTranslationName(name) {
@@ -448,7 +448,7 @@ export default defineComponent({
async function SaveMask() {
debugger
//
if (canvasHistory.length <= 1) {
if (canvasHistory.length <= 0) {
message.error('请先选择去水印的区域')
return
}