LaiTool 3.1.3

This commit is contained in:
lq1405 2024-09-15 14:35:33 +08:00
parent 8500fd3446
commit 595cbe8374
15 changed files with 557 additions and 132 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "laitool",
"version": "3.1.2",
"version": "3.1.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "laitool",
"version": "3.1.2",
"version": "3.1.3",
"hasInstallScript": true,
"dependencies": {
"@alicloud/alimt20181012": "^1.2.0",

View File

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

Binary file not shown.

View File

@ -144,6 +144,7 @@ if (!app.isPackaged) {
define['remotemj_api'] = 'https://api.laitool.net/'
define['serverUrl'] = 'http://lapi.laitool.cn'
// define['serverUrl'] = 'http://localhost:1578'
define['hkServerUrl'] = 'https://laitool.net/'
define['bakServerUrl'] = 'https://laitool.net/'
define['API'] = 'f85d39ed5a40fd09966f13f12b6cf0f0'

View File

@ -125,7 +125,11 @@ export const DEFINE_STRING = {
INIT_SERVER_GPT_OPTIONS: 'INIT_SERVER_GPT_OPTIONS',
GET_AI_SETTING: 'GET_AI_SETTING',
SAVE_AI_SETTING: 'SAVE_AI_SETTING',
SYNC_GPT_KEY: "SYNC_GPT_KEY"
SYNC_GPT_KEY: "SYNC_GPT_KEY",
/**
* GPT流式返回的监听
*/
GPT_STREAM_RETURN: "GPT_STREAM_RETURN"
},
QUEUE_BATCH: {
@ -303,7 +307,7 @@ export const DEFINE_STRING = {
/**
* MJ的消息ID
*/
GET_IMAGE_URL_AND_DOWNLOAD : "GET_IMAGE_URL_AND_DOWNLOAD",
GET_IMAGE_URL_AND_DOWNLOAD: "GET_IMAGE_URL_AND_DOWNLOAD",
//#endregion

View File

@ -13,20 +13,166 @@ import {
GetKimiErrorResponse,
GetOpenAISuccessResponse,
GetRixApiErrorResponse
} from '../../define/response/openAIResponse.ts'
} from '../../define/response/openAIResponse'
import axios from 'axios'
import { ValidateJson } from '../../define/Tools/validate.ts'
import { ValidateJson } from '../../define/Tools/validate'
import { RetryWithBackoff } from '../../define/Tools/common'
const { v4: uuidv4 } = require('uuid') // 引入UUID库来生成唯一标识符
let tools = new Tools()
export class Writing extends ServiceBase {
pm: PublicMethod
constructor(global) {
super()
this.global = global
this.pm = new PublicMethod(global)
axios.defaults.baseURL = define.serverUrl
}
/**
* AI
* @param {*} setting
* @param {*} aiData
* @param {*} word
* @returns
*/
async AIRequest(setting, aiData, word): Promise<string> {
// 开始请求AI
let axiosRes = await axios.post('/api/Forward/ForwardWord', {
promptTypeId: setting.gptType,
promptId: setting.gptData,
gptUrl: aiData.gpt_url + '/v1/chat/completions',
model: aiData.model,
machineId: global.machineId,
apiKey: aiData.api_key,
word: word
})
// 判断返回的状态,如果是失败的话直接返回错误信息
if (axiosRes.status != 200) {
throw new Error('请求失败')
}
let dataRes = axiosRes.data
if (dataRes.code == 1) {
// 获取成功
// 解析返回的数据
return GetOpenAISuccessResponse(dataRes.data);
} else {
// 系统报错
if (dataRes.code == 5000) {
throw new Error('系统错误,错误信息如下:' + dataRes.message)
} else {
// 处理不同类型的错误消息
if (setting.gptAI == 'laiapi') {
throw new Error(GetRixApiErrorResponse(dataRes.data))
} else if (setting.gptAI == 'kimi') {
throw new Error(GetKimiErrorResponse(dataRes.data))
} else if (setting.gptAI == 'doubao') {
throw new Error(GetDoubaoErrorResponse(dataRes.data))
} else {
throw new Error(dataRes.data)
}
}
}
}
/**
*
* @param setting
* @param aiData
* @param word
*/
async AIRequestStream(setting, aiData, word, oldData: string) {
let body = {
promptTypeId: setting.gptType,
promptId: setting.gptData,
gptUrl: aiData.gpt_url,
model: aiData.model,
machineId: global.machineId,
apiKey: aiData.api_key,
word: word
}
var myHeaders = new Headers();
myHeaders.append("User-Agent", "Apifox/1.0.0 (https://apifox.com)");
myHeaders.append("Content-Type", "application/json");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: JSON.stringify(body),
};
let resData = oldData;
return new Promise((resolve, reject) => {
fetch(define.serverUrl + "/api/Forward/ForwardWordStream", requestOptions)
.then(response => {
if (!response.body) {
throw new Error('ReadableStream not yet supported in this browser.');
}
const reader = response.body.getReader();
return new ReadableStream({
start(controller) {
function push() {
reader.read().then(({
done,
value
}) => {
if (done) {
controller.close();
resolve(resData)
return;
}
// 假设服务器发送的是文本数据
const text = new TextDecoder().decode(value);
resData += text
// 将数据返回前端
global.newWindow[0].win.webContents.send(DEFINE_STRING.GPT.GPT_STREAM_RETURN, resData)
controller.enqueue(value); // 可选:将数据块放入流中
push();
}).catch(err => {
controller.error(err);
reject(err)
});
}
push();
}
});
})
.catch(error => {
reject(error)
});
})
}
async SplitWord(word: string, wordCount: number) {
let word_list = word.split('\n')
let new_word = []
let tmp_str = ''
let result = []
for (let i = 0; i < word_list.length; i++) {
const element = word_list[i];
if (tmp_str.length + element.length > wordCount) {
result.push({
index: i,
word: new_word.join('\n')
})
new_word = []
tmp_str = ""
new_word.push(element);
} else {
tmp_str += ',' + element
new_word.push(element);
}
}
result.push({
index: word_list.length,
word: new_word.join('\n')
})
return result
}
/**
* GPT进行推理
* @param {*} setting
@ -67,48 +213,38 @@ export class Writing extends ServiceBase {
if (isEmpty(word)) {
throw new Error('请先设置文案')
}
// 开始请求AI
let axiosRes = await axios.post('/api/Forward/ForwardWord', {
promptTypeId: setting.gptType,
promptId: setting.gptData,
gptUrl: aiData.gpt_url,
model: aiData.model,
machineId: this.global.machineId,
apiKey: aiData.api_key,
word: word
})
// 判断返回的状态,如果是失败的话直接返回错误信息
if (axiosRes.status != 200) {
throw new Error('请求失败')
}
let dataRes = axiosRes.data
if (dataRes.code == 1) {
// 获取成功
// 解析返回的数据
return successMessage(
GetOpenAISuccessResponse(dataRes.data),
'请求成功',
'Writing_ActionStart'
)
} else {
// 系统报错
if (dataRes.code == 5000) {
throw new Error('系统错误,错误信息如下:' + dataRes.message)
} else {
// 处理不同类型的错误消息
if (setting.gptAI == 'laiapi') {
throw new Error(GetRixApiErrorResponse(dataRes.data))
} else if (setting.gptAI == 'kimi') {
throw new Error(GetKimiErrorResponse(dataRes.data))
} else if (setting.gptAI == 'doubao') {
throw new Error(GetDoubaoErrorResponse(dataRes.data))
let result = ''
if (setting.isSplit) {
// 这边拆分文案
let spiltWord = await this.SplitWord(word, setting.splitNumber)
console.log(spiltWord)
for (let i = 0; i < spiltWord.length; i++) {
const element = spiltWord[i];
if (setting.isStream) {
result += await RetryWithBackoff(async () => {
return await this.AIRequestStream(setting, aiData, element.word, result)
}, 3, 1000) + '\n'
} else {
throw new Error(dataRes.data)
result = await RetryWithBackoff(async () => {
return await this.AIRequest(setting, aiData, word)
}, 3, 1000)
}
}
} else {
if (setting.isStream) {
result += await RetryWithBackoff(async () => {
return await this.AIRequestStream(setting, aiData, word, '')
}, 3, 1000) + '\r\n\n'
} else {
result = await RetryWithBackoff(async () => {
return await this.AIRequest(setting, aiData, word)
}, 3, 1000)
}
}
// let tasks =
// ExecuteConcurrently
return successMessage(result, "执行文案相关任务成功", 'Writing_ActionStart');
} catch (error) {
return errorMessage(
'执行文案相关任务失败,失败信息如下:' + error.toString(),
@ -307,13 +443,12 @@ export class Writing extends ServiceBase {
let text_count = 0
let tmp_str = ''
for (let i = 0; i < data.length; ) {
for (let i = 0; i < data.length;) {
iii = i
sss = data[i].after_gpt
let srt_value = data[i].text
current_text = `字幕: “${srt_value}” 和文案第${text_count + 1} 行数据 “${
textData[text_count].after_gpt
} `
current_text = `字幕: “${srt_value}” 和文案第${text_count + 1} 行数据 “${textData[text_count].after_gpt
} `
let start_time = data[i].start
let end_time = data[i].end
let obj = {
@ -403,7 +538,7 @@ export class Writing extends ServiceBase {
textData.push(obj)
}
}
this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
code: 0,
message: current_text
})

View File

@ -102,6 +102,9 @@
>
设置
</n-button>
<div style="margin-left: 10px">
<MonitorStatus />
</div>
</div>
<div class="right-button">
@ -134,6 +137,7 @@ import { TranslateType } from '../../../../../define/enum/translate'
import { ContainsChineseOrPunctuation } from '../../../../../define/Tools/common'
import ImportWordAndSrt from '../../Original/Components/ImportWordAndSrt.vue'
import GetWaterMaskRectangle from '../../Watermark/GetWaterMaskRectangle.vue'
import MonitorStatus from './MonitorStatus.vue'
export default defineComponent({
components: {
@ -141,7 +145,8 @@ export default defineComponent({
NCheckbox,
NDropdown,
NDivider,
GetWaterMaskRectangle
GetWaterMaskRectangle,
MonitorStatus
},
setup() {

View File

@ -0,0 +1,195 @@
<template>
<div style="display: flex; align-items: center; font-size: 12px; font-weight: bold">
<div style="border: 1px dashed #ccc; padding: 5px">
<div style="display: flex; align-items: center">
<div style="width: 75px">提示词</div>
<n-progress
type="line"
style="width: 100px; cursor: pointer"
status="info"
:percentage="gptPromptPercentage"
@click="ErrorPosition('gptPrompt')"
rail-color="#bbb"
indicator-placement="inside"
/>
</div>
<div
style="display: flex; align-items: center"
v-if="
reverseManageStore.selectBook.type == 'mj_reverse' ||
reverseManageStore.selectBook.type == 'sd_reverse'
"
>
<div style="width: 75px">反推提示词</div>
<n-progress
type="line"
:class="test"
style="width: 100px; cursor: pointer"
status="info"
:percentage="reversePromptPercentage"
@click="ErrorPosition('reverseGptPrompt')"
rail-color="#bbb"
indicator-placement="inside"
/>
</div>
</div>
<div style="border: 1px dashed #ccc; padding: 5px; margin-left: 5px">
<div style="display: flex; align-items: center">
<div>提示词命令</div>
<n-progress
type="line"
style="width: 100px; cursor: pointer"
status="info"
:percentage="promptPercentage"
rail-color="#bbb"
@click="ErrorPosition('prompt')"
indicator-placement="inside"
/>
</div>
</div>
<div style="border: 1px dashed #ccc; padding: 5px; margin-left: 5px">
<div style="display: flex; align-items: center">
<div>出图</div>
<n-progress
type="line"
style="width: 100px; cursor: pointer"
status="info"
:percentage="imagePercentage"
@click="ErrorPosition('image')"
rail-color="#bbb"
indicator-placement="inside"
/>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { NProgress, useMessage } from 'naive-ui'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { useSoftwareStore } from '../../../../../stores/software'
import { isEmpty } from 'lodash'
let gptPromptPercentage = ref(0)
let promptPercentage = ref(0)
let imagePercentage = ref(0)
let reversePromptPercentage = ref(0)
let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore()
let message = useMessage()
let test = ref('error-class')
//
function ComputePercentage() {
debugger
if (
reverseManageStore &&
reverseManageStore.selectBookTaskDetail &&
reverseManageStore.selectBookTaskDetail.length > 0
) {
let total = reverseManageStore.selectBookTaskDetail.length
let gptPromptCount = 0
let promptCount = 0
let imageCount = 0
let reversePromptCount = 0
reverseManageStore.selectBookTaskDetail.forEach((item) => {
if (!isEmpty(item.gptPrompt)) {
gptPromptCount++
}
if (!isEmpty(item.prompt)) {
promptCount++
}
//
if (item.outImagePath) {
imageCount++
}
if (item.reversePrompt && item.reversePrompt.length > 0) {
reversePromptCount++
}
})
//
gptPromptPercentage.value = Math.floor((gptPromptCount / total) * 100)
//
promptPercentage.value = Math.floor((promptCount / total) * 100)
imagePercentage.value = Math.floor((imageCount / total) * 100)
reversePromptPercentage.value = Math.floor((reversePromptCount / total) * 100)
}
}
onMounted(() => {
//
ComputePercentage()
//
setInterval(() => {
ComputePercentage()
}, 5000)
})
function ErrorPosition(type) {
let index = -1
softwareStore.skipRowIndex = 0
if (type == 'gptPrompt') {
//
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
if (isEmpty(reverseManageStore.selectBookTaskDetail[i].gptPrompt)) {
index = i
break
}
}
} else if (type == 'reverseGptPrompt') {
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
let element = reverseManageStore.selectBookTaskDetail[i]
if (!element.reversePrompt || element.reversePrompt.length <= 0) {
index = i
break
}
}
} else if (type == 'prompt') {
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
if (isEmpty(reverseManageStore.selectBookTaskDetail[i].prompt)) {
index = i
break
}
}
} else if (type == 'image') {
for (let i = 0; i < reverseManageStore.selectBookTaskDetail.length; i++) {
if (isEmpty(reverseManageStore.selectBookTaskDetail[i].outImagePath)) {
index = i
break
}
}
} else {
message.error('未知的操作类型')
return
}
if (index == -1) {
message.success('全部已完成,不必跳转')
return
}
softwareStore.skip = {
skipRowIndex: index + 1,
clickCount: softwareStore.skip.clickCount++
}
}
</script>
<style>
.error-class {
color: red;
cursor: pointer;
}
</style>

View File

@ -1,6 +1,7 @@
<template>
<div>
<n-data-table
ref="datatable"
:columns="columns"
:data="reverseManageStore.selectBookTaskDetail"
:max-height="maxHeight"
@ -10,8 +11,8 @@
</template>
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, h } from 'vue'
import { useMessage, NDataTable, NImage, NInput } from 'naive-ui'
import { ref, onMounted, defineComponent, watch, h } from 'vue'
import { useMessage, NDataTable, NImage } from 'naive-ui'
import { useSoftwareStore } from '../../../../../stores/software'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import DataTableShowGenerateImage from '../../Original/Components/DataTableShowGenerateImage.vue'
@ -33,6 +34,17 @@ export default defineComponent({
let reverseManageStore = useReverseManageStore()
let message = useMessage()
let maxHeight = ref(0)
let datatable = ref(null)
watch(
() => softwareStore.skip,
(newValue) => {
let doc = document.querySelectorAll('.n-data-table-tr')
let sk = doc[newValue.skipRowIndex]
datatable.value.scrollTo({ el: sk })
},
{ deep: true }
)
const createColumns = () => [
{
@ -152,7 +164,8 @@ export default defineComponent({
softwareStore,
reverseManageStore,
maxHeight,
columns: createColumns()
columns: createColumns(),
datatable
}
}
})

View File

@ -1,62 +1,67 @@
<template>
<div style="display: flex">
<n-button strong secondary @click="ReturnMain" size="small">返回</n-button>
<n-divider vertical style="height: 30px" />
<!-- <n-button strong secondary @click="ReturnMain" size="small">一键全自动</n-button>
<div style="display: flex; align-items: center">
<div style="display: flex">
<n-button strong secondary @click="ReturnMain" size="small">返回</n-button>
<n-divider vertical style="height: 30px" />
<!-- <n-button strong secondary @click="ReturnMain" size="small">一键全自动</n-button>
<n-divider vertical style="height: 30px" /> -->
<n-button :color="softwareStore.SoftColor.ORANGE" @click="ImportWord" size="small"
>导入字幕/SRT</n-button
>
<n-button
:color="softwareStore.SoftColor.ORANGE"
style="margin-left: 10px"
@click="CharacterLibrary"
size="small"
>角色分析标签集</n-button
>
<n-button
:color="softwareStore.SoftColor.ORANGE"
style="margin-left: 10px"
@click="ImportPrompt"
size="small"
>导入提示词</n-button
>
<n-dropdown trigger="hover" :options="GptButtonOptions" @select="ButtonSelect">
<n-button :color="softwareStore.SoftColor.ORANGE" @click="ImportWord" size="small"
>导入字幕/SRT</n-button
>
<n-button
:color="softwareStore.SoftColor.ORANGE"
style="margin-left: 10px"
@click="GetPromptAll"
@click="CharacterLibrary"
size="small"
>一键推理提示词</n-button
>角色分析标签集</n-button
>
</n-dropdown>
<n-dropdown trigger="hover" :options="GenerateImageOptions" @select="ButtonSelect">
<n-button
:color="softwareStore.SoftColor.ORANGE"
style="margin-left: 10px"
@click="GenerateImageAll(true)"
@click="ImportPrompt"
size="small"
>生成所有的图片</n-button
>导入提示词</n-button
>
</n-dropdown>
<n-dropdown trigger="hover" :options="GptButtonOptions" @select="ButtonSelect">
<n-button
:color="softwareStore.SoftColor.ORANGE"
style="margin-left: 10px"
@click="GetPromptAll"
size="small"
>一键推理提示词</n-button
>
</n-dropdown>
<n-dropdown trigger="hover" :options="GenerateImageOptions" @select="ButtonSelect">
<n-button
:color="softwareStore.SoftColor.ORANGE"
style="margin-left: 10px"
@click="GenerateImageAll(true)"
size="small"
>生成所有的图片</n-button
>
</n-dropdown>
<n-dropdown trigger="hover" :options="ResetDataOptions" @select="ButtonSelect">
<n-button
:color="softwareStore.SoftColor.ORANGE"
style="margin-left: 10px"
@click="resetALLData"
size="small"
>重置数据</n-button
>
</n-dropdown>
<n-dropdown trigger="hover" :options="ResetDataOptions" @select="ButtonSelect">
<n-button
:color="softwareStore.SoftColor.ORANGE"
style="margin-left: 10px"
@click="resetALLData"
@click="OpenPromptSetting"
size="small"
>重置数据</n-button
>设置</n-button
>
</n-dropdown>
<n-button
:color="softwareStore.SoftColor.ORANGE"
style="margin-left: 10px"
@click="OpenPromptSetting"
size="small"
>设置</n-button
>
</div>
<div style="margin-left: 10px">
<MonitorStatus />
</div>
</div>
</template>
@ -68,6 +73,7 @@ import { useReverseManageStore } from '../../../../../stores/reverseManage'
import ImportWordAndSrt from '../Components/ImportWord/ImportWordAndSrt.vue'
import CharacterAnalyze from '../Components/PresetLibrary/CharacterAnalyze.vue'
import PromptSetting from '../../Original/Components/PromptSetting.vue'
import MonitorStatus from '../Components/MonitorStatus.vue'
import {
BookBackTaskType,
BookImageCategory,

View File

@ -1,7 +1,9 @@
<template>
<div>
<n-data-table
ref="datatable"
id="1111"
classMame="cd-22223"
:max-height="maxHeight"
:loading="softwareStore.loading.originDatatableDataLoading"
:row-key="rowKey"
@ -16,31 +18,8 @@
</template>
<script setup>
import {
ref,
h,
onMounted,
defineComponent,
onUnmounted,
watch,
toRaw,
render,
onBeforeUnmount,
provide,
nextTick
} from 'vue'
import {
NDataTable,
NImage,
useMessage,
NInput,
NButton,
NSwitch,
NPopover,
useDialog,
NCheckbox,
NIcon
} from 'naive-ui'
import { ref, h, onMounted, watch } from 'vue'
import { NDataTable, useMessage } from 'naive-ui'
import DatatableHeaderAfterGpt from '../Components/DatatableHeaderAfterGpt.vue'
import DatatableAfterGpt from '../Components/DatatableAfterGpt.vue'
import ODatatableHeaderCharacterAndScene from './ODataTableHeaderCharacterAndScene.vue'
@ -54,11 +33,21 @@ import DatatableHeaderGenerateImage from '../Components/DatatableHeaderGenerateI
import DatatableGenerateImage from '../Components/DatatableGenerateImage.vue'
import { useReverseManageStore } from '../../../../../stores/reverseManage'
import { useSoftwareStore } from '../../../../../stores/software'
import { set } from 'lodash'
let reverseManageStore = useReverseManageStore()
let softwareStore = useSoftwareStore()
let maxHeight = ref(0)
let message = useMessage()
let datatable = ref(null)
watch(
() => softwareStore.skip,
(newValue) => {
let doc = document.querySelectorAll('.n-data-table-tr')
let sk = doc[newValue.skipRowIndex]
datatable.value.scrollTo({ el: sk })
},
{ deep: true }
)
onMounted(async () => {
setTimeout(() => {

View File

@ -14,7 +14,7 @@
</n-form-item>
<n-form-item label="选择预设" path="gptData">
<n-select
style="width: 160px"
style="width: 200px"
v-model:value="formValue.gptData"
:options="gptDataOptions"
placeholder="请选择提示词数据"
@ -37,6 +37,25 @@
<n-button type="primary" @click="ActionStart">开始生成</n-button>
</n-form-item>
</n-form>
<n-form :model="formValue" inline label-placement="left">
<n-form-item path="isStream">
<n-checkbox label="是否流式发送" v-model:checked="formValue.isStream" />
</n-form-item>
<n-form-item path="isSplit">
<n-checkbox label="是否拆分发送" v-model:checked="formValue.isSplit" />
</n-form-item>
<n-form-item label="每次发送字符" path="splitNumber">
<n-input-number
v-model:value="formValue.splitNumber"
:min="1"
:show-button="false"
:max="99999"
></n-input-number>
</n-form-item>
<n-form-item path="splitNumber">
<div style="color: red">注意爆款开头不要分段发送</div>
</n-form-item>
</n-form>
</div>
<div style="display: flex; width: 100%">
<div style="flex: 1; margin-right: 10px">
@ -61,21 +80,46 @@
<script>
import { ref, onMounted, defineComponent, onUnmounted, toRaw, watch, h } from 'vue'
import { useMessage, useDialog, NForm, NFormItem, NInput, NSelect, NButton, NIcon } from 'naive-ui'
import {
useMessage,
useDialog,
NForm,
NFormItem,
NInput,
NSelect,
NButton,
NIcon,
NCheckbox,
NInputNumber
} from 'naive-ui'
import { SettingsOutline } from '@vicons/ionicons5'
import ManageAISetting from './ManageAISetting.vue'
import { useSoftwareStore } from '../../../../stores/software'
import { isEmpty } from 'lodash'
import { DEFINE_STRING } from '../../../../define/define_string'
export default defineComponent({
components: { NForm, NFormItem, NInput, NSelect, NButton, NIcon, SettingsOutline },
components: {
NForm,
NFormItem,
NInput,
NSelect,
NButton,
NIcon,
SettingsOutline,
NCheckbox,
NInputNumber
},
setup() {
let message = useMessage()
let dialog = useDialog()
let formValue = ref({
gptType: undefined,
gptData: undefined,
gptAI: undefined
gptAI: undefined,
isStream: true,
isSplit: false,
splitNumber: 1000
})
let oldWord = ref(undefined)
let newWord = ref(undefined)
@ -110,8 +154,41 @@ export default defineComponent({
allPromptDataOptions.value = gptRes.data.promptData
}
function debounce(func, wait) {
let timeoutId
let shouldExecute = true
return function (...args) {
const context = this
if (shouldExecute) {
func.apply(context, args)
shouldExecute = false
timeoutId = setTimeout(() => {
shouldExecute = true
}, wait)
} else {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
shouldExecute = true
}, wait)
}
}
}
let UpdateWord = debounce((value) => {
newWord.value = value
}, 500)
onMounted(async () => {
await InitServerGptOptions()
//
window.api.setEventListen([DEFINE_STRING.GPT.GPT_STREAM_RETURN], (value) => {
UpdateWord(value)
})
})
onUnmounted(() => {
window.api.removeEventListen(DEFINE_STRING.GPT.GPT_STREAM_RETURN)
})
let ruleObj = (errorMessage) => {

View File

@ -1,7 +1,7 @@
<template>
<div>
<div id="video-canvas">
<video ref="videoRef" muted :src="videoSrc" id="video" autoplay></video>
<video style="width: 800px" ref="videoRef" muted :src="videoSrc" id="video" autoplay></video>
<canvas
ref="canvasRef"
@mousemove="handleMouseMove"
@ -91,10 +91,7 @@ export default defineComponent({
let reverseManageStore = useReverseManageStore()
let videoRef = ref(null)
let canvasRef = ref(null)
let videoSrc = ref(
props.videoSrc ||
'D:\\文\\物价暴跌百万倍,我成了神豪-七猫\\1\\价暴跌百万倍,我成了神豪1_output_crop_00001.mp4'
)
let videoSrc = ref(props.videoSrc)
let type = ref(props.type ? props.type : SubtitleSavePositionType.MAIN_VIDEO)
let mark = ref(props.mark)
let videoWidth = ref(props.videoWidth == null ? 800 : props.videoWidth)
@ -120,7 +117,6 @@ export default defineComponent({
setTimeout(() => {
video.play()
isPlaying.value = true
debugger
let { width, height } = video.getBoundingClientRect()
canvasRef.value.width = width
canvasRef.value.height = height

View File

@ -26,6 +26,10 @@ export const useSoftwareStore = defineStore('software', {
},
globalSetting: {} as SoftwareSettingModel.GlobalSetting,
show_logger: false, // 是否显示日志
skip: {
skipRowIndex: 0, // 表格跳转的行数
clickCount: 0
},
componentSize: [], // 组件尺寸(通用的选项)
SoftColor: null, // 按钮颜色
loading: {