将第三方拨号程序与 Dynamics 365 对话智能集成(预览版)
[本文为预发布文档,可能会发生变化。]
通过此集成,Dynamics 365 用户可以使用 Twilio Flex 等第三方电话服务公司提供的拨号程序,在 Dynamics 365 中发出或接收呼叫,并获得实时的 AI 生成的见解和丰富的通话后分析。 了解有关 Dynamics 365 对话智能的更多信息
重要提示
- 这是一项预览功能。
- 预览功能不适用于生产环境,并且可能具有受限的功能。 这些功能受补充使用条款约束,在正式发布之前已经可用,以便客户可以及早使用并提供反馈。
集成的工作原理
在高级别上,集成包括三个部分:
注册提供商:注册提供商详细信息,使用对话智能 API 获取要记录的用户列表。
创建媒体分支:使用 SIPREC 协议将音频流分流到对话智能记录器。
发送实时事件:要启用实时听录和呼叫见解体验,将 UI 事件从提供程序的客户端 UI 发送到 Dynamics 365 对话智能。
有关 Dynamics 365 对话智能与第三方电话服务提供商 Twilio Flex 之间的集成示例,请参阅将 Twilio Flex 与 Dynamics 365 对话智能集成。
下图说明了集成的工作原理:
步骤 1:注册提供商
为媒体记录添加 API 权限:
在您创建的 Microsoft Entra ID 应用程序中,转到 API 权限。
选择添加权限。
在我的组织使用的 API 下,搜索 Dynamics 365 Sales 的媒体记录并选择它:
添加 Users.Read.All 权限,然后选择添加权限
备注
确保获得管理员同意,以允许在应用上下文中调用对话智能 API。 了解有关权限和同意的详细信息。
获取令牌以使用上一节中创建的应用运行对话智能 API:
curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token -d 'client_id=<your app id>' -d 'grant_type=client_credentials' -d 'scope=f448d7e5-e313-4f90-a3eb-5dbb3277e4b3/.default' -d 'client_secret=<your app secret>'
scope
参数指定对话智能应用的应用程序 ID。 不要更改此值。有关 curl 命令的更多信息,请参阅为服务主体获取 Microsoft Entra ID 令牌。
调用以下对话智能 API 来注册第三方服务提供商:
POST /api/v1.0/providers/tenants
在请求正文中指定以下参数:
orgID:指定 Dynamics 365 组织 ID。
类型:为第三方拨号程序指定“自定义”。
托管:指定电话服务提供商的托管类型。 例如,“云”或“本地”。
AccountId:指定电话服务提供商的帐户 ID。
CerfificateSubjectName 和 CertificateIssuer:指定电话服务提供商的证书详细信息。
SourceIPNetwork:指定 SIPREC 客户端的 IP 地址。 如果您不想限制 IP 地址,指定“0.0.0.0”。
以下片段是请求正文的示例:{ "orgId": "ad3dca46-962a-4895-9f85-d25f3828781f", "Type": "custom", "hosting": "cloud", "displayName": "Test Custom Provider", "AuthenticationDetails": { "AccountId":"adxxxxx-xxxx-xxxx-xxxx-xxxxxxxx", "CertificateSubjectName": "certSubject", "CertificateIssuer": "issuer", "SourceIPNetwork": "0.0.0.0" } }
有关 API 的更多信息,请参阅 Swagger 文档。
调用以下对话智能 API 来获取要记录的用户列表:
GET /api/v1.0/providers/users
Dynamics 365 Sales 管理员创建记录策略后,提供商可以使用此终结点来筛选将分流到对话智能记录器的媒体。
步骤 2:创建媒体分支(BSREC 集成)
对话智能记录器实施标准 SIPREC 协议。
使用 SIPS(端口 5061)和 SRTP 协议保护通信的安全。 身份验证在 SIPS 消息连接中使用 mTLS 完成,基于提供给 API 的证书 – 这意味着必须为租户注册提供程序才能建立 SIPS 连接。
以下屏幕截图显示了 SIPREC 客户端和 SIPREC 服务器之间的通信:
对话智能需要以下元数据:
标头:
标头名称 | 描述 | 值示例 |
---|---|---|
Call-ID | 呼叫的唯一标识符。 此 ID 用于将 SIP 信号与用户操作(如开始/停止录制)关联。 | efxxxxxxxxxxxxx |
X-AccountId | 呼叫所属帐户的唯一标识符。 此 ID 用于身份验证和授权。 与在 API 中注册的租户的帐户 ID 相同。 | ACxxxxxxxxxxxxxxxxxxxxxxx |
元数据
元数据键名称 | 描述 | 值示例 |
---|---|---|
角色 | 指示是销售人员的入站呼叫还是出站呼叫。 | ["inbound", "outbound"] |
CallerDisplayName | 呼叫方显示名称。 如果没有,将显示电话号码。 | Kenny Smith |
CalleeDisplayName | 接收方的显示名称。 如果没有,将显示电话号码。 | Alex Baker |
以下是带有所需标头和元数据的邀请和再见消息的示例:
邀请消息:
INVITE sip:SRS@media.recording.dynamics.com:5061;transport=tls SIP/2.0
Via: SIP/2.0/TLS 84.172.x.x:5061;branch=z9hG4bK4fa2.cdabfe83d76d3c41987802096d3b342a.0;received=172.16.x.x;rport=40334
Via: SIP/2.0/UDP 172.25.x.x:5060;rport=5060;branch=z9hG4bK917ce574-0345-4c3d-9b63-d98c2c57dbe6_c3356d0b_599-10236398515455707148
To: <sip:SRS@media.recording.dynamics.com:5061;transport=tls>
From: <sip:SRC@sip.provider.com>;tag=66790678_c3356d0b_917ce574-0345-4c3d-9b63-d98c2c57dbe6
Call-ID: efab0870bc597cb3fb56010921e2f57f
CSeq: 1 INVITE
Contact: <sip:SRC@172.25.x.x:5060;transport=udp>;+sip.src
Max-Forwards: 67
Record-Route: <sip:84.172.x.x:5061;transport=tls;r2=on;lr>,<sip:84.172.x.x;r2=on;lr>
User-Agent: provider Gateway
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,NOTIFY
Require: siprec
Content-Length: 3194
Content-Type: multipart/mixed;boundary=\"----=_Part_1253_283419664.1674116473425\"
Min-SE: 35
X-AccountId: ACxxxxxxxxxxxxxxxxxxxx
------=_Part_1253_283419664.1674116473425
Content-Type: application/sdp
v=0
o=root 1176539620 1176539620 IN IP4 172.18.x.x
s=provider Media Gateway
c=IN IP4 84.172.x.x
t=0 0
m=audio 15352 RTP/SAVP 0 8 101
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:<Encryption_key>
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
a=maxptime:20
a=sendonly
a=label:inbound
m=audio 16022 RTP/SAVP 0 8 101
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:<Encryption_key>
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
a=maxptime:20
a=sendonly
a=label:outbound
------=_Part_1253_283419664.1674116473425
Content-Type: application/rs-metadata+xml
Content-Disposition: recording-session
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<recording xmlns='urn:ietf:params:xml:ns:recording:1'>
<datamode>complete</datamode>
<session session_id=\"Wd/putWgTWCW2z1lI5Db9w==\">
<ExtensionParameters xmlns=\"http://provider.com/siprec\">
<Parameter name=\"Role\" value=\"inbound\"/>
<Parameter name=\"CallerDisplayName\" value=\"Kiana Anderson\"/>
<Parameter name=\"CalleeDisplayName\" value=\"Tomas Richardson\"/>
</ExtensionParameters>
</session>
<participant participant_id=\"bXCloPcETS6P/kfeeJtiow==\">
<nameID aor=\"EE5C7EF0\"/>
</participant>
<participant participant_id=\"3nPi8XzBSzWrtSLlkU8Gjw==\">
<nameID aor=\"230908\"/>
</participant>
<stream stream_id=\"9xff8FcdRUaJCSTxWFbV9g==\" session_id=\"Wd/putWgTWCW2z1lI5Db9w==\"><label>inbound</label></stream>
<stream stream_id=\"f/Qezx4jTMqiWSB1vW7oJA==\" session_id=\"Wd/putWgTWCW2z1lI5Db9w==\"><label>outbound</label></stream>
<sessionrecordingassoc session_id=\"Wd/putWgTWCW2z1lI5Db9w==\">
<associate-time>2023-01-19T08:21:13.382512Z</associate-time>
</sessionrecordingassoc>
<participantsessionassoc participant_id=\"bXCloPcETS6P/kfeeJtiow==\" session_id=\"Wd/putWgTWCW2z1lI5Db9w==\">
<associate-time>2023-01-19T08:21:13.382512Z</associate-time>
</participantsessionassoc>
<participantsessionassoc participant_id=\"3nPi8XzBSzWrtSLlkU8Gjw==\" session_id=\"Wd/putWgTWCW2z1lI5Db9w==\">
<associate-time>2023-01-19T08:21:13.382512Z</associate-time>
</participantsessionassoc>
<participantstreamassoc participant_id=\"bXCloPcETS6P/kfeeJtiow==\">
<send>9xff8FcdRUaJCSTxWFbV9g==</send>
<recv>f/Qezx4jTMqiWSB1vW7oJA==</recv>
</participantstreamassoc>
<participantstreamassoc participant_id=\"3nPi8XzBSzWrtSLlkU8Gjw==\">
<send>f/Qezx4jTMqiWSB1vW7oJA==</send>
<recv>9xff8FcdRUaJCSTxWFbV9g==</recv>
</participantstreamassoc>
</recording>
------=_Part_1253_283419664.1674116473425--
再见消息:
BYE sip:SRS@media.recording.dynamics.com:5061;transport=tls SIP/2.0
Via: SIP/2.0/TLS 84.172.x.x:5061;branch=z9hG4bK1fa2.d03c36b567136fcfae84281e926cda62.0;received=172.16.x.x;rport=40334
Via: SIP/2.0/UDP 172.25.x.x:5060;rport=5060;received=84.144.x.x;branch=z9hG4bK917ce574-0345-4c3d-9b63-d98c2c57dbe6_c3356d0b_600-2513288074170844985
To: <sip:SRS@media.recording.dynamics.com:5061;transport=tls>;tag=OXFWHPJQTL
From: <sip:SRC@sip.provider.com>;tag=66790678_c3356d0b_917ce574-0345-4c3d-9b63-d98c2c57dbe6
Call-ID: efab0870bc597cb3fb56010921e2f57f
CSeq: 2 BYE
Max-Forwards: 68
User-Agent: provider Gateway
Require: siprec
Content-Length: 901
Content-Type: multipart/mixed;boundary=\"----=_Part_29418_1017575873.1674116842924\"
X-AccountId: ACxxxxxxxxxxxxx
支持的记录器终结点和区域
下表列出了支持的记录器终结点及其区域。 您可以在电话服务提供商设置中配置要使用的记录器。 要了解如何为 Twilio Flex 进行配置,请参阅步骤 2:安装 SIPREC 连接器并将呼叫路由到 Dynamics 365。
终结点 | 区域 |
---|---|
media.recording.dynamics.com | 全球(最近的区域) |
southeastasia.media.recording.dynamics.com | 东南亚 |
australiaeast.media.recording.dynamics.com | 澳大利亚 |
sam.media.recording.dynamics.com | 南美 |
canadacentral.media.recording.dynamics.com | 加拿大 |
switzerlandnorth.media.recording.dynamics.com | 瑞士 |
eastus.media.recording.dynamics.com | US |
francecentral.media.recording.dynamics.com | 法国 |
centralindia.media.recording.dynamics.com | 印度 |
japaneast.media.recording.dynamics.com | 日本 |
uae.media.recording.dynamics.com | UAE |
uksouth.media.recording.dynamics.com | 英国 |
westeurope.media.recording.dynamics.com | 西欧 |
zaf.media.recording.dynamics.com | 南非 |
步骤 3:发送实时事件(拨号程序的客户端集成)
为了让对话智能提供实时听录和见解,第三方拨号程序可以使用两个事件来通知呼叫何时开始或结束。
呼叫开始事件:当对话智能收到“呼叫开始”事件时,它将显示记录按钮以及实时听录和见解。
呼叫结束事件:当对话智能收到“呼叫结束”事件时,它将结束呼叫,显示完整摘要按钮,以获得 AI 生成的通话摘要和见解。
要发送事件,使用 Dynamics 365 渠道集成框架 (CIF) 中的 raiseEvent API。
以下是发送事件的示例代码片段:
export interface CallStartedEvent {
callId: string;
startTime: Date;
isIncomingCall: boolean;
contactNumber: string;
contactName: string;
}
export interface CallEndedEvent {
callId: string;
callDurationInSeconds: number;
callTerminationReason: string; // ['success', 'error']
callEndTime: Date;
isCallStarted: boolean;
}
dialer.Actions.addListener('onCallStarted', (payload: any) => {
const callStartedEvent : CallStartedEvent = {
callId: payload.call_sid,
startTime: new Date(),
isIncomingCall: payload.attributes.is_incoming_call,
contactName: payload.attributes.caller_name,
contactNumber: payload.attributes.caller_phone_number
};
// @ts-ignore
Microsoft.CIFramework.raiseEvent('WIDGET_CALL_STARTED', callStartedEvent);
});
dialer.Actions.addListener('onCallEnded', (payload: any) => {
const callEndedEvent : CallEndedEvent = {
callId: payload.call_sid,
callEndTime: new Date(),
callTerminationReason: 'success',
isCallStarted: true,
callDurationInSeconds: payload.attributes.call_length
};
// @ts-ignore
Microsoft.CIFramework.raiseEvent('WIDGET_CALL_ENDED', callEndedEvent);
});
测试集成
在向租户注册新提供商并设置 SIPREC 分支和客户端拨号程序事件后,您可以通过在新提供商创建新记录策略来测试集成。
以系统管理员身份登录销售中心应用。
从更改区域,选择 Sales Insights 设置。
转到全球设置>对话智能。 在呼叫提供商部分,您将看到您已注册的第三方提供商。
为新提供商创建记录策略。 有关详细信息,请参阅为对话智能设置 Microsoft Teams
以下屏幕截图是 Twilio 记录策略的一个示例。
现在,呼叫一个属于所选安全角色的用户(在我们的示例中,为所有安全角色启用了策略)。
当 Dynamics 365 从拨号程序收到 callStarted 事件时,您可以选择开始记录:
选择记录后,您能够看到通话过程中的实时听录,并会在通话结束时看到完整摘要和联络见解。