Commit b3fc196c authored by xuchaozou's avatar xuchaozou

pref: 优化指令集结构

parent 079e26d1
Pipeline #86483 waiting for manual action with stages
......@@ -2,14 +2,16 @@ import { request, event } from '@wisdom-utils/utils';
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
import { message } from 'antd';
import { init, cut, extract, ready } from '@congcongcai/jieba.js';
import { PandaRecordWebSocket } from './core';
import { PandaRecordWebSocket, Utils } from './core';
import PandaTip from './Ui/PandaTip';
import context from './config'
import testCommand from './testCommand';
const PandaUi = props => {
const pandaRecordWebSocketRef = useRef(null);
const [isStartRecorder, setIsStartRecorder] = useState(false);
const {globalConfig , setGlobalConfig} = useContext(context)
const { globalConfig, setGlobalConfig } = useContext(context)
const isDebug = globalConfig.get('isDebug')
useEffect(async () => {
try {
......@@ -29,26 +31,32 @@ const PandaUi = props => {
const changeSwitch = useCallback(
async ({ recordData, e: checked }) => {
if (checked) {
emitSwitch({
loading: true,
});
createPandaRecordWebSocket();
const data = await pandaRecordWebSocketRef.current.start();
emitSwitch({
loading: false,
});
if (!data.isSuccess) {
return message.info(data.msg);
if (!isDebug) {
emitSwitch({
loading: true,
});
createPandaRecordWebSocket();
const data = await pandaRecordWebSocketRef.current.start();
emitSwitch({
loading: false,
});
if (!data.isSuccess) {
return message.info(data.msg);
}
} else {
testCommand()
}
emitSwitch({
checked: true,
});
setIsStartRecorder(true);
} else {
emitSwitch({
loading: true,
});
await destroyPandaRecorderWebSocket();
if (!isDebug) {
emitSwitch({
loading: true,
});
await destroyPandaRecorderWebSocket();
}
emitSwitch({
loading: false,
checked: false,
......@@ -56,13 +64,13 @@ const PandaUi = props => {
setIsStartRecorder(false);
}
},
[createPandaRecordWebSocket],
[]
);
const createPandaRecordWebSocket = async () => {
destroyPandaRecorderWebSocket();
pandaRecordWebSocketRef.current = new PandaRecordWebSocket({
config : globalConfig.get('key').shortSound,
config: globalConfig.get('key').shortSound,
events: {
frame(data) {
event.emit('aiSound:frame', data);
......@@ -81,44 +89,8 @@ const PandaUi = props => {
},
},
});
// await testText("请打开海港泵站。")
// await testText("打开第1个");
// await testText("打开熊猫孪生水厂。");
// await testText("关闭当前菜单")
// await testText("关闭所有菜单。");
// await testText("请打开泵站。")
// await testText("第2个")
// await testText("请打开泵站。")
// await testText("第3个")
// await testText("关闭泵站。");
// await testText("第二个");
// await testText("我需要打开浩源孪生平台菜单")
// await testText("我需要返回首页")
// await testText("我需要打开礼泉孪生平台菜单")
// await testText("我需要打开浩源孪生平台菜单")
// await testText("我需要关闭平台菜单")
// await testText("我需要打开孪生平台菜单")
// await testText("我需要打开第二个菜单")
// await testText("我需要打开浩源孪生平台菜单")
};
const testText = text =>
new Promise((resolve, reject) => {
setTimeout(() => {
event.emit('aiSound:frame', {
resultTextTemp: text,
});
setTimeout(() => {
event.emit('aiSound:finish', {
resultText: text,
});
setTimeout(() => {
resolve();
}, 500);
}, 500);
}, 500);
});
const destroyPandaRecorderWebSocket = async () => {
if (pandaRecordWebSocketRef.current) {
await pandaRecordWebSocketRef.current.destroy();
......
......@@ -9,201 +9,194 @@ import context from '../../config'
import SparkDirective from '../../core/directive/SparkDirective'
const Dialog = props => {
const { globalConfig, setGlobalConfig } = useContext(context)
const { pandaRecordWebSocketRef, close } = props
const ulRef = useRef(null)
const directiveRef = useRef(null)
const toolTipRef = useRef(null)
const timeRef = useRef(null)
const { globalConfig, setGlobalConfig } = useContext(context)
const { pandaRecordWebSocketRef, close } = props
const ulRef = useRef(null)
const directiveRef = useRef(null)
const toolTipRef = useRef(null)
const timeRef = useRef(null)
const isDebug = globalConfig.get("isDebug")
const templateData = [
"打开模型搭建功能菜单",
"打开场景搭建菜单组",
"回到首页",
"关闭当前菜单",
"熊猫智慧水务解决方案"
]
const [data, setData] = useState(() => [{
role: "system",
content: `嗨,您好!猜测您可能问以下的问题\n ${templateData.map((i, index) => `${index + 1}.${i}。`).join("\n")}`,
time: new moment().format("HH:mm:ss"),
}])
const [data, setData] = useState(() => [{
role: "system",
content: `嗨,您好!猜测您可能问以下的问题\n ${globalConfig.get('guideTemplateData').toJS().map((i, index) => `${index + 1}.${i}。`).join("\n")}`,
time: new moment().format("HH:mm:ss"),
}])
useEffect(() => {
if (!ulRef.current.lastChild) return
ulRef.current.lastChild.scrollIntoView({
block: 'end',
behavior: 'smooth'
})
startTime()
}, [data])
useEffect(() => {
startTime()
if (!ulRef.current.lastChild) return
ulRef.current.lastChild.scrollIntoView({
block: 'end',
behavior: 'smooth'
})
}, [data])
useEffect(() => {
directiveRef.current = new Directive({
params: {
sparkModelConfig: globalConfig.getIn(['key']).shortSound
}
})
if (globalConfig.get('key').isOpenSparkModel) {
directiveRef.current.directiveTypes.push(SparkDirective)
}
event.on("aiSound:finish", finish)
event.on("aiSound:frame", frame)
startTime()
return () => {
event.off("aiSound:finish", finish)
event.off("aiSound:frame", frame)
destroyTime()
}
}, [])
useEffect(() => {
directiveRef.current = new Directive({
params: {
sparkModelConfig: globalConfig.getIn(['key']).shortSound
}
})
if (globalConfig.get('key').isOpenSparkModel) {
directiveRef.current.directiveTypes.push(SparkDirective)
}
event.on("aiSound:finish", finish)
event.on("aiSound:frame", frame)
return () => {
event.off("aiSound:finish", finish)
event.off("aiSound:frame", frame)
destroyTime()
}
}, [])
const finish = useCallback(async ({ resultText }) => {
if (!resultText) return
pandaRecordWebSocketRef.current.setStatus("pause")
const directive = directiveRef.current.parse({
text: resultText
})
if (directive) {
sendContent({
role: "system",
content: "系统正在思考中,请稍后..."
})
let resultMsg = ""
await directive.excute({
sendMsg: msg => {
resultMsg += msg
updateLastData({
content: resultMsg
})
}
})
pandaRecordWebSocketRef.current.setStatus("playing")
return
const finish = useCallback(async ({ resultText }) => {
if (!resultText) return
!isDebug && pandaRecordWebSocketRef.current.setStatus("pause")
const directive = directiveRef.current.parse({
text: resultText
})
if (directive) {
sendContent({
role: "system",
content: "系统正在思考中,请稍后..."
})
let resultMsg = ""
await directive.excute({
sendMsg: msg => {
resultMsg += msg
updateLastData({
content: resultMsg
})
}
sendContent({
role: "system",
content: "亲,我暂时还未理解你的意思,请换一种方式表达或者描述更加具体"
})
pandaRecordWebSocketRef.current.setStatus("playing")
}, [])
})
!isDebug && pandaRecordWebSocketRef.current.setStatus("playing")
return
}
sendContent({
role: "system",
content: "亲,我暂时还未理解你的意思,请换一种方式表达或者描述更加具体"
})
!isDebug && pandaRecordWebSocketRef.current.setStatus("playing")
}, [])
const frame = useCallback((data) => {
const { resultText, resultTextTemp } = data
if (!resultTextTemp) return
setData(data => {
const length = data.length
const lastData = data.at(-1)
if (length == 0 || lastData.role == "system") {
return data.concat([{
role: "user",
time: new moment().format("HH:mm:ss"),
content: resultTextTemp
}])
} else {
return data.map((data, index) => {
if (index < length - 1) {
return {
...data
}
} else {
return {
...data,
content: resultTextTemp
}
}
})
const frame = useCallback((data) => {
const { resultText, resultTextTemp } = data
if (!resultTextTemp) return
setData(data => {
const length = data.length
const lastData = data.at(-1)
if (length == 0 || lastData.role == "system") {
return data.concat([{
role: "user",
time: new moment().format("HH:mm:ss"),
content: resultTextTemp
}])
} else {
return data.map((data, index) => {
if (index < length - 1) {
return {
...data
}
} else {
return {
...data,
content: resultTextTemp
}
}
})
}, [])
}
})
}, [])
const updateLastData = ({ content, ...params }) => {
setData(data => data.map((item, index) => {
if (index < data.length - 1) {
return {
...item
}
} else {
return {
...item,
content,
...params,
}
}
}))
}
const updateLastData = ({ content, ...params }) => {
setData(data => data.map((item, index) => {
if (index < data.length - 1) {
return {
...item
}
} else {
return {
...item,
content,
...params,
}
}
}))
}
const sendContent = ({ role = "system", content, ...params }) => {
setData(i => i.concat([{
role,
time: new moment().format("HH:mm:ss"),
content,
...params
}]))
}
const sendContent = ({ role = "system", content, ...params }) => {
setData(i => i.concat([{
role,
time: new moment().format("HH:mm:ss"),
content,
...params
}]))
}
const startTime = () => {
destroyTime()
timeRef.current = setTimeout(() => {
close && close()
}, globalConfig.getIn(['closePandaAiTime']))
}
const startTime = () => {
destroyTime()
timeRef.current = setTimeout(() => {
close && close()
}, globalConfig.getIn(['closePandaAiTime']))
}
const destroyTime = () => {
if (timeRef.current) {
clearTimeout(timeRef.current)
timeRef.current = null
}
const destroyTime = () => {
if (timeRef.current) {
clearTimeout(timeRef.current)
timeRef.current = null
}
}
return (<div className={style.container}>
<div className={style.pandaIcon}></div>
<div className={style.main}>
<div className={style.header}>
<p>熊猫智能语音库</p>
<div className={style.help}>
<Tooltip
placement="bottomRight"
title={
<div className={style.toolTipContent}>
<p className={style.toolTipTitle}>支持以下语音指令集</p>
<div className={style.toolTipWrapper}>
<ul>
{
AllDirectiveTypes.filter(item => !!item.name).map((item, index) => <li key={index}>{index + 1}.{item.name}</li>)
}
</ul>
</div>
</div>
}
getPopupContainer={() => toolTipRef.current}
arrowPointAtCenter={true}
>
<span className={style.helpIcon} ref={toolTipRef}></span>
</Tooltip>
</div>
</div>
<div className={style.content}>
<div className={style.display}>
<ul className={style.ul} ref={ulRef}>
{
data.map((item, index) => <Fragment key={index}>
{
item.interval ? <li className={style.interval}>{item.time}</li> : null
}
<li data-role={item.role} key={index} className={style.list}>
<span className={style.avater}></span>
<div className={style.aiContent}>
<p className={style.aiText}> {item.content}</p>
</div>
</li>
</Fragment>)
}
</ul>
return (<div className={style.container}>
<div className={style.pandaIcon}></div>
<div className={style.main}>
<div className={style.header}>
<p>熊猫智能语音库</p>
<div className={style.help}>
<Tooltip
placement="bottomRight"
title={
<div className={style.toolTipContent}>
<p className={style.toolTipTitle}>支持以下语音指令集</p>
<div className={style.toolTipWrapper}>
<ul>
{
AllDirectiveTypes.filter(item => !!item.name).map((item, index) => <li key={index}>{index + 1}.{item.name}</li>)
}
</ul>
</div>
</div>
</div>
}
getPopupContainer={() => toolTipRef.current}
arrowPointAtCenter={true}
>
<span className={style.helpIcon} ref={toolTipRef}></span>
</Tooltip>
</div>
</div>
<div className={style.content}>
<div className={style.display}>
<ul className={style.ul} ref={ulRef}>
{
data.map((item, index) => <Fragment key={index}>
{
item.interval ? <li className={style.interval}>{item.time}</li> : null
}
<li data-role={item.role} key={index} className={style.list}>
<span className={style.avater}></span>
<div className={style.aiContent}>
<p className={style.aiText}> {item.content}</p>
</div>
</li>
</Fragment>)
}
</ul>
</div>
</div>)
</div>
</div>
</div>)
}
export default withRouter(Dialog)
\ No newline at end of file
......@@ -4,102 +4,88 @@ import image from '@/assets/images/soundAi/眨眼.gif'
import { event } from '@wisdom-utils/utils'
import { AwakenDirective, ByeDirective, Directive } from '../../core'
import Dialog from '../Dialog'
import context from '../../config'
import context from '../../config'
const PandaTip = props => {
const { pandaRecordWebSocketRef } = props
const {globalConfig , setGlobalConfig} = useContext(context)
const [status, setStatus] = useState("close")
const directiveRef = useRef(null)
const [initOpen, setInitOpen] = useState(false)
const [showTip, setShowTip] = useState(true)
const timeRef = useRef(null)
// const finish = useCallback(({ resultText }) => {
// console.log("说完")
// const directive = directiveRef.current.parse({
// text: resultText
// })
// if (!directive) return null
// if (directive instanceof AwakenDirective && status == "close") {
// setStatus("open")
// } else if (directive instanceof ByeDirective && status == "open") {
// // setStatus("close")
// close()
// }
// }, [status])
const { pandaRecordWebSocketRef } = props
const { globalConfig, setGlobalConfig } = useContext(context)
const isDebug = globalConfig.get("isDebug")
const [status, setStatus] = useState(isDebug == false ? "close" : "open")
const directiveRef = useRef(null)
const [initOpen, setInitOpen] = useState(false)
const [showTip, setShowTip] = useState(true)
const timeRef = useRef(null)
const frame = useCallback(({ resultTextTemp }) => {
const directive = directiveRef.current.parse({
text: resultTextTemp
})
console.log(resultTextTemp)
if(!directive) return null
if (directive instanceof AwakenDirective && status == "close") {
setStatus("open")
pandaRecordWebSocketRef.current.wsClose()
} else if (directive instanceof ByeDirective && status == "open") {
close()
pandaRecordWebSocketRef.current.wsClose()
}
}, [status])
useEffect(() => {
directiveRef.current = new Directive({
directiveTypes: [AwakenDirective, ByeDirective],
})
}, [])
const frame = useCallback(({ resultTextTemp }) => {
if (isDebug) return
const directive = directiveRef.current.parse({
text: resultTextTemp
})
if (!directive) return null
if (directive instanceof AwakenDirective && status == "close") {
setStatus("open")
pandaRecordWebSocketRef.current.wsClose()
} else if (directive instanceof ByeDirective && status == "open") {
close()
pandaRecordWebSocketRef.current.wsClose()
}
}, [status])
useEffect(() => {
// event.on("aiSound:finish", finish)
event.on("aiSound:frame", frame)
if (status == "open") {
destroyTime()
} else if (status == "close") {
if (initOpen == true) {
startTime()
setShowTip(false)
} else {
setShowTip(true)
}
}
return () => {
// event.off("aiSound:finish", finish)
event.off("aiSound:frame", frame)
}
}, [status , initOpen])
useEffect(() => {
directiveRef.current = new Directive({
directiveTypes: [AwakenDirective, ByeDirective],
})
}, [])
const startTime = () => {
destroyTime()
timeRef.current = setTimeout(() => {
setShowTip(true)
}, globalConfig.getIn(['showOpenAiTipTime']))
useEffect(() => {
if (isDebug) return
event.on("aiSound:frame", frame)
if (status == "open") {
destroyTime()
} else if (status == "close") {
if (initOpen == true) {
startTime()
setShowTip(false)
} else {
setShowTip(true)
}
}
const destroyTime = () => {
if (timeRef.current) {
clearTimeout(timeRef.current)
timeRef.current = null
}
return () => {
event.off("aiSound:frame", frame)
}
}, [status, initOpen])
const startTime = () => {
destroyTime()
timeRef.current = setTimeout(() => {
setShowTip(true)
}, globalConfig.getIn(['showOpenAiTipTime']))
}
const close = () => {
setStatus("close")
setInitOpen(true)
const destroyTime = () => {
if (timeRef.current) {
clearTimeout(timeRef.current)
timeRef.current = null
}
}
return (<div className={style.container}>
const close = () => {
setStatus("close")
setInitOpen(true)
}
return (<div className={style.container}>
{
status == "open" ? <Dialog close={close} pandaRecordWebSocketRef={pandaRecordWebSocketRef} /> : <div className={style.content}>
{
status == "open" ? <Dialog close={close} pandaRecordWebSocketRef={pandaRecordWebSocketRef} /> : <div className={style.content}>
{
showTip ? <div className={style.tipImage}>
<span>呼叫“熊猫熊猫”唤醒语音小助手。</span>
</div> : null
}
<img src={image} className={style.image} />
</div>
showTip ? <div className={style.tipImage}>
<span>呼叫“熊猫熊猫”唤醒语音小助手。</span>
</div> : null
}
</div>)
<img src={image} className={style.image} />
</div>
}
</div>)
}
export default PandaTip
\ No newline at end of file
......@@ -3,9 +3,19 @@ import { createContext } from "react"
export default createContext(null)
const guideTemplateData = [
"打开模型搭建功能菜单",
"打开场景搭建菜单组",
"回到首页",
"关闭当前菜单",
"熊猫智慧水务解决方案"
]
export const contextData = data => fromJS({
closePandaAiTime : 1000 * 60,
showOpenAiTipTime : 1000 * 60,
key : null,
isDebug : process.env.NODE_ENV == "development",
guideTemplateData,
...data ?? {}
})
\ No newline at end of file
import BaseDirective from "./BaseDirective"
import BaseDirective from './BaseDirective';
class AwakenDirective extends BaseDirective{
static name = "熊猫熊猫唤醒"
match () {
const {text} = this
if(/熊猫|什么/.test(text)) {
return true
}
return false
}
class AwakenDirective extends BaseDirective {
static name = '熊猫熊猫唤醒';
async excute ({sendMsg = function() {}}) {
match() {
const { text } = this;
if (/熊猫|什么/.test(text)) {
return true;
}
return false;
}
async excute({ sendMsg = function() {
sendMsg("已经打开首页了")
} }) {}
}
export default AwakenDirective
\ No newline at end of file
export default AwakenDirective;
import BaseDirective from "../BaseDirective";
import CloseMenuDirective from "./";
import {store, event} from '@wisdom-utils/utils'
class CloseSingleDirective extends BaseDirective {
static name = '关闭菜单或者模糊匹配关闭菜单';
match() {
const { text } = this;
let result = null;
if (this.getBeforeLastGroupDirective()) {
result = text.match(/第([一|二|三|四|五|六|七|八|九|十]+)个/);
if (result && result.length >= 2) {
this.matchResult = Utils.chineseToNumber(result[1]);
} else if (!result) {
result = text.match(/第[\u4e00-\u9fa5]?(\d+)个/);
if (result && result.length >= 2) {
this.matchResult = Number(result[1]);
}
}
}
return !!this.matchResult;
}
getBeforeLastGroupDirective() {
const lastMenu = this.directives.at(-1);
if (!lastMenu) return false;
if (!(lastMenu instanceof CloseMenuDirective)) return false;
if (!lastMenu.data || lastMenu.data.type != 'widgets' || lastMenu.data.widgets.length == 0) return false;
return true;
}
async excute({
sendMsg = function () {}
}) {
if (typeof this.matchResult === 'number') {
const widgets = this.getOpenedMenus();
if (this.matchResult == 0 || this.matchResult > widgets.length) {
this.data = {};
this.data.type = 'widgets';
this.data.widgets = widgets;
return sendMsg(`索引超出了界限,请重新语音选择关闭第几个菜单`);
}
const menu = widgets[this.matchResult];
event.emit('event:closeMenuByName', menu.name);
return sendMsg(`关闭${menu.name}菜单成功`);
}
}
getOpenedMenus() {
const menus = store.get('event:openedMenus');
return Array.from(menus.current.values());
}
}
export default CloseSingleDirective
\ No newline at end of file
import { store, event } from '@wisdom-utils/utils';
import BaseDirective from './BaseDirective';
import Utils from '../utils/Utils';
import BaseDirective from '../BaseDirective';
import CloseSingleDirective from './CloseSingleDirective';
class CloseMenuDirective extends BaseDirective {
static name = '关闭菜单或者模糊匹配关闭菜单';
static beforeLoadDirectives = [CloseSingleDirective]
match() {
const { text } = this;
let result = null;
if (this.getBeforeLastGroupDirective()) {
result = text.match(/第([一|二|三|四|五|六|七|八|九|十]+)个/);
if (result && result.length >= 2) {
this.matchResult = Utils.chineseToNumber(result[1]);
} else if (!result) {
result = text.match(/第[\u4e00-\u9fa5]?(\d+)个/);
if (result && result.length >= 2) {
this.matchResult = Number(result[1]);
}
}
}
result = text.match(/关闭(所有).*(?=(?:,|,|。))/);
if (!result) {
result = text.match(/关闭(当前).*(?=(?:,|,|。))/);
......@@ -36,30 +24,10 @@ class CloseMenuDirective extends BaseDirective {
return !!this.matchResult;
}
getBeforeLastGroupDirective() {
const lastMenu = this.directives.at(-1);
if (!lastMenu) return false;
if (!(lastMenu instanceof CloseMenuDirective)) return false;
if (!lastMenu.data || lastMenu.data.type != 'widgets' || lastMenu.data.widgets.length == 0) return false;
return true;
}
async excute({
sendMsg = function () {}
sendMsg = function () { }
}) {
let widgets = null;
if (typeof this.matchResult === 'number') {
const widgets = this.getOpenedMenus();
if (this.matchResult == 0 || this.matchResult > widgets.length) {
this.data = {};
this.data.type = 'widgets';
this.data.widgets = widgets;
return sendMsg(`索引超出了界限,请重新语音选择关闭第几个菜单`);
}
const menu = widgets[this.matchResult];
event.emit('event:closeMenuByName', menu.name);
return sendMsg(`关闭${menu.name}菜单成功`);
}
if (this.matchResult == '所有') {
return sendMsg(this.closeAllMenu());
}
......@@ -95,8 +63,6 @@ class CloseMenuDirective extends BaseDirective {
}
closeCurrentMenu() {
console.log(store);
console.log(window.location);
const menus = this.getOpenedMenus();
const menu = location.pathname.match(/\/civbase(.*)/);
if (!menu || menu.length <= 1) {
......@@ -133,4 +99,5 @@ class CloseMenuDirective extends BaseDirective {
}
}
export default CloseMenuDirective;
export default CloseMenuDirective
\ No newline at end of file
import BaseDirective from './BaseDirective'
class CloseSessionDirective extends BaseDirective {
match (){
const {text} = this
if(/结束对话/.test(text)) {
return true
}
return false
}
}
export default CloseSessionDirective
\ No newline at end of file
import BaseDirective from "./BaseDirective";
import BaseDirective from "../BaseDirective";
import OpenMenuDirective from "./";
import { cut, extract } from '@congcongcai/jieba.js'
import Utils from "../utils/Utils";
import { uniq } from "lodash";
import Utils from "../../utils/Utils";
class OpenSingleDirective extends BaseDirective {
class OpenMenuDirective extends BaseDirective {
static name="打开菜单或者模糊匹配打开菜单"
match() {
const { text } = this
let result = null
if(this.getBeforeLastGroupDirective()) {
if (this.getBeforeLastGroupDirective()) {
result = text.match(/第([一|二|三|四|五|六|七|八|九|十]+)个/)
if(result && result.length >= 2) {
if (result && result.length >= 2) {
this.matchResult = Utils.chineseToNumber(result[1])
} else if(!result) {
} else if (!result) {
result = text.match(/第[\u4e00-\u9fa5]?(\d+)个/)
if(result && result.length >= 2) {
if (result && result.length >= 2) {
this.matchResult = Number(result[1])
}
}
}
if(!result) {
result = text.match(/打开(.*)(?=(?:菜单|功能|路径))/)
}
if (!result) {
result = text.match(/打开(.*)(?=(?:,|,|。))/)
}
if (result && result.length >= 2 && !this.matchResult) {
this.matchResult = result[1]
}
return !!this.matchResult
}
getBeforeLastGroupDirective () {
const lastMenu = this.directives.at(-1)
if(!lastMenu) return false
if(!(lastMenu instanceof OpenMenuDirective) ) return false
if(!(lastMenu instanceof OpenMenuDirective || lastMenu instanceof this.openSingleMenu) ) return false
if(!lastMenu.data || lastMenu.data.type != "widgets" || lastMenu.data.widgets.length == 0) return false
return true
}
async excute({
sendMsg = function () {}
sendMsg = function () { }
}) {
let widgets = null
if(typeof this.matchResult == "number") {
if(typeof this.matchResult == "number") {
const lastMenu = this.directives.at(-2)
const widgets = lastMenu.data.widgets
if(this.matchResult == 0 || this.matchResult > widgets.length) {
......@@ -53,43 +43,18 @@ class OpenMenuDirective extends BaseDirective {
return sendMsg(`索引超出了界限,请重新语音选择第几个菜单`)
} else {
const currentMenu = widgets[this.matchResult - 1]
this.openSingleMenu(currentMenu)
return sendMsg(`成功打开${currentMenu.label}菜单`)
}
}
else {
widgets = this.getCompleteMenus()
if (!widgets) {
widgets = this.getPatternMenus()
}
if (!widgets) {
return sendMsg("没有查找到此菜单,请检查语音是否正确")
}
if (widgets.length == 1) {
return sendMsg(this.handleOneSingleMenu(widgets[0]))
} else {
this.data = {}
this.data.type = "widgets"
this.data.widgets = widgets
sendMsg(`${this.widgetsToMsg(widgets)}`)
if(currentMenu.url) {
this.openSingleMenu(currentMenu)
return sendMsg(`成功打开${currentMenu.label}菜单`)
} else {
this.data = {}
this.data.type = "widgets"
this.data.widgets = currentMenu.widgets
return sendMsg(this.widgetsToMsg(currentMenu.widgets))
}
}
}
}
handleOneSingleMenu(widget) {
if (widget.url) {
this.openSingleMenu(widget)
return `打开${widget.label}成功`
} else {
this.data = {}
this.data.type = "widgets"
this.data.widgets = widget.widgets
return `你打开的${widget.label}是一个菜单组,${this.widgetsToMsg(widget.widgets)}`
}
}
widgetsToMsg (widgets) {
return `有以下${widgets.length}个菜单\n${widgets.map((widget, index) => `${index + 1}.${widget.label}`).join("\n")}\n请语音确认一下打开第几个菜单`
return sendMsg("打开菜单失败")
}
getCompleteMenus() {
......@@ -100,6 +65,11 @@ class OpenMenuDirective extends BaseDirective {
return widgets.length > 0 ? widgets : null
}
widgetsToMsg (widgets) {
return `有以下${widgets.length}个菜单\n${widgets.map((widget, index) => `${index + 1}.${widget.label}${widget.widgets ? "(菜单组)" : ""}`).join("\n")}\n请语音确认一下打开第几个菜单`
}
getPatternMenus() {
const weights = extract(this.matchResult, 4)
let data = []
......@@ -122,4 +92,4 @@ class OpenMenuDirective extends BaseDirective {
}
}
export default OpenMenuDirective
\ No newline at end of file
export default OpenSingleDirective
\ No newline at end of file
import BaseDirective from "../BaseDirective";
import { cut, extract } from '@congcongcai/jieba.js'
import Utils from "../../utils/Utils";
import { uniq } from "lodash";
import OpenSingleDirective from "./OpenSingleDirective";
class OpenMenuDirective extends BaseDirective {
static name="打开菜单或者模糊匹配打开菜单"
static beforeLoadDirectives = [OpenSingleDirective]
match() {
const { text } = this
let result = null
if(!result) {
result = text.match(/打开(.*)(?=(?:菜单|功能|路径))/)
}
if (!result) {
result = text.match(/打开(.*)(?=(?:,|,|。))/)
}
if (result && result.length >= 2 && !this.matchResult) {
this.matchResult = result[1]
}
return !!this.matchResult
}
async excute({
sendMsg = function () {}
}) {
let widgets = null
widgets = this.getCompleteMenus()
if (!widgets) {
widgets = this.getPatternMenus()
}
if (!widgets) {
return sendMsg("没有查找到此菜单,请检查语音是否正确")
}
if (widgets.length == 1) {
return sendMsg(this.handleOneSingleMenu(widgets[0]))
} else {
this.data = {}
this.data.type = "widgets"
this.data.widgets = widgets
sendMsg(`${this.widgetsToMsg(widgets)}`)
}
}
handleOneSingleMenu(widget) {
if (widget.url) {
this.openSingleMenu(widget)
return `打开${widget.label}成功`
} else {
this.data = {}
this.data.type = "widgets"
this.data.widgets = widget.widgets
return `你打开的${widget.label}是一个菜单组,${this.widgetsToMsg(widget.widgets)}`
}
}
widgetsToMsg (widgets) {
return `有以下${widgets.length}个菜单\n${widgets.map((widget, index) => `${index + 1}.${widget.label}${widget.widgets ? "(菜单组)" : ""}`).join("\n")}\n请语音确认一下打开第几个菜单`
}
getCompleteMenus() {
const result = Utils.findMenus({
name: this.matchResult
})
const { widgets } = result
return widgets.length > 0 ? widgets : null
}
getPatternMenus() {
const weights = extract(this.matchResult, 4)
let data = []
if (weights.length == 0) return null
weights.map(({ word }) => {
const name = new RegExp(word)
const result = Utils.findMenus({
name
})
if(result.widgets.length > 0) {
data = data.concat(result.widgets)
}
})
data = uniq(data)
return data.length > 0 ? data : null
}
openSingleMenu(widget) {
Utils.openMenu({widget})
}
}
export default OpenMenuDirective
\ No newline at end of file
import AwakenDirective from "./AwakenDirective"
import OpenMenuDirective from "./OpenMenuDirective"
import HomePageDirective from "./HomePageDirective"
import CloseMenuDirective from "./CloseMenuDirective"
import CloseMenuDirective from "./CloseMenuDirective/index"
import ByeDirective from "./ByeDirective"
import OpenMenuDirective from "./OpenMenuDirective/index"
const DirectiveTypes = [
AwakenDirective,
......@@ -10,24 +10,35 @@ const DirectiveTypes = [
OpenMenuDirective,
CloseMenuDirective
]
const AllDirectiveTypes = [
AwakenDirective,
HomePageDirective,
OpenMenuDirective,
CloseMenuDirective,
ByeDirective
]
const AllDirectiveTypes = DirectiveTypes.concat(ByeDirective)
class Directive {
constructor (options = {}) {
this.directiveTypes = options.directiveTypes || DirectiveTypes
this._directiveTypes = this.parseDirectiveTypes();
this.params = options.params || {}
this.directives = []
}
parseDirectiveTypes () {
const directiveTypes = []
this.directiveTypes.map(directiveType => {
this.circlePushDirective(directiveType , directiveTypes)
})
return directiveTypes
}
circlePushDirective(directiveType, directiveTypes) {
if(directiveType.beforeLoadDirectives && directiveType.beforeLoadDirectives.length > 0 ) {
directiveType.beforeLoadDirectives.map(i => this.circlePushDirective(i, directiveTypes))
}
directiveTypes.push(directiveType)
}
parse ({text}) {
let isHasSuccess = false
for(let i = 0 ; i < this.directiveTypes.length ; i++) {
const directive = new this.directiveTypes[i]({text , directives : this.directives, params : this.params})
for(let i = 0 ; i < this._directiveTypes.length ; i++) {
const directive = new this._directiveTypes[i]({text , directives : this.directives, params : this.params})
if(directive.match()) {
isHasSuccess = true
this.directives.push(directive)
......
import { request, event } from '@wisdom-utils/utils'
import { Suspense, lazy, useCallback, useEffect, useRef, useState } from 'react'
import Context , { contextData } from './config'
import Context, { contextData } from './config'
const PandaUi = lazy(() => import("./PandaUi"))
const SoundAi = props => {
const keyRef = useRef(null)
const [visible, setVisible] = useState(false)
const [globalConfig , setGlobalConfig] = useState(contextData())
const keyRef = useRef(null)
const [visible, setVisible] = useState(false)
const [globalConfig, setGlobalConfig] = useState(contextData())
useEffect(async () => {
try {
await getKey()
await getIsOpenConfig()
setVisible(true)
} catch (error) {
console.warn(error)
}
return () => {
}
}, [])
useEffect(async () => {
try {
await getKey()
await getIsOpenConfig()
setVisible(true)
} catch (error) {
console.warn(error)
}
return () => {
}
}, [])
const getIsOpenConfig = () => new Promise((resolve, reject) => {
request("/PandaOMS/OMS/DataManger/GetDicConfigs", {
params: {
ParentName: "智能语音",
ChilName: "是否开启,是否开启人机交互"
}
}).then(res => {
if (res.code != 0) {
reject("没有配置智能语音此条目")
return
}
const data = res.data
const config = data.find(item => item.nodeName == "是否开启")
if (!config) {
reject("没有配置是否开启字段")
}
const value = config.nodeValue
if (value != "开") {
reject("字段开启字段值为空")
return
}
const spark = data.find(item => item.nodeName == "是否开启人机交互")
if (spark && spark.nodeValue == "开") {
setGlobalConfig(globalConfig => globalConfig.set("key", {
...keyRef.current,
isOpenSparkModel : true
}))
} else {
setGlobalConfig(globalConfig => globalConfig.set("key", {
...keyRef.current,
isOpenSparkModel : false
}))
}
resolve()
}).catch(error => {
reject(error)
})
const getIsOpenConfig = () => new Promise((resolve, reject) => {
request("/PandaOMS/OMS/DataManger/GetDicConfigs", {
params: {
ParentName: "智能语音",
ChilName: "是否开启,是否开启人机交互"
}
}).then(res => {
if (res.code != 0) {
reject("没有配置智能语音此条目")
return
}
const data = res.data
const config = data.find(item => item.nodeName == "是否开启")
if (!config) {
reject("没有配置是否开启字段")
}
const value = config.nodeValue
if (value != "开") {
reject("字段开启字段值为空")
return
}
const spark = data.find(item => item.nodeName == "是否开启人机交互")
if (spark && spark.nodeValue == "开") {
setGlobalConfig(globalConfig => globalConfig.set("key", {
...keyRef.current,
isOpenSparkModel: true
}))
} else {
setGlobalConfig(globalConfig => globalConfig.set("key", {
...keyRef.current,
isOpenSparkModel: false
}))
}
resolve()
}).catch(error => {
reject(error)
})
})
const getKey = () => new Promise((resolve, reject) => {
fetch("https://civgis.panda-water.cn/system/pandaAiSoundWorker/key.json", {
mode: "cors"
}).then(res => res.json())
.then(res => {
keyRef.current = res
resolve(res)
}).catch(error => {
reject(error)
})
})
const getKey = () => new Promise((resolve, reject) => {
fetch("https://civgis.panda-water.cn/system/pandaAiSoundWorker/key.json", {
mode: "cors"
}).then(res => res.json())
.then(res => {
keyRef.current = res
resolve(res)
}).catch(error => {
reject(error)
})
})
return (<>
{
visible && globalConfig.get("key")? <Context.Provider value={{globalConfig , setGlobalConfig}}>
<Suspense fallback={<></>}>
<PandaUi />
</Suspense>
</Context.Provider> : null
}
</>)
return (<>
{
visible && globalConfig.get("key") ? <Context.Provider value={{ globalConfig, setGlobalConfig }}>
<Suspense fallback={<></>}>
<PandaUi />
</Suspense>
</Context.Provider> : null
}
</>)
}
export default SoundAi
\ No newline at end of file
import { event } from '@wisdom-utils/utils'
import { Utils } from './core'
const testText = text =>
new Promise((resolve, reject) => {
setTimeout(() => {
event.emit('aiSound:frame', {
resultTextTemp: text,
});
setTimeout(() => {
event.emit('aiSound:finish', {
resultText: text,
});
setTimeout(() => {
resolve();
}, 500);
}, 500);
}, 500);
});
const testCommand = async () => {
await Utils.delayTime(500);
// await testText("打开泵站。")
// await testText("打开第2个。")
// await testText("打开铁山全景图菜单。")
// await testText("打开顺平全景图菜单。")
// await testText("关闭全景图菜单。")
// await testText("关闭第1个。");
await testText("打开实景。")
await testText("打开第1个。")
await testText("打开第4个。")
}
export default testCommand
\ No newline at end of file
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