CRM 客户关系管理系统 通常是企业为提高核心竞争力,利用相应的信息技术以及互联网技术协调企业与客户间在销售、营销和服务上的交互,从而通过不断的优化,提升企业管理方式,向客户提供创新式的个性化的客户交互和服务的过程。
那么如何来提升客户的体验,来增强客户的归属感,从而让客户认可企业产品,并且不断的吸引新客户,这就到了我们今天的主角上场:腾讯云语音识别(Automatic Speech Recognition,ASR)。
可能到这里,您还是会有点懵,提升客户体验,吸引新客户,怎么就跟ASR 扯上关系了呢?下面我来细细聊聊。
企业和客户之间的纽带是什么?什么样的角色和客户最接近,最能反映客户需求?和客户沟通最多的是什么人?答案就是:电销或者说客服。那么如何提升客户体验,就可以理解为如何提升电销服务水平了。只有电销服务的好,可以解决客户问题,帮助客户做好产品选择,这样才能提升客户对于企业的满意度。
那么如何提升电销人员服务水平,或者如何优化电销人员的沟通技巧,可以让客户更好的接受,这就需要电销管理者通过对电销人员日常工作语音通话的分析总结,不断优化沟通话术,为客户考虑。过去,电销管理者想要了解电销与客户的对话来总结分析什么样的沟通可以促成交易,只能通过不断的听通话记录,每天的工作量很大,对于时长较长的通话,往往容易听到后面忘记前面的内容。那么通过ASR 将语音通话记录转成文字之后,原本需要听10分钟的通话记录,文字只需要10秒就可以提取到核心内容,从而提高电销管理者的工作效率,同时也等于降低了企业时间成本。
经过上面的场景分析后,可能不懂CRM系统的小伙伴还是不太理解 ASR 在这其中的重要性,那么什么是ASR呢?以下是官方的描述:腾讯云语音识别(Automatic Speech Recognition,ASR)是将语音转成文字的 PaaS 产品,能够为企业提供极具性价比的语音识别服务。被微信、王者荣耀、腾讯视频等大量内部业务使用,外部亦服务于呼叫中心录音转写、会议实时转写、语音输入法、数字人、互动直播、课堂内容分析等多个业务场景,产品具备丰富的行业落地经验。
在体验腾讯云语音识别 ASR之前,需要先开通ASR 服务:https://cloud.tencent.com/product/asr?from_column=20421&from=20421 新用户的话可以直接免费领取体验资格
点击【免费领取】跳转到 ASR 控制台,勾选协议,点击【立即开通】
开通成功
开通语音识别 ASR 后,点击控制台的【功能体验】找一段电话语音通话记录,在线体验一下识别效果
这里选择【音频类别】为电话 8k,上传本地语音文件后点击【开始识别】等待识别显示【识别成功】后点击【下载】按钮,下载识别成功后的文本内容
整体识别的文本内容与实际通话内容没有太大差异,识别效果很不错。
这里同样的语音文件,我再切换一下 语音识别 ASR 新上线的识别类型【大模型语音识别】看一下识别的效果,
不知道什么原因,第一次【大模型语音识别】失败了
又尝试了几次,还是没有成功,后来才发现原来使用【大模型语音识别】需要先购买资源包,没有免费调用资格
希望后续官方可以在下方的文件识别列表中详细说明一下失败的原因,比如:未购买资源包。这样可以防止用户以为是操作失误而导致的语音识别结果失败。
对于语音识别类型产品,通常都是需要有热词存在的,毕竟语音识别对于一些专有名词的识别或者生僻词组的识别效果会不那么好,这个时候你就可以通过配置热词来提高识别准确度。
点击【热词】,选择【新建热词表】
点击【热词使用文档】先来了解一下热词具体如何添加
关于热词功能,腾讯云语音识别 ASR 开放了 通用热词、超级热词、热词增强版三个维度的热词能力,关于热词设置的这几个数值需要牢记
然后回到热词添加页面,选择【点击下载样例】,比如我这里增加一个热词,将 东奥 替换成 冬奥
添加热词成功后如图
再次进行语音识别,识别刚才的本地文件,选择【关联已有热词】
勾选我们刚才添加成功的热词 【冬奥】点击【确定】
再次识别刚才上传的文件,查看文件内容
看来还是正确的 东奥 识别更对啊,改成错误的 冬奥 之后没有替换原来的 东奥,后续大家可以拿语音识别中错误的专业词汇更改成正确的专业词汇后尝试,看是否可以正确替换,这里我就不再把对的往错误的改了,哈哈。
这里我将会采用API接入的方式来使用腾讯云语音识别ASR能力,那么在接入之前首先来看一下API文档:https://cloud.tencent.com/document/product/1093/35637 方便后续查找需要用到的 API 接口,这里我主要用到的是
在接入语音识别API到项目之前,首先需要创建密钥
进入访问管理控制台:https://console.cloud.tencent.com/cam/capi 点击【API密钥管理】,选择【新建密钥】,在弹出的页面点击 复制 可以保存密钥 SecretId 和 SecretKey 信息
关于录音文件识别相关接口,其中 录音文件识别请求 接口主要是识别您上传的录音文件,而 录音文件识别结果查询 主要是获取识别录音文件成功后的文本内容文档。
录音文件识别请求 接口文档:https://cloud.tencent.com/document/api/1093/37823
录音文件识别结果查询 接口文档:https://cloud.tencent.com/document/api/1093/37822
为了方便用户调用,官方还提供了录音文件识别回调方式,有需要的用户可以参考,具体文档地址:https://cloud.tencent.com/document/api/1093/52632
下面我们来尝试在线调试后续项目中需要用到的【录音文件识别请求】
【录音文件识别结果查询】
点击【点击调试】进入到在线接口调试页面
输入 录音识别文件请求 CreateRecTask 接口文档要求的必传参数后 点击发起调用,这里关于入参 Data 由于本人这里没有在线的录音文件地址,希望后续在线调试页面可以在 入参 Data 处增加上传文件按钮,选择本地文件上传成功后自动转化为Data数据供在线调试接口使用
这里我没有可以公网访问的通话录音文件,因此这里就先不进行在线调试了,直接进入后面的项目接入操作。
在CRM 客户关系管理系统后台增加功能菜单,电销重要录音查询,如图
列表中整体数据来自于电销通话记录,以及隐藏的字段通话录音文件地址,点击按钮【上传】会调用腾讯云语音识别ASR 接口 【录音文件识别请求】,点击按钮【获取结果】会调用 腾讯云语音识别ASR 接口 【录音文件识别结果查询】并将识别结果保存在数据库中。
按钮【会话详情】则展示本次通话记录中双方的详细通话文本内容
这里用到两张表,设计表 asr_call_record 用来记录发起 【录音文件识别请求】 的接口相关数据,
CREATE TABLE `asr_call_record` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`call_record_id` varchar(32) DEFAULT NULL COMMENT '通话记录id',
`call_user_id` bigint(20) DEFAULT NULL COMMENT '外呼人',
`resource_url` varchar(500) DEFAULT NULL COMMENT '资源文件地址',
`start_time` datetime DEFAULT NULL COMMENT '开始时间',
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
`bridge_duration` bigint(20) DEFAULT NULL COMMENT '双方通话时长(单位:秒)',
`total_duration` bigint(20) DEFAULT NULL COMMENT '总通话时长(单位:秒)',
`service_provider` tinyint(2) DEFAULT NULL COMMENT '服务提供方0.科大讯飞1.腾讯',
`asr_status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '转写状态0.未转写1.已转写2.转写中',
`asr_order_id` varchar(255) DEFAULT NULL COMMENT '转写结果id',
`create_user_id` bigint(20) DEFAULT NULL COMMENT '创建人',
`create_time` datetime NOT NULL DEFAULT NULL COMMENT '创建时间',
`update_user_id` bigint(20) DEFAULT NULL COMMENT '更新人',
`update_time` datetime NOT NULL DEFAULT NULL COMMENT '更新时间',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_start_time` (`start_time`) USING BTREE,
KEY `idx_call_record_id` (`call_record_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='asr通话记录';
设计表 asr_call_record_detail 用来记录发起 【录音文件识别结果查询】接口请求获取转写后文本内容的记录
CREATE TABLE `asr_call_record_detail` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`asr_id` bigint(20) DEFAULT NULL COMMENT '转写通话记录id',
`sort` int(10) DEFAULT NULL COMMENT '排序',
`content` text COMMENT '段落内容',
`speaker` varchar(20) DEFAULT NULL COMMENT '说话方',
`start_point` bigint(20) DEFAULT NULL COMMENT '开始节点',
`end_point` bigint(20) DEFAULT NULL COMMENT '结束节点',
`lid` varchar(20) DEFAULT NULL COMMENT 'lid',
`create_user_id` bigint(20) DEFAULT NULL COMMENT '创建人',
`create_time` datetime NOT NULL DEFAULT NULL COMMENT '创建时间',
`update_user_id` bigint(20) DEFAULT NULL COMMENT '更新人',
`update_time` datetime NOT NULL DEFAULT NULL COMMENT '更新时间',
`remark` text COMMENT '备注',
`del_flag` tinyint(2) NOT NULL DEFAULT '0' COMMENT '逻辑删除0.有效2.删除',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_asr_id` (`asr_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='asr转写内容';
这里主要记录代码实现的大致框架,并不是全部的代码内容。首先实现按钮【上传】功能,上传功能需要获取通话录音文件URL,并传入接口 【录音文件识别请求】创建一个语音识别任务 controller 类增加方法
/**
* 上传三方进行转写
*
* @param asrId asr表id
* @param serviceProvider 区分语音转写平台
* @return
*/
@PostMapping("/asr/upload")
@ResponseBody
public AjaxResult upload(@RequestParam("asrId") Long asrId, @RequestParam("serviceProvider") Integer serviceProvider) {
AsrCallRecord asrCallRecord = asrCallRecordService.selectAsrCallRecordById(asrId);
// 多次上传转写,删除历史数据
if ( Integer.valueOf(1).equals(asrCallRecord.getAsrStatus()) ) {
asrCallRecordDetailService.removeAsrCallRecordDetailByAsrId(asrId);
}
//获取具体转写平台对应的实现类
IAsrTemplate asrTemplate = asrTemplateFactory.getAsrTemplate(serviceProvider);
CreateTaskResultModel result = asrTemplate.createTask(asrCallRecord.getResourceUrl());
if ( result.getCode() != 1 ) {
return AjaxResult.error("失败,未知异常,请联系管理员", result);
}
//更新操作到转写记录表
AsrCallRecord update = new AsrCallRecord();
update.setId(asrId);
update.setAsrStatus(2);
update.setAsrOrderId(result.getTaskId());
update.setUpdateUserId(ShiroUtils.getUserId());
update.setUpdateTime(new Date());
update.setServiceProvider(serviceProvider);
asrCallRecordService.updateAsrCallRecord(update);
return AjaxResult.success("上传成功,请等待片刻后,手动获取转写结果");
}
其中创建语音识别任务方法如下 createTask
public CreateTaskResultModel createTask(String resourceUrl) {
if (StrUtil.isEmpty(resourceUrl)) {
throw new IllegalArgumentException("resourceUrl 不能为空");
}
CreateTaskResultModel createTaskResultModel = new CreateTaskResultModel();
createTaskResultModel.setCode(-1);
createTaskResultModel.setMsg("失败,未知异常");
//获取加密参数 secretId secretKey
JSONObject config = getConfig();
String secretId = config.getString("secretId");
String secretKey = config.getString("secretKey");
try{
// 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
// 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305
// 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
Credential cred = new Credential(secretId, secretKey);
// 实例化一个http选项,可选的,没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("asr.tencentcloudapi.com");
// 实例化一个client选项,可选的,没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
AsrClient client = new AsrClient(cred, "", clientProfile);
// 实例化一个请求对象,每个接口都会对应一个request对象
CreateRecTaskRequest req = new CreateRecTaskRequest();
// 请求参数
req.setUrl(resourceUrl);
req.setEngineModelType("8k_zh");
req.setChannelNum(1L);
// 识别结果返回形式。0: 识别结果文本(含分段时间戳); 1:词级别粒度的详细识别结果(不含标点,含语速值);2:词级别粒度的详细识别结果(包含标点、语速值);3: 标点符号分段,包含每段时间戳,特别适用于字幕场景(包含词级时间、标点、语速值)。4:【付费功能】将对ASR结果按照语义分段,并展示词级别粒度的详细识别结果(注意:如果开启后付费,将自动计费)
req.setResTextFormat(2L);
// 0:语音 URL;1:语音数据(post body)。
req.setSourceType(0L);
req.setSpeakerDiarization(1L);
req.setSpeakerNumber(2L);
// 自学习模型
//req.setCustomizationId("79882fef1c7211ee9c9d446a2eb5fd98");
//是否过滤语气词(目前支持中文普通话引擎)。0:不过滤语气词;1:部分过滤;2:严格过滤 。默认值为 0。
req.setFilterModal(0L);
// 情绪能量值,取值为音量分贝值/10。取值范围:[1,10]。值越高情绪越强烈。0:不开启,1:开启
req.setEmotionalEnergy(1L);
// 热词增强功能。1:开启后(仅支持8k_zh,16k_zh),将开启同音替换功能,同音字、词在热词中配置。举例:热词配置“蜜制”并开启增强功能后,与“蜜制”同拼音(mizhi)的“秘制”的识别结果会被强制替换成“蜜制”。因此建议客户根据自己的实际情况开启该功能。
req.setReinforceHotword(1L);
// 情绪识别能力(目前支持16k_zh) 默认为0,不开启。 1:开启情绪识别但是不会在文本展示“情绪标签”, 2:开启情绪识别并且在文本展示“情绪标签”。(该功能需要设置ResTextFormat 大于0)
req.setEmotionRecognition(0L);
// 返回的resp是一个CreateRecTaskResponse的实例,与请求对象对应
CreateRecTaskResponse resp = client.CreateRecTask(req);
createTaskResultModel.setApiResult(CreateRecTaskResponse.toJsonString(resp));
Optional.ofNullable(resp)
.map(CreateRecTaskResponse::getData)
.map(Task::getTaskId)
.ifPresent(taskId->{
createTaskResultModel.setCode(1);
createTaskResultModel.setMsg("成功");
createTaskResultModel.setTaskId(String.valueOf(taskId));
});
} catch (TencentCloudSDKException e) {
Cat.logError("腾讯asr上传转写资源异常:", e);
}
return createTaskResultModel;
}
到这里,关于上传按钮创建语音识别任务接口的相关代码大致就写完了,细节大家可以根据具体场景补充,下面开始介绍获取语音识别结果 【录音文件识别结果查询】 接口的相关代码 controller 增加方法
/**
* 获取三方转写结果
*
* @param asrId asr表id
* @return
*/
@PostMapping("/asr/getResult")
@ResponseBody
public AjaxResult getResult(@RequestParam("asrId") Long asrId) {
AsrCallRecord asrCallRecord = asrCallRecordService.selectAsrCallRecordById(asrId);
if ( Integer.valueOf(1).equals(asrCallRecord.getAsrStatus()) ) {
return AjaxResult.success("已保存转写结果,请刷新查看");
}
if ( Objects.isNull(asrCallRecord.getAsrOrderId()) ) {
return AjaxResult.success("录音未上传,不能取转写结果!");
}
Integer serviceProvider = asrCallRecord.getServiceProvider();
IAsrTemplate asrTemplate = asrTemplateFactory.getAsrTemplate(serviceProvider);
GetResultModel result = asrTemplate.getResult(asrCallRecord.getAsrOrderId());
if ( result.getCode() != 1 ) {
return AjaxResult.error(result.getMsg(), result);
}
return toAjax(asrCallRecordService.saveAsrResult(asrId, result.getParaList()));
}
其中,请求语音识别 【录音文件识别结果查询】 接口 获取语音识别结果方法 getResult 代码
public GetResultModel getResult(String taskId) {
if (StrUtil.isEmpty(taskId)) {
throw new IllegalArgumentException("taskId 不能为空");
}
GetResultModel getResultModel = new GetResultModel();
getResultModel.setCode(-1);
getResultModel.setMsg("失败,未知异常");
JSONObject config = getConfig();
String secretId = config.getString("secretId");
String secretKey = config.getString("secretKey");
try{
// 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
// 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305
// 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
Credential cred = new Credential(secretId, secretKey);
// 实例化一个http选项,可选的,没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("asr.tencentcloudapi.com");
// 实例化一个client选项,可选的,没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
AsrClient client = new AsrClient(cred, "", clientProfile);
// 实例化一个请求对象,每个接口都会对应一个request对象
DescribeTaskStatusRequest req = new DescribeTaskStatusRequest();
req.setTaskId(Long.valueOf(taskId));
// 返回的resp是一个DescribeTaskStatusResponse的实例,与请求对象对应
DescribeTaskStatusResponse resp = client.DescribeTaskStatus(req);
getResultModel.setApiResult(CreateRecTaskResponse.toJsonString(resp));
TaskStatus data = resp.getData();
// 任务状态码,0:任务等待,1:任务执行中,2:任务成功,3:任务失败。
if ( data.getStatus() == 0 || data.getStatus() == 1 ) {
getResultModel.setCode(-1);
getResultModel.setMsg("转写中,请稍后再试!");
return getResultModel;
}
if ( data.getStatus() == 2 ) {
SentenceDetail[] paras = data.getResultDetail();
// each para:[0:35.660,0:38.360,0] 嗯,对,我我我还没有时间去看呢。
List<GetResultParaModel> paraModels = new ArrayList<>();
for (SentenceDetail para : paras) {
GetResultParaModel paraModel = new GetResultParaModel();
paraModel.setContent(para.getFinalSentence());
paraModel.setSpeaker("段落-".concat(String.valueOf(para.getSpeakerId())));
paraModel.setStartPoint(para.getStartMs());
paraModel.setEndPoint(para.getEndMs());
paraModel.getUserFields().put("speechSpeed", para.getSpeechSpeed());
paraModel.getUserFields().put("emotionalEnergy", para.getEmotionalEnergy());
paraModel.setApiResult(JSON.toJSONString(para));
paraModels.add(paraModel);
}
getResultModel.setCode(1);
getResultModel.setMsg("成功");
getResultModel.setParaList(paraModels);
}
} catch (TencentCloudSDKException e) {
Cat.logError("腾讯asr获取转写结果异常:", e);
}
return getResultModel;
}
saveAsrResult 方法用于保存语音识别返回的结果到数据库中
public int saveAsrResult(Long asrId, List<GetResultParaModel> paraList) {
asrCallRecordDetailService.removeAsrCallRecordDetailByAsrId(asrId);
AsrCallRecord update = new AsrCallRecord();
update.setId(asrId);
update.setAsrStatus(1);
update.setUpdateUserId(ShiroUtils.getUserId());
update.setUpdateTime(new Date());
int i = asrCallRecordMapper.updateAsrCallRecord(update);
int sort = 0;
for (GetResultParaModel paraModel : paraList) {
AsrCallRecordDetail insert = new AsrCallRecordDetail();
insert.setAsrId(asrId);
insert.setSort(++sort);
insert.setContent(paraModel.getContent());
insert.setSpeaker(paraModel.getSpeaker());
insert.setStartPoint(paraModel.getStartPoint());
insert.setEndPoint(paraModel.getEndPoint());
insert.setLid(MapUtil.getStr(paraModel.getUserFields(), "lid"));
insert.setCreateUserId(update.getUpdateUserId());
insert.setCreateTime(new Date());
insert.setUpdateUserId(update.getUpdateUserId());
insert.setUpdateTime(new Date());
insert.setRemark(paraModel.getApiResult());
insert.setDelFlag(Constants.DEL_FLAG.YES.getValue());
asrCallRecordDetailService.insertAsrCallRecordDetail(insert);
}
return i;
}
到这里,关于腾讯云语音识别ASR 接入项目实践的全部内容就结束了,整体上实现过程比较简单,对于语音识别ASR两个接口的调用代码也可以直接从 在线调试 页面中获取示例代码,接入的学习成本还是可控的。
其实对于语音识别ASR的应用场景,除了本文介绍的CRM 客户关系管理系统中需要用到外,其他的场景比如语音转写功能(王者荣耀、英雄联盟、微信、QQ等)都是有应用空间的,接入的方式也有很多种,包括API接入、SDK接入等,官方文档关于接入操作的说明描述的也是比较清晰,文档地址:https://cloud.tencent.com/document/product/1093/35637 ,有需要的可以放心接入哦。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。