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