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

《FreeSWITCH案例大全》

5.2 用阿里云的SDM实现一个FreeSWITCH里的“复读”机器人

wandoubaba / 2023-04-01

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

5.2.1 编写脚本

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

--[[
    要使脚本正确运行,需要安装这些包:
    luarocks install xml2lua
]]

--[[
    向终端说“再来”,然后再等待终端发来声音
    @param s    传的是当前会话session
]]
function again(s)
    s:speak("再来")
    s:execute("detect_speech", "unimrcp:aliyun-mrcpserver alimrcp hello")
    s:streamFile("silence_stream://-1");
end

--[[
    session:setInputCallback的回调函数
    @param s        session
    @param type     由FreeSWITCH传递的input-type,可能是dtmf,event等
    @param obj      发生input的消息包,包括消息头和消息体
    @param arg      自定义的参数
]]
function onInput(s, type, obj, arg)
    -- 终端触发了dtmf(按了按键)
    if (type == "dtmf") then
        s:speak("你按到了" .. obj.digit .. "\n")
        again(s)
        -- return "break"
    end
    -- 发生终端输入事件
    if (type == "event") then
        local event = obj:getHeader("Speech-Type")
        -- 触发了begin-speaking事件,也就是发现终端开始说话了
        if (event == "begin-speaking") then
            return ""
        end
        -- 触发了detected-speech事件,也就是发现终端说话结束了
        if (event == "detected-speech") then
            s:execute("detect_speech", "pause")
            local speech_output = obj:getBody() -- 取到事件的消息体,也就是xml类型的语音识别结果
            if (speech_output) then
                results = getResults(speech_output)
                if (results.result ~= nil) then
                    s:speak("" .. results.result .. "\n")   -- 把识别结果再说给终端
                else
                    s:speak("对不起,我没听清你说什么了")
                end
                again(s)    -- 继续下一轮游戏
            end
            return "break"
        else
            s:speak("对不起,我没听见你说什么")
            return "break"
        end
        return "break"
    end
    return "break"
end

--[[
    把mrcp传来的xml识别结果解析成lua的table类型
    @param asrXml   mrcp的语音识别结果
]]
function getResults(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

-- 脚本实际上从这里开始
session:execute("ring_ready", "1000")
-- 播放一个回铃音
session:execute("playback", "tone_stream://%(1850,4150,475,425);loops=1")
-- 接电话
session:answer()
-- 设置input回调和tts参数
session:setInputCallback('onInput', '')
-- zhibei_emo可以换成阿里云的其他发音人
session:set_tts_params("unimrcp:aliyun-mrcpserver", "zhibei_emo")
-- 播放欢迎语
session:speak("嗨~我们玩个游戏吧,你说什么我就说什么,现在开始!")
-- 等待对端说话
session:execute("detect_speech", "unimrcp:aliyun-mrcpserver alimrcp hello")
-- 用无限长静音来使保持会话
session:streamFile("silence_stream://-1");

5.2.2 呼入测试

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

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

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

5.2.3 呼出测试

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

在fs_cli控制台执行命令:

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

至此,你的FreeSWITCH已能“说“而且会“听”了,你可以根据实际业务场景和结合自己的创意,玩出更多花样。



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