在React中基于AWS Connect实现外呼语音通话的进阶问询
AWS Connect外呼通话进阶实现(React场景)
你已经成功实现了AWS Connect外呼的基础功能,下面针对你提出的三个进阶需求给出具体实现方案和代码示例:
1. 获取通话状态
要查询外呼通话的状态,可使用AWS Connect的describeContact API,传入发起通话后获取的ContactId和InstanceId即可获取当前通话的状态信息。
代码整合示例
首先在组件中添加状态存储当前通话状态:
const [contactStatus, setContactStatus] = useState(null);
然后添加查询状态的函数:
const checkContactStatus = async () => { if (!apiResponse?.ContactId) return; try { const connect = new AWS.Connect(); const statusResponse = await connect.describeContact({ InstanceId: "--InstanceId--", ContactId: apiResponse.ContactId }).promise(); setContactStatus(statusResponse.Contact.Status); console.log("当前通话状态:", statusResponse.Contact.Status); } catch (error) { console.error("查询通话状态失败:", error); } };
你可以选择定期轮询(比如每3秒查询一次)来实时获取状态,常见的通话状态包括:
IN_PROGRESS:通话进行中COMPLETED:通话已正常结束FAILED:通话发起失败BUSY:被叫方占线NO_ANSWER:无人接听
2. 事件处理:实时响应通话生命周期事件
对于通话过程中的各类事件(接入坐席、通话终止、错误),推荐使用Amazon EventBridge捕获AWS Connect原生事件,再通过Lambda函数将事件推送给前端,实现实时通知。
实现步骤
配置EventBridge规则:
创建规则匹配AWS Connect的通话事件,事件源为aws.connect,重点关注以下事件类型:aws.connect:ContactInitiated:通话发起aws.connect:ContactConnected:通话接通aws.connect:ContactDisconnected:通话终止aws.connect:ContactFailed:通话失败
Lambda函数处理事件:
编写Lambda函数接收EventBridge事件,将事件信息(如ContactId、状态、事件类型)通过WebSocket(如AWS API Gateway WebSocket)或实时数据库(如DynamoDB + AppSync订阅)推送给前端。前端监听事件:
在React组件中建立WebSocket连接,接收推送的事件并更新UI:useEffect(() => { if (!apiResponse?.ContactId) return; const ws = new WebSocket("wss://your-api-gateway-endpoint"); ws.onopen = () => { ws.send(JSON.stringify({ action: "subscribe", contactId: apiResponse.ContactId })); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); console.log("收到通话事件:", data); // 根据事件类型更新状态 if (data.eventType === "ContactDisconnected") { setContactStatus("COMPLETED"); setIsCalling(false); } }; return () => ws.close(); }, [apiResponse]);
另外,也可以在Contact Flow中配置自定义事件,比如通话转接坐席时触发Lambda通知前端,实现更精细化的事件处理。
3. 额外配置与用户体验增强
功能增强配置
- 通话记录:在Contact Flow中启用通话录音,配置将录音文件存储到S3桶,用于复盘或合规需求。
- 错误分支处理:在Contact Flow中添加错误处理节点,处理拨号失败、号码无效、无人接听等场景,返回自定义提示音或触发通知。
- 号码格式验证:前端添加手机号格式校验,避免无效API调用:
const validatePhoneNumber = (num) => { const regex = /^\+[1-9]\d{1,14}$/; return regex.test(num); }; - IAM权限优化:确保IAM角色包含必要权限:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "connect:StartOutboundVoiceContact", "connect:DescribeContact" ], "Resource": "arn:aws:connect:你的区域:你的账号:instance/你的实例ID/*" } ] }
用户体验注意事项
- 状态反馈:在UI中显示当前通话状态(如“拨号中...”、“通话中”、“已结束”),避免用户重复操作。
- 错误提示:将API调用错误转化为用户友好的提示(如“拨号失败,请检查号码格式”)。
- 速率限制:AWS Connect有外呼速率限制,前端可添加节流控制,避免短时间内发起大量呼叫。
- 异常处理:处理网络异常,比如WebSocket断开时自动重连。
整合后的完整代码示例
import AWS from "aws-sdk"; import React, { useState, useEffect } from "react"; function IndexPopup() { const [phoneNumber, setPhoneNumber] = useState(""); const [isCalling, setIsCalling] = useState(false); const [apiResponse, setApiResponse] = useState(null); const [contactStatus, setContactStatus] = useState(null); // 初始化AWS配置 useEffect(() => { AWS.config.update({ region: "--region--" }); }, []); const validatePhoneNumber = (num) => { const regex = /^\+[1-9]\d{1,14}$/; return regex.test(num); }; const makeCall = async () => { if (!validatePhoneNumber(phoneNumber)) { alert("请输入有效的手机号格式"); return; } setIsCalling(true); setContactStatus("DIALING"); try { const connect = new AWS.Connect(); const response = await connect .startOutboundVoiceContact({ DestinationPhoneNumber: phoneNumber, ContactFlowId: "--flowId--", InstanceId: "--InstanceId--" }) .promise(); setApiResponse(response); console.log("通话发起成功:", response); } catch (error) { console.error("API调用错误:", error); setContactStatus("FAILED"); alert(`拨号失败: ${error.message}`); } finally { setIsCalling(false); } }; const checkContactStatus = async () => { if (!apiResponse?.ContactId) return; try { const connect = new AWS.Connect(); const statusResponse = await connect.describeContact({ InstanceId: "--InstanceId--", ContactId: apiResponse.ContactId }).promise(); setContactStatus(statusResponse.Contact.Status); } catch (error) { console.error("查询状态失败:", error); } }; // 定期轮询状态(无EventBridge时的备选方案) useEffect(() => { if (!apiResponse?.ContactId || contactStatus === "COMPLETED" || contactStatus === "FAILED") return; const interval = setInterval(checkContactStatus, 3000); return () => clearInterval(interval); }, [apiResponse, contactStatus]); return ( <div style={{ padding: "20px" }}> <div> <input value={phoneNumber} onChange={(event) => setPhoneNumber(event.target.value)} placeholder="输入手机号(如+1234567890)" style={{ padding: "8px", marginRight: "10px" }} /> <button disabled={isCalling} onClick={makeCall} style={{ padding: "8px 16px" }}> {isCalling ? "拨号中..." : "呼叫"} </button> </div> {contactStatus && ( <div style={{ marginTop: "15px" }}> <strong>当前通话状态:</strong> {contactStatus} </div> )} </div> ); } export default IndexPopup;
内容的提问来源于stack exchange,提问作者Bhumi Lodhari
相关产品推荐
相关产品推荐

