Pastaba
Prieigai prie šio puslapio reikalingas įgaliojimas. Galite bandyti prisijungti arba pakeisti katalogus.
Prieigai prie šio puslapio reikalingas įgaliojimas. Galite bandyti pakeisti katalogus.
Naudodami daugiakanalį ryšį, skirtą klientų aptarnavimui, galite įdiegti jungtį, skirtą integruoti pasirinktinius pranešimų kanalus naudodami "Direct Line API 3.0", kuri yra .NET SDK dalis. Visas kodo pavyzdys iliustruoja, kaip galite sukurti savo jungtį. Norėdami sužinoti daugiau apie tiesioginės linijos API 3.0, žiūrėkite Pagrindinės tiesioginės eilutės 3.0 API sąvokos.
Šiame straipsnyje paaiškinama, kaip kanalas yra prijungtas prie "Microsoft Direct Line Bot Framework", kuri yra viduje prijungta prie daugiakanalio, skirto klientų aptarnavimo tarnybai. Šiame skyriuje pateikiami kodo fragmentai, kurie naudoja "Direct Line API 3.0", kad sukurtų "Direct Line" klientą, ir sąsają, IChannelAdapter
kad sukurtų pavyzdinę jungtį.
Pastaba
Šaltinio kode ir dokumentacijoje aprašomas bendras srautas, kaip kanalas gali prisijungti prie daugiakanalio, skirto klientų aptarnavimui per tiesioginę liniją, ir nekreipiamas dėmesys į patikimumo ir mastelio keitimo aspektus.
Komponentai
Adapterio "Webhook" API paslauga
Kai vartotojas įveda pranešimą, adapterio API iškviečiamas iš kanalo. Jis apdoroja gaunamą užklausą ir kaip atsakymą siunčia sėkmės arba nesėkmės būseną. Adapterio API paslauga turi įdiegti IChannelAdapter
sąsają ir siunčia gaunamą užklausą į atitinkamą kanalo adapterį, kad apdorotų užklausą.
/// <summary>
/// Accept an incoming web-hook request from MessageBird Channel
/// </summary>
/// <param name="requestPayload">Inbound request Object</param>
/// <returns>Executes the result operation of the action method asynchronously.</returns>
[HttpPost("postactivityasync")]
public async Task<IActionResult> PostActivityAsync(JToken requestPayload)
{
if (requestPayload == null)
{
return BadRequest("Request payload is invalid.");
}
try
{
await _messageBirdAdapter.ProcessInboundActivitiesAsync(requestPayload, Request).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.LogError($"postactivityasync: {ex}");
return StatusCode(500, "An error occured while handling your request.");
}
return StatusCode(200);
}
Kanalų adapteriai
Kanalo adapteris apdoroja gaunamą ir siunčiamą IAdapterBuilder
veiklą ir turi įdiegti sąsają.
Gaunamų veiklų apdorojimas
Kanalo adapteris atlieka šias gavimo veiklas:
- Patikrinkite gaunamo laiško užklausos parašą.
Gaunama užklausa iš kanalo patvirtinama pagal pasirašymo raktą. Jei užklausa negalioja, pateikiamas "negaliojančio parašo" išimties pranešimas. Jei prašymas galioja, jis atliekamas taip:
/// <summary>
/// Validate Message Bird Request
/// </summary>
/// <param name="content">Request Content</param>
/// <param name="request">HTTP Request</param>
/// <param name="messageBirdSigningKey">Message Bird Signing Key</param>
/// <returns>True if there request is valid, false if there aren't.</returns>
public static bool ValidateMessageBirdRequest(string content, HttpRequest request, string messageBirdSigningKey)
{
if (string.IsNullOrWhiteSpace(messageBirdSigningKey))
{
throw new ArgumentNullException(nameof(messageBirdSigningKey));
}
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}
if (string.IsNullOrWhiteSpace(content))
{
throw new ArgumentNullException(nameof(content));
}
var messageBirdRequest = new MessageBirdRequest(
request.Headers?["Messagebird-Request-Timestamp"],
request.QueryString.Value?.Equals("?",
StringComparison.CurrentCulture) != null
? string.Empty
: request.QueryString.Value,
GetBytes(content));
var messageBirdRequestSigner = new MessageBirdRequestSigner(GetBytes(messageBirdSigningKey));
string expectedSignature = request.Headers?["Messagebird-Signature"];
return messageBirdRequestSigner.IsMatch(expectedSignature, messageBirdRequest);
}
- Konvertuokite gaunamą užklausą į roboto veiklą.
Gaunamos užklausos naudingoji apkrova konvertuojama į veiklą, kurią gali suprasti "Bot Framework".
Pastaba
Veiklos naudingoji apkrova neturi viršyti 28 KB pranešimo dydžio apribojimo.
Šiame veiklos objekte yra šie atributai:
Atributas | Aprašas |
---|---|
iš | Saugo kanalo paskyros informaciją, kurią sudaro unikalus vartotojo identifikatorius ir vardas (vardo ir pavardės derinys, atskirtas tarpo skyrikliu). |
channelId | Nurodo kanalo identifikatorių. Gaunamų užklausų kanalo ID yra directline . |
serviceUrl | Nurodo paslaugos URL. Gaunamų užklausų paslaugos URL yra https://directline.botframework.com/ . |
rūšis | Nurodo veiklos tipą. Pranešimų veiklos tipas yra message . |
SMS žinutė | Saugo laiško turinį. |
Id | Nurodo identifikatorių, kurį adapteris naudoja atsakydamas į siunčiamus pranešimus. |
kanalasDuomenys | Nurodo kanalo duomenis, kuriuos sudaro channelType , conversationcontext ir customercontext . |
channelType | Nurodo kanalo, kuriuo klientas siunčia pranešimus, pavadinimą. Pavyzdžiui, "MessageBird", "KakaoTalk", "Snapchat" |
pokalbio kontekstas | Nurodo žodyno objektą, kuriame yra darbo sraute apibrėžti konteksto kintamieji. Daugiakanalis kanalas, skirtas klientų aptarnavimo tarnybai, naudoja šią informaciją, kad nukreiptų pokalbį tinkamam klientų aptarnavimo atstovui (aptarnavimo atstovui arba atstovui). Pavyzdys. "pokalbiskontekstas ":{ "Produkto pavadinimas": "Xbox", "Problema":"Diegimas" } Šiame pavyzdyje kontekstas nukreipia pokalbį į tarnybos atstovą, kuris užsiima "Xbox" diegimu. |
kliento kontekstas | Nurodo žodyno objektą, kuriame yra išsami kliento informacija, pvz., telefono numeris ir el. pašto adresas. "Customer Service" daugiakanalis naudoja šią informaciją vartotojo kontakto įrašui identifikuoti. "customercontext":{ "email":email@email.com, "phonenumber":"1234567890" } |
/// <summary>
/// Build Bot Activity type from the inbound MessageBird request payload<see cref="Activity"/>
/// </summary>
/// <param name = "messagePayload"> Message Bird Activity Payload</param>
/// <returns>Direct Line Activity</returns>
public static Activity PayloadToActivity(MessageBirdRequestModel messagePayload)
{
if (messagePayload == null)
{
throw new ArgumentNullException(nameof(messagePayload));
}
if (messagePayload.Message?.Direction == ConversationMessageDirection.Sent ||
messagePayload.Type == ConversationWebhookMessageType.MessageUpdated)
{
return null;
}
var channelData = new ActivityExtension
{
ChannelType = ChannelType.MessageBird,
// Add Conversation Context in below dictionary object. Please refer the document for more information.
ConversationContext = new Dictionary<string, string>(),
// Add Customer Context in below dictionary object. Please refer the document for more information.
CustomerContext = new Dictionary<string, string>()
};
var activity = new Activity
{
From = new ChannelAccount(messagePayload.Message?.From, messagePayload.Contact?.DisplayName),
Text = messagePayload.Message?.Content?.Text,
Type = ActivityTypes.Message,
Id = messagePayload.Message?.ChannelId,
ServiceUrl = Constant.DirectLineBotServiceUrl,
ChannelData = channelData
};
return activity;
}
JSON naudingosios apkrovos pavyzdys yra toks:
{
"type": "message",
"id": "bf3cc9a2f5de...",
"serviceUrl": https://directline.botframework.com/,
"channelId": "directline",
"from": {
"id": "1234abcd",// userid which uniquely identify the user
"name": "customer name" // customer name as First Name <space> Last Name
},
"text": "Hi,how are you today.",
"channeldata":{
"channeltype":"messageBird",
"conversationcontext ":{ // this holds context variables defined in Workstream
"ProductName" : "XBox",
"Issue":"Installation"
},
"customercontext":{
"email":email@email.com,
"phonenumber":"1234567890"
}
}
}
- Siųskite veiklą pranešimų perdavimo procesoriui.
Sukūręs veiklos naudingąją apkrovą, jis iškviečia pranešimų perdavimo procesoriaus "PostActivityAsync" metodą, kad nusiųstų veiklą į "Direct Line". Kanalo adapteris taip pat turėtų perduoti įvykio apdorojimo programą, kurią perdavimo procesorius iškviečia, kai gauna siunčiamą pranešimą iš daugiakanalio, skirto klientų aptarnavimui per tiesioginę liniją.
Apdoroti siunčiamą veiklą
Perdavimo procesorius iškviečia įvykio apdorojimo programą, kad išsiųstų siuntimo veiklą į atitinkamą kanalo adapterį, o adapteris apdoroja siunčiamą veiklą. Kanalo adapteris atlieka šias siuntimo veiklas:
- Konvertuokite siunčiamas veiklas į kanalo atsako modelį.
Tiesioginės linijos veikla konvertuojama į konkretaus kanalo atsako modelį.
/// <summary>
/// Creates MessageBird response object from a Bot Framework <see cref="Activity"/>.
/// </summary>
/// <param name="activities">The outbound activities.</param>
/// <param name="replyToId">Reply Id of Message Bird user.</param>
/// <returns>List of MessageBird Responses.</returns>
public static List<MessageBirdResponseModel> ActivityToMessageBird(IList<Activity> activities, string replyToId)
{
if (string.IsNullOrWhiteSpace(replyToId))
{
throw new ArgumentNullException(nameof(replyToId));
}
if (activities == null)
{
throw new ArgumentNullException(nameof(activities));
}
return activities.Select(activity => new MessageBirdResponseModel
{
To = replyToId,
From = activity.ChannelId,
Type = "text",
Content = new Content
{
Text = activity.Text
}
}).ToList();
}
- Siųskite atsakymus per kanalą REST API.
Kanalo adapteris iškviečia REST API, kad išsiųstų į kanalą siunčiamą atsakymą, kuris vėliau siunčiamas vartotojui.
/// <summary>
/// Send Outbound Messages to Message Bird
/// </summary>
/// <param name="messageBirdResponses">Message Bird Response object</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task SendMessagesToMessageBird(IList<MessageBirdResponseModel> messageBirdResponses)
{
if (messageBirdResponses == null)
{
throw new ArgumentNullException(nameof(messageBirdResponses));
}
foreach (var messageBirdResponse in messageBirdResponses)
{
using (var request = new HttpRequestMessage(HttpMethod.Post, $"{MessageBirdDefaultApi}/send"))
{
var content = JsonConvert.SerializeObject(messageBirdResponse);
request.Content = new StringContent(content, Encoding.UTF8, "application/json");
await _httpClient.SendAsync(request).ConfigureAwait(false);
}
}
}
Pranešimų perdavimo procesorius
Pranešimų perdavimo procesorius gauna gaunamą veiklą iš kanalo adapterio ir atlieka veiklos modelio tikrinimą. Perdavimo procesorius patikrina, ar pokalbis yra aktyvus konkrečioje veikloje, prieš siųsdamas šią veiklą į tiesioginę liniją
Norėdami sužinoti, ar pokalbis aktyvus, perdavimo procesorius žodyne palaiko aktyvių pokalbių rinkinį. Šiame žodyne yra raktas kaip vartotojo ID, kuris unikaliai identifikuoja vartotoją ir reikšmę kaip šios klasės objektą:
/// <summary>
/// Direct Line Conversation to store as an Active Conversation
/// </summary>
public class DirectLineConversation
{
/// <summary>
/// .NET SDK Client to connect to Direct Line Bot
/// </summary>
public DirectLineClient DirectLineClient { get; set; }
/// <summary>
/// Direct Line response after start a new conversation
/// </summary>
public Conversation Conversation { get; set; }
/// <summary>
/// Watermark to guarantee that no messages are lost
/// </summary>
public string WaterMark { get; set; }
}
Jei pokalbis neaktyvus dėl veiklos, kurią gauna perdavimo procesorius, jis atlieka šiuos veiksmus:
- Pradedamas pokalbis su tiesiogine linija ir įrašo tiesioginės linijos siųstą pokalbio objektą pagal žodyno vartotojo ID.
/// <summary>
/// Initiate Conversation with Direct Line Bot
/// </summary>
/// <param name="inboundActivity">Inbound message from Aggregator/Channel</param>
/// <param name="adapterCallBackHandler">Call Back to send activities to Messaging API</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
private async Task InitiateConversation(Activity inboundActivity, EventHandler<IList<Activity>> adapterCallBackHandler)
{
var directLineConversation = new DirectLineConversation
{
DirectLineClient = new DirectLineClient(_relayProcessorConfiguration.Value.DirectLineSecret)
};
// Start a conversation with Direct Line Bot
directLineConversation.Conversation = await directLineConversation.DirectLineClient.Conversations.
StartConversationAsync().ConfigureAwait(false);
await directLineConversation.DirectLineClient.Conversations.
StartConversationAsync().ConfigureAwait(false);
if (directLineConversation.Conversation == null)
{
throw new Exception(
"An error occurred while starting the Conversation with direct line. Please validate the direct line secret in the configuration file.");
}
// Adding the Direct Line Conversation object to the lookup dictionary and starting a thread to poll the activities from the direct line bot.
if (ActiveConversationCache.ActiveConversations.TryAdd(inboundActivity.From.Id, directLineConversation))
{
// Starts a new thread to poll the activities from Direct Line Bot
new Thread(async () => await PollActivitiesFromBotAsync(
directLineConversation.Conversation.ConversationId, inboundActivity, adapterCallBackHandler).ConfigureAwait(false))
.Start();
}
}
- Paleidžia naują giją, kad apklaustų siunčiamą veiklą iš "Direct Line" roboto, atsižvelgiant į apklausos intervalą, sukonfigūruotą konfigūracijos faile. Apklausos gija yra aktyvi tol, kol pokalbio veiklos pabaiga gaunama iš tiesioginės linijos.
/// <summary>
/// Polling the activities from BOT for the active conversation
/// </summary>
/// <param name="conversationId">Direct Line Conversation Id</param>
/// <param name="inboundActivity">Inbound Activity from Channel/Aggregator</param>
/// <param name="lineActivitiesReceived">Call Back to send activities to Messaging API</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
private async Task PollActivitiesFromBotAsync(string conversationId, Activity inboundActivity, EventHandler<IList<Activity>> lineActivitiesReceived)
{
if (!int.TryParse(_relayProcessorConfiguration.Value.PollingIntervalInMilliseconds, out var pollingInterval))
{
throw new FormatException($"Invalid Configuration value of PollingIntervalInMilliseconds: {_relayProcessorConfiguration.Value.PollingIntervalInMilliseconds}");
}
if (!ActiveConversationCache.ActiveConversations.TryGetValue(inboundActivity.From.Id,
out var conversationContext))
{
throw new KeyNotFoundException($"No active conversation found for {inboundActivity.From.Id}");
}
while (true)
{
var watermark = conversationContext.WaterMark;
// Retrieve the activity set from the bot.
var activitySet = await conversationContext.DirectLineClient.Conversations.
GetActivitiesAsync(conversationId, watermark).ConfigureAwait(false);
// Set the watermark to the message received
watermark = activitySet?.Watermark;
// Extract the activities sent from our bot.
if (activitySet != null)
{
var activities = (from activity in activitySet.Activities
where activity.From.Id == _relayProcessorConfiguration.Value.BotHandle
select activity).ToList();
if (activities.Count > 0)
{
SendReplyActivity(activities, inboundActivity, lineActivitiesReceived);
}
// Update Watermark
ActiveConversationCache.ActiveConversations[inboundActivity.From.Id].WaterMark = watermark;
if (activities.Exists(a => a.Type.Equals("endOfConversation", StringComparison.InvariantCulture)))
{
if (ActiveConversationCache.ActiveConversations.TryRemove(inboundActivity.From.Id, out _))
{
Thread.CurrentThread.Abort();
}
}
}
await Task.Delay(TimeSpan.FromMilliseconds(pollingInterval)).ConfigureAwait(false);
}
}
Pastaba
Pranešimą gaunančio kodo centre yra "GetActivitiesAsync" metodas, kuris ima ConversationId
ir watermark
kaip parametrus. Parametro watermark
paskirtis yra nuskaityti pranešimus, kurie nepristatomi tiesiogine linija. Jei vandenženklio parametras nurodytas, pokalbis kartojasi iš vandenženklio, kad nebūtų prarasti jokie pranešimai.
Veiklos siuntimas į "Direct Line"
/// <summary>
/// Send the activity to the bot using Direct Line client
/// </summary>
/// <param name="inboundActivity">Inbound message from Aggregator/Channel</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
private static async Task SendActivityToBotAsync(Activity inboundActivity)
{
if (!ActiveConversationCache.ActiveConversations.TryGetValue(inboundActivity.From.Id,
out var conversationContext))
{
throw new KeyNotFoundException($"No active conversation found for {inboundActivity.From.Id}");
}
await conversationContext.DirectLineClient.Conversations.PostActivityAsync(
conversationContext.Conversation.ConversationId, inboundActivity).ConfigureAwait(false);
}
Jei pokalbis yra aktyvus dėl relės procesoriaus gautos veiklos, jis siunčia veiklą pranešimų perdavimo procesoriui.
Baigti pokalbį
Norėdami baigti pokalbį, žiūrėkite Baigti pokalbį tiesiogine linija.
Kiti veiksmai
Tiesioginių pokalbių ir asinchroninių kanalų palaikymas
Markdown formatai pasirinktiniuose kanaluose, kurie naudoja Direct Line
Susijusi informacija
Tinkinto pranešimų kanalo konfigūravimas
"MessageBird" API nuoroda
Geriausia robotų konfigūravimo praktika