You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

481 lines
12 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<script setup lang="ts">
import { ref, onMounted, onUnmounted, watchEffect } from "vue";
import { InfoFilled } from "@element-plus/icons-vue";
import { message } from "@/utils/message";
import { interruptTalk } from "@/api/chat";
const liveList = ref([
{
name: "livetalking",
status: "1"
},
{
name: "gptsovits",
status: "1"
},
{
name: "chat",
status: "0"
}
]);
const livetlking_enable_status = ref<any>("0");
const gptsovits_enable_status = ref<any>("0");
const chat_enable_status = ref<any>("0");
const statusMap = [
{ key: "livetalking", statusRef: livetlking_enable_status },
{ key: "gptsovits", statusRef: gptsovits_enable_status },
{ key: "chat", statusRef: chat_enable_status }
];
// 监听所有状态变化同步到liveList
watchEffect(() => {
// 遍历映射关系,逐个同步
statusMap.forEach(({ key, statusRef }) => {
// 找到liveList中name匹配的项
const targetItem = liveList.value.find(item => item.name === key);
if (targetItem) {
// 同步status值如果需要转换状态格式可在此处处理
targetItem.status = statusRef.value;
}
});
});
const bulletSetList = ref([
{
title: "进入直播间",
key: "reply_prob_enter_live_room",
value: 100
},
{
title: "关注",
key: "reply_prob_follow",
value: 100
},
{
title: "送礼物",
key: "reply_prob_gift",
value: 100
},
{
title: "点赞",
key: "reply_prob_like",
value: 100
},
{
title: "弹幕回复",
key: "reply_prob_chat",
value: 100
}
]);
const interactiveNode = ref<any>("1");
//是否显示弹幕
const isShowBullet = ref(false);
// 是否启动ai互动
const isAIInteractionEnabled = ref(false);
//启用人工接管
const isManualTakeoverEnabled = ref(false);
const getStatusText = val => {
switch (val) {
case "2":
return "启动成功";
case "1":
return "启动中";
case "3":
return "启动失败";
case "0":
return "未启动";
}
};
const start = async item => {
if (item.name === "livetalking") {
window.electronAPI.startProcess("LiveTalking", "LiveTalking.exe");
} else if (item.name === "gptsovits") {
window.electronAPI.startProcess("gptsovits", "go-gptsovits.bat");
} else if (item.name === "chat") {
const liveRoom = await window.electronAPI.getConfig(
"live_config",
"live_id"
);
if (liveRoom) {
window.electronAPI.startProcess("chat", "chat.exe");
} else {
message("请填写房间号", { type: "error" });
}
}
};
const getLiveTalkingResult = async () => {
livetlking_enable_status.value = await window.electronAPI.getConfig(
"live_config",
"livetlking_enable_status"
);
gptsovits_enable_status.value = await window.electronAPI.getConfig(
"live_config",
"gptsovits_enable_status"
);
chat_enable_status.value = await window.electronAPI.getConfig(
"live_config",
"chat_enable_status"
);
};
const resetStart = async item => {
if (item.name === "chat") {
window.electronAPI.stopChatProcesses();
setTimeout(() => {
start(item);
}, 500);
} else {
window.electronAPI.updateConfig(
"live_config",
"livetlking_enable_status",
"0"
);
window.electronAPI.updateConfig(
"live_config",
"gptsovits_enable_status",
"0"
);
window.electronAPI.updateConfig("live_config", "chat_enable_status", "0");
window.electronAPI.stopAllProcesses();
setTimeout(async () => {
init();
}, 2000);
}
};
const changeNumber = (e, item) => {
window.electronAPI.updateConfig("config", item.key, e);
};
const changeType = async e => {
const livetalking_sessionid = await window.electronAPI.getConfig(
"live_config",
"livetalking_sessionid"
);
const res = await interruptTalk({
current_control_mode: e ? 0 : 1,
sessionid: Number(livetalking_sessionid)
});
if (res.code === 200) {
message("设置成功", { type: "success" });
} else {
message(res.message || "设置失败", { type: "error" });
}
};
const init = () => {
window.electronAPI.startProcess("LiveTalking", "LiveTalking.exe");
window.electronAPI.startProcess("gptsovits", "go-gptsovits.bat");
// 启动定时器每3秒执行一次
const checkInterval = setInterval(() => {
getLiveTalkingResult();
if (
livetlking_enable_status.value === "2" &&
gptsovits_enable_status.value === "2" &&
chat_enable_status.value === "2"
) {
clearInterval(checkInterval); // 清除定时器,停止检查
}
}, 500);
};
onMounted(() => {
init();
bulletSetList.value.forEach(async item => {
item.value = Number(await window.electronAPI.getConfig("config", item.key));
});
});
</script>
<template>
<div class="live-monitor">
<div class="monitor-top">
<div class="card-title">
<span>直播服务监测</span>
</div>
<div class="live-list">
<div class="live-item" v-for="(item, index) in liveList" :key="index">
<div
class="live-item-left"
:class="{
'status-success': item.status === '2',
'status-pending': item.status === '0',
'status-loading': item.status === '1',
'status-error': item.status === '3'
}"
>
<span>{{ item.name }}</span>
<span class="point" />
<span class="status">{{ getStatusText(item.status) }}</span>
<span />
</div>
<!-- 根据不同状态显示不同按钮文本 -->
<div class="btn" @click="start(item)" v-if="item.status === '0'">
启动
</div>
<div class="loading btn" v-else-if="item.status === '1'">启动中</div>
<div
class="btn"
@click="resetStart(item)"
v-else-if="item.status === '3' || item.status === '2'"
>
重启
</div>
</div>
</div>
</div>
<div class="monitor-mid">
<div class="card-title">
<div class="title">弹幕与互动</div>
<div class="card-title-right">
<span>显示弹幕</span>
<el-switch v-model="isShowBullet" />
</div>
</div>
<div class="monitor-mid-content">
<div class="bullet-content">
<span>启动后弹幕会打印在屏幕上 ,未启用默认为空</span>
</div>
<div class="interaction-item">
<div class="set-title">互动设置</div>
<div class="set-content">
<el-icon><InfoFilled /></el-icon>
<span>启动AI互动</span>
<el-switch v-model="isAIInteractionEnabled" />
</div>
</div>
<div class="mid-content-title">回复方式</div>
<el-radio-group v-model="interactiveNode">
<el-radio label="1" size="large">话术类型</el-radio>
<el-radio label="2" size="large">话术段落</el-radio>
</el-radio-group>
<div class="bullet-set">
<div
class="bullet-set-item"
v-for="(item, index) in bulletSetList"
:key="index"
>
<span>{{ item.title }}</span>
<el-input-number
@change="e => changeNumber(e, item)"
v-model="item.value"
:min="0"
:max="100"
/>
</div>
</div>
</div>
</div>
<div class="monitor-bottom">
<div class="card-title">
<div class="title">人工接管</div>
</div>
<div class="monitor-bottom-main">
<span>启用人工接管</span>
<el-switch @change="changeType" v-model="isManualTakeoverEnabled" />
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.live-monitor {
width: 528px;
margin-left: 16px;
.monitor-top {
background: #ffffff;
height: 236px;
box-shadow: 0px 4px 8px 0px rgba(46, 128, 250, 0.1);
border-radius: 8px 8px 8px 8px;
.card-title {
border-bottom: 1px solid rgba(46, 128, 250, 0.1);
line-height: 54px;
height: 54px;
padding-left: 16px;
font-weight: bold;
font-size: 16px;
color: #1d2129;
}
.live-list {
display: flex;
flex-direction: column;
padding: 16px 16px 0 16px;
.live-item {
height: 40px;
background: rgba(46, 128, 250, 0.1);
border-radius: 2px 2px 2px 2px;
display: flex;
align-items: center;
padding: 0 16px;
justify-content: space-between;
margin-bottom: 16px;
.live-item-left {
font-weight: 500;
font-size: 14px;
color: #1d2129;
display: flex;
align-items: center;
.point {
width: 6px;
height: 6px;
// background: #c9cdd4;
margin-left: 12px;
margin-right: 4px;
border-radius: 50%;
display: block;
}
}
.btn {
width: 50px;
height: 28px;
background: #ffffff;
border-radius: 4px 4px 4px 4px;
border: 1px solid #2e80fa;
font-weight: 500;
font-size: 14px;
color: #2e80fa;
text-align: center;
line-height: 28px;
cursor: pointer;
}
.loading {
opacity: 0.6;
}
.status-success {
.point {
background: rgba(0, 180, 42, 1);
}
.status {
color: rgba(0, 180, 42, 1);
}
}
.status-pending {
.point {
background: #c9cdd4;
}
.status {
color: #c9cdd4;
}
}
.status-loading {
.point {
background: #2e80fa;
}
.status {
color: #2e80fa;
}
}
.status-error {
.point {
background: rgba(234, 42, 42, 1);
}
.status {
color: rgba(234, 42, 42, 1);
}
}
}
}
}
.monitor-mid {
margin-top: 16px;
background: #ffffff;
box-shadow: 0px 4px 8px 0px rgba(46, 128, 250, 0.1);
border-radius: 8px 8px 8px 8px;
.card-title {
border-bottom: 1px solid rgba(46, 128, 250, 0.1);
display: flex;
align-items: center;
justify-content: space-between;
height: 54px;
padding: 0 16px;
font-weight: bold;
font-size: 16px;
color: #1d2129;
.card-title-right {
font-weight: 500;
font-size: 14px;
color: #1d2129;
span {
margin-right: 12px;
}
}
}
.monitor-mid-content {
padding: 16px;
.bullet-content {
width: 496px;
height: 200px;
background: #000000;
border-radius: 4px 4px 4px 4px;
padding: 12px;
span {
font-family: Alibaba PuHuiTi 2, Alibaba PuHuiTi 20;
font-weight: normal;
font-size: 14px;
color: #ffffff;
}
}
.interaction-item {
display: flex;
margin-top: 16px;
justify-content: space-between;
align-items: center;
.set-title {
font-weight: bold;
font-size: 14px;
color: #1d2129;
}
.set-content {
display: flex;
align-items: center;
font-weight: 500;
font-size: 14px;
color: #1d2129;
span {
margin: 0 4px;
}
}
}
.mid-content-title {
margin-top: 12px;
font-weight: 500;
font-size: 14px;
color: #1d2129;
}
.bullet-set {
display: flex;
flex-wrap: wrap;
.bullet-set-item {
display: flex;
flex-direction: column;
width: 150px;
font-weight: 500;
font-size: 14px;
color: #1e1e1e;
margin: 0 12px 12px 0;
span {
margin-bottom: 6px;
}
}
}
}
}
.monitor-bottom {
margin-top: 16px;
background: #ffffff;
box-shadow: 0px 4px 8px 0px rgba(46, 128, 250, 0.1);
border-radius: 8px 8px 8px 8px;
.card-title {
border-bottom: 1px solid rgba(46, 128, 250, 0.1);
display: flex;
align-items: center;
justify-content: space-between;
height: 54px;
padding: 0 16px;
font-weight: bold;
font-size: 16px;
color: #1d2129;
}
.monitor-bottom-main {
padding: 16px;
span {
margin-right: 10px;
}
}
}
}
</style>