Skip to content

Commit 750f448

Browse files
committed
adding bot connector app sample
1 parent 9483060 commit 750f448

7 files changed

Lines changed: 333 additions & 0 deletions

File tree

BotConnectorApp/App.config

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<appSettings>
4+
<add key="BotId" value="" />
5+
<add key="BotTenantId" value="" />
6+
<add key="BotName" value="" />
7+
<add key="BotTokenEndpoint" value="https://powerva.microsoft.com/api/botmanagement/v1/directline/directlinetoken" />
8+
<add key="EndConversationMessage" value="quit" />
9+
</appSettings>
10+
</configuration>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
6+
namespace Microsoft.PowerVirtualAgents.Samples.BotConnectorApp
7+
{
8+
/// <summary>
9+
/// class with bot info
10+
/// </summary>
11+
public class BotEndpoint
12+
{
13+
/// <summary>
14+
/// constructor
15+
/// </summary>
16+
/// <param name="botId">Bot Id GUID</param>
17+
/// <param name="tenantId">Bot tenant GUID</param>
18+
/// <param name="tokenEndPoint">REST API endpoint to retreive directline token</param>
19+
public BotEndpoint(string botId, string tenantId, string tokenEndPoint)
20+
{
21+
BotId = botId;
22+
TenantId = tenantId;
23+
UriBuilder uriBuilder = new UriBuilder(tokenEndPoint);
24+
uriBuilder.Query = $"botId={BotId}&tenantId={TenantId}";
25+
TokenUrl = uriBuilder.Uri;
26+
}
27+
28+
public string BotId { get; }
29+
30+
public string TenantId { get; }
31+
32+
public Uri TokenUrl { get; }
33+
}
34+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.Rest.Serialization;
5+
using System;
6+
using System.Net.Http;
7+
using System.Threading.Tasks;
8+
9+
namespace Microsoft.PowerVirtualAgents.Samples.BotConnectorApp
10+
{
11+
/// <summary>
12+
/// Bot Service class to interact with bot
13+
/// </summary>
14+
public class BotService
15+
{
16+
private static readonly HttpClient s_httpClient = new HttpClient();
17+
18+
public string BotName { get; set; }
19+
20+
public string BotId { get; set; }
21+
22+
public string TenantId { get; set; }
23+
24+
public string TokenEndPoint { get; set; }
25+
26+
/// <summary>
27+
/// Get directline token for connecting bot
28+
/// </summary>
29+
/// <returns>directline token as string</returns>
30+
public async Task<string> GetTokenAsync()
31+
{
32+
string token;
33+
using (var httpRequest = new HttpRequestMessage())
34+
{
35+
httpRequest.Method = HttpMethod.Get;
36+
UriBuilder uriBuilder = new UriBuilder(TokenEndPoint);
37+
uriBuilder.Query = $"botId={BotId}&tenantId={TenantId}";
38+
httpRequest.RequestUri = uriBuilder.Uri;
39+
using (var response = await s_httpClient.SendAsync(httpRequest))
40+
{
41+
var responseString = await response.Content.ReadAsStringAsync();
42+
token = SafeJsonConvert.DeserializeObject<DirectLineToken>(responseString).Token;
43+
}
44+
}
45+
46+
return token;
47+
}
48+
}
49+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
namespace Microsoft.PowerVirtualAgents.Samples.BotConnectorApp
5+
{
6+
/// <summary>
7+
/// class for serialization/deserialization DirectLineToken
8+
/// </summary>
9+
public class DirectLineToken
10+
{
11+
/// <summary>
12+
/// constructor
13+
/// </summary>
14+
/// <param name="token">Directline token string</param>
15+
public DirectLineToken(string token)
16+
{
17+
Token = token;
18+
}
19+
20+
public string Token { get; set; }
21+
}
22+
}

BotConnectorApp/BotConnectorApp.cs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.Bot.Connector.DirectLine;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Configuration;
8+
using System.Linq;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
12+
namespace Microsoft.PowerVirtualAgents.Samples.BotConnectorApp
13+
{
14+
public class BotConnectorApp
15+
{
16+
private static string _watermark = null;
17+
private const int _botReplyWaitIntervalInMilSec = 3000;
18+
private const string _botDisplayName = "Bot";
19+
private const string _userDisplayName = "You";
20+
private static string s_endConversationMessage;
21+
private static BotService s_botService;
22+
23+
/// <summary>
24+
/// Start BotConnectorApp console
25+
/// See <see cref="README.md"/> for information on how to update bot settings in App.config
26+
/// Takes user input and output bot reply, until user types EndConversationMessage
27+
/// </summary>
28+
public static void Main(string[] args)
29+
{
30+
var botId = ConfigurationManager.AppSettings["BotId"] ?? string.Empty;
31+
var tenantId = ConfigurationManager.AppSettings["BotTenantId"] ?? string.Empty;
32+
var botTokenEndpoint = ConfigurationManager.AppSettings["BotTokenEndpoint"] ?? string.Empty;
33+
var botName = ConfigurationManager.AppSettings["BotName"] ?? string.Empty;
34+
s_endConversationMessage = ConfigurationManager.AppSettings["EndConversationMessage"] ?? "quit";
35+
if (string.IsNullOrEmpty(botId) || string.IsNullOrEmpty(tenantId) || string.IsNullOrEmpty(botTokenEndpoint) || string.IsNullOrEmpty(botName))
36+
{
37+
Console.WriteLine("Update App.config and start again.");
38+
Console.WriteLine("Press any key to exit");
39+
Console.Read();
40+
Environment.Exit(0);
41+
}
42+
43+
s_botService = new BotService()
44+
{
45+
BotName = botName,
46+
BotId = botId,
47+
TenantId = tenantId,
48+
TokenEndPoint = botTokenEndpoint,
49+
};
50+
StartConversation().Wait();
51+
}
52+
53+
private static async Task StartConversation()
54+
{
55+
var token = await s_botService.GetTokenAsync();
56+
using (var directLineClient = new DirectLineClient(token))
57+
{
58+
var conversation = await directLineClient.Conversations.StartConversationAsync();
59+
var conversationtId = conversation.ConversationId;
60+
string inputMessage;
61+
62+
while (!string.Equals(inputMessage = GetUserInput(), s_endConversationMessage, StringComparison.OrdinalIgnoreCase))
63+
{
64+
// Send user message using directlineClient
65+
await directLineClient.Conversations.PostActivityAsync(conversationtId, new Activity()
66+
{
67+
Type = ActivityTypes.Message,
68+
From = new ChannelAccount { Id = "userId", Name = "userName" },
69+
Text = inputMessage,
70+
TextFormat = "plain",
71+
Locale = "en-Us",
72+
});
73+
74+
Console.WriteLine($"{_botDisplayName}:");
75+
Thread.Sleep(_botReplyWaitIntervalInMilSec);
76+
77+
// Get bot response using directlinClient
78+
List<Activity> responses = await GetBotResponseActivitiesAsync(directLineClient, conversationtId);
79+
BotReply(responses);
80+
}
81+
}
82+
}
83+
84+
/// <summary>
85+
/// Prompt for user input
86+
/// </summary>
87+
/// <returns>user message as string</returns>
88+
private static string GetUserInput()
89+
{
90+
Console.WriteLine($"{_userDisplayName}:");
91+
var inputMessage = Console.ReadLine();
92+
return inputMessage;
93+
}
94+
95+
/// <summary>
96+
/// Use directlineClient to get bot response
97+
/// </summary>
98+
/// <returns>List of DirectLine activities</returns>
99+
/// <param name="directLineClient">directline client</param>
100+
/// <param name="conversationtId">current conversation ID</param>
101+
/// <param name="botName">name of bot to connect to</param>
102+
private static async Task<List<Activity>> GetBotResponseActivitiesAsync(DirectLineClient directLineClient, string conversationtId)
103+
{
104+
ActivitySet response = null;
105+
List<Activity> result = new List<Activity>();
106+
107+
do
108+
{
109+
response = await directLineClient.Conversations.GetActivitiesAsync(conversationtId, _watermark);
110+
if (response == null)
111+
{
112+
// response can be null if directLineClient token expires
113+
Console.WriteLine("Conversation expired. Press any key to exit.");
114+
Console.Read();
115+
directLineClient.Dispose();
116+
Environment.Exit(0);
117+
}
118+
119+
_watermark = response?.Watermark;
120+
result = response?.Activities?.Where(x =>
121+
x.Type == ActivityTypes.Message &&
122+
string.Equals(x.From.Name, s_botService.BotName, StringComparison.Ordinal)).ToList();
123+
124+
if (result != null && result.Any())
125+
{
126+
return result;
127+
}
128+
129+
Thread.Sleep(1000);
130+
} while (response != null && response.Activities.Any());
131+
132+
return new List<Activity>();
133+
}
134+
135+
/// <summary>
136+
/// Print bot reply to console
137+
/// </summary>
138+
/// <param name="responses">List of DirectLine activities <see cref="https://github.com/Microsoft/botframework-sdk/blob/master/specs/botframework-activity/botframework-activity.md"/>
139+
/// </param>
140+
private static void BotReply(List<Activity> responses)
141+
{
142+
responses?.ForEach(responseActivity =>
143+
{
144+
// responseActivity is standard Microsoft.Bot.Connector.DirectLine.Activity
145+
// See https://github.com/Microsoft/botframework-sdk/blob/master/specs/botframework-activity/botframework-activity.md for reference
146+
// Showing examples of Text & SuggestedActions in response payload
147+
if (!string.IsNullOrEmpty(responseActivity.Text))
148+
{
149+
Console.WriteLine(string.Join(Environment.NewLine, responseActivity.Text));
150+
}
151+
152+
if (responseActivity.SuggestedActions != null && responseActivity.SuggestedActions.Actions != null)
153+
{
154+
var options = responseActivity.SuggestedActions?.Actions?.Select(a => a.Title).ToList();
155+
Console.WriteLine($"\t{string.Join(" | ", options)}");
156+
}
157+
});
158+
}
159+
}
160+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp2.1</TargetFramework>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Microsoft.Bot.Connector.DirectLine" Version="3.0.2" />
10+
<PackageReference Include="Microsoft.Rest.ClientRuntime" Version="2.3.20" />
11+
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.6.0" />
12+
</ItemGroup>
13+
14+
</Project>

BotConnectorApp/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Bot Connector
2+
3+
This console app shows the minimum code required to connect customized client to an existing virtual agent.
4+
5+
## Prerequisites
6+
7+
- [.NET Core SDK](https://dotnet.microsoft.com/download) version 2.1
8+
9+
```powershell
10+
# determine dotnet version
11+
dotnet --version
12+
```
13+
14+
## To try this sample
15+
- Update following settings in `BotConnectorApp\App.config`
16+
17+
1) Set value for `BotName` to name of the bot to connect
18+
2) Update `BotId` and `BotTenantId` as follows:
19+
20+
To retrieve your bot's bot ID and tenant ID, click on left side pane's ***Manage***, click ***Channels*** and click on the Azure Bot Service channel that you need to connect to.
21+
Copy and save the bot ID and tenant ID value by clicking Copy.
22+
23+
3) Update `EndConversationMessage` if needed
24+
25+
- Run `BotConnectorApp` from a terminal
26+
27+
```
28+
# change into project folder
29+
cd BotConnectorApp
30+
31+
# run the bot
32+
dotnet run
33+
```
34+
35+
- Run `BotConnectorApp` from Visual Studio
36+
37+
1) Launch Visual Studio
38+
2) File -> Open -> Project/Solution
39+
3) Navigate to `BotConnectorApp` folder and select `BotConnectorApp.csproj` file
40+
4) Press `F5` to run the project
41+
42+
## Further reading
43+
- [Power Virtual Agents Bot](https://www.bing.com) ***to be updated once formal doc url determined**
44+
- [Power Virtual Agents - connect bot to custom application](https://www.bing.com) ***to be updated once formal doc url determined**

0 commit comments

Comments
 (0)