干货 | 携程客服机器人ASR引擎的负载均衡实践

使用阿里funasr作为freeswitch的ASR语音识别服务 要使用unimrcp 必须先编译一个正常的unimrcpserver ,再修改里面的asr语音识别模块。 阅读详情

作者简介

玉修,携程技术专家,专注于电话音视频通信、智能客服机器人等领域。

一、前言

携程拥有庞大的呼叫中心,涉及上万客服人员,覆盖机票、酒店、火车票、度假等产线的售前售后业务,每天的电话业务量超百万通。近年来,通信技术、人工智能技术和智能终端等都在不断革新,我们也一直在思考如何去做更智能化、自动化的呼叫中心,为未来海量的客户需求提供稳定和优质的服务。

携程呼叫中心的智能化包含多个方面:

  • 用户侧:智能在线聊天机器人(IM)、智能语音导航/智能语音客服机器人/智能邀评插件(电话)

  • 客服侧:智能工单和排班系统、智能质检系统、智能客户资源管理系统、服务渠道智能化

  • 系统基建:平台部署智能化、业务监控智能化

本文旨在探讨携程实现呼叫中心电话智能语音客服机器人的基建服务——语音识别服务(即ASR)的负责均衡的演进历程,以及最佳实践。

二、背景

随着人工智能技术的发展,在呼叫中心业务中,传统的 IVR(交互式语音应答)按键导航模式逐步向IVR智能客服机器人转变(客户与IVR机器人进行语音对话的方式来办理业务)。携程呼叫中心系统下的IVR业务也在不断地向电话智能语音机器人转变,目前携程酒店、机票、火车票的国内IVR呼入业务,以及IBU国际英语机票的IVR呼入业务,已经全部由电话智能语音机器人来为客户提供自助服务。

下图是国内酒店业务场景中,客户拨打携程服务热线后,客户与电话机器人通过语音沟通的记录。可以看出,客户顺利完成了“取消订单”的业务办理。

734efcde410f5b169bb24de5d8a1a569.png

智能客服机器人要想实现上图的交互效果,离不开ASR服务的使用,以及功能完善且稳定的呼叫中心系统的支撑。携程呼叫中心的整个平台依赖了众多组件,底层包括CC-Gateway(语音网关)、SBC(会话边际控制服务)、REG(分机注册服务)、SM(会话管理服务)、RS(呼叫路由服务)、CM(呼叫管理服务,基于FreeSWITCH)、ASR(语音识别服务)等系列服务。

下图是携程呼叫中心,客户呼入到智能客服机器人场景,进行语音自助业务办理时所涉及的部分核心组件架构图。

b8d315b3c8c0a1f47166d49d56242e54.png

从上图可以看出,携程呼叫中心系统底层(如FreeSWITCH)调用实时ASR完成语音识别是基于MRCP协议来实现的。我们将上图中涉及ASR使用部分的组件交互进行简化,得出其包含下面3种组件:

  • MRCP客户端:发送RTP和SIP/MRCP的发起者,如FreeSWITCH(下文简称FS

  • MRCP服务端:处理MRCP/SIP信令,接收并转发RTP

  • ASR引擎  :解析RTP,将语音转换成文本,并返回给MRCP Server

7de391e445959f25b53c405291f941a0.png

可以发现,对于呼叫中心ASR调用者而言,只需要关心怎么对接MRCP Server即可,无需关注ASR Engine部分。在实际使用过程中,如果你采购第三方ASR系统进行私有化部署的话(比如科大讯飞ASR、百度ASR),通常MRCP Server和ASR Engine是打包在一起,并部署在同一机器上。

但无论你采购哪家的ASR产品进行集群化部署,厂商都没有提供ASR的负载均衡解决方案,需要客户自行解决。携程为了让ASR引擎具备更高的可用性,采用了多集群、多IDC、多供应商的ASR产品(如携程自研、百度、阿里、微软等)来提供服务。针对这么多的集群和ASR产品,设计出一个调度策略和负载均衡方案来合理有效地利用ASR资源就变得极为重要了。

三、方案探索

目标已经理清,接下来深入分析调用ASR涉及的技术点,看看如何实现目标。

调用MRCP Server包含SIP(UDP/TCP)、MRCP(TCP)、RTP(UDP)三部分,MRCP和RTP的服务端地址是由SIP INVITE的响应 200 OK中SDP指定(如下图),所以只要完成对SIP的负载均衡就能解决另外两个,要给MRCP Server做负载均衡就变成了给 SIP(UDP/TCP)做负载均衡。

我们期望负载均衡的效果是:只要MRCP-Server服务端集群下有多台机器,即使客户端只有一个,负载均衡设备也能将请求均匀分发给服务端的每一个成员。

78086c2db6a32c836802c84b3095c00a.png

常规的负载均衡方案,无外乎基于硬件负载均衡设备实现,如A10(即AX)、F5、NetScaler等;或者基于软负载实现,如LVS、Nginx等。但这些常规方法,都无法真正做到给MRCP Server实现负载均衡。 

携程的基建服务中,恰好有AX、Netscaler、TDLB相关负载均衡服务,所以我们基于这几种基建服务都进行过验证性测试,可惜最终效果都不尽人意。

以FS作为MRCP Client,AX作为负载均衡设备为例。假如只有1台FS设备,1台AX设备,4台MRCP-Server设备。从FS依次发起4次请求,或者同时发起4次请求,最终使ASR驻留并发达到4个。

602493a35eecdec0648e9e2d71938b9c.png

上图是左侧“卖家秀”是我们想要达到的预期效果,右侧“买家秀”是我们实验所得的实际效果,所有的请求都被分配到了同一台MRCP-Server机器上,没能均匀的分配给集群下的各成员。理想很丰满,但现实太骨感。

那么,AX设备没能做到均匀分配的原因是什么呢?FS基于AX来给MRCP做负载又存在什么弊端呢?

首先,对于FS和AX设备相对固定的情况下,SIP请求的IP四元组(Source IP、Source port、Destination IP、Destination port)不会发生变化,因为FS对接MRCP Server时,会在MRCP配置文件中指定客户端和服务端的IP/Port,所以AX每次分配给FS的MRCP Server都是同一台,这显然不符合负载均衡的预期。

其次,电话场景,在收到200 OK后,可能长达半小时不会再有SIP交互,期间的MRCP和RTP都是MRCP-Client和MRCP-Server之间进行直连交互,根本不经过AX设备,而AX设备默认的会话保持时长为120秒,超过这个时间,SIP通道会被AX关闭,这会导致后续的SIP无法送达。

既然此路不通,我们要考虑其他解决方案,经过深入研究和各种尝试,认为下面这两种解决方案比较适合,但各有优缺点:

  • 方案A:通过FreeSWITCH的distributor模块实现

  • 方案B:通过OpenSIPs实现


优点

缺点

方案A

1、无需依赖第三方负载均衡组件

1、配置繁琐复杂

2、MRCP Server节点增删,都需要调整FS配置文件,而且得在无ASR业务时,才能加载生效

3、端口数量消耗大(每个MRCP Server都需要单独分配端口段)

4、负载均衡策略相对单一,只支持按比例分配。而且单机所占有的最小比例不能小于0

方案B

1、配置简单

2、MRCP Server节点增删,只需调整OpenSIPs的DB即可,有ASR调用时,也可更改,实时生效

3、端口数量消耗小(只需要配置一个MRCP Profile文件,多个MRCP Server共用端口段)

4、负载均衡方案多种多样,支持按比例、轮询等多种方式

1、需要依赖第三方负载均衡组件OpenSIPs

我们最终将两个方案结合,来实现负载均衡,FS上使用distributor模块来实现对 OpenSIPs做负载均衡,OpenSIPs上再对MRCP-Server做负载均衡,效果如下:

1)FS、OpenSIPs、MRCP-Server三个组件之间实现了IDC优先就近访问(如上所述,FS未能做到100%的就近访问)。

2)当相同IDC下的下游服务全部不可用时,则自动将流量分配到其他IDC下,如下图,IDC-A 下 FS的ASR请求,优先请求到 IDC-A 的OpenSIPs,然后IDC-A的OpenSIPs再根据分配策略,将请求优先分配给 IDC-A下的MRCP-Server,如果IDC-A下的MRCP-Server全宕机了,会自动分配给IDC-B下的MRCP-Server。

3)负载均衡服务可自动检测下游集群各成员的状态,当某成员服务不可用时自动拉出,服务状态恢复后,再自动拉入。FS和OpenSIPs都是通过发送SIP OPTION 来自动探测下游服务的状态。

36cda0f6aefbd8578e2a550ad74936b0.png

四、方案实践

接下来,我们详细看看每种方案的具体实现方式。以下方案运行环境为:CentOS 7.6、FreeSWITCH 1.6.20、OpenSIPs 2.4.2。

本篇文章中,我们不详细讲解每种方式的实现原理,只介绍解决方法,有兴趣的同学可以自行学习FS和OpenSIPs的相关功能点,这里给出几个链接:

假设我们只有一台FS作为MRCP 客户端,并且MRCP Server 集群中有两台服务器,分别是 mrcp1 和 mrcp2,希望FS针对每一通电话执行ASR命令时,请求可均匀分配给两个MRCP Server。

4.1 基于FS的distributor模块实现MRCP Server的LB

该方案的核心思路如下:

1)FS直接与MRCP  Server对接,为MRCP Server集群下每一个成员配置一个profile

2)将MRCP Server集群下的所有成员配置成 FS 的网关,并开启网关的SIP OPTION探测功能,同时确保gateway的name要与mrcp_profile文件中profile的name一致

3)通过FS的distributor 模块为这些MRCP网关配置负载均衡策略

4)最后,实际执行ASR命令时,先通过 expand eval ${distributor mrcp ${sofia profile external gwlist down}} 负载均衡分配得到一个可用的 MRCP Server Profile的名称,然后用该MRCP Profile的名称作为FS play_and_detect_speech ASR命令的参数即可。

详细的配置步骤如下所示:

第一步:FS与MRCP Server对接 

在 /usr/local/freeswitch/conf/mrcp_profiles/下配置FS对接MRCP Server的文件
tree /usr/local/freeswitch/conf/mrcp_profiles
├── mrcp1.xml
└── mrcp2.xml

下面只给出mrcp1.xml的部分核心配置,只需要确保mrcp1.xml和mrcp2.xml里client-port、rtp-port-min、rtp-port-max配置不同即可。

这里可以看到,如果MRCP Server集群有很多机器,那么这里的RTP端口段可能不够用,一通电话进行ASR解析需要2个端口,一个用来传输RTP、一个传RTCP。

<include>
  <profile name="mrcp1" version="2">   【每个MRCP Server这里配置的名称都不一样,但一定有一个相同名称的网关】
    <param name="client-ip" value="192.168.1.99"/>
    <param name="client-port" value="client-port-1"/>
    <param name="server-ip" value="server-ip-1"/>
    <param name="server-port" value="8060"/>
    <param name="sip-transport" value="tcp"/>   【也可以是UDP哦】
    <param name="rtp-ip" value="192.168.1.99"/>
    <param name="rtp-port-min" value="min-port-1"/>
    <param name="rtp-port-max" value="max-port-1"/>
    <param name="ua-name" value="FreeSWITCH"/>
  </profile>
</include>

第二步:配置FS网关

在 /usr/local/freeswitch/conf/sip_profiles/external/下配置网关对接文件
/usr/local/freeswitch/conf/sip_profiles/external
├── mrcp1.xml
└── mrcp2.xml

mrcp1.xml 的详细配置如下:

<gateway name="mrcp1">  【gateway的name要与mrcp_profile文件中profile的name一致,或可以按照某种规则转换】
        <param name="username" value=""/>
        <param name="proxy" value="mrcp1-server-ip:8060"/>  【当然这里端口可能是其他值】
        <param name="realm" value="mrcp1-server-ip"/>
        <param name="register" value="false"/>
        <param name="rtp-autofix-timing" value="false"/>
        <param name="caller-id-in-from" value="true"/>
        <param name="ping" value="10"/>    【FS给proxy对应地址发送探测的周期】
        <param name="ping-max" value="5"/>
        <param name="ping-min" value="2"/>
</gateway>

第三步:配置FS的distributor模块

vim /usr/local/freeswitch/conf/autoload_configs/distributor.conf.xml
<configuration name="distributor.conf" description="Distributor Configuration">
  <lists>
    <list name="mrcp">  【权重配置成一样,相当于两个MCRP server 按 1:1 分配】
      <node name="mrcp1" weight="5"/>  【node name值与sip gateway 名称相同】
      <node name="mrcp2" weight="5"/>
    </list>
  </lists>
</configuration>

最后,来看看使用效果。按照上述配置,将mrcp2服务宕机后,执行负载均衡的效果如下:

freeswitch@LPT0596> sofia profile external gwlist down   【获取宕机的网关】
mrcp2
freeswitch@LPT0596> expand eval ${distributor mrcp ${sofia profile external gwlist down}}   【将宕机的网关排除在外后,获取分配的SM节点】
mrcp1
freeswitch@LPT0596> expand eval ${distributor mrcp ${sofia profile external gwlist down}}   【如果mrcp2没有宕机,这里将返回mrcp2】
mrcp1


使用得到的MRCP Server Profile名称执行ASR命令:play_and_detect_speech
/usr/local/freeswitch/sounds/ivr_prompt_voice.wav detect:unimrcp:mrcp1 
{start-input-timers=false,no-input-timeout=10000,recognition-timeout=10000}ahlt_ats

其他FS相关命令:

  • reload mod_unimrcp : 修改FS与MRCP server对接的文件后,重新加载生效【只有当前没有正在执行的ASR操作时,才能重加载】

  • sofia profile external rescan : 重新加载FS的网关配置

4.2 基于OpenSIPs实现MRCP Server的LB

4.2.1 核心思路

FS不直接与MRCP Server对接,而是与OpenSIPs进行对接。对接方式是把OpenSIPs配置成一个MRCP profile,文件中的server-ip 和 server-port 地址配置成OpenSIPS 的服务地址即可。

FS执行ASR命令时,先将SIP请求发送给OpenSIPs,再由OpenSIPs负载均衡到MRCP Server集群中的成员,交互的时序图如下:

639776619df1cb705e3a40c9a90c9130.png

4.2.2 方案分析

通过OpenSIPs来实现对MRCP的负载均衡需要解决下面几个问题:

问题1、如何判断收到的INVITE请求是要执行ASR命令,还是普通呼叫命令?

问题2、知道是执行ASR命令后,如何选择MRCP Server,进行分配?

问题3、如果有多套MRCP Server集群,比如一套百度MRCP,一套阿里MRCP,客户端希望能指定引擎使用,该如何解决?

既然已经明确了问题点,那咱就各个击破即可,下面是各问题点的解决方法:

  • 问题1的解决方法

我们来看一条FS发送给OpenSIPs,请求执行MRCP负载均衡的SIP INVITE信息,其中 192.168.1.99是FS,192.168.1.18是OpenSIPs。

INVITE sip:192.168.1.18:5070 SIP/2.0
Via:  SIP/2.0/UDP 192.168.1.99:5102;rport;branch=z9hG4bKQ21yZS46ytrgF
Max-Forwards:  70
From:  <sip:192.168.1.99:5102>;tag=4B8SvQe66FNvc
To:  <sip:192.168.1.18:5070>
Call-ID: ed9f5f6b-0673-123b-199a-fa163e72d95e
CSeq:  47770741 INVITE
Contact:  <sip:192.168.1.99:5102>
User-Agent:  FreeSWITCH
Allow:  INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE
Supported:  timer, 100rel
Content-Type:  application/sdp
Content-Disposition:  session
Content-Length:  306


v=0
o=FreeSWITCH 2480643166757753319 6144298267054033408 IN IP4 192.168.1.99
s=-
c=IN IP4 192.168.1.99
t=0 0
m=application 9 TCP/MRCPv2 1
a=setup:active
a=connection:existing
a=resource:speechrecog
a=cmid:1
m=audio 31799 RTP/AVP 0 8
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=sendonly
a=mid:1

从上面信令可以看到,FS发起的INVITE中,没有主被叫号码信息,只有FS和OpenSIPs的IP和端口信息。如果我们的OpenSIPs只用来给MRCP Server做负载均衡,那么就很简单,收到INVITE请求,都认为是请求执行ASR命令,分配给MRCP Server即可。但是,OpenSIPs只给MRCP Server做负载岂不是大材小用了!

所以,实际我们不会这样使用,OpenSIPs通常还会给其他呼叫中心组件做负载均衡,比如给FreeSWITCH、语音网关、分机注册服务等做LB。这样OpenSIPs就会收到来自各种组件的SIP INVITE请求。那么该如何判断收到的 INVITE 是要执行ASR命令,还是要做其他业务呢?

常规思路,自然是OpenSIPs分析INVITE的SIP消息头,从中进行判断。可是由于FS的mod_unimrcp模块的限制,FS执行ASR命令时,发送的SIP INVITE里不支持增加自定义SIP消息头,所以只能从标准 SIP 消息头中进行挖掘。

  • 根据INVITE请求的源IP:不可行,因为同一个源IP可能发起多种请求的INVITE,比如FS可能是请求执行ASR,也可能是请求呼叫手机;此外,即使可行,源IP也不方便维护。

  • 根据INVITE请求的目的IP:不可行,所有INVITE请求的该值都一样

  • 根据INVITE请求的User-Agent头:可行,OpenSIPs通过$ua就能获取该值。虽然不能针对每次INVITE自定义不同的UA头,但FS对接MRCP Server的Profile中可以指定一个统一的User-Agent头,默认是FreeSWITCH。

  • 根据INVITE请求SDP信息中的‘m’头:可行,OpenSIPs通过$(rb{sdp.line,m})就能获取该值。如 上面报文中“m=application 9 TCP/MRCPv2 1” 里面有MRCPv2,可根据这个判断是执行ASR。

建议使用User-Agent头进行区分,取值方便,效率高。所以,FS对接OpenSIPs时,配置的MRCP Profile时,指定一个特别的User-Agent,比如叫ASR_MRCP_CLIENT_FS,OpenSIPs收到INVITE请求,优先判断UA信息,如果是ASR_MRCP_CLIENT_FS,那么就是要执行ASR命令。

  • 问题2的解决方法

可以使用OpenSIPS的load_balancer 或 dispatcher 模块来实现对 MRCP Server 服务端的负载均衡,两种方式的特点如下:

如果MRCP-Server集群下的成员可支持的并发数不一样,想做到哪台机器剩余的可用资源最多,就优先分配给谁,当各成员可用资源数相同时,在轮训分配,那么可以使用 load_balancer 模块来实现负载均衡;

如果MRCP-Server集群下的成员可支持的并发数完全一样,无差别,那么建议使用dispatcher模块来试想负载均衡,可以做到均匀的将请求分配给每一台服务器。


优点

缺点

load_balancer

可控制每个MRCP Server的最大并发量

支持监控分配给每个MRCP Server的实时并发量

分配策略单一:只支持空闲优先策略分配和按比例分配两种策略,无法支持记忆轮训,这就导致但MRCP Server集群新增成员时,会将流量全部分配给新增的机器,这种情况,新机器的突增压力可能较大

dispatcher    

分配策略多种多样:如支持记忆轮训、Hash分配等

不能控制每个MRCP Server的最大并发量,话务量暴涨时,存在雪崩隐患

不能监控分配给每个MRCP Server的实时并发量(但可以自行通过OpenSIPs其他模块实现)

  • 问题3的解决方法

在FS上为每一套MRCP Server集群,配置一个MRCP Profile并且都指向OpenSIPs,但User-Agent的值配置成不一样,OpenSIPs根据UA的不同,来选择该给哪个集群做LB。

baidu_mrcp_lb.xml  下面只给出特有配置,其他配置被省略了
<include>
  <profile name="baidu_mrcp_lb" version="2">   【阿里的配置,name为ali_mrcp_lb】
    <param name="server-ip" value="opensips-ip"/>
    <param name="ua-name" value="ASR_MRCP_CLIENT_FS_BAIDU"/>    【阿里的配置,ua-name为ASR_MRCP_CLIENT_FS_ALI】
    <param name="sdp-origin" value="FS_MRCP"/>
  </profile>
</include>

OpenSIPs给MRCP Server做负载均衡的处理流程图如下:依赖dialplan模块进行选择具体通过哪个模块来执行LB。

93e1f7438346695d27403c4741252d36.png

4.2.3 具体实现

如果OpenSIPs本身也是集群化部署,那么可以通过本文3.1章节的方法实现对OpenSIPs的负载均衡。

下面代码涉及OpenSIPs对dialplan、dispatcher、load_balancer几个模块的使用,本文不讲解这部分的使用方法。

  • 数据库初始化

说明:

1)下方配置了百度、阿里两个MRCP Server集群,并且每个集群都部署在了两个IDC(IDC_A和IDC_B)

2)OpenSIPs根据dialplan拨号方案来为阿里和百度选择负载均衡的方式,dialplan表中字段“attrs”配置逻辑是:[MRCP集群第一路由的集群ID:负载均衡实现方式:集群名称],如“90:DS:ASR_MRCP_SERVER_CTRIP_ALI”代表,阿里MRCP第一路由的集群ID是90,采用dispacher模块实现LB;"90:DS:ASR_MRCP_SERVER_CTRIP_ALI”代表,百度MRCP第一路由的集群ID是91,采用load_balancer模块实现LB

3)无论是dispacher,还是load_balancer,都配置了单IDC下负载均衡的基础上,增加了逃生路由的功能。集群ID为 90/91代表第一路由,10090/10091代表第二路由

dialplan的attrs字段被赋予了特殊用途
INSERT INTO `dialplan`(`dpid`,`pr`,`match_op`,`match_exp`,`match_flags`,`subst_exp`,`repl_exp`,`timerec`,`disabled`,`attrs`) VALUES
    (90,1000,1,'^ASR_MRCP_CLIENT_CTRIP_FS_ALI$',0,NULL,NULL,NULL,0,'90:DS:ASR_MRCP_SERVER_CTRIP_ALI'),
    (90,1000,1,'^ASR_MRCP_CLIENT_CTRIP_FS_BAIDU$',0,NULL,NULL,NULL,0,'91:LB:ASR_MRCP_SERVER_BAIDU');


dispatcher的attrs字段没有实际作用
INSERT INTO `dispatcher` (`setid`, `destination`, `state`, `weight`, `priority`, `attrs`, `description`) VALUES
    (90, 'sip:192.168.1.190:8060', 0, 1, 100, 'pstn=100', 'IDC_A:ASR_MRCP_SEVER_ALI'),
    (90, 'sip:192.168.1.191:8060', 0, 1, 100, 'pstn=100', 'IDC_A:ASR_MRCP_SEVER_ALI'),
    (10090, 'sip:192.168.2.198:8060', 0, 1, 100, 'pstn=100', 'IDC_B:ASR_MRCP_SEVER_ALI');


load_balancer的resources字段可以控制最大并发数
INSERT INTO `load_balancer`(`group_id`,`dst_uri`,`resources`,`probe_mode`,`description`) VALUES
    (91,'sip:192.168.1.180:8060','pstn=50',2,'IDC_A:ASR_MRCP_SEVER_BAIDU'),
    (91,'sip:192.168.1.181:8060','pstn=50',2,'IDC_A:ASR_MRCP_SEVER_BAIDU'),
    (10091,'sip:192.168.2.188:8060','pstn=50',2,'IDC_B:ASR_MRCP_SEVER_BAIDU');

配置好后,可查看集群内MRCP成员的状态:

sudo /usr/local/opensips/sbin/opensipsctl fifo lb_list
Destination:: sip:192.168.1.180:8060 id=1 group=90 enabled=yes auto-reenable=on
        Resources::
                Resource:: pstn max=50 load=50
Destination:: sip:192.168.1.180:8060 id=2 group=90 enabled=no auto-reenable=on
        Resources::
                Resource:: pstn max=50 load=0
Destination:: sip:192.168.2.188:8060 id=3 group=90 enabled=yes auto-reenable=on
        Resources::
                Resource:: pstn max=50 load=10




sudo /usr/local/opensips/sbin/opensipsctl fifo ds_list
PARTITION:: default
        SET:: 90
                URI:: sip:192.168.1.190:5080 state=Active first_hit_counter=8
                        attr:: pstn=500
                URI:: sip:192.168.1.191:5080 state=Inactive first_hit_counter=0
                        attr:: pstn=500
        SET:: 10090
                URI:: sip:192.168.2.198:8060 state=Active first_hit_counter=0
                        attr:: pstn=100
  • OpenSIPs代码实现

route{
    #省略N多代码...


    # check sip INVITE message source ip and port
    if (is_method("INVITE")) {
        xlog("ua = $ua , callid = $ci, fu = $fu , tu = $tu , ru = $ru , du =$du src:$si, $(rb{sdp.line,m}))");
        $var(dlgPingTag) = "Pp";
        if ( $ua == "ASR_MRCP_CLIENT_FS" ) { #to_asr_mrcp_server
               $var(dlgPingTag) = ""; # ASR 的SIP通道不能做OPTION探测
        }
        if ( !create_dialog("$var(dlgPingTag)") ) {
            route(PRINT_LOG, "create_dialog error :  Internal Server Error");
            send_reply("500","SM Internal Server Error");
            exit();
        }


        if ( $ua =~ "^ASR_MRCP_CLIENT_CTRIP_FS*" ) { #to_asr_mrcp_server 【需要修改FS mrcp client配置文件,<param name="ua-name" value="ASR_MRCP_CLIENT_FS..."/>】
                if ( dp_translate("90", "$ua/$avp(dest)", "$var(attrs)") ) { #拨号方案判断
                        route(exeLb, $(var(attrs){s.int}), "pstn", $(var(attrs){s.select, 1,:}), $(var(attrs){s.select, 2,:}));
                }
        } else { #处理其他呼叫类型,如呼叫手机等
            #省略N多代码...
        }
    }
    exit();
}
#usage : route(exeLb, lb_group_id, resource_type, node_type, lb_method)
#e.g.  route(exeLb, 90, "pstn", "ASR_MRCP_SERVER_ALI", "LB")
#e.g.  route(exeLb, 90, "pstn", "ASR_MRCP_SERVER_ALI", "DS")
route[exeLb]{
    $var(lb_group_id) = $param(1);
    $var(lb_group_id_bak) = $param(1) + 10000;
    $var(resource_type) = $param(2);
    $var(node_type) = $param(3);
    $var(lb_method) = $param(4);


    xlog("[$fU->$rU] Route $rU to '$var(node_type)' by load_balancer group_id : '$var(lb_group_id)' [back_group_id:'$var(lb_group_id_bak)'], resource_type : '$var(resource_type)', node_type : '$var(node_type)' [ci:$ci] [xcid:$hdr(X-CID)]");


    $var(lbRst) = 0;
    if( $var(lb_method) == "DS" ) {
        $var(lbRst) = ds_select_dst("$var(lb_group_id)", "4");
        if($var(lbRst) == -1) {
            xlog("[exeLb4CM] [$fU->$rU] Failed --->lbRst=$var(lbRst) Route $rU to '$var(node_type)' by dispatcher group_id : '$var(lb_group_id)', resource_type : '$var(resource_type)' [ci:$ci]");
            $var(lbRst) = ds_select_dst("$var(lb_group_id_bak)", "4");
            if(!$var(lbRst)) {
                xlog("[exeLb4CM] [$fU->$rU] Failed ===>lbRst=$var(lbRst) Route $rU to '$var(node_type)' by dispatcher [back_group_id:'$var(lb_group_id_bak)'], resource_type : '$var(resource_type)' [ci:$ci]");
                }
        }


    } else {
        $var(lbRst) = lb_start_or_next("$var(lb_group_id)", "$var(resource_type)", "s");
        if( $var(lbRst) < 0) {
            xlog("[$fU->$rU] Failed --->lbRst=$var(lbRst) Route $rU to '$var(node_type)' by load_balancer group_id : '$var(lb_group_id)', resource_type : '$var(resource_type)' [ci:$ci]");
            $var(lbRst) = lb_start("$var(lb_group_id_bak)", "$var(resource_type)", "s");
            if( $var(lbRst) < 0) {
                xlog("[$fU->$rU] Failed ===>lbRst=$var(lbRst) Route $rU to '$var(node_type)' by load_balancer [back_group_id:'$var(lb_group_id_bak)'], resource_type : '$var(resource_type)' [ci:$ci]");
            }
        }


    }


    if ( $var(lbRst) > 0) {
            if ( $rU == null ) {  #对于FS 发起的 MRCP INVITE 请求, $rU 为 null, 而不设置 $rU 将导致 Load balancer 失败,所以需要初始化一个值
                    xlog("[$fU->$rU] rU is null, then initialize to 'Null2Sm' [ci:$ci] [xcid:$hdr(X-CID)]");
                    #$rU = "Null2SM";
                     $ru = "sip:" + $(du{uri.host}) + ":" + $dp;
            } else {
                   $ru = "sip:" + $rU + "@" + $(du{uri.host}) + ":" + $dp;
            }
            xlog("[$fU->$rU] Route to '$var(node_type)' --> [$du] [ci:$ci] [xcid:$hdr(X-CID)]");
            route(relay);
    } else {
            xlog("[$fU->$rU] No available '$var(node_type)' now [ci:$ci] [xcid:$hdr(X-CID)]");
            t_reply("480", "$var(node_type) Unavailable");
            exit();
    }


}

如果按照上面脚本执行了 $ru = "sip:" + $rU + "@" + $(du{uri.host}) + ":" + $dp;,但是$rU== null 并且不设置 $rU="Null2SM"或者其他非空值,会报如下错误:

Feb 12 22:27:35 fat5410 /usr/local/opensips/sbin/opensips[3710]: ERROR:core:parse_uri: bad char '@' in state 0 parsed: <sip:> (4) / <sip:@192.168.1.190:8060> (20)
Feb 12 22:27:35 fat5410 /usr/local/opensips/sbin/opensips[3710]: ERROR:core:parse_sip_msg_uri: bad uri <sip:@192.168.1.190:8060>
Feb 12 22:27:35 fat5410 /usr/local/opensips/sbin/opensips[3710]: ERROR:core:pv_get_ruri_attr: failed to parse the R-URI

解决办法:

1)设置$rU 为一个非空值

2)直接不修改$ru 的值

3)修改 $ru = "sip:" + $(du{uri.host}) + ":" + $dp;

4.2.4 信令记录:

  • FS 发送INVITE给 OpenSIPs

2022-02-13 13:50:53 +0800 : 192.168.1.99:5221 -> 192.168.1.18:5070
INVITE sip:192.168.1.18:5070 SIP/2.0   你可以看到,这里没有被叫号码,所以到了OpenSIPs 后  $rU是null
Via: SIP/2.0/UDP 192.168.1.99:5221;rport;branch=z9hG4bKFUXeX5r0Q0gXp
Max-Forwards: 70
From: <sip:192.168.1.99:5221>;tag=3pU7FrrQBQ1NS
To: <sip:192.168.1.18:5070>
Call-ID: 5c97aeaf-64b4-123a-02b4-fa163ea03f01
CSeq: 38878534 INVITE
Contact: <sip:192.168.1.99:5221>
User-Agent: ASR_MRCP_CLIENT_FS_ALI
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE
Supported: timer, 100rel
Content-Type: application/sdp
Content-Disposition: session
Content-Length: 299


v=0
o=FS_MRCP 1321904497415698834 1659019553944433241 IN IP4 192.168.1.99
s=-
c=IN IP4 192.168.1.99
t=0 0
m=application 9 TCP/MRCPv2 1
a=setup:active
a=connection:new
a=resource:speechrecog
a=cmid:1
m=audio 16416 RTP/AVP 0 8
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=sendonly
a=mid:1
  • OpenSIPS 转发INVITE给 MRCP server

2022-02-13 13:50:53 +0800 : 192.168.1.18:5070 -> 192.168.1.190:8060
INVITE sip:192.168.1.18:5070 SIP/2.0    [如果修改$rU, 这里就是  INVITE sip:Null2SM@192.168.1.18:5070 SIP/2.0]
Record-Route: <sip:192.168.1.18:5070;lr;did=de7.2517abb1>
Via: SIP/2.0/UDP 192.168.1.18:5070;branch=z9hG4bK9443.c1265465.0
Via: SIP/2.0/UDP 192.168.1.99:5221;received=192.168.1.99;rport=5221;branch=z9hG4bKFUXeX5r0Q0gXp
Max-Forwards: 69
From: <sip:192.168.1.99:5221>;tag=3pU7FrrQBQ1NS
To: <sip:192.168.1.18:5070>
Call-ID: 5c97aeaf-64b4-123a-02b4-fa163ea03f01
CSeq: 38878534 INVITE
Contact: <sip:192.168.1.99:5221>
User-Agent:ASR_MRCP_CLIENT_FS_ALI
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE
Supported: timer, 100rel
Content-Type: application/sdp
Content-Disposition: session
Content-Length: 299
X-UUI: &XCID=0dc0196031626864653EXCIDEND
X-CID: 0dc0196031626864653EXCIDEND


v=0
o=FS_MRCP 1321904497415698834 1659019553944433241 IN IP4 192.168.1.99
s=-
c=IN IP4 192.168.1.99
t=0 0
m=application 9 TCP/MRCPv2 1
a=setup:active
a=connection:new
a=resource:speechrecog
a=cmid:1
m=audio 16416 RTP/AVP 0 8
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=sendonly
a=mid:1
  • MRCP Server 回复200 OK,返回后续接收RTP的真实地址

2022-02-13 13:50:53 +0800 : 192.168.1.190:8060 -> 192.168.1.18:5070
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.1.18:5070;branch=z9hG4bK9443.c1265465.0
Via: SIP/2.0/UDP 192.168.1.99:5221;received=192.168.1.99;rport=5221;branch=z9hG4bKFUXeX5r0Q0gXp
Record-Route: <sip:192.168.1.18:5070;lr;did=de7.2517abb1>
From: <sip:192.168.1.99:5221>;tag=3pU7FrrQBQ1NS
To: <sip:192.168.1.18:5070>;tag=45D4K1DvpQQXK
Call-ID: 5c97aeaf-64b4-123a-02b4-fa163ea03f01
CSeq: 38878534 INVITE
Contact: <sip:192.168.1.190:8060>
User-Agent: BaiduSpeech SofiaSIP 1.5.0
Accept: application/sdp
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE
Supported: timer, 100rel
Session-Expires: 600;refresher=uac
Min-SE: 120
Content-Type: application/sdp
Content-Disposition: session
Content-Length: 303


v=0
o=BaiduSpeechServer 8512797916186481341 4497985761629564802 IN IP4 192.168.1.190    【接收RTP的IP】
s=-
c=IN IP4 192.168.1.190
t=0 0
m=application 1544 TCP/MRCPv2 1
a=setup:passive
a=connection:new
a=channel:b250b76cea1011eb@speechrecog
a=cmid:1
m=audio 18380 RTP/AVP 0    【接收RTP的端口】
a=rtpmap:0 PCMU/8000
a=recvonly
a=mid:1
  • FS发送ACK给OpenSIPs

2022-02-13 13:50:53 +0800 : 192.168.1.99:5221 -> 192.168.1.18:5070
ACK sip:192.168.1.190:8060 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.99:5221;rport;branch=z9hG4bKFUXeX5r0Q0gXp
Route:  <sip:192.168.1.18:5070;lr;did=355.53f8e331>
Max-Forwards:  70
From: <sip:192.168.1.99:5221>;tag=3pU7FrrQBQ1NS
To: <sip:192.168.1.18:5070>
Call-ID: 5c97aeaf-64b4-123a-02b4-fa163ea03f01
CSeq:  38878534 ACK
Contact: <sip:192.168.1.99:5221>
Content-Length:  0
  • 最后,OpenSIPs将ACK转发给MRCP Server

五、结语

从上文中提到的携程呼叫中心客户呼入到智能客服机器人场景的核心组件架构图可以看出,ASR引擎的负载均衡只是携程呼叫中心平台各组件中很小的一个功能点,但也是不可或缺的一部分。

正因为有了这个技术方案的实现,使得多集群、多数据中心、多供应商的ASR产品得以很好地整合,为携程电话智能客服机器人业务的稳定运行提供了良好的技术保障,提升了携程客户的通话体验。

本文主要讲解了对于ASR引擎做负载均衡的设计以及实现方案,希望能对从事智能呼叫中心领域工作或研究的同学们提供一些帮助。

【推荐阅读】

bc61a43410889a0d1db7570e882e52c7.jpeg

 “携程技术”公众号

  分享,交流,成长

FreeSWITCH模块详解 该目录下的模块提供了大部分的应用功能,有的模块实现了多种Interface不好归类也会存在该目录中。我们基于FreeSWITCH 1.8版,以自然的顺序来讲解。,大部分模块也都有自己的页面,它们的URL也比较规范,如。各种类型的音、视频编码。大多数名称都很直观,不再多做解释。关于模块的介绍,在官方的Wiki页面上大部分也都能查到。各个模块根据其主要功能和能提供的接口分到不同的目录中。提供自动语音识别及语音合成的功能。查找的,West对应键盘按键。各种Endpoint的实现。各种嵌入式编码语言接口。 阅读详情

相关推荐

携程基于云的软呼叫中心及客服平台架构实践\n

背景及设计理念自携程创立以来,呼叫中心就一直伴随着公司业务一同发展壮大。经过近20年的迭代,目前携程的呼叫中心系统已经演进为第五代呼叫中心系统了,也就是我们完全自主研发的基于FreeSwitch的软交换与IVR、微信Server、邮件系统、无线IM Server的全渠道全媒体客服系统。那么,基于现有可扩展架构的这套客服系统为携程的客服业务提供了什么样的支撑呢?我们可以从以下几个方面一窥全貌。多渠道...

weixin_34351321的博客 914

ASR引擎私有化部署

首先是硬件信息:一般采用的CPU来计算,GPU成本很多企业无法接受,2核心4G一个服务,那么500并发的ASR至少需要1000核2000G内存,还有中间件管理系统等需求20核心32G内存。服务在docker里面运行,这意味着需要启动500多个容器,加上K8S调度使用的资源,CPU按照E2696v4来计算,需要10块*2就是20块cpu,88线程256G内存需要10台服务器。我们拿磐石云ASR引擎部署为例;项目需求500路ASR部署。ASR中文普通话引擎私有化部署一些必备的条件;

qq_43488731的博客 1174

基于555定时器的D类功放设计:从PWM原理到无反馈电路实践

D类功放(数字功放)是一种高效率的音频放大技术,其核心原理是脉冲宽度调制(PWM)。它将输入的模拟音频信号转换为一系列高速开关的脉冲,通过控制功率开关管(如MOSFET)的通断,再经低通滤波器还原放大后的音频。相比传统AB类功放,其转换效率通常超过90%,显著降低了热能损耗。这项技术在追求高能效和小型化的现代音频设备中价值凸显,广泛应用于有源音箱、汽车音响和便携式设备。本文聚焦于一种独特的实现方案:以经典的555定时器芯片为核心,构建一个无整体负反馈的D类功放。通过剖析其PWM调制器、FET电压-电流转换级

weixin_30162121的博客 222

开源(离线)中文语音识别ASR(语音转文本)工具整理

ASRT是一个基于深度学习的语音识别工具,可以用于开发最先进的语音识别系统,是由AI柠檬博主(西安电子科技大学 · 西安市大数据与视觉智能重点实验室)从2016年起做的开源语音识别项目,基线为85%识别准确率,在某些条件下可做到95%左右的识别准确率。ASRT包含了语音识别算法服务端(用于训练或部署API服务)和多种平台及编程语言的客户端SDK,支持一句话识别和实时流式识别,相关的代码已经开源在GitHub和Gitee上。微软语音服务通过 Azure 语音资源提供语音转文本和文本转语音功能。

guigenyi的专栏 1万+

QT编程之PCM音频播放与采集

Qt5/Qt6通用方案。

深之JohnChen的专栏 1171

ORB-SLAM3复现的详细过程——配置安装及ROS和脚本运行---Ubuntu20.04

所提供的图像具有高动态范围,事先进行了光度标定,用20Hz的帧率采集,分辨率为1024像素*1024像素;需要下载数据集dataset-room1_512_16和rgbd_dataset_freiburg1_desk。在一键安装ROS后,只需要再安装Pangolin即可,其他所有的需要都已经存在。用微型飞行器采集的视觉惯性数据集,包含双目相机和IMU同步测量数据及位姿的真值。第二条命令中的${ROS_PACKAGE_PATH}是自己文件的路径。其采用的相机和IMU传感器,在硬件上进行了时间同步。

琉璃轻纱的博客 1万+

freeswitch智能语音开发之ASR

ASR(Automatic Speech Recognition)自动语音识别技术是一种将人的语音转换为文本的技术。一、freeswitch如何使用asrfreeswitch提供两个app功能detect_speech和play_and_detect_speech给用户调用,detect_speech是异步的,play_and_detect_speech是同步的。1、detect_speech1.1语法:mod_name: 识别模块名称 如ali_asr[:params],其中params是param1=v

飞鸟的博客 7119

【STK】手把手教你利用STK进行导弹和反导仿真01 - STK/MMT模块安装部署

【STK】手把手教你利用STK进行导弹和反导仿真01 - STK/MMT模块安装部署MMT模块与STK的版本是一一对应的,比如我现在手上的版本是MMT9的,那么我使用的STK的版本也必须是9版本的,如果你现在正在使用的是更高版本的STK,比如说10、11.2、11.6、12.2,那么该怎么办呢?这个经本人尝试,目前是可以多个STK版本共存的,我们可以根据自己的需要安装多个版本的STK下面开始讲解具体的安装步骤,

weixin_44184852的博客 2919

推荐项目:FreeSWITCH ASR模块 - 开启高效语音处理之旅

推荐项目:FreeSWITCH ASR模块 - 开启高效语音处理之旅 去发现同类优质开源项目:https://gitcode.com/ 在当今智能化语音交互日益普及的时代,【FreeSWITCH ASR模块】犹如一股清流,专为那些对高效语音处理感兴趣的技术探索者准备。该模块是由一位深谙FreeSWITCH与ASR对接之道的开发者倾力打造,旨在降低进入门槛,让开发者无需昂贵投入也能触达先进的人工智能...

gitblog_00072的博客 1027

18、基于FSDD数据集的深度学习案例分析

本文基于FSDD(Free Spoken Digit Dataset)数据集,系统介绍了深度学习在语音数字识别中的应用。内容涵盖动态与静态计算图的对比、数据预处理流程(包括数据增强、固定长度处理和归一化)、监督学习与无监督学习的模型构建与训练过程,并通过实验对比了不同网络架构的性能。文中使用PyTorch实现2层全连接网络和自编码器模型,展示了正则化技术对提升模型准确率的关键作用。最后总结了关键技术并提出了实际应用建议,展望了未来在复杂模型、多模态融合和实时应用方向的发展潜力。

vscode6remote的博客 260

【DaVinci Configurator专题】-5-通过Data Mapping自动创建CAN信号关联的Port并添加到APP SWC

目录 1 导入CAN Matrix变更后的Arxml文件 2 自动创建CAN信号关联的APP Port 3 CAN信号与App SWC的接口映射/连接 4 结尾 <--返回「实战篇」博文-总目录--> <--返回「Autosar从入门到精通-实战篇」专栏主页--> 关键词: DaVinci Developer DaVinci Configurator Pro ARXML AUTOSAR System Description Network Explorer 1

「汽车电子助手」的博客 5130

freeswtich的模块介绍【来自ChatGPT】

applications/mod_valet_parking 提供与虚拟电话交换机(如自动接听与呼叫分配)相关的功能。asr_tts/mod_tts_commandline 允许通过命令行工具实现TTS功能,支持外部语音合成引擎的调用。applications/mod_voicemail_ivr 提供语音邮件与交互式语音响应(IVR)的集成。applications/mod_http_cache 提供HTTP缓存功能,提升Web请求的处理效率。

唯有代码让我痴狂 465

Python学习第1天:初识Python

Python 作为目前最流行的编程语言之一,凭借其简洁优雅的语法和强大的生态系统,成为了无数开发者的首选。本系列文章将带你从零基础入门,逐步掌握 Python 编程的核心技能。今天我们先来认识 Python,并安装好开发环境。Python(英式发音:/ˈpaɪθən/;美式发音:/ˈpaɪθɑːn/)是由荷兰人吉多·范罗苏姆(Guido von Rossum)发明的一种编程语言,是目前世界上最受欢迎和拥有最多用户的编程语言。

tigerhhzz的博客 434

13个最佳开源语音识别引擎

它主要支持日语ASR,但作为一个独立于语言的程序,该模型可以理解和处理多种语言,包括英语,斯洛文尼亚语,法语,泰语等。ESPnet是一个基于Apache 2.0许可证发布的开源语音转文本软件,它提供端到端语音处理功能,涵盖了ASR、翻译、语音合成、增强和日志化等任务。语音识别基本过程一般包括:分析音频、音频分解、格式转换、文本匹配,但实际的语音识别系统可能会更复杂,并且可能包括其他步骤和功能组件,例如:噪声抑制、声学模型、语言模型和置信度评估等。它训练执行转录,翻译,自动语音识别和情感分析任务的语言模型。

9062

Davinci配置临界区Exclusive Area

在Exclusive Area专属区域内的代码段执行不会被中断,可以用于保护多个Runnable间的共享资源。Exclusive Area会对RTE的调度策略和配置进行约束。如果两个或多个Runnable指向同一个Exclusive Area,那么只有其中一个Runnable被允许在该Exclusive Area内执行。即这些Runnable在ExlcusiveArea内执行时不能并发运行(相互抢占)。:在完整执行期间,整个runnable都在临界区运行。:执行期间可以进入临界区。

qq_42851449的博客 506

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

freeswitch对接FunASR实时语音听写

damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404-onnx(nn热词)# damo/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-onnx(时间戳)# 每行一个热词,格式(热词 权重):阿里巴巴 20(注:热词理论上无限制,但为了兼顾性能和效果,建议热词长度不超过10,个数不超过1k,权重1~100)

Java_lilin的专栏 5155

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Freeswitch之ASR(语音识别)总结大全

在做智能外呼的时候要做智能交互的功能,所以就了解了些ASR相关的功能,这里分享下留下的一些资料。根据FS权威指南中Freeswitch使用的第三方模块进行试验,但是效果很不理想,所以如果你想要一个准确率比较好的效果,就需要自己训练声音模型。 1、使用Pocket Sphinx进行英文语音识别 参考:https://wsonh.com/article/60.html 2、PocketSphinx语音...

Magician的博客 1万+

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

ASR 开发入门:使用 C++ 实现高精度语音识别引擎

基于火山引擎豆包大模型,从零搭建一个实时语音通话应用。它不是简单的问答,而是需要你亲手打通 ASR(语音识别)→ LLM(大脑思考)→ TTS(语音合成)的完整 WebSocket 链路。对于想要掌握 AI 原生应用架构的同学来说,这是个绝佳的练手项目。架构理解:掌握实时语音应用的完整技术链路(ASR→LLM→TTS)技能提升:学会申请、配置与调用火山引擎AI服务定制能力:通过代码修改自定义角色性格与音色,实现“从使用到创造”从0到1构建生产级别应用,脱离Demo,点击打开。

2600_94959838的博客 745

ASR技术与Whisper引擎

ASR技术简介及Whisper引擎介绍和入门

R_Here_Waiting的博客 2347

探索未来语音识别的奥秘:Athena——开源全端到端ASR引擎

探索未来语音识别的奥秘:Athena——开源全端到端ASR引擎 Athena 是一个开源的全自动语音识别(Automatic Speech Recognition, ASR)引擎,它支持基于Connectionist Temporal Classification (CTC) 的模型训练和解码,以及Transformer和Hybrid CTC/Attention混合模型。此外,该项目还提供了MPC...

gitblog_00085的博客 1049

一文看懂“语音识别ASR” | AI产品经理需要了解的AI技术概念

是语音交互中最基础的一个AI技术环节,大家可以先在手机上体验siri等各种语音助手,或者各种智能音箱,找找感觉:)本文,是我收集了很多线上/线下的相关信息后,提炼出的不仅帮大家节省了时间,更是过滤了很多无用信息和过于技术的内容。一、核心概念:语音识别ASR、远场语音识别(语音激活检测VAD、语音唤醒、麦克风阵列、全双工、纠错)二、当前技术边界三、瓶颈和机会附:相关资料(文章和书籍)11、(Automatic Speech Recognition),一般简称;是的过程,相当于人类的。1)

优快云_224022的博客 5182

FreeSWITCH FunASR语音识别模块

mod_funasr是一个为 FreeSWITCH 开发的语音识别模块,集成了阿里巴巴的 FunASR(Fun Automatic Speech Recognition)语音识别服务。该模块通过 WebSocket 连接实现实时语音识别功能,支持语音转文本以及相关的语音事件处理。

pzhu1015的专栏 1305

FreeSWITCH 简单图形化界面46 - 收集打包的一些ASR服务

本文介绍了FreeSWITCH中集成ASR(语音识别)服务的方案。提供了4个不同规格的Docker镜像(asr-47m/asr-14m/asr-124m/my-funasr),支持中英文识别。详细说明了镜像下载、运行命令及参数配置方法,并给出实际应用示例:通过mod_audio_fork模块将音频流推送到ASR服务,利用ESL捕获识别结果。最后附有测试视频链接,展示了124M模型的识别效果。文档包含完整的呼叫路由配置、Python脚本以及结果处理说明,帮助用户快速实现语音识别功能集成。

jia198810的博客 1154

Google AI Studio实战:构建智能客服聊天机器人

传统客服系统往往只能处理固定话术,而我们需要的是能理解自然语言、支持多轮对话的智能助手。完成开发后,通过AI Studio生成API接口,用Python写了个简单的Web服务做中转。比如当用户问"怎么退货"后接着问"要收费吗",模型会自动关联到退货政策。部署时遇到个小插曲:最初直接用的开发环境API,结果请求量一大就超限了。比如"退货流程"、"订单查询"、"投诉建议"等,每个类别提供20-30条示例语句。:在AI Studio中选择"对话应用"模板,设置基础参数如对话长度、响应风格等。

ThunderstormLynx23的博客 304

Qwen2.5-0.5B极速对话机器人:多轮对话系统

本文介绍了基于星图GPU平台自动化部署🤖 Qwen/Qwen2.5-0.5B-Instruct 极速对话机器人的实践方案。该轻量级镜像专为CPU环境优化,支持多轮对话与流式输出,适用于智能客服、本地知识助手等边缘计算场景,实现低延迟、高响应的AI交互体验。

weixin_35756624的博客 772
上一篇: 干货 | 携程光网络抵御光缆中断实践
下一篇: 前沿 | 携程商旅在 Atomic Css 下的探索
携程技术
博客等级 码龄10年 3716粉丝 324原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值