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
         }
     </>)
 }