diff --git a/package.json b/package.json index 73c2c5244f1a03be864127d1f4a39011d53a092c..defc73e6ba3954bbf1183d8965bd90bb6f79b83c 100644 --- a/package.json +++ b/package.json @@ -118,6 +118,7 @@ "@wisdom-utils/components": "0.1.349", "@wisdom-utils/runtime": "0.0.48", "@wisdom-utils/utils": "0.1.388", + "@congcongcai/jieba.js" : "0.0.3", "animate.css": "^4.1.1", "antd": "4.21.2", "long": "^5.2.3", diff --git a/src/components/SoundAi/Ui/Dialog/index.jsx b/src/components/SoundAi/Ui/Dialog/index.jsx index 60a5a0108c8512c8b110c3522ebf1d892ee2d554..a8edffe3922e83dd5c58541b64e71087fbe91408 100644 --- a/src/components/SoundAi/Ui/Dialog/index.jsx +++ b/src/components/SoundAi/Ui/Dialog/index.jsx @@ -9,13 +9,13 @@ import { Directive } from '../../core' const Dialog = props => { - const {history , pandaRecordWebSocketRef} = props + const { pandaRecordWebSocketRef} = props const ulRef = useRef(null) const directiveRef = useRef(null) const [data , setData] = useState([]) const finish = useCallback(async ({resultText}) => { - pandaRecordWebSocketRef.setStatus("pause") + pandaRecordWebSocketRef.current.setStatus("pause") const directive = directiveRef.current.parse({ text : resultText }) @@ -25,16 +25,19 @@ const Dialog = props => { content : "绯荤粺姝e湪鎬濊€冧腑,璇风◢鍚�..." }) const msg = await directive.excute() - updateLastData({ - content : msg - }) + setTimeout(() => { + updateLastData({ + content : msg + }) + }, 1000) + pandaRecordWebSocketRef.current.setStatus("playing") return } sendContent({ role : "system", content : "浜�,鎴戞殏鏃惰繕鏈悊瑙d綘鐨勬剰鎬濓紝璇锋崲涓€绉嶆柟寮忚〃杈炬垨鑰呮弿杩版洿鍔犲叿浣�" }) - pandaRecordWebSocketRef.setStatus("playing") + pandaRecordWebSocketRef.current.setStatus("playing") }, []) const frame = useCallback((data) => { @@ -68,7 +71,6 @@ const Dialog = props => { useEffect(() => { directiveRef.current = new Directive({ params : { - history } }) }, []) @@ -92,14 +94,14 @@ const Dialog = props => { } const updateLastData = ({content , ...params }) => { - setData(data => data.map((data , index) => { - if(index < length -1) { + setData(data => data.map((item , index) => { + if(index < data.length -1) { return { - ...data + ...item } } else { return { - ...data, + ...item, content, ...params, } diff --git a/src/components/SoundAi/Ui/PandaTip/index.jsx b/src/components/SoundAi/Ui/PandaTip/index.jsx index 5ada363216801cff2776150e20df55f120a07398..77a70a91c3508d8475bf443d110c7f2cbb37755f 100644 --- a/src/components/SoundAi/Ui/PandaTip/index.jsx +++ b/src/components/SoundAi/Ui/PandaTip/index.jsx @@ -20,12 +20,11 @@ const PandaTip = props => { } else if(directive instanceof ByeDirective && status == "open") { setStatus("close") } - }, []) + }, [status]) useEffect(() => { directiveRef.current = new Directive({ - // directiveTypes : [AwakenDirective , ByeDirective], - directiveTypes : [] + directiveTypes : [AwakenDirective , ByeDirective], }) }, []) diff --git a/src/components/SoundAi/core/directive/BaseDirective.js b/src/components/SoundAi/core/directive/BaseDirective.js index a29d5d5c8bfd787668db14e507fc714156073820..dfc7ee889d5111a6dba431fa672f828b66241cbc 100644 --- a/src/components/SoundAi/core/directive/BaseDirective.js +++ b/src/components/SoundAi/core/directive/BaseDirective.js @@ -3,6 +3,8 @@ class BaseDirective { this.options = options this.text = this.options.text this.directives = options.directives + this.params = options.params || {} + this.data = null } match () { diff --git a/src/components/SoundAi/core/directive/ByeDirective.js b/src/components/SoundAi/core/directive/ByeDirective.js index f810587e8c39c6fd2e350b7924083eb2340fac54..933d4acd3a40e767cbf51a5d3bc05978a71fcff7 100644 --- a/src/components/SoundAi/core/directive/ByeDirective.js +++ b/src/components/SoundAi/core/directive/ByeDirective.js @@ -3,7 +3,7 @@ import BaseDirective from "./BaseDirective"; class ByeDirective extends BaseDirective { match () { const {text} = this - if(/鍐嶈鍐嶈|鎷滄嫓/.test(text)) { + if(/鍐嶈|鎷滄嫓|鍏抽棴/.test(text)) { return true } return false diff --git a/src/components/SoundAi/core/directive/CloseMenuDirective.js b/src/components/SoundAi/core/directive/CloseMenuDirective.js new file mode 100644 index 0000000000000000000000000000000000000000..abe6a33ed5c4a08f3e85c9675539a9246c584fd5 --- /dev/null +++ b/src/components/SoundAi/core/directive/CloseMenuDirective.js @@ -0,0 +1,35 @@ +import BaseDirective from "./BaseDirective"; + +class CloseMenuDirective extends BaseDirective { + match () { + const { text } = this + let result = null + result = text.match(/鍏抽棴(.*)(?=(?:鑿滃崟|鍔熻兘|璺緞))/) + if (!result) { + result = text.match(/鍏抽棴(.*)(?=(?:,|锛寍銆倈))/) + } + if (result && result.length >= 2) { + this.matchResult = result[1] + } + return !!(result && result.length >= 2) + } + + async excute () { + let widgets = null + if(this.data) { + + } else { + widgets = this.getCompleteMenus() + } + } + + getCompleteMenus () { + const result = Utils.findMenus({ + name: this.matchResult + }) + const { widgets } = result + // return widgets.length > 0 ? widgets : null + } +} + +export default CloseMenuDirective \ No newline at end of file diff --git a/src/components/SoundAi/core/directive/HomePageDirective.js b/src/components/SoundAi/core/directive/HomePageDirective.js new file mode 100644 index 0000000000000000000000000000000000000000..c28c8ab5180ecd5d688f7579b7e1b5c86f43ef1b --- /dev/null +++ b/src/components/SoundAi/core/directive/HomePageDirective.js @@ -0,0 +1,21 @@ +import Utils from '../utils/Utils' +import BaseDirective from './BaseDirective' + +class HomePageDirective extends BaseDirective { + match () { + const {text} = this + if(/棣栭〉/.test(text)) { + return true + } + return false + } + async excute () { + if(!window.globalConfig.homepage) { + return "娌℃湁閰嶇疆棣栭〉" + } + Utils.openMenu({url : window.globalConfig.homepage}) + return "杩斿洖棣栭〉鎴愬姛" + } +} + +export default HomePageDirective \ No newline at end of file diff --git a/src/components/SoundAi/core/directive/OpenMenuDirective.js b/src/components/SoundAi/core/directive/OpenMenuDirective.js index edf99af91197dbc67f9ab76973d30c251856c353..3bfc4defd8199139b02ff139e0936c4024aa8113 100644 --- a/src/components/SoundAi/core/directive/OpenMenuDirective.js +++ b/src/components/SoundAi/core/directive/OpenMenuDirective.js @@ -1,12 +1,89 @@ import BaseDirective from "./BaseDirective"; +import { cut, extract } from '@congcongcai/jieba.js' +import Utils from "../utils/Utils"; +import { uniq } from "lodash"; class OpenMenuDirective extends BaseDirective { - match () { + match() { + const { text } = this + let result = null + result = text.match(/鎵撳紑(.*)(?=(?:鑿滃崟|鍔熻兘|璺緞))/) + if (!result) { + result = text.match(/鎵撳紑(.*)(?=(?:,|锛寍銆倈))/) + } + if (result && result.length >= 2) { + this.matchResult = result[1] + } + return !!(result && result.length >= 2) + } + + async excute() { + let widgets = null + if (this.data) { + + } else { + widgets = this.getCompleteMenus() + if (!widgets) { + widgets = this.getPatternMenus() + } + if (!widgets) { + return "娌℃湁鏌ユ壘鍒版鑿滃崟,璇锋鏌ヨ闊虫槸鍚︽纭�" + } + if (widgets.length == 1) { + return this.handleOneSingleMenu(widgets[0]) + } else { + this.data = {} + this.data.type = "widgets" + this.data.widgets = widgets + return `${this.widgetsToMsg(widgets)}` + } + } + //鍏堝垽鏂竴涓嬫槸鍚﹁兘瀹屽叏鍖归厤涓€涓彍鍗� + } + + handleOneSingleMenu(widget) { + if (widget.url) { + this.openSingleMenu(widget) + return `鎵撳紑${widget.label}鎴愬姛` + } else { + this.data = {} + this.data.type = "widgets" + this.data.widgets = widgets + return `浣犳墦寮€鐨�${widget.label}鏄竴涓彍鍗曠粍,${this.widgetsToMsg(widget.widgets)}` + } + } + + widgetsToMsg (widgets) { + return `鏈変互涓�${widgets.length - 1}涓彍鍗昞n${widgets.map((widget, index) => `${index + 1}.${widget.label}`).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 } - async excute () { - + openSingleMenu(widget) { + Utils.openMenu({widget}) } } diff --git a/src/components/SoundAi/core/directive/index.js b/src/components/SoundAi/core/directive/index.js index 1acfd6e5301c185199a5ec2637b4f30b646cc260..90aa475787182dbe02d36df046383221136bc55f 100644 --- a/src/components/SoundAi/core/directive/index.js +++ b/src/components/SoundAi/core/directive/index.js @@ -1,8 +1,10 @@ import AwakenDirective from "./AwakenDirective" import OpenMenuDirective from "./OpenMenuDirective" +import HomePageDirective from "./HomePageDirective" const DirectiveTypes = [ AwakenDirective, + HomePageDirective, OpenMenuDirective ] class Directive { diff --git a/src/components/SoundAi/core/utils/Utils.js b/src/components/SoundAi/core/utils/Utils.js index fe8af5225cfa74a5d5e51d4d5a443b002c9c983b..101be75aea3e6d25fd690aff0b6c3462a44675fb 100644 --- a/src/components/SoundAi/core/utils/Utils.js +++ b/src/components/SoundAi/core/utils/Utils.js @@ -56,6 +56,32 @@ const Utils = { } return realLength; }, + findMenus ({ name }) { + const result = { + widgets : [], + } + window.globalConfig.widgets.map(widget => this._findMenus({widget, name , result})) + return result + }, + _findMenus({widget, name , result}) { + if(widget.hideInMenu) return + if( name instanceof RegExp) { + const isPattern = name.test(widget.label) + if(isPattern) { + result.widgets.push(widget) + } + } else if(name == widget.label){ + result.widgets.push(widget) + } + if(widget.widgets && Array.isArray(widget.widgets)) { + return widget.widgets.map(widget => this._findMenus({widget , name , result})) + } + }, + openMenu ({widget = {}, url}) { + if(!((widget.url && widget.product) || url)) return + const _url = url || `${widget.product}/${widget.url}` + window.history.pushState(null, '', `/civbase/${_url}`); + } }; export default Utils; diff --git a/src/components/SoundAi/index.js b/src/components/SoundAi/index.js index 0a108cc21c6d83d9ad8abf4ab940887a8c2a42a2..62d2cd6017ab572c4703b336de811c59f78bb766 100644 --- a/src/components/SoundAi/index.js +++ b/src/components/SoundAi/index.js @@ -3,22 +3,24 @@ import { useCallback, useEffect, useRef, useState } from 'react' import { PandaRecordWebSocket } from './core' import { message } from 'antd' import PandaTip from './Ui/PandaTip' +import { init, cut, extract, ready } from "@congcongcai/jieba.js"; const SoundAi = props => { const pandaRecordWebSocketRef = useRef(null) const keyRef = useRef(null) - const [isStartRecorder , setIsStartRecorder] = useState(false) + const [isStartRecorder, setIsStartRecorder] = useState(false) useEffect(async () => { try { await getIsOpenConfig() await getKey() + await initJieBa() event.emit("record:changeVisible", { - visible : true + visible: true }) event.on("record:changedStaus", changeSwitch) - } catch (error){ + } catch (error) { console.warn(error) } return () => { @@ -26,38 +28,38 @@ const SoundAi = props => { } }, []) - + const changeSwitch = useCallback(async ({ recordData, e: checked }) => { if (checked) { emitSwitch({ - loading : true + loading: true }) createPandaRecordWebSocket() const data = await pandaRecordWebSocketRef.current.start() emitSwitch({ - loading : false + loading: false }) - if(!data.isSuccess) { + if (!data.isSuccess) { return message.info(data.msg) } emitSwitch({ - checked : true + checked: true }) setIsStartRecorder(true) } else { emitSwitch({ - loading : true + loading: true }) await destroyPandaRecorderWebSocket() emitSwitch({ - loading : false, - checked : false + loading: false, + checked: false }) setIsStartRecorder(false) } }, []) - const createPandaRecordWebSocket = () => { + const createPandaRecordWebSocket = async () => { destroyPandaRecorderWebSocket() pandaRecordWebSocketRef.current = new PandaRecordWebSocket({ config : keyRef.current.shortSound, @@ -70,10 +72,28 @@ const SoundAi = props => { } } }) + // 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) { + if (pandaRecordWebSocketRef.current) { await pandaRecordWebSocketRef.current.destroy() pandaRecordWebSocketRef.current = null } @@ -110,20 +130,29 @@ const SoundAi = props => { }) }) - const getKey = () => new Promise((resolve , reject) => { - fetch("https://civgis.panda-water.cn/system/pandaAiSoundWorker/key.json",{ - mode : "cors" + 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) + .then(res => { + keyRef.current = res + resolve(res) + }).catch(error => { + reject(error) + }) + }) + + const initJieBa = () => new Promise((resolve, reject) => { + ready().then(() => { + init() + resolve() + }).catch(() => { + reject() }) }) return (<> { - isStartRecorder ? <PandaTip pandaRecordWebSocketRef = {pandaRecordWebSocketRef} /> : null + isStartRecorder ? <PandaTip pandaRecordWebSocketRef={pandaRecordWebSocketRef} /> : null } </>) }