广告 《大道至简,给所有人看的编程课》 🔥

《FreeSWITCH案例大全》

5.3 用play_and_detect_speech实现人机语音交互的示例

wandoubaba / 2023-05-09

本文脚本需要以下先决条件,请参考:

5.3.1 编写脚本

在FreeSWITCH安装目录的 scripts目录下创建脚本文件,假设文件名为 play_and_detect_speech.lua,脚本内容:

while session:ready() == true do

    local s = session
    local tts_voice = 'zhitian_emo'
    -- 设置tts_engine和tts_voice,执行say的前提条件是要有这两个参数
    s:execute('set', 'tts_engine=unimrcp')
    s:execute('set', 'tts_voice=' .. tts_voice)
    -- 设置tts_params,执行speak的前提是要有这个参数
    s:set_tts_params("unimrcp:aliyun-mrcpserver", tts_voice)
    -- sleep一小会,避免连接过程中丢失最开头的语音
    s:sleep(300)

    --[[
        把mrcp传来的xml识别结果解析成lua的table类型
        @param asrXml   mrcp的语音识别结果
    ]]
    function getResultTable(asrXml)
        local xml2lua = require('xml2lua')
        local handler = require('xmlhandler.tree')
        local xmlHandler = handler:new()
        local xmlParser = xml2lua.parser(xmlHandler)
        xmlParser:parse(asrXml)
        xml2lua.printable(xmlHandler.root)
        --[[
            <?xml version="1.0" encoding="utf-8"?><result>
            <interpretation grammar="session:hello" confidence="1">
            <instance>
            <result>乘风破浪。</result>
            <beginTime>160</beginTime>
            <endTime>1660</endTime>
            <taskId>0a07801cb19c48ad9ebe75e001b00e07</taskId>
            <waveformUri>dc834b5c7039441f-1.wav</waveformUri>
            </instance>
            <input mode="speech">乘风破浪。</input>
            </interpretation>
            </result>
        ]]
        if (xmlHandler.root ~= nil) then
            local rec_result = xmlHandler.root.result.interpretation.instance
            return rec_result
        else
            return nil
        end
    end
    -- 播放一段语音并同时监听对方声音
    s:execute("play_and_detect_speech", "say:大风起兮云飞扬,我说的这句话好长好长……大风起兮云飞扬,我说的这句话好长好长……大风起兮云飞扬,我说的这句话好长好长…… detect:unimrcp:aliyun-mrcpserver alimrcp")
    -- 接收asr识别到的语音信息
    local xml = s:getVariable('detect_speech_result')
    -- 在控制台打印出asr识别结果的日志
    if xml ~= nil then
        freeswitch.consoleLog("INFO", xml .."\n")
    else
        freeswitch.consoleLog("INFO", "No result!\n")
    end
    -- mod_unimrcp识别出来的结果是xml格式的,我们把它转换成table
    local result = getResultTable(xml)
    if (result.result ~= nil) then
        if (result.result == "你瞅啥?") then
            s:speak("瞅你咋地" .. "\n")   -- 把识别结果再说给终端
        else
            s:speak("" .. result.result .. "\n")   -- 把识别结果再说给终端
        end
    else
        s:speak("对不起,我没听清你说什么了")
    end
    s:speak("再见")
    s:hangup()
end

5.3.2 呼入测试

我们这里只是在internal中做一个演示,所以就把拨号计划做到 conf/dialplan/default.xml中,你可以根据自己的情况酌情配置。

<!-- 一个简单通过mrcp实现speak的脚本,用于证明mrcp模块与服务都正常 -->
<extension name="detect_speech">
    <condition field="destination_number" expression="^(005)$">
        <action application="lua" data="play_and_detect_speech.lua"/>
    </condition>
</extension>

好了,在这台FreeSWITCH上注册一个分机,比如 1001,然后用这个分机直接拨号 005,应该可以听到声音了。

5.3.3 呼出测试

如果不想做拨号计划,可以让FreeSWITCH向分机发起外呼,分机接听后同样会听到声音。

在fs_cli控制台执行命令:

freeswitch@debian> bgapi originate {ignore_early_media=true}user/1001 &lua(play_and_detect_speech.lua)

至此,你已经用play_and_detect_speech实现了一个支持打断的人机对话交互示例,不过在实际测试中我们发现,play_and_detect_speech在识别人声时实在是太灵敏了,小小的呼吸声、碰撞声、路上的车声都会把它“打断”,所以在真实应用场景中,要谨慎使用这个功能。

5.3.4 最后的说明

play_and_detect_speech是支持语音打断的,而且它实在是太过于灵敏了,以至于在笔者测试的时候,连笔记本风扇转速过高时都会把它打断,所以在实以生产场景下,最好还是谨慎使用这个功能的好。



本书版权所有 © 杜金房及各位贡献者 2016-2023,仅供在线阅读,谢绝一切形式转载。 本书还在写作中,持续更新。 如果你也想写上几句,欢迎加入我们。 | 返回首页 |