├── .gitignore
├── BotFramework
├── Actions
│ ├── Actions.csproj
│ ├── IMyRPAClient.cs
│ ├── Models
│ │ ├── CancelOrderInput.cs
│ │ ├── CancelOrderOutput.cs
│ │ ├── CreatePurchaseOrderInput.cs
│ │ ├── CreatePurchaseOrderOutput.cs
│ │ ├── CreateSalesOrderInput.cs
│ │ ├── CreateSalesOrderOutput.cs
│ │ ├── GetItemsInput.cs
│ │ ├── GetItemsOutput.cs
│ │ ├── Internal
│ │ │ └── GetItemsOutputInternal.cs
│ │ └── Item.cs
│ ├── MyRPAClient.cs
│ └── MyRPAClientMock.cs
├── ActionsTest
│ ├── ActionsTest.csproj
│ ├── GetItemsOutputInternal.cs
│ └── MyRpaClientTest.cs
├── Common
│ ├── AdapterWithErrorHandler.cs
│ ├── BotDialogSet.cs
│ ├── BotIntents.cs
│ ├── BotServices.cs
│ ├── BotSettings.cs
│ ├── Common.csproj
│ ├── Models
│ │ ├── DetourIntent.cs
│ │ ├── EntityState.cs
│ │ ├── Intent.cs
│ │ ├── IntentType.cs
│ │ ├── LuisEntity.cs
│ │ └── TerminationIntent.cs
│ └── MultiTurnBot.cs
├── Data
│ ├── Luis
│ │ ├── .luisrc
│ │ ├── Sample.json
│ │ └── Sample.lu
│ └── Packages
│ │ ├── CancelOrder.1.0.1-alpha.nupkg
│ │ ├── CreatePurchaseOrder.1.0.1-alpha.1.nupkg
│ │ ├── CreateSalesOrder.1.0.1-alpha.1.nupkg
│ │ └── GetItems.1.0.1-alpha.3.nupkg
├── Dialogs
│ ├── Dialogs.csproj
│ ├── MyBot.cs
│ ├── MyBotSettings.cs
│ ├── MyDialog
│ │ ├── Base
│ │ │ ├── DialogBase.cs
│ │ │ └── StatefulDialogBase.cs
│ │ ├── CannotFindOrderDialog.cs
│ │ ├── DelayedShipmentDialog.cs
│ │ ├── GetCustomerProfileDialog.cs
│ │ ├── GreetingDialog.cs
│ │ └── ReplaceItemDialog.cs
│ ├── MyIntents.cs
│ └── Utils.cs
├── DialogsTest
│ ├── DialogTest.cs
│ ├── DialogsTest.csproj
│ └── IntentTest.cs
├── OrchestratorClient.Test
│ ├── AuthHeadHandlerTest.cs
│ ├── ClientTest.cs
│ ├── MockHelper.cs
│ ├── OrchestratorClient.Test.csproj
│ ├── OrchestratorSettingsTest.cs
│ └── UtilsTest.cs
├── OrchestratorClient
│ ├── Auth
│ │ ├── BasicAuthHeadHandler.cs
│ │ ├── BasicAuthResponse.cs
│ │ ├── BasicAuthSettings.cs
│ │ ├── CloudAuthHeadHandler.cs
│ │ ├── CloudAuthResponse.cs
│ │ ├── CloudAuthSettings.cs
│ │ ├── ITokenService.cs
│ │ └── TokenService.cs
│ ├── IOrchestratorClient.cs
│ ├── JobModels
│ │ ├── ODataList.cs
│ │ ├── StartJobBody.cs
│ │ ├── StartJobInfo.cs
│ │ └── StartJobResponse.cs
│ ├── OrchestratorClient.cs
│ ├── OrchestratorClient.csproj
│ ├── OrchestratorSettings.cs
│ ├── ProcessKey.cs
│ └── Utils.cs
├── README.md
├── Resources
│ ├── Resource.Designer.cs
│ ├── Resource.resx
│ └── Resources.csproj
├── SampleBot.sln
├── SampleBot
│ ├── ConfigurationCredentialProvider.cs
│ ├── Controllers
│ │ └── BotController.cs
│ ├── DeploymentTemplates
│ │ ├── template-with-new-rg.json
│ │ └── template-with-preexisting-rg.json
│ ├── Program.cs
│ ├── SampleBot.csproj
│ ├── Startup.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── samplebot.bot
│ └── wwwroot
│ │ └── default.htm
├── Test.Common
│ ├── OrchestratorSettingOption.cs
│ └── Test.Common.csproj
├── Utils.Test
│ ├── CheckNullReferenceTest.cs
│ ├── OrdinalEqualTest.cs
│ ├── TestType.cs
│ └── Utils.Test.csproj
└── Utils
│ ├── CommonExtensions.cs
│ └── Utils.csproj
├── LICENSE.md
├── README.md
└── User guide.pdf
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | # *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | # **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 |
--------------------------------------------------------------------------------
/BotFramework/Actions/Actions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | UiPath.ChatbotSamples.BotFramework.Actions
6 | UiPath.ChatbotSamples.BotFramework.Actions
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ..\..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.options\2.1.1\lib\netstandard2.0\Microsoft.Extensions.Options.dll
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/BotFramework/Actions/IMyRPAClient.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using UiPath.ChatbotSamples.BotFramework.Actions.Models;
3 |
4 | namespace UiPath.ChatbotSamples.BotFramework.Actions
5 | {
6 | public interface IMyRpaClient
7 | {
8 | Task GetItemsAsync(GetItemsInput input);
9 |
10 | Task CreatePurchaseOrderAsync(CreatePurchaseOrderInput input);
11 |
12 | Task CreateSalesOrderAsync(CreateSalesOrderInput input);
13 |
14 | Task CancelOrderAsync(CancelOrderInput input);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/BotFramework/Actions/Models/CancelOrderInput.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.Actions.Models
2 | {
3 | public class CancelOrderInput
4 | {
5 | public string OrderId { get; set; }
6 |
7 | public string CancelReason { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/BotFramework/Actions/Models/CancelOrderOutput.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.Actions.Models
2 | {
3 | public class CancelOrderOutput
4 | {
5 | public string ReturnLabelLocation { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/BotFramework/Actions/Models/CreatePurchaseOrderInput.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.Actions.Models
2 | {
3 | public class CreatePurchaseOrderInput
4 | {
5 | public string ItemId { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/BotFramework/Actions/Models/CreatePurchaseOrderOutput.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.Actions.Models
2 | {
3 | public class CreatePurchaseOrderOutput
4 | {
5 | public string PurchaseOrderId { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/BotFramework/Actions/Models/CreateSalesOrderInput.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.Actions.Models
2 | {
3 | public class CreateSalesOrderInput
4 | {
5 | public string CustomerId { get; set; }
6 |
7 | public string Quantity { get; set; }
8 |
9 | public string ItemId { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/BotFramework/Actions/Models/CreateSalesOrderOutput.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UiPath.ChatbotSamples.BotFramework.Actions.Models
4 | {
5 | public class CreateSalesOrderOutput
6 | {
7 | public DateTime DeliveryDate { get; set; }
8 |
9 | public string OrderId { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/BotFramework/Actions/Models/GetItemsInput.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.Actions.Models
2 | {
3 | public class GetItemsInput
4 | {
5 | public string CustomerId { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/BotFramework/Actions/Models/GetItemsOutput.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.Actions.Models
2 | {
3 | public class GetItemsOutput
4 | {
5 | public Item[] Items { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/BotFramework/Actions/Models/Internal/GetItemsOutputInternal.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.Actions.Models
2 | {
3 | internal class GetItemsOutputInternal
4 | {
5 | public string[] DeliveryDate { get; set; }
6 |
7 | public string[] DeliveryStatus { get; set; }
8 |
9 | public string[] ItemId { get; set; }
10 |
11 | public string[] ItemName { get; set; }
12 |
13 | public string[] OrderId { get; set; }
14 |
15 | public string[] Quantity { get; set; }
16 |
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/BotFramework/Actions/Models/Item.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UiPath.ChatbotSamples.BotFramework.Actions.Models
4 | {
5 | public class Item
6 | {
7 | public string ItemId { get; set; }
8 |
9 | public string ItemName { get; set; }
10 |
11 | public string Quantity { get; set; }
12 |
13 | public string OrderId { get; set; }
14 |
15 | public DateTime DeliveryDate { get; set; }
16 |
17 | public string DeliveryStatus { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/BotFramework/Actions/MyRPAClient.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using UiPath.ChatbotSamples.BotFramework.Actions.Models;
8 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient;
9 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient.JobModels;
10 | using UiPath.ChatbotSamples.BotFramework.Utils;
11 |
12 | namespace UiPath.ChatbotSamples.BotFramework.Actions
13 | {
14 | public class MyRpaClient: IMyRpaClient
15 | {
16 | private readonly IOrchestratorClient _orchestratorClient;
17 | private readonly OrchestratorSettings _orchestratorSettings;
18 |
19 | public MyRpaClient(IOrchestratorClient orchestratorClient, IOptionsMonitor orchestratorSettingsAccessor)
20 | {
21 | _orchestratorClient = orchestratorClient.CheckNullReference();
22 | _orchestratorSettings = orchestratorSettingsAccessor.CheckNullReference().CurrentValue;
23 | }
24 |
25 | public async Task CreatePurchaseOrderAsync(CreatePurchaseOrderInput input)
26 | {
27 | var jobInfo = CreateStartJobInfo(GetProcessKey(nameof(CreatePurchaseOrderAsync)), input);
28 | var job = await _orchestratorClient.ExecuteJobAsync(jobInfo);
29 | return JsonConvert.DeserializeObject(job.OutputArguments);
30 | }
31 |
32 | public async Task CreateSalesOrderAsync(CreateSalesOrderInput input)
33 | {
34 | var jobInfo = CreateStartJobInfo(GetProcessKey(nameof(CreateSalesOrderAsync)), input);
35 | var job = await _orchestratorClient.ExecuteJobAsync(jobInfo);
36 | return JsonConvert.DeserializeObject(job.OutputArguments);
37 | }
38 |
39 | public async Task GetItemsAsync(GetItemsInput input)
40 | {
41 | var jobInfo = CreateStartJobInfo(GetProcessKey(nameof(GetItemsAsync)), input);
42 | var job = await _orchestratorClient.ExecuteJobAsync(jobInfo);
43 | var itemsOutputInternal = JsonConvert.DeserializeObject(job.OutputArguments);
44 | return GetItemsOutputFromInternalResult(itemsOutputInternal);
45 | }
46 |
47 | public async Task CancelOrderAsync(CancelOrderInput input)
48 | {
49 | var jobInfo = CreateStartJobInfo(GetProcessKey(nameof(CancelOrderAsync)), input);
50 | var job = await _orchestratorClient.ExecuteJobAsync(jobInfo);
51 | return JsonConvert.DeserializeObject(job.OutputArguments);
52 | }
53 |
54 | // this is just a simple example. A mapper library is recommended if lots of conversion is needed.
55 | private GetItemsOutput GetItemsOutputFromInternalResult(GetItemsOutputInternal itemsOutputInternal)
56 | {
57 | var items = new List- ();
58 | for (var i = 0; i < itemsOutputInternal.ItemId.Length; i++)
59 | {
60 | var item = new Item()
61 | {
62 | DeliveryDate = Convert.ToDateTime(itemsOutputInternal.DeliveryDate[i]),
63 | ItemId = itemsOutputInternal.ItemId[i],
64 | OrderId = itemsOutputInternal.OrderId[i],
65 | ItemName = itemsOutputInternal.ItemName[i],
66 | Quantity = itemsOutputInternal.Quantity[i],
67 | DeliveryStatus = itemsOutputInternal.DeliveryStatus[i],
68 | };
69 | items.Add(item);
70 | }
71 |
72 | return new GetItemsOutput()
73 | {
74 | Items = items.ToArray(),
75 | };
76 | }
77 |
78 | private string GetProcessKey(string methodName)
79 | {
80 | // default mapping is Process + Async = MethodName. If the procss key not found, it will throw here.
81 | var processName = methodName.EndsWith("Async") ?
82 | methodName.Substring(0, methodName.Length - "Async".Length) : methodName;
83 | return _orchestratorSettings.ProcessKeys.Where(p => p.Process.OrdinalEquals(processName)).First().Key;
84 | }
85 |
86 | private StartJobInfo CreateStartJobInfo(string processKey)
87 | {
88 | return new StartJobInfo()
89 | {
90 | ReleaseKey = processKey,
91 | RobotIds = _orchestratorSettings.RobotIds,
92 | JobsCount = _orchestratorSettings.JobsCount,
93 | Strategy = _orchestratorSettings.Strategy,
94 | };
95 | }
96 |
97 | private StartJobInfo CreateStartJobInfo(string processKey, T input) where T: class
98 | {
99 | return new StartJobInfo()
100 | {
101 | ReleaseKey = processKey,
102 | RobotIds = _orchestratorSettings.RobotIds,
103 | JobsCount = _orchestratorSettings.JobsCount,
104 | Strategy = _orchestratorSettings.Strategy,
105 | InputArguments = JsonConvert.SerializeObject(input),
106 | };
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/BotFramework/Actions/MyRPAClientMock.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using UiPath.ChatbotSamples.BotFramework.Actions.Models;
4 | using UiPath.ChatbotSamples.BotFramework.Utils;
5 |
6 | namespace UiPath.ChatbotSamples.BotFramework.Actions
7 | {
8 | public class MyRpaClientMock : IMyRpaClient
9 | {
10 | public async Task GetItemsAsync(GetItemsInput input)
11 | {
12 | if (input.CustomerId.OrdinalEquals("123456"))
13 | {
14 | return new GetItemsOutput()
15 | {
16 | Items = new Item[]
17 | {
18 | new Item()
19 | {
20 | DeliveryDate = DateTime.Today.AddDays(2),
21 | ItemId = "35678",
22 | OrderId = "45436",
23 | ItemName = "wireless speaker",
24 | Quantity = "1",
25 | DeliveryStatus = "out of stock",
26 | },
27 | new Item()
28 | {
29 | DeliveryDate = DateTime.Today.AddDays(10),
30 | ItemId = "35678",
31 | OrderId = "45436",
32 | ItemName = "TV",
33 | Quantity = "1",
34 | DeliveryStatus = "out of stock",
35 | },
36 | new Item()
37 | {
38 | DeliveryDate = DateTime.Today.AddDays(-1),
39 | ItemId = "123",
40 | OrderId = "5645",
41 | ItemName = "monitor",
42 | Quantity = "1",
43 | DeliveryStatus = "delivered",
44 | },
45 | new Item()
46 | {
47 | DeliveryDate = DateTime.Today.AddDays(-5),
48 | ItemId = "123",
49 | OrderId = "5645",
50 | ItemName = "headphone",
51 | Quantity = "1",
52 | DeliveryStatus = "delivered",
53 | },
54 | },
55 | };
56 | }
57 | else
58 | {
59 | return new GetItemsOutput();
60 | }
61 | }
62 |
63 | public async Task CreatePurchaseOrderAsync(CreatePurchaseOrderInput input)
64 | {
65 | return new CreatePurchaseOrderOutput()
66 | {
67 | PurchaseOrderId = "12345",
68 | };
69 | }
70 |
71 | public async Task CreateSalesOrderAsync(CreateSalesOrderInput input)
72 | {
73 | return new CreateSalesOrderOutput()
74 | {
75 | DeliveryDate = DateTime.Today.AddDays(7),
76 | OrderId = "45678",
77 | };
78 | }
79 |
80 | public async Task CancelOrderAsync(CancelOrderInput input)
81 | {
82 | return new CancelOrderOutput()
83 | {
84 | ReturnLabelLocation = "http://returnurl/123",
85 | };
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/BotFramework/ActionsTest/ActionsTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 | UiPath.ChatbotSamples.BotFramework.Actions.Test
6 | UiPath.ChatbotSamples.BotFramework.Actions.Test
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/BotFramework/ActionsTest/GetItemsOutputInternal.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.Actions.Test
2 | {
3 | // instead of open up the protection level in Actions project,
4 | // copy the definition here for test only purpose.
5 | internal class GetItemsOutputInternal
6 | {
7 | public string[] DeliveryDate { get; set; }
8 |
9 | public string[] DeliveryStatus { get; set; }
10 |
11 | public string[] ItemId { get; set; }
12 |
13 | public string[] ItemName { get; set; }
14 |
15 | public string[] OrderId { get; set; }
16 |
17 | public string[] Quantity { get; set; }
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/BotFramework/ActionsTest/MyRpaClientTest.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 | using Newtonsoft.Json;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 | using UiPath.ChatbotSamples.BotFramework.Actions.Models;
7 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient;
8 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient.JobModels;
9 | using UiPath.ChatbotSamples.BotFramework.Test.Common;
10 | using Xunit;
11 |
12 | namespace UiPath.ChatbotSamples.BotFramework.Actions.Test
13 | {
14 | public class MyRpaClientTest
15 | {
16 | private readonly OrchestratorSettingOption _invalidSetting = new OrchestratorSettingOption(
17 | new OrchestratorSettings()
18 | {
19 | AuthMode = "Cloud",
20 | RefreshToken = "randometoken",
21 | ServiceInstanceLogicalName = "test",
22 | AccountLogicalName = "test",
23 | BaseUrl = "Https://platform.uipath.com",
24 | Strategy = "Specific",
25 | RobotIds = new long[] { 1, 2, 3 },
26 | ProcessKeys = new ProcessKey[] { new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "test" } },
27 | });
28 |
29 | private readonly OrchestratorSettingOption _validSetting = new OrchestratorSettingOption(
30 | new OrchestratorSettings()
31 | {
32 | AuthMode = "Cloud",
33 | RefreshToken = "randometoken",
34 | ServiceInstanceLogicalName = "test",
35 | AccountLogicalName = "test",
36 | BaseUrl = "Https://platform.uipath.com",
37 | Strategy = "Specific",
38 | RobotIds = new long[] { 1, 2, 3 },
39 | ProcessKeys = new ProcessKey[] {
40 | new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "CreatePurchaseOrder" },
41 | new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "CreateSalesOrder" },
42 | new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "GetItems" },
43 | new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "CancelOrder" },
44 | },
45 | });
46 |
47 | [Fact]
48 | public void ThrowIfCannotFindProcessKey()
49 | {
50 | var orchestratorClient = new Mock();
51 |
52 | var client = new MyRpaClient(orchestratorClient.Object, _invalidSetting);
53 | Assert.Throws(() => client.CreatePurchaseOrderAsync(new CreatePurchaseOrderInput()).GetAwaiter().GetResult());
54 | }
55 |
56 | [Fact]
57 | public void CreatePurchaseOrderThrowIfNoOutput()
58 | {
59 | CreatePurchaseOrderOutput mockOutput = null;
60 | var mockResponse = CreateJobResponse(mockOutput);
61 |
62 | var client = new MyRpaClient(GetMockOrchestratorClient(mockResponse), _validSetting);
63 | Assert.Throws(() => client.CreatePurchaseOrderAsync(new CreatePurchaseOrderInput()).GetAwaiter().GetResult());
64 | }
65 |
66 | [Fact]
67 | public void CreatePurchaseOrderSuccess()
68 | {
69 | var mockOutput = new CreatePurchaseOrderOutput()
70 | {
71 | PurchaseOrderId = "123456",
72 | };
73 |
74 | var mockResponse = CreateJobResponse(mockOutput);
75 |
76 | var client = new MyRpaClient(GetMockOrchestratorClient(mockResponse), _validSetting);
77 | var output = client.CreatePurchaseOrderAsync(new CreatePurchaseOrderInput()).GetAwaiter().GetResult();
78 | Assert.Equal(mockOutput.PurchaseOrderId, output.PurchaseOrderId);
79 | }
80 |
81 | [Fact]
82 | public void CreateSalesOrderThrowIfNoOutput()
83 | {
84 | CreateSalesOrderOutput mockOutput = null;
85 | var mockResponse = CreateJobResponse(mockOutput);
86 |
87 | var client = new MyRpaClient(GetMockOrchestratorClient(mockResponse), _validSetting);
88 | Assert.Throws(() => client.CreateSalesOrderAsync(new CreateSalesOrderInput()).GetAwaiter().GetResult());
89 | }
90 |
91 | [Fact]
92 | public void CreateSalesOrderSuccess()
93 | {
94 | var mockOutput = new CreateSalesOrderOutput()
95 | {
96 | OrderId = "123456",
97 | DeliveryDate = DateTime.Today.AddDays(3),
98 | };
99 |
100 | var mockResponse = CreateJobResponse(mockOutput);
101 |
102 | var client = new MyRpaClient(GetMockOrchestratorClient(mockResponse), _validSetting);
103 | var output = client.CreateSalesOrderAsync(new CreateSalesOrderInput()).GetAwaiter().GetResult();
104 | Assert.Equal(mockOutput.OrderId, output.OrderId);
105 | Assert.Equal(mockOutput.DeliveryDate.ToShortDateString(), output.DeliveryDate.ToShortDateString());
106 | }
107 |
108 | [Fact]
109 | public void GetItemsThrowIfNoOutput()
110 | {
111 | GetItemsOutput mockOutput = null;
112 | var mockResponse = CreateJobResponse(mockOutput);
113 |
114 | var client = new MyRpaClient(GetMockOrchestratorClient(mockResponse), _validSetting);
115 | Assert.Throws(() => client.GetItemsAsync(new GetItemsInput()).GetAwaiter().GetResult());
116 | }
117 |
118 | [Fact]
119 | public void GetItemsSuccess()
120 | {
121 | var mockOutput = new GetItemsOutputInternal()
122 | {
123 | DeliveryDate = new string[]
124 | {
125 | DateTime.Today.AddDays(2).ToShortDateString(),
126 | DateTime.Today.AddDays(10).ToShortDateString()
127 | },
128 | ItemId = new string[] { "1234", "5678" },
129 | OrderId = new string[] { "7890", "1357" },
130 | ItemName = new string[] { "Name1", "Name2" },
131 | Quantity = new string[] { "1", "2" },
132 | DeliveryStatus = new string[] { "out of stock", "delivered" },
133 | };
134 |
135 | var mockResponse = CreateJobResponse(mockOutput);
136 |
137 | var client = new MyRpaClient(GetMockOrchestratorClient(mockResponse), _validSetting);
138 | var output = client.GetItemsAsync(new GetItemsInput()).GetAwaiter().GetResult();
139 | Assert.Equal(mockOutput.ItemId.Length, output.Items.Length);
140 | Assert.Equal(mockOutput.ItemId[0], output.Items[0].ItemId);
141 | }
142 |
143 | [Fact]
144 | public void CancelOrderThrowIfNoOutput()
145 | {
146 | CancelOrderOutput mockOutput = null;
147 | var mockResponse = CreateJobResponse(mockOutput);
148 |
149 | var client = new MyRpaClient(GetMockOrchestratorClient(mockResponse), _validSetting);
150 | Assert.Throws(() => client.CancelOrderAsync(new CancelOrderInput()).GetAwaiter().GetResult());
151 | }
152 |
153 | [Fact]
154 | public void CancelOrderSuccess()
155 | {
156 | var mockOutput = new CancelOrderOutput()
157 | {
158 | ReturnLabelLocation = "randome locaion",
159 | };
160 |
161 | var mockResponse = CreateJobResponse(mockOutput);
162 |
163 | var client = new MyRpaClient(GetMockOrchestratorClient(mockResponse), _validSetting);
164 | var output = client.CancelOrderAsync(new CancelOrderInput()).GetAwaiter().GetResult();
165 | Assert.Equal(mockOutput.ReturnLabelLocation, output.ReturnLabelLocation);
166 | }
167 |
168 | private IOrchestratorClient GetMockOrchestratorClient(StartJobResponse mockResponse)
169 | {
170 | var orchestratorClient = new Mock();
171 | orchestratorClient
172 | .Setup(c => c.ExecuteJobAsync(It.IsAny()))
173 | .ReturnsAsync(mockResponse);
174 | return orchestratorClient.Object;
175 | }
176 |
177 | private StartJobResponse CreateJobResponse(T t)
178 | {
179 | return new StartJobResponse()
180 | {
181 | Id = "random",
182 | Key = "random",
183 | State = "random",
184 | OutputArguments = t == null? null : JsonConvert.SerializeObject(t),
185 | };
186 | }
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/BotFramework/Common/AdapterWithErrorHandler.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder;
2 | using Microsoft.Bot.Builder.Integration.AspNet.Core;
3 | using Microsoft.Bot.Connector.Authentication;
4 | using Microsoft.Extensions.Logging;
5 | using System;
6 | using UiPath.ChatbotSamples.BotFramework.Resources;
7 |
8 | namespace UiPath.ChatbotSamples.BotFramework.Bot.Common
9 | {
10 | public class AdapterWithErrorHandler : BotFrameworkHttpAdapter
11 | {
12 | public AdapterWithErrorHandler(ICredentialProvider credentialProvider, ILogger logger, ConversationState conversationState = null)
13 | : base(credentialProvider)
14 | {
15 | OnTurnError = async (turnContext, exception) =>
16 | {
17 | // Log any leaked exception from the application.
18 | logger.LogError($"Exception caught : {exception.Message}");
19 |
20 | // Send a catch-all apology to the user.
21 | await turnContext.SendActivityAsync(Resource.Internal_Exception);
22 |
23 | if (conversationState != null)
24 | {
25 | try
26 | {
27 | // Delete the conversationState for the current conversation to prevent the
28 | // bot from getting stuck in a error-loop caused by being in a bad state.
29 | // ConversationState should be thought of as similar to "cookie-state" in a Web pages.
30 | await conversationState.DeleteAsync(turnContext);
31 | }
32 | catch (Exception e)
33 | {
34 | logger.LogError($"Exception caught on attempting to Delete ConversationState : {e.Message}");
35 | }
36 | }
37 | };
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/BotFramework/Common/BotDialogSet.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using Microsoft.Extensions.Logging;
4 | using System.Threading.Tasks;
5 | using UiPath.ChatbotSamples.BotFramework.Common.Models;
6 |
7 | namespace UiPath.ChatbotSamples.BotFramework.Common
8 | {
9 | public class BotDialogSet
10 | {
11 | private DialogSet _dialogs;
12 |
13 | public BotDialogSet(IStatePropertyAccessor dialogStateAccessor, IStatePropertyAccessor userProfileStateAccessor, ILoggerFactory loggerFactory)
14 | {
15 | _dialogs = new DialogSet(dialogStateAccessor);
16 | }
17 |
18 | public void AddDialogToSet(Dialog dialog)
19 | {
20 | _dialogs.Add(dialog);
21 | }
22 |
23 | public async Task CreateDialogContextAsync(ITurnContext turnContext)
24 | {
25 | return await _dialogs.CreateContextAsync(turnContext);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/BotFramework/Common/BotIntents.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Schema;
2 | using System.Collections.Generic;
3 | using UiPath.ChatbotSamples.BotFramework.Common.Models;
4 |
5 | namespace UiPath.ChatbotSamples.BotFramework.Common
6 | {
7 | public interface IBotIntents
8 | {
9 | IReadOnlyDictionary Intents { get; }
10 |
11 | double IntentTriggerThreshold { get; }
12 |
13 | Intent DefaultIntent { get; }
14 |
15 | IActivity FallbackActivity { get; }
16 |
17 | IActivity WelcomeActivity { get; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/BotFramework/Common/BotServices.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.AI.Luis;
2 | using Microsoft.Bot.Configuration;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace UiPath.ChatbotSamples.BotFramework.Common
7 | {
8 | ///
9 | /// Represents references to external services.
10 | ///
11 | /// For example, LUIS services are kept here as a singleton. This external service is configured
12 | /// using the class.
13 | ///
14 | // See https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1
15 | // for more information regarding dependency injection
16 | // See https://www.luis.ai/home" for more information regarding language understanding using LUIS
17 | public class BotServices
18 | {
19 | ///
20 | /// Initializes a new instance of the class.
21 | /// A dictionary of named instances for usage within the bot.
22 | ///
23 | public BotServices(BotConfiguration botConfiguration)
24 | {
25 | foreach (var service in botConfiguration.Services)
26 | {
27 | switch (service.Type)
28 | {
29 | case ServiceTypes.Luis:
30 | {
31 | var luis = (LuisService)service;
32 | EnsureNotNull(luis, ServiceTypes.Luis);
33 |
34 | var app = new LuisApplication(luis.AppId, luis.AuthoringKey, luis.GetEndpoint());
35 | var recognizer = new LuisRecognizer(app);
36 | LuisServices.Add(luis.Name, recognizer);
37 | break;
38 | }
39 | case ServiceTypes.Endpoint:
40 | {
41 | var endPoint = (EndpointService)service;
42 | EnsureNotNull(endPoint, ServiceTypes.Endpoint);
43 | EndpointServices.Add(endPoint.Name, endPoint);
44 | break;
45 | }
46 | }
47 | }
48 |
49 | if (EndpointServices.Count == 0)
50 | {
51 | throw new InvalidOperationException($"The .bot file does not contain an endpoint.");
52 | }
53 | }
54 |
55 | ///
56 | /// Gets the set of LUIS Services used.
57 | /// Given there can be multiple services used in a single bot,
58 | /// LuisServices is represented as a dictionary. This is also modeled in the
59 | /// ".bot" file since the elements are named.
60 | /// The LUIS services collection should not be modified while the bot is running.
61 | ///
62 | /// A client instance created based on configuration in the .bot file.
63 | ///
64 | ///
65 | public Dictionary LuisServices { get; } = new Dictionary();
66 |
67 | ///
68 | /// Gets the set of endpoint services used.
69 | /// Given there can be multiple endpoints for different environments,
70 | /// EndpointServices is represented as a dictionary.
71 | ///
72 | public Dictionary EndpointServices { get; } = new Dictionary();
73 |
74 | private void EnsureNotNull(T service, string serviceType)
75 | {
76 | if (service == null)
77 | {
78 | throw new InvalidCastException($"The {serviceType} service is not configured correctly in your .bot file.");
79 | }
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/BotFramework/Common/BotSettings.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UiPath.ChatbotSamples.BotFramework.Common.Models;
3 |
4 | namespace UiPath.ChatbotSamples.BotFramework.Common
5 | {
6 | public abstract class BotSettings
7 | {
8 | public abstract string LuisConfiguration { get; }
9 |
10 |
11 | public abstract IReadOnlyDictionary Entities { get; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/BotFramework/Common/Common.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | UiPath.ChatbotSamples.BotFramework.Common
6 | UiPath.ChatbotSamples.BotFramework.Common
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/BotFramework/Common/Models/DetourIntent.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Schema;
2 |
3 | namespace UiPath.ChatbotSamples.BotFramework.Common.Models
4 | {
5 | public class DetourIntent : Intent
6 | {
7 | public IActivity[] DetourActivities { get; private set; }
8 |
9 | public DetourIntent(string name, IActivity[] detourActivities)
10 | : base(name, string.Empty, IntentType.Detour)
11 | {
12 | DetourActivities = detourActivities;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/BotFramework/Common/Models/EntityState.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace UiPath.ChatbotSamples.BotFramework.Common.Models
4 | {
5 | public class EntityState
6 | {
7 | public IDictionary Entities { get; } = new Dictionary();
8 |
9 | public void AddOrUpdate(string key, string value)
10 | {
11 | if (Entities.ContainsKey(key))
12 | {
13 | Entities[key] = value;
14 | }
15 | else
16 | {
17 | Entities.Add(key, value);
18 | }
19 | }
20 |
21 | public string TryGet(string key)
22 | {
23 | if (Entities.ContainsKey(key))
24 | {
25 | return Entities[key];
26 | }
27 | else
28 | {
29 | return string.Empty;
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/BotFramework/Common/Models/Intent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UiPath.ChatbotSamples.BotFramework.Common.Models
4 | {
5 | public class Intent
6 | {
7 | public string Name { get; private set; }
8 |
9 | public string DialogName { get; private set; }
10 |
11 | public IntentType Type { get; private set; }
12 |
13 | public Intent(string name, string dialogName, IntentType type)
14 | {
15 | Name = name;
16 | DialogName = dialogName;
17 | Type = type;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/BotFramework/Common/Models/IntentType.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.Common.Models
2 | {
3 | public enum IntentType
4 | {
5 | None = 0,
6 | Normal,
7 | Termination,
8 | Detour,
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/BotFramework/Common/Models/LuisEntity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace UiPath.ChatbotSamples.BotFramework.Common.Models
5 | {
6 | public class LuisEntity
7 | {
8 | private Func _postProcess;
9 | public LuisEntity(List patterns, Func postProcess = null)
10 | {
11 | Patterns.AddRange(patterns);
12 | _postProcess = postProcess;
13 | }
14 |
15 | // entity names in luis that map in bot entity
16 | public List Patterns { get; } = new List();
17 |
18 | // postproces the entity value and customize it for bot use
19 | public string PostProcess(string value)
20 | {
21 | if (_postProcess != null)
22 | {
23 | return _postProcess(value);
24 | }
25 | return value;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/BotFramework/Common/Models/TerminationIntent.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Schema;
2 |
3 | namespace UiPath.ChatbotSamples.BotFramework.Common.Models
4 | {
5 | public class TerminationIntent : Intent
6 | {
7 | public IActivity[] TerminationSuccessActivities { get; private set; }
8 |
9 | public IActivity[] TerminationFailActivities { get; private set; }
10 |
11 | public TerminationIntent(string name, IActivity[] successActivities, IActivity[] failActivities)
12 | : base(name, string.Empty, IntentType.Termination)
13 | {
14 | TerminationSuccessActivities = successActivities;
15 | TerminationFailActivities = failActivities;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/BotFramework/Common/MultiTurnBot.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder;
2 | using Microsoft.Bot.Builder.AI.Luis;
3 | using Microsoft.Bot.Builder.Dialogs;
4 | using Microsoft.Bot.Schema;
5 | using Microsoft.Extensions.Logging;
6 | using System;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using UiPath.ChatbotSamples.BotFramework.Common.Models;
10 | using UiPath.ChatbotSamples.BotFramework.Utils;
11 |
12 | namespace UiPath.ChatbotSamples.BotFramework.Common
13 | {
14 | public class MultiTurnBot : IBot
15 | {
16 | protected readonly UserState _userState;
17 | protected readonly ConversationState _conversationState;
18 | protected readonly LuisRecognizer _luisRecognizer;
19 | protected readonly BotDialogSet _dialogSet;
20 | protected readonly BotSettings _botSettings;
21 | protected readonly IBotIntents _botIntents;
22 | protected readonly ILogger _logger;
23 |
24 | protected readonly IStatePropertyAccessor _entityStateAccessor;
25 |
26 | public MultiTurnBot(BotServices services, UserState userState, ConversationState conversationState, BotSettings botSettings, IBotIntents botIntents, ILoggerFactory loggerFactory)
27 | {
28 | _userState = userState.CheckNullReference();
29 | _conversationState = conversationState.CheckNullReference();
30 | _botSettings = botSettings.CheckNullReference();
31 | _botIntents = botIntents.CheckNullReference();
32 |
33 | // Verify LUIS configuration.
34 | if (!services.CheckNullReference().LuisServices.ContainsKey(botSettings.LuisConfiguration))
35 | {
36 | throw new InvalidOperationException($"The bot configuration does not contain a service type of `luis` with the id `{botSettings.LuisConfiguration}`.");
37 | }
38 | _luisRecognizer = services.LuisServices[botSettings.LuisConfiguration];
39 |
40 |
41 | _entityStateAccessor = _userState.CreateProperty(nameof(EntityState));
42 | var dialogStateAccessor = _conversationState.CreateProperty(nameof(DialogState));
43 | _dialogSet = new BotDialogSet(dialogStateAccessor, _entityStateAccessor, loggerFactory);
44 |
45 | _logger = loggerFactory.CheckNullReference().CreateLogger();
46 | }
47 |
48 | public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
49 | {
50 | var activity = turnContext.Activity;
51 | var dialogContext = await _dialogSet.CreateDialogContextAsync(turnContext);
52 |
53 | if (activity.Type == ActivityTypes.Message)
54 | {
55 |
56 | var luisResults = await _luisRecognizer.RecognizeAsync(dialogContext.Context, cancellationToken);
57 | var topIntent = GetTopIntent(luisResults);
58 |
59 | await UpdateEntityState(luisResults, turnContext);
60 |
61 | // Handle conversation interrupts first.
62 | var interrupted = await IsTurnInterruptedAsync(dialogContext, topIntent);
63 | if (interrupted)
64 | {
65 | await ExitTurnAsync(turnContext);
66 | return;
67 | }
68 |
69 | var dialogResult = await dialogContext.ContinueDialogAsync(cancellationToken);
70 |
71 | if (!dialogContext.Context.Responded)
72 | {
73 | // examine results from active dialog
74 | switch (dialogResult.Status)
75 | {
76 | case DialogTurnStatus.Empty:
77 | if (!string.IsNullOrEmpty(topIntent.DialogName))
78 | {
79 | await dialogContext.BeginDialogAsync(topIntent.DialogName);
80 | }
81 | else
82 | {
83 | await dialogContext.Context.SendActivityAsync(_botIntents.FallbackActivity);
84 | }
85 | break;
86 |
87 | case DialogTurnStatus.Waiting:
88 | // The active dialog is waiting for a response from the user, so do nothing.
89 | break;
90 |
91 | case DialogTurnStatus.Complete:
92 | await dialogContext.EndDialogAsync();
93 | break;
94 |
95 | default:
96 | await dialogContext.CancelAllDialogsAsync();
97 | break;
98 | }
99 | }
100 | }
101 | else if (activity.Type == ActivityTypes.ConversationUpdate)
102 | {
103 | await SendWelcomeMessageAsync(activity, dialogContext);
104 | }
105 |
106 | await ExitTurnAsync(turnContext);
107 | }
108 |
109 | protected async Task SendWelcomeMessageAsync(Activity activity, DialogContext dialogContext)
110 | {
111 | if (activity.MembersAdded != null)
112 | {
113 | // Iterate over all new members added to the conversation.
114 | foreach (var member in activity.MembersAdded)
115 | {
116 | // Greet anyone that was not the target (recipient) of this message.
117 | if (member.Id != activity.Recipient.Id)
118 | {
119 | await dialogContext.Context.SendActivityAsync(_botIntents.WelcomeActivity);
120 | }
121 | }
122 | }
123 | }
124 |
125 | protected async Task ExitTurnAsync(ITurnContext turnContext)
126 | {
127 | await _conversationState.SaveChangesAsync(turnContext);
128 | await _userState.SaveChangesAsync(turnContext);
129 | }
130 |
131 | protected Intent GetTopIntent(RecognizerResult luisResult)
132 | {
133 | if (luisResult == null)
134 | {
135 | return _botIntents.DefaultIntent;
136 | }
137 |
138 | var topScoringIntent = luisResult.GetTopScoringIntent();
139 | if (topScoringIntent.score >= _botIntents.IntentTriggerThreshold)
140 | {
141 | var topIntent = topScoringIntent.intent;
142 | if (_botIntents.Intents.ContainsKey(topIntent))
143 | {
144 | return _botIntents.Intents[topIntent];
145 | }
146 | else
147 | {
148 | _logger.LogError($"Fail to find intent {topIntent} in bot definition.");
149 | }
150 | }
151 | return _botIntents.DefaultIntent;
152 | }
153 |
154 | protected async Task IsTurnInterruptedAsync(DialogContext dialogContext, Intent topIntent)
155 | {
156 | // See if there are any conversation interrupts we need to handle.
157 | if (topIntent.Type == IntentType.Termination)
158 | {
159 | return await TerminateIntentAsync(dialogContext, topIntent as TerminationIntent);
160 | }
161 |
162 | if (topIntent.Type == IntentType.Detour)
163 | {
164 | return await DetourIntentAsync(dialogContext, topIntent as DetourIntent);
165 | }
166 |
167 | return false;
168 | }
169 |
170 | protected async Task TerminateIntentAsync(DialogContext dialogContext, TerminationIntent intent)
171 | {
172 | IActivity[] activities = intent.TerminationFailActivities;
173 | if (dialogContext.ActiveDialog != null)
174 | {
175 | await dialogContext.CancelAllDialogsAsync();
176 | activities = intent.TerminationSuccessActivities;
177 | }
178 |
179 | foreach (var activity in activities)
180 | {
181 | await dialogContext.Context.SendActivityAsync(activity);
182 | }
183 |
184 | return true;
185 | }
186 |
187 | protected async Task DetourIntentAsync(DialogContext dialogContext, DetourIntent intent)
188 | {
189 | IActivity[] activities = intent.DetourActivities;
190 |
191 | foreach (var activity in activities)
192 | {
193 | await dialogContext.Context.SendActivityAsync(activity);
194 | }
195 |
196 | if (dialogContext.ActiveDialog != null)
197 | {
198 | await dialogContext.RepromptDialogAsync();
199 | }
200 |
201 | return true;
202 | }
203 |
204 | protected async Task UpdateEntityState(RecognizerResult luisResult, ITurnContext turnContext)
205 | {
206 | try
207 | {
208 | if (luisResult.Entities != null && luisResult.Entities.HasValues)
209 | {
210 | var entityState = await _entityStateAccessor.GetAsync(turnContext, () => new EntityState());
211 | var entities = luisResult.Entities;
212 |
213 | foreach (var entityMapping in _botSettings.Entities)
214 | {
215 | var luisEntity = entityMapping.Value;
216 | foreach (var entity in luisEntity.Patterns)
217 | {
218 | if (entities[entity] != null)
219 | {
220 | entityState.AddOrUpdate(entityMapping.Key, luisEntity.PostProcess((string)entities[entity][0]));
221 | }
222 | }
223 | }
224 |
225 | await _entityStateAccessor.SetAsync(turnContext, entityState);
226 | }
227 | }
228 | catch (Exception e)
229 | {
230 | _logger.LogError($"{nameof(UpdateEntityState)} failed with exception {e.ToString()}");
231 | }
232 | }
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/BotFramework/Data/Luis/.luisrc:
--------------------------------------------------------------------------------
1 | {
2 | "authoringKey": "231bce45531f463bb77c8217e8534661",
3 | "versionId": "0.1",
4 | "region": "westus"
5 | }
6 |
--------------------------------------------------------------------------------
/BotFramework/Data/Luis/Sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "intents": [
3 | {
4 | "name": "Greeting"
5 | },
6 | {
7 | "name": "Help"
8 | },
9 | {
10 | "name": "Cancel"
11 | },
12 | {
13 | "name": "Bye"
14 | },
15 | {
16 | "name": "DelayedShipment"
17 | },
18 | {
19 | "name": "ReplaceItem"
20 | },
21 | {
22 | "name": "CustomerId"
23 | }
24 | ],
25 | "entities": [
26 | {
27 | "name": "Id",
28 | "roles": []
29 | }
30 | ],
31 | "composites": [],
32 | "closedLists": [],
33 | "regex_entities": [],
34 | "model_features": [],
35 | "regex_features": [],
36 | "utterances": [
37 | {
38 | "text": "good evening",
39 | "intent": "Greeting",
40 | "entities": []
41 | },
42 | {
43 | "text": "good morning",
44 | "intent": "Greeting",
45 | "entities": []
46 | },
47 | {
48 | "text": "hello",
49 | "intent": "Greeting",
50 | "entities": []
51 | },
52 | {
53 | "text": "hello bot",
54 | "intent": "Greeting",
55 | "entities": []
56 | },
57 | {
58 | "text": "hey",
59 | "intent": "Greeting",
60 | "entities": []
61 | },
62 | {
63 | "text": "hey there",
64 | "intent": "Greeting",
65 | "entities": []
66 | },
67 | {
68 | "text": "hi",
69 | "intent": "Greeting",
70 | "entities": []
71 | },
72 | {
73 | "text": "hi bot",
74 | "intent": "Greeting",
75 | "entities": []
76 | },
77 | {
78 | "text": "hiya",
79 | "intent": "Greeting",
80 | "entities": []
81 | },
82 | {
83 | "text": "how are you",
84 | "intent": "Greeting",
85 | "entities": []
86 | },
87 | {
88 | "text": "how are you today",
89 | "intent": "Greeting",
90 | "entities": []
91 | },
92 | {
93 | "text": "what's your name",
94 | "intent": "Greeting",
95 | "entities": []
96 | },
97 | {
98 | "text": "who am i speaking to",
99 | "intent": "Greeting",
100 | "entities": []
101 | },
102 | {
103 | "text": "who am i speaking with",
104 | "intent": "Greeting",
105 | "entities": []
106 | },
107 | {
108 | "text": "who are you",
109 | "intent": "Greeting",
110 | "entities": []
111 | },
112 | {
113 | "text": "yo",
114 | "intent": "Greeting",
115 | "entities": []
116 | },
117 | {
118 | "text": "I need help",
119 | "intent": "Help",
120 | "entities": []
121 | },
122 | {
123 | "text": "please help",
124 | "intent": "Help",
125 | "entities": []
126 | },
127 | {
128 | "text": "what can you do",
129 | "intent": "Help",
130 | "entities": []
131 | },
132 | {
133 | "text": "?",
134 | "intent": "Help",
135 | "entities": []
136 | },
137 | {
138 | "text": "I'm lost",
139 | "intent": "Help",
140 | "entities": []
141 | },
142 | {
143 | "text": "lost",
144 | "intent": "Help",
145 | "entities": []
146 | },
147 | {
148 | "text": "confused",
149 | "intent": "Help",
150 | "entities": []
151 | },
152 | {
153 | "text": "frustrated",
154 | "intent": "Help",
155 | "entities": []
156 | },
157 | {
158 | "text": "what are your capabilities",
159 | "intent": "Help",
160 | "entities": []
161 | },
162 | {
163 | "text": "help me",
164 | "intent": "Help",
165 | "entities": []
166 | },
167 | {
168 | "text": "help",
169 | "intent": "Help",
170 | "entities": []
171 | },
172 | {
173 | "text": "how do I interact with you",
174 | "intent": "Help",
175 | "entities": []
176 | },
177 | {
178 | "text": "help please",
179 | "intent": "Help",
180 | "entities": []
181 | },
182 | {
183 | "text": "i'm stuck",
184 | "intent": "Help",
185 | "entities": []
186 | },
187 | {
188 | "text": "i don't understand",
189 | "intent": "Help",
190 | "entities": []
191 | },
192 | {
193 | "text": "what can I say",
194 | "intent": "Help",
195 | "entities": []
196 | },
197 | {
198 | "text": "what can you help me with",
199 | "intent": "Help",
200 | "entities": []
201 | },
202 | {
203 | "text": "what can you do",
204 | "intent": "Help",
205 | "entities": []
206 | },
207 | {
208 | "text": "what do i do now",
209 | "intent": "Help",
210 | "entities": []
211 | },
212 | {
213 | "text": "why doesn't this work",
214 | "intent": "Help",
215 | "entities": []
216 | },
217 | {
218 | "text": "can you help me",
219 | "intent": "Help",
220 | "entities": []
221 | },
222 | {
223 | "text": "cancel",
224 | "intent": "Cancel",
225 | "entities": []
226 | },
227 | {
228 | "text": "stop what you are doing",
229 | "intent": "Cancel",
230 | "entities": []
231 | },
232 | {
233 | "text": "please cancel",
234 | "intent": "Cancel",
235 | "entities": []
236 | },
237 | {
238 | "text": "I don't want to continue",
239 | "intent": "Cancel",
240 | "entities": []
241 | },
242 | {
243 | "text": "quit",
244 | "intent": "Cancel",
245 | "entities": []
246 | },
247 | {
248 | "text": "stop",
249 | "intent": "Cancel",
250 | "entities": []
251 | },
252 | {
253 | "text": "abort",
254 | "intent": "Cancel",
255 | "entities": []
256 | },
257 | {
258 | "text": "don't do it",
259 | "intent": "Cancel",
260 | "entities": []
261 | },
262 | {
263 | "text": "don't do that",
264 | "intent": "Cancel",
265 | "entities": []
266 | },
267 | {
268 | "text": "i would like to cancel",
269 | "intent": "Cancel",
270 | "entities": []
271 | },
272 | {
273 | "text": "i will not give you my name",
274 | "intent": "Cancel",
275 | "entities": []
276 | },
277 | {
278 | "text": "i won't give you my name",
279 | "intent": "Cancel",
280 | "entities": []
281 | },
282 | {
283 | "text": "no way, I won't give you my location",
284 | "intent": "Cancel",
285 | "entities": []
286 | },
287 | {
288 | "text": "I'm not going to tell you where i live",
289 | "intent": "Cancel",
290 | "entities": []
291 | },
292 | {
293 | "text": "I will not give you my location or name",
294 | "intent": "Cancel",
295 | "entities": []
296 | },
297 | {
298 | "text": "no way",
299 | "intent": "Cancel",
300 | "entities": []
301 | },
302 | {
303 | "text": "please stop",
304 | "intent": "Cancel",
305 | "entities": []
306 | },
307 | {
308 | "text": "I'm bailing",
309 | "intent": "Cancel",
310 | "entities": []
311 | },
312 | {
313 | "text": "Bye",
314 | "intent": "Bye",
315 | "entities": []
316 | },
317 | {
318 | "text": "Talk to agent",
319 | "intent": "Bye",
320 | "entities": []
321 | },
322 | {
323 | "text": "I want to talk to human",
324 | "intent": "Bye",
325 | "entities": []
326 | },
327 | {
328 | "text": "no, thank you",
329 | "intent": "Bye",
330 | "entities": []
331 | },
332 | {
333 | "text": "that's all I need for today",
334 | "intent": "Bye",
335 | "entities": []
336 | },
337 | {
338 | "text": "My order is delayed",
339 | "intent": "DelayedShipment",
340 | "entities": []
341 | },
342 | {
343 | "text": "shipment is delayed",
344 | "intent": "DelayedShipment",
345 | "entities": []
346 | },
347 | {
348 | "text": "why my order is not shipped",
349 | "intent": "DelayedShipment",
350 | "entities": []
351 | },
352 | {
353 | "text": "The headphones shipped to me are broken",
354 | "intent": "ReplaceItem",
355 | "entities": []
356 | },
357 | {
358 | "text": "The item is broken",
359 | "intent": "ReplaceItem",
360 | "entities": []
361 | },
362 | {
363 | "text": "The item is not working",
364 | "intent": "ReplaceItem",
365 | "entities": []
366 | },
367 | {
368 | "text": "The wireless speakers are not working",
369 | "intent": "ReplaceItem",
370 | "entities": []
371 | },
372 | {
373 | "text": "I want to replace my item",
374 | "intent": "ReplaceItem",
375 | "entities": []
376 | },
377 | {
378 | "text": "I want to replace",
379 | "intent": "ReplaceItem",
380 | "entities": []
381 | },
382 | {
383 | "text": "I want to return my item",
384 | "intent": "ReplaceItem",
385 | "entities": []
386 | },
387 | {
388 | "text": "I want to return the headphones",
389 | "intent": "ReplaceItem",
390 | "entities": []
391 | },
392 | {
393 | "text": "My customer Id is 12345",
394 | "intent": "CustomerId",
395 | "entities": [
396 | {
397 | "entity": "Id",
398 | "startPos": 18,
399 | "endPos": 22
400 | }
401 | ]
402 | },
403 | {
404 | "text": "It is 234",
405 | "intent": "CustomerId",
406 | "entities": [
407 | {
408 | "entity": "Id",
409 | "startPos": 6,
410 | "endPos": 8
411 | }
412 | ]
413 | },
414 | {
415 | "text": "My Id is 4678",
416 | "intent": "CustomerId",
417 | "entities": [
418 | {
419 | "entity": "Id",
420 | "startPos": 9,
421 | "endPos": 12
422 | }
423 | ]
424 | },
425 | {
426 | "text": "Account id 890",
427 | "intent": "CustomerId",
428 | "entities": [
429 | {
430 | "entity": "Id",
431 | "startPos": 11,
432 | "endPos": 13
433 | }
434 | ]
435 | }
436 | ],
437 | "patterns": [],
438 | "patternAnyEntities": [],
439 | "prebuiltEntities": [],
440 | "luis_schema_version": "3.0.0",
441 | "versionId": "0.1",
442 | "name": "SampleBot",
443 | "desc": "",
444 | "culture": "en-us"
445 | }
--------------------------------------------------------------------------------
/BotFramework/Data/Luis/Sample.lu:
--------------------------------------------------------------------------------
1 | # Greeting
2 | - good evening
3 | - good morning
4 | - hello
5 | - hello bot
6 | - hey
7 | - hey there
8 | - hi
9 | - hi bot
10 | - hiya
11 | - how are you
12 | - how are you today
13 | - what's your name
14 | - who am i speaking to
15 | - who am i speaking with
16 | - who are you
17 | - yo
18 |
19 | # Help
20 | - I need help
21 | - please help
22 | - what can you do
23 | - ?
24 | - I'm lost
25 | - lost
26 | - confused
27 | - frustrated
28 | - what are your capabilities
29 | - help me
30 | - help
31 | - how do I interact with you
32 | - help please
33 | - i'm stuck
34 | - i don't understand
35 | - what can I say
36 | - what can you help me with
37 | - what can you do
38 | - what do i do now
39 | - why doesn't this work
40 | - can you help me
41 |
42 | # Cancel
43 | - cancel
44 | - stop what you are doing
45 | - please cancel
46 | - I don't want to continue
47 | - quit
48 | - stop
49 | - abort
50 | - don't do it
51 | - don't do that
52 | - i would like to cancel
53 | - i will not give you my name
54 | - i won't give you my name
55 | - no way, I won't give you my location
56 | - I'm not going to tell you where i live
57 | - I will not give you my location or name
58 | - no way
59 | - please stop
60 | - I'm bailing
61 |
62 | # Bye
63 | - Bye
64 | - Talk to agent
65 | - I want to talk to human
66 | - no, thank you
67 | - that's all I need for today
68 |
69 | # DelayedShipment
70 | - My order is delayed
71 | - shipment is delayed
72 | - why my order is not shipped
73 |
74 | # ReplaceItem
75 | - The headphones shipped to me are broken
76 | - The item is broken
77 | - The item is not working
78 | - The wireless speakers are not working
79 | - I want to replace my item
80 | - I want to replace
81 | - I want to return my item
82 | - I want to return the headphones
83 |
84 | # CustomerId
85 | - My customer Id is {Id=12345}
86 | - It is {Id=234}
87 | - My Id is {Id=4678}
88 | - Account id {Id=890}
89 |
--------------------------------------------------------------------------------
/BotFramework/Data/Packages/CancelOrder.1.0.1-alpha.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UiPath/Chatbot-Samples/6e4fb400456c725070e8d3691ba17827baaac7aa/BotFramework/Data/Packages/CancelOrder.1.0.1-alpha.nupkg
--------------------------------------------------------------------------------
/BotFramework/Data/Packages/CreatePurchaseOrder.1.0.1-alpha.1.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UiPath/Chatbot-Samples/6e4fb400456c725070e8d3691ba17827baaac7aa/BotFramework/Data/Packages/CreatePurchaseOrder.1.0.1-alpha.1.nupkg
--------------------------------------------------------------------------------
/BotFramework/Data/Packages/CreateSalesOrder.1.0.1-alpha.1.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UiPath/Chatbot-Samples/6e4fb400456c725070e8d3691ba17827baaac7aa/BotFramework/Data/Packages/CreateSalesOrder.1.0.1-alpha.1.nupkg
--------------------------------------------------------------------------------
/BotFramework/Data/Packages/GetItems.1.0.1-alpha.3.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UiPath/Chatbot-Samples/6e4fb400456c725070e8d3691ba17827baaac7aa/BotFramework/Data/Packages/GetItems.1.0.1-alpha.3.nupkg
--------------------------------------------------------------------------------
/BotFramework/Dialogs/Dialogs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | UiPath.ChatbotSamples.BotFramework.Dialogs
6 | UiPath.ChatbotSamples.BotFramework.Dialogs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/BotFramework/Dialogs/MyBot.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder;
2 | using Microsoft.Extensions.Logging;
3 | using UiPath.ChatbotSamples.BotFramework.Actions;
4 | using UiPath.ChatbotSamples.BotFramework.Common;
5 | using UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog;
6 |
7 | namespace UiPath.ChatbotSamples.BotFramework.Dialogs
8 | {
9 | public class MyBot : MultiTurnBot
10 | {
11 | public MyBot(BotServices services, UserState userState, ConversationState conversationState, IMyRpaClient rpaClient, ILoggerFactory loggerFactory)
12 | :base(services, userState, conversationState, new MyBotSettings(), new MyIntents(), loggerFactory)
13 | {
14 | // Must make sure all the dialogs add to dialog set here.
15 | _dialogSet.AddDialogToSet(new GreetingDialog());
16 | _dialogSet.AddDialogToSet(new GetCustomerProfileDialog(_entityStateAccessor));
17 | _dialogSet.AddDialogToSet(new DelayedShipmentDialog(rpaClient, _entityStateAccessor));
18 | _dialogSet.AddDialogToSet(new ReplaceItemDialog(rpaClient, _entityStateAccessor));
19 | _dialogSet.AddDialogToSet(new CannotFindOrderDialog());
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/BotFramework/Dialogs/MyBotSettings.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UiPath.ChatbotSamples.BotFramework.Common;
3 | using UiPath.ChatbotSamples.BotFramework.Common.Models;
4 |
5 | namespace UiPath.ChatbotSamples.BotFramework.Dialogs
6 | {
7 | public sealed class MyBotSettings: BotSettings
8 | {
9 | ///
10 | /// Key in the bot config (.bot file) for the LUIS instance.
11 | /// In the .bot file, multiple instances of LUIS can be configured.
12 | ///
13 | public override string LuisConfiguration {
14 | get {
15 | return "Sample";
16 | }
17 | }
18 |
19 | public override IReadOnlyDictionary Entities { get; }
20 | = new Dictionary
21 | {
22 | { "CustomerId", new LuisEntity(new List(){ "Id" }, NomalizeCustomerId) },
23 | };
24 |
25 | private static string NomalizeCustomerId(string value)
26 | {
27 | if (!string.IsNullOrEmpty(value))
28 | {
29 | value = value.ToUpperInvariant();
30 | }
31 | return value;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/BotFramework/Dialogs/MyDialog/Base/DialogBase.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 |
3 | namespace UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog.Base
4 | {
5 | public class DialogBase: ComponentDialog
6 | {
7 | private readonly string _dialogId;
8 |
9 | protected DialogBase(string dialogId)
10 | : base(dialogId)
11 | {
12 | _dialogId = dialogId;
13 | }
14 |
15 | protected string GetWaterFallDialogId(string id)
16 | {
17 | return $"WaterFall{id}";
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/BotFramework/Dialogs/MyDialog/Base/StatefulDialogBase.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using System.Threading.Tasks;
4 | using UiPath.ChatbotSamples.BotFramework.Common.Models;
5 |
6 | namespace UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog.Base
7 | {
8 | public class StatefulDialogBase: DialogBase
9 | {
10 | private readonly IStatePropertyAccessor _entityStateAccessor;
11 |
12 | public StatefulDialogBase(string dialogId, IStatePropertyAccessor entityStateAccessor)
13 | : base(dialogId)
14 | {
15 | _entityStateAccessor = entityStateAccessor;
16 | }
17 |
18 | protected async Task GetEntityStateAsync(WaterfallStepContext stepContext)
19 | {
20 | var entityState = await _entityStateAccessor.GetAsync(stepContext.Context, () => null);
21 | if (entityState == null)
22 | {
23 | entityState = new EntityState();
24 | await _entityStateAccessor.SetAsync(stepContext.Context, entityState);
25 | }
26 | return entityState;
27 | }
28 |
29 | protected async Task TryGetEntityValueAsync(WaterfallStepContext stepContext, string key)
30 | {
31 | var entityState = await GetEntityStateAsync(stepContext);
32 | return entityState.TryGet(key);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/BotFramework/Dialogs/MyDialog/CannotFindOrderDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog.Base;
5 | using UiPath.ChatbotSamples.BotFramework.Resources;
6 | using UiPath.ChatbotSamples.BotFramework.Utils;
7 |
8 | namespace UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog
9 | {
10 | public class CannotFindOrderDialog : DialogBase
11 | {
12 | public CannotFindOrderDialog()
13 | : base(nameof(CannotFindOrderDialog))
14 | {
15 | var waterfallSteps = new WaterfallStep[]
16 | {
17 | NoUndeliveredOrderStepAsync,
18 | ProcessTalkToAgentStepAsync,
19 | };
20 | AddDialog(new WaterfallDialog(GetWaterFallDialogId(nameof(CannotFindOrderDialog)), waterfallSteps));
21 | AddDialog(new ConfirmPrompt(nameof(NoUndeliveredOrderStepAsync)));
22 | AddDialog(new TextPrompt(nameof(ProcessTalkToAgentStepAsync)));
23 | }
24 |
25 | private async Task NoUndeliveredOrderStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
26 | {
27 | return await stepContext.PromptAsync(nameof(NoUndeliveredOrderStepAsync), Utils.CreateMessagePrompt(Resource.No_Undelivered_Order, Utils.GetYesNoOptions()));
28 | }
29 |
30 | private async Task ProcessTalkToAgentStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
31 | {
32 | var message = stepContext.Context.Activity.AsMessageActivity().Text;
33 | if (message.OrdinalEquals(Resource.Yes))
34 | {
35 | await stepContext.Context.SendActivityAsync(Resource.Talk_To_Agent);
36 | }
37 | else
38 | {
39 | await stepContext.Context.SendActivityAsync(Resource.Anything_Else);
40 | }
41 | await stepContext.EndDialogAsync();
42 | return await stepContext.Parent.CancelAllDialogsAsync();
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/BotFramework/Dialogs/MyDialog/DelayedShipmentDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using System;
4 | using System.Linq;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 | using UiPath.ChatbotSamples.BotFramework.Actions;
8 | using UiPath.ChatbotSamples.BotFramework.Actions.Models;
9 | using UiPath.ChatbotSamples.BotFramework.Common.Models;
10 | using UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog.Base;
11 | using UiPath.ChatbotSamples.BotFramework.Resources;
12 | using UiPath.ChatbotSamples.BotFramework.Utils;
13 |
14 | namespace UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog
15 | {
16 | public class DelayedShipmentDialog : StatefulDialogBase
17 | {
18 | private readonly IMyRpaClient _myRpaClient;
19 | private readonly IStatePropertyAccessor _entityStateAccessor;
20 |
21 | public DelayedShipmentDialog(IMyRpaClient myRpaClient, IStatePropertyAccessor entityStateAccessor)
22 | : base(nameof(DelayedShipmentDialog), entityStateAccessor)
23 | {
24 | var waterfallSteps = new WaterfallStep[]
25 | {
26 | GetCustomerIdStepAsync,
27 | ListItemsStepAsync,
28 | ProcessItemSelectionStepAsync,
29 | PlaceOrderStepAsync,
30 | };
31 | AddDialog(new WaterfallDialog(GetWaterFallDialogId(nameof(DelayedShipmentDialog)), waterfallSteps));
32 | AddDialog(new TextPrompt(nameof(GetCustomerIdStepAsync)));
33 | AddDialog(new ChoicePrompt(nameof(ListItemsStepAsync)));
34 | AddDialog(new ChoicePrompt(nameof(ProcessItemSelectionStepAsync)));
35 | AddDialog(new TextPrompt(nameof(PlaceOrderStepAsync)));
36 |
37 | _myRpaClient = myRpaClient;
38 | _entityStateAccessor = entityStateAccessor;
39 | }
40 |
41 | private async Task GetCustomerIdStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
42 | {
43 | return await stepContext.BeginDialogAsync(nameof(GetCustomerProfileDialog));
44 | }
45 |
46 | private async Task ListItemsStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
47 | {
48 | await stepContext.Context.SendActivityAsync(Resource.Working_On);
49 | var customerId = await TryGetEntityValueAsync(stepContext, "CustomerId");
50 | stepContext.Values["CustomerId"] = customerId;
51 |
52 | var result = await _myRpaClient.GetItemsAsync(new GetItemsInput() { CustomerId = customerId });
53 |
54 | if (result?.Items == null || result.Items.Length == 0)
55 | {
56 | return await stepContext.BeginDialogAsync(nameof(CannotFindOrderDialog));
57 | }
58 | else
59 | {
60 | stepContext.Values["Items"] = result;
61 | var unDelivered = result.Items.Where(i => i.DeliveryDate >= DateTime.Today).Select(i => i.ItemName).ToList();
62 | unDelivered.Add(Resource.None_Of_Above);
63 | return await stepContext.PromptAsync(nameof(ListItemsStepAsync), Utils.CreateMessagePrompt(Resource.Which_Undelivered, unDelivered));
64 | }
65 | }
66 |
67 | private async Task ProcessItemSelectionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
68 | {
69 | var message = stepContext.Context.Activity.AsMessageActivity().Text;
70 | if (message.OrdinalEquals(Resource.None_Of_Above))
71 | {
72 | return await stepContext.BeginDialogAsync(nameof(CannotFindOrderDialog));
73 | }
74 | else
75 | {
76 | var matchedItems = ((GetItemsOutput)stepContext.Values["Items"]).Items.Where(i => i.ItemName.OrdinalEquals(message)).ToList();
77 | if (matchedItems.Count == 0)
78 | {
79 | return await stepContext.BeginDialogAsync(nameof(CannotFindOrderDialog));
80 | }
81 |
82 | stepContext.Values["SelectedItem"] = matchedItems[0];
83 |
84 | return await stepContext.PromptAsync(nameof(ProcessItemSelectionStepAsync), Utils.CreateMessagePrompt(string.Format(Resource.Deliver_Status, matchedItems[0].DeliveryStatus), Utils.GetYesNoOptions()));
85 | }
86 | }
87 |
88 | private async Task PlaceOrderStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
89 | {
90 |
91 | var message = stepContext.Context.Activity.AsMessageActivity().Text;
92 | if (message.OrdinalEquals(Resource.Yes))
93 | {
94 | await stepContext.Context.SendActivityAsync(Resource.Working_On);
95 | var item = (Item)stepContext.Values["SelectedItem"];
96 | var purchaseOrderOutput = await _myRpaClient.CreatePurchaseOrderAsync(new CreatePurchaseOrderInput() { ItemId = item.ItemId });
97 |
98 | var cancelInput = new CancelOrderInput()
99 | {
100 | OrderId = item.OrderId,
101 | CancelReason = "Delayed shipment",
102 | };
103 | var cancelOrderOutput = await _myRpaClient.CancelOrderAsync(cancelInput);
104 | var orderCancelMessage = string.Format(Resource.Order_Cancelled, item.OrderId, cancelOrderOutput.ReturnLabelLocation);
105 | await stepContext.Context.SendActivityAsync(orderCancelMessage);
106 |
107 | var salesOrderInput = new CreateSalesOrderInput()
108 | {
109 | CustomerId = (string)stepContext.Values["CustomerId"],
110 | ItemId = item.ItemId,
111 | Quantity = item.Quantity,
112 | };
113 | var createSaledOrderOuput = await _myRpaClient.CreateSalesOrderAsync(salesOrderInput);
114 | var orderCreatedMessage = string.Format(Resource.Order_Created, createSaledOrderOuput.OrderId, createSaledOrderOuput.DeliveryDate.ToShortDateString());
115 | await stepContext.Context.SendActivityAsync(orderCreatedMessage);
116 | }
117 | await stepContext.Context.SendActivityAsync(Resource.Anything_Else);
118 | return await stepContext.EndDialogAsync();
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/BotFramework/Dialogs/MyDialog/GetCustomerProfileDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using UiPath.ChatbotSamples.BotFramework.Common.Models;
6 | using UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog.Base;
7 | using UiPath.ChatbotSamples.BotFramework.Resources;
8 |
9 | namespace UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog
10 | {
11 | public class GetCustomerProfileDialog: StatefulDialogBase
12 | {
13 | private readonly IStatePropertyAccessor _entityStateAccessor;
14 |
15 | public GetCustomerProfileDialog(IStatePropertyAccessor entityStateAccessor) : base(nameof(GetCustomerProfileDialog), entityStateAccessor)
16 | {
17 | var waterfallSteps = new WaterfallStep[]
18 | {
19 | PromptForCustomerIdStepAsync,
20 | ProcessCustomerIdStepAsync,
21 | };
22 | AddDialog(new WaterfallDialog(GetWaterFallDialogId(nameof(GetCustomerProfileDialog)), waterfallSteps));
23 | AddDialog(new TextPrompt(nameof(PromptForCustomerIdStepAsync)));
24 | AddDialog(new TextPrompt(nameof(ProcessCustomerIdStepAsync)));
25 |
26 | _entityStateAccessor = entityStateAccessor;
27 | }
28 | private async Task PromptForCustomerIdStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
29 | {
30 | var customerId = await GetCustomerIdAsync(stepContext);
31 | if (string.IsNullOrEmpty(customerId))
32 | {
33 | return await stepContext.PromptAsync(nameof(PromptForCustomerIdStepAsync), Utils.CreateMessagePrompt(Resource.Ask_Customer_Id));
34 | }
35 | else
36 | {
37 | return await stepContext.NextAsync();
38 | }
39 | }
40 |
41 | private async Task ProcessCustomerIdStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
42 | {
43 | var customerId = await GetCustomerIdAsync(stepContext);
44 | if (string.IsNullOrEmpty(customerId))
45 | {
46 | // loop until get customer id
47 | return await stepContext.ReplaceDialogAsync(nameof(GetCustomerProfileDialog), cancellationToken);
48 | }
49 | return await stepContext.Parent.ContinueDialogAsync();
50 | }
51 |
52 | private async Task GetCustomerIdAsync(WaterfallStepContext stepContext)
53 | {
54 | return await TryGetEntityValueAsync(stepContext, "CustomerId");
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/BotFramework/Dialogs/MyDialog/GreetingDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog.Base;
5 | using UiPath.ChatbotSamples.BotFramework.Resources;
6 |
7 | namespace UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog
8 | {
9 | public class GreetingDialog : DialogBase
10 | {
11 | public GreetingDialog()
12 | : base(nameof(GreetingDialog))
13 | {
14 | // Add control flow dialogs
15 | var waterfallSteps = new WaterfallStep[]
16 | {
17 | ShowHelpStepAsync,
18 | };
19 | AddDialog(new WaterfallDialog(GetWaterFallDialogId(nameof(GreetingDialog)), waterfallSteps));
20 | AddDialog(new TextPrompt(nameof(ShowHelpStepAsync)));
21 | }
22 |
23 | private async Task ShowHelpStepAsync(
24 | WaterfallStepContext stepContext,
25 | CancellationToken cancellationToken)
26 | {
27 | await stepContext.Context.SendActivityAsync(Resource.Help);
28 | return await stepContext.EndDialogAsync();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/BotFramework/Dialogs/MyDialog/ReplaceItemDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using UiPath.ChatbotSamples.BotFramework.Actions;
9 | using UiPath.ChatbotSamples.BotFramework.Actions.Models;
10 | using UiPath.ChatbotSamples.BotFramework.Common.Models;
11 | using UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog.Base;
12 | using UiPath.ChatbotSamples.BotFramework.Resources;
13 | using UiPath.ChatbotSamples.BotFramework.Utils;
14 |
15 | namespace UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog
16 | {
17 | public class ReplaceItemDialog : StatefulDialogBase
18 | {
19 | private readonly IMyRpaClient _myRpaClient;
20 | private readonly IStatePropertyAccessor _entityStateAccessor;
21 | private const string c_customerId = "CustomerId";
22 |
23 | public ReplaceItemDialog(IMyRpaClient myRPAClient, IStatePropertyAccessor entityStateAccessor) : base(nameof(ReplaceItemDialog), entityStateAccessor)
24 | {
25 | var waterfallSteps = new WaterfallStep[]
26 | {
27 | GetCustomerIdStepAsync,
28 | ListItemsStepAsync,
29 | ProcessItemSelectionStepAsync,
30 | AskReplacementStepAsync,
31 | PlaceOrderStepAsync,
32 | };
33 | AddDialog(new WaterfallDialog(GetWaterFallDialogId(nameof(ReplaceItemDialog)), waterfallSteps));
34 | AddDialog(new TextPrompt(nameof(GetCustomerIdStepAsync)));
35 | AddDialog(new ChoicePrompt(nameof(ListItemsStepAsync)));
36 | AddDialog(new TextPrompt(nameof(ProcessItemSelectionStepAsync)));
37 | AddDialog(new ChoicePrompt(nameof(AskReplacementStepAsync)));
38 | AddDialog(new TextPrompt(nameof(PlaceOrderStepAsync)));
39 |
40 | _myRpaClient = myRPAClient;
41 | _entityStateAccessor = entityStateAccessor;
42 | }
43 |
44 | private async Task GetCustomerIdStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
45 | {
46 | return await stepContext.BeginDialogAsync(nameof(GetCustomerProfileDialog));
47 | }
48 |
49 | private async Task ListItemsStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
50 | {
51 | await stepContext.Context.SendActivityAsync(Resource.Working_On);
52 | var customerId = await TryGetEntityValueAsync(stepContext, c_customerId);
53 | stepContext.Values[c_customerId] = customerId;
54 |
55 | var result = await _myRpaClient.GetItemsAsync(new GetItemsInput() { CustomerId = customerId });
56 |
57 | if (result?.Items == null || result.Items.Length == 0)
58 | {
59 | return await stepContext.BeginDialogAsync(nameof(CannotFindOrderDialog));
60 | }
61 | else
62 | {
63 | stepContext.Values["Items"] = result;
64 | var delivered = result.Items.Where(i => i.DeliveryDate < DateTime.Today).Select(i => i.ItemName).ToList();
65 | delivered.Add(Resource.None_Of_Above);
66 | return await stepContext.PromptAsync(nameof(ListItemsStepAsync), Utils.CreateMessagePrompt(Resource.Which_Delivered, delivered));
67 | }
68 | }
69 |
70 | private async Task ProcessItemSelectionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
71 | {
72 | var message = stepContext.Context.Activity.AsMessageActivity().Text;
73 | if (message.OrdinalEquals(Resource.None_Of_Above))
74 | {
75 | return await stepContext.BeginDialogAsync(nameof(CannotFindOrderDialog));
76 | }
77 | else
78 | {
79 | var matchedItems = ((GetItemsOutput)stepContext.Values["Items"]).Items.Where(i => i.ItemName.OrdinalEquals(message)).ToList();
80 | if (matchedItems.Count == 0)
81 | {
82 | return await stepContext.BeginDialogAsync(nameof(CannotFindOrderDialog));
83 | }
84 |
85 | stepContext.Values["SelectedItem"] = matchedItems[0];
86 |
87 | return await stepContext.PromptAsync(nameof(ProcessItemSelectionStepAsync), Utils.CreateMessagePrompt(Resource.Describe_Damage));
88 | }
89 | }
90 |
91 | private async Task AskReplacementStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
92 | {
93 | var damage = stepContext.Context.Activity.AsMessageActivity().Text;
94 | stepContext.Values["Damage"] = damage;
95 | return await stepContext.PromptAsync(nameof(AskReplacementStepAsync), Utils.CreateMessagePrompt(Resource.Return_Or_Replace, new List(){ Resource.Replace, Resource.Return }));
96 | }
97 |
98 | private async Task PlaceOrderStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
99 | {
100 | var message = stepContext.Context.Activity.AsMessageActivity().Text;
101 |
102 |
103 | if (message.OrdinalEquals(Resource.Return) || message.OrdinalEquals(Resource.Replace))
104 | {
105 | await stepContext.Context.SendActivityAsync(Resource.Working_On);
106 | var item = (Item)stepContext.Values["SelectedItem"];
107 |
108 | var cancelInput = new CancelOrderInput()
109 | {
110 | OrderId = item.OrderId,
111 | CancelReason = (string)stepContext.Values["Damage"],
112 | };
113 | var cancelOrderOutput = await _myRpaClient.CancelOrderAsync(cancelInput);
114 | var orderCancelMessage = string.Format(Resource.Order_Cancelled, item.OrderId, cancelOrderOutput.ReturnLabelLocation);
115 | await stepContext.Context.SendActivityAsync(orderCancelMessage);
116 |
117 | if (message.OrdinalEquals(Resource.Replace))
118 | {
119 | var salesOrderInput = new CreateSalesOrderInput()
120 | {
121 | CustomerId = (string)stepContext.Values[c_customerId],
122 | ItemId = item.ItemId,
123 | Quantity = item.Quantity,
124 | };
125 | var createSaledOrderOuput = await _myRpaClient.CreateSalesOrderAsync(salesOrderInput);
126 | var orderCreatedMessage = string.Format(Resource.Order_Created, createSaledOrderOuput.OrderId, createSaledOrderOuput.DeliveryDate.ToShortDateString());
127 | await stepContext.Context.SendActivityAsync(orderCreatedMessage);
128 | }
129 | await stepContext.Context.SendActivityAsync(Resource.Anything_Else);
130 | }
131 | else
132 | {
133 | await stepContext.Context.SendActivityAsync(Resource.Cannot_Understand);
134 | }
135 |
136 | return await stepContext.EndDialogAsync();
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/BotFramework/Dialogs/MyIntents.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Schema;
2 | using System.Collections.Generic;
3 | using UiPath.ChatbotSamples.BotFramework.Common;
4 | using UiPath.ChatbotSamples.BotFramework.Common.Models;
5 | using UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog;
6 | using UiPath.ChatbotSamples.BotFramework.Resources;
7 |
8 | namespace UiPath.ChatbotSamples.BotFramework.Dialogs
9 | {
10 | public sealed class MyIntents: IBotIntents
11 | {
12 | public MyIntents()
13 | {
14 | var noneIntent = new Intent("None", null, IntentType.None);
15 | Intents = IntentsToDictionary(new Intent[] {
16 | new Intent("Greeting", nameof(GreetingDialog), IntentType.Normal),
17 | new Intent("DelayedShipment", nameof(DelayedShipmentDialog), IntentType.Normal),
18 | new Intent("ReplaceItem", nameof(ReplaceItemDialog), IntentType.Normal),
19 | new TerminationIntent("Cancel", Utils.CreateMessageActivityArray(Resource.Cancel_Success), Utils.CreateMessageActivityArray(Resource.Cancel_Fail)),
20 | new TerminationIntent("Bye", Utils.CreateMessageActivityArray(Resource.Bye_With_Active_Dialog, Resource.Talk_To_Agent), Utils.CreateMessageActivityArray(Resource.Thank_You, Resource.Bye)),
21 | new DetourIntent("Help", Utils.CreateMessageActivityArray(Resource.Help, Resource.Talk_To_Agent)),
22 | noneIntent,
23 | });
24 | DefaultIntent = noneIntent;
25 | }
26 |
27 | public IReadOnlyDictionary Intents { get; }
28 |
29 | public double IntentTriggerThreshold { get; } = 0.5;
30 |
31 | public Intent DefaultIntent { get; }
32 |
33 | public IActivity FallbackActivity
34 | {
35 | get
36 | {
37 | return Utils.CreateMessageActivity(Resource.Cannot_Understand);
38 | }
39 | }
40 |
41 | public IActivity WelcomeActivity
42 | {
43 | get
44 | {
45 | return Utils.CreateMessageActivity(Resource.Greeting);
46 | }
47 | }
48 |
49 | private Dictionary IntentsToDictionary(Intent[] intents)
50 | {
51 | var dictionary = new Dictionary();
52 | foreach (var intent in intents)
53 | {
54 | dictionary.Add(intent.Name, intent);
55 | }
56 | return dictionary;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/BotFramework/Dialogs/Utils.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Builder.Dialogs.Choices;
3 | using Microsoft.Bot.Schema;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using UiPath.ChatbotSamples.BotFramework.Resources;
7 |
8 | namespace UiPath.ChatbotSamples.BotFramework.Dialogs
9 | {
10 | internal static class Utils
11 | {
12 | internal static PromptOptions CreateMessagePrompt(string message)
13 | {
14 | return new PromptOptions
15 | {
16 | Prompt = new Activity
17 | {
18 | Type = ActivityTypes.Message,
19 | Text = message,
20 | },
21 | };
22 | }
23 |
24 | internal static PromptOptions CreateMessagePrompt(string message, List choiceStrings)
25 | {
26 | var choices = new List();
27 | choices.AddRange(choiceStrings.Select(s => new Choice(s)));
28 |
29 | return new PromptOptions
30 | {
31 | Prompt = new Activity
32 | {
33 | Type = ActivityTypes.Message,
34 | Text = message,
35 | },
36 | Choices = choices,
37 | };
38 | }
39 |
40 | internal static IMessageActivity CreateMessageActivity(string message)
41 | {
42 | var activity = Activity.CreateMessageActivity();
43 | activity.Text = message;
44 | return activity;
45 | }
46 |
47 | internal static IActivity[] CreateMessageActivityArray(params string[] messages)
48 | {
49 | var activities = new IActivity[messages.Length];
50 | for (var i = 0; i < messages.Length; i++)
51 | {
52 | activities[i] = CreateMessageActivity(messages[i]);
53 | }
54 | return activities;
55 | }
56 |
57 | internal static List GetYesNoOptions()
58 | {
59 | return new List() { Resource.Yes, Resource.No };
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/BotFramework/DialogsTest/DialogTest.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Reflection;
3 | using UiPath.ChatbotSamples.BotFramework.Dialogs;
4 | using Xunit;
5 |
6 | namespace UiPath.ChatbotSamples.BotFramework.DialogsTest
7 | {
8 | public class DialogTest
9 | {
10 | [Fact]
11 | public void ShouldHaveAtLeastOneDialog()
12 | {
13 | string name_space = "UiPath.ChatbotSamples.BotFramework.Dialogs.MyDialog";
14 | var q = from t in Assembly.GetAssembly(typeof(MyBot)).GetTypes()
15 | where t.IsClass && t.Namespace == name_space && !t.IsNested
16 | select t;
17 | var result = q.ToList();
18 | Assert.True(result.Count >= 1);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/BotFramework/DialogsTest/DialogsTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 | UiPath.ChatbotSamples.BotFramework.DialogsTest
6 | UiPath.ChatbotSamples.BotFramework.DialogsTest
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/BotFramework/DialogsTest/IntentTest.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using UiPath.ChatbotSamples.BotFramework.Dialogs;
3 | using Xunit;
4 |
5 | namespace UiPath.ChatbotSamples.BotFramework.DialogsTest
6 | {
7 | public class IntentTest
8 | {
9 | private readonly MyIntents intents = new MyIntents();
10 |
11 | [Fact]
12 | public void DefaultIntentShouldBeDefined()
13 | {
14 | Assert.NotNull(intents.DefaultIntent);
15 | }
16 |
17 | [Fact]
18 | public void FallbackActivityShouldBeDefined()
19 | {
20 | Assert.NotNull(intents.FallbackActivity);
21 | }
22 |
23 | [Fact]
24 | public void WelcomActivityShouldBeDefined()
25 | {
26 | Assert.NotNull(intents.WelcomeActivity);
27 | }
28 |
29 | [Fact]
30 | public void ShouldHaveAtLeastOneIntent()
31 | {
32 | Assert.NotNull(intents.Intents);
33 | Assert.True(intents.Intents.Keys.ToList().Count > 1);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient.Test/AuthHeadHandlerTest.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 | using Moq.Protected;
3 | using System.Linq;
4 | using System.Net.Http;
5 | using System.Threading;
6 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth;
7 | using Xunit;
8 |
9 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Test
10 | {
11 | public class AuthHeadHandlerTest
12 | {
13 | [Fact]
14 | public void BasicAuthShouldAddTokenHead()
15 | {
16 | var mockTokenService = MockHelper.CreateMockTokenService();
17 | var mockMessageHandler = MockHelper.CreateMockMessagHandler();
18 |
19 | var basicAuthHeadhandler = new BasicAuthHeadHandler(mockTokenService.Object, mockMessageHandler.Object);
20 |
21 | var httpClient = new HttpClient(basicAuthHeadhandler)
22 | {
23 | BaseAddress = new System.Uri("http://localhost"),
24 | };
25 |
26 | httpClient.GetAsync(httpClient.BaseAddress).GetAwaiter().GetResult();
27 |
28 | mockMessageHandler.Protected().Verify(
29 | "SendAsync",
30 | Times.Exactly(1), // we expected a single external request
31 | ItExpr.Is(req =>
32 | req.Headers.Contains("Authorization") &&
33 | req.Headers.GetValues("Authorization").FirstOrDefault() == $"Bearer {MockHelper.Token}"),
34 | ItExpr.IsAny());
35 |
36 | }
37 |
38 | [Fact]
39 | public void CloudAuthShouldAddTokenHead()
40 | {
41 | var mockTokenService = MockHelper.CreateMockTokenService();
42 | var mockMessageHandler = MockHelper.CreateMockMessagHandler();
43 | const string serviceInstanceLogicalName = "TestLogicalName";
44 | var cloudAuthHeadhandler = new CloudAuthHeadHandler(mockTokenService.Object, serviceInstanceLogicalName, mockMessageHandler.Object);
45 |
46 | var httpClient = new HttpClient(cloudAuthHeadhandler)
47 | {
48 | BaseAddress = new System.Uri("http://localhost"),
49 | };
50 |
51 | httpClient.GetAsync(httpClient.BaseAddress).GetAwaiter().GetResult();
52 |
53 | mockMessageHandler.Protected().Verify(
54 | "SendAsync",
55 | Times.Exactly(1), // we expected a single external request
56 | ItExpr.Is(req =>
57 | req.Headers.Contains("Authorization") &&
58 | req.Headers.GetValues("Authorization").FirstOrDefault() == $"Bearer {MockHelper.Token}" &&
59 | req.Headers.Contains("X-UIPATH-TenantName") &&
60 | req.Headers.GetValues("X-UIPATH-TenantName").FirstOrDefault() == serviceInstanceLogicalName),
61 | ItExpr.IsAny());
62 |
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient.Test/ClientTest.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 | using Moq.Protected;
3 | using System;
4 | using System.Net;
5 | using System.Net.Http;
6 | using System.Threading;
7 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth;
8 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient.JobModels;
9 | using UiPath.ChatbotSamples.BotFramework.Test.Common;
10 | using Xunit;
11 |
12 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Test
13 | {
14 | public class ClientTest
15 | {
16 | private readonly OrchestratorSettingOption _settingOption = new OrchestratorSettingOption(
17 | new OrchestratorSettings()
18 | {
19 | AuthMode = "Cloud",
20 | RefreshToken = "randometoken",
21 | ServiceInstanceLogicalName = "test",
22 | AccountLogicalName = "test",
23 | BaseUrl = "Https://platform.uipath.com",
24 | Strategy = "Specific",
25 | RobotIds = new long[] { 1, 2, 3 },
26 | ProcessKeys = new ProcessKey[] { new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "test" } },
27 | });
28 |
29 | private readonly ITokenService _mockTokenService = MockHelper.CreateMockTokenService().Object;
30 |
31 | private readonly OrchestratorClient _orchestratorClient;
32 |
33 | public ClientTest()
34 | {
35 | _orchestratorClient = new OrchestratorClient(_mockTokenService, _settingOption);
36 | }
37 |
38 | [Fact]
39 | public void ThrowsIfFailedToStart()
40 | {
41 | var mockMessageHandler = MockHelper.CreateMockMessagHandler(HttpStatusCode.NotFound);
42 | var basicAuthHeadhandler = new BasicAuthHeadHandler(_mockTokenService, mockMessageHandler.Object);
43 | var httpClient = new HttpClient(basicAuthHeadhandler);
44 |
45 | Assert.Throws(() => _orchestratorClient.StartJobAsync(new StartJobInfo(), httpClient).GetAwaiter().GetResult());
46 | }
47 |
48 | [Fact]
49 | public void SuccessIfStart()
50 | {
51 | var mockResponse = new ODataList()
52 | {
53 | Value = new StartJobResponse[] {
54 | new StartJobResponse()
55 | {
56 | Id = "1",
57 | Key = Guid.NewGuid().ToString(),
58 | State = "Started",
59 | },
60 | },
61 | };
62 | var mockMessageHandler = MockHelper.CreateMockMessagHandler(HttpStatusCode.OK, Utils.GetPostBody(mockResponse));
63 |
64 | var basicAuthHeadhandler = new BasicAuthHeadHandler(_mockTokenService, mockMessageHandler.Object);
65 |
66 | var httpClient = new HttpClient(basicAuthHeadhandler);
67 |
68 | var response = _orchestratorClient.StartJobAsync(new StartJobInfo(), httpClient).GetAwaiter().GetResult();
69 | Assert.Equal(mockResponse.Value[0].Key, response.Key);
70 | }
71 |
72 | [Fact]
73 | public void ThrowsIfJobFaulted()
74 | {
75 | var mockResponse = new ODataList()
76 | {
77 | Value = new StartJobResponse[] {
78 | new StartJobResponse()
79 | {
80 | Id = "1",
81 | Key = Guid.NewGuid().ToString(),
82 | State = "Faulted",
83 | },
84 | },
85 | };
86 | var mockMessageHandler = MockHelper.CreateMockMessagHandler(HttpStatusCode.OK, Utils.GetPostBody(mockResponse));
87 |
88 | var basicAuthHeadhandler = new BasicAuthHeadHandler(_mockTokenService, mockMessageHandler.Object);
89 |
90 | var httpClient = new HttpClient(basicAuthHeadhandler);
91 |
92 | Assert.Throws(() => _orchestratorClient.WaitForJobCompletionAsync("1", httpClient).GetAwaiter().GetResult());
93 | }
94 |
95 | [Fact]
96 | public void ThrowsIfJobStopped()
97 | {
98 | var mockResponse = new ODataList()
99 | {
100 | Value = new StartJobResponse[] {
101 | new StartJobResponse()
102 | {
103 | Id = "1",
104 | Key = Guid.NewGuid().ToString(),
105 | State = "Stopped",
106 | },
107 | },
108 | };
109 | var mockMessageHandler = MockHelper.CreateMockMessagHandler(HttpStatusCode.OK, Utils.GetPostBody(mockResponse));
110 |
111 | var basicAuthHeadhandler = new BasicAuthHeadHandler(_mockTokenService, mockMessageHandler.Object);
112 |
113 | var httpClient = new HttpClient(basicAuthHeadhandler);
114 |
115 | Assert.Throws(() => _orchestratorClient.WaitForJobCompletionAsync("1", httpClient).GetAwaiter().GetResult());
116 | }
117 |
118 | [Fact]
119 | public void ThrowsIfJobTimeOut()
120 | {
121 | var mockResponse = new ODataList()
122 | {
123 | Value = new StartJobResponse[] {
124 | new StartJobResponse()
125 | {
126 | Id = "1",
127 | Key = Guid.NewGuid().ToString(),
128 | State = "Started",
129 | },
130 | },
131 | };
132 | var mockMessageHandler = MockHelper.CreateMockMessagHandler(HttpStatusCode.OK, Utils.GetPostBody(mockResponse));
133 |
134 | var basicAuthHeadhandler = new BasicAuthHeadHandler(_mockTokenService, mockMessageHandler.Object);
135 |
136 | var httpClient = new HttpClient(basicAuthHeadhandler);
137 |
138 | Assert.Throws(() => _orchestratorClient.WaitForJobCompletionAsync("1", httpClient).GetAwaiter().GetResult());
139 |
140 | mockMessageHandler.Protected().Verify(
141 | "SendAsync",
142 | Times.Exactly(_settingOption.CurrentValue.StatusCheckMaxRetry),
143 | ItExpr.IsAny(),
144 | ItExpr.IsAny());
145 | }
146 |
147 | [Fact]
148 | public void SuccessIfJobCompletedSuccess()
149 | {
150 | var mockResponse = new ODataList()
151 | {
152 | Value = new StartJobResponse[] {
153 | new StartJobResponse()
154 | {
155 | Id = "1",
156 | Key = Guid.NewGuid().ToString(),
157 | State = "Successful",
158 | },
159 | },
160 | };
161 | var mockMessageHandler = MockHelper.CreateMockMessagHandler(HttpStatusCode.OK, Utils.GetPostBody(mockResponse));
162 |
163 | var basicAuthHeadhandler = new BasicAuthHeadHandler(_mockTokenService, mockMessageHandler.Object);
164 |
165 | var httpClient = new HttpClient(basicAuthHeadhandler);
166 |
167 | _orchestratorClient.WaitForJobCompletionAsync("1", httpClient).GetAwaiter().GetResult();
168 | }
169 |
170 | [Fact]
171 | public void ThrowsIfFailedToGetDetail()
172 | {
173 | var mockMessageHandler = MockHelper.CreateMockMessagHandler(HttpStatusCode.NotFound);
174 | var basicAuthHeadhandler = new BasicAuthHeadHandler(_mockTokenService, mockMessageHandler.Object);
175 | var httpClient = new HttpClient(basicAuthHeadhandler);
176 |
177 | Assert.Throws(() => _orchestratorClient.GetJobDetailAsync("1", httpClient).GetAwaiter().GetResult());
178 | }
179 |
180 | [Fact]
181 | public void SuccessIfGetJobDetail()
182 | {
183 | var mockResponse = new StartJobResponse()
184 | {
185 | Id = "1",
186 | Key = Guid.NewGuid().ToString(),
187 | State = "Successful",
188 | OutputArguments = "{\"key\":\"value\"}",
189 | };
190 |
191 | var mockMessageHandler = MockHelper.CreateMockMessagHandler(HttpStatusCode.OK, Utils.GetPostBody(mockResponse));
192 |
193 | var basicAuthHeadhandler = new BasicAuthHeadHandler(_mockTokenService, mockMessageHandler.Object);
194 |
195 | var httpClient = new HttpClient(basicAuthHeadhandler);
196 |
197 | var response = _orchestratorClient.GetJobDetailAsync("1", httpClient).GetAwaiter().GetResult();
198 | Assert.Equal(mockResponse.Key, response.Key);
199 | }
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient.Test/MockHelper.cs:
--------------------------------------------------------------------------------
1 | using Moq;
2 | using Moq.Protected;
3 | using System.Net;
4 | using System.Net.Http;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth;
8 |
9 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Test
10 | {
11 | public sealed class MockHelper
12 | {
13 | public static string Token => "Test Token";
14 |
15 | public static Mock CreateMockTokenService()
16 | {
17 | var mockTokenService = new Mock();
18 |
19 | mockTokenService.Setup(t => t.BasicAuthenticateAsync())
20 | .Returns(Task.FromResult(new BasicAuthResponse() { Result = Token, }));
21 |
22 | mockTokenService.Setup(t => t.CloudAuthenticateAsync())
23 | .Returns(Task.FromResult(new CloudAuthResponse() { access_token = Token, }));
24 |
25 | return mockTokenService;
26 | }
27 |
28 | public static Mock CreateMockMessagHandler(HttpStatusCode statusCode = HttpStatusCode.OK, HttpContent response = null)
29 | {
30 | var handlerMock = new Mock(MockBehavior.Strict);
31 | handlerMock
32 | .Protected()
33 | .Setup>(
34 | "SendAsync",
35 | ItExpr.IsAny(),
36 | ItExpr.IsAny()
37 | )
38 | .ReturnsAsync(new HttpResponseMessage()
39 | {
40 | StatusCode = statusCode,
41 | Content = response,
42 | })
43 | .Verifiable();
44 |
45 | return handlerMock;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient.Test/OrchestratorClient.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 | UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Test
6 | UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Test
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient.Test/OrchestratorSettingsTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Xunit;
3 |
4 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Test
5 | {
6 | public class OrchestratorSettingsTest
7 | {
8 | [Fact]
9 | public void OnlyTwoAuthModeAllowed()
10 | {
11 | var setting = new OrchestratorSettings()
12 | {
13 | AuthMode = "another mode",
14 | TenancyName = "Default",
15 | UsernameOrEmailAddress = "Test",
16 | Password = "Test",
17 | BaseUrl = "Http://localhost",
18 | Strategy = "JobsCount",
19 | JobsCount = 1,
20 | ProcessKeys = new ProcessKey[] { new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "test" } },
21 | };
22 |
23 | Assert.False(setting.Validate());
24 | }
25 |
26 | [Fact]
27 | public void UerNamePasswordRequiredForBasicAuth()
28 | {
29 | var setting = new OrchestratorSettings()
30 | {
31 | AuthMode = "Basic",
32 | BaseUrl = "Http://localhost",
33 | Strategy = "JobsCount",
34 | JobsCount = 1,
35 | ProcessKeys = new ProcessKey[] { new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "test" } },
36 | };
37 |
38 | Assert.False(setting.Validate());
39 | }
40 |
41 | [Fact]
42 | public void UerTokenRequiredForCloudAuth()
43 | {
44 | var setting = new OrchestratorSettings()
45 | {
46 | AuthMode = "Cloud",
47 | BaseUrl = "Http://localhost",
48 | Strategy = "JobsCount",
49 | JobsCount = 1,
50 | ProcessKeys = new ProcessKey[] { new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "test" } },
51 | };
52 |
53 | Assert.False(setting.Validate());
54 | }
55 |
56 | [Fact]
57 | public void UrlShouldBeValid()
58 | {
59 | var setting = new OrchestratorSettings()
60 | {
61 | AuthMode = "Basic",
62 | TenancyName = "Default",
63 | UsernameOrEmailAddress = "Test",
64 | Password = "Test",
65 | BaseUrl = "invalid",
66 | Strategy = "JobsCount",
67 | JobsCount = 1,
68 | ProcessKeys = new ProcessKey[] { new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "test" } },
69 | };
70 |
71 | Assert.False(setting.Validate());
72 | }
73 |
74 | [Fact]
75 | public void TwoStrategyAllowed()
76 | {
77 | var setting = new OrchestratorSettings()
78 | {
79 | AuthMode = "Basic",
80 | TenancyName = "Default",
81 | UsernameOrEmailAddress = "Test",
82 | Password = "Test",
83 | BaseUrl = "Http://localhost",
84 | Strategy = "invalid",
85 | ProcessKeys = new ProcessKey[] { new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "test" } },
86 | };
87 |
88 | Assert.False(setting.Validate());
89 | }
90 |
91 | [Fact]
92 | public void SpecificStrategyShouldHaveAtLeastOneRobot()
93 | {
94 | var setting = new OrchestratorSettings()
95 | {
96 | AuthMode = "Basic",
97 | TenancyName = "Default",
98 | UsernameOrEmailAddress = "Test",
99 | Password = "Test",
100 | BaseUrl = "Http://localhost",
101 | Strategy = "Specific",
102 | RobotIds = null,
103 | };
104 |
105 | Assert.False(setting.Validate());
106 | }
107 |
108 | [Fact]
109 | public void JobsCountStrategyShouldHavePositiveCount()
110 | {
111 | var setting = new OrchestratorSettings()
112 | {
113 | AuthMode = "Basic",
114 | TenancyName = "Default",
115 | UsernameOrEmailAddress = "Test",
116 | Password = "Test",
117 | BaseUrl = "Http://localhost",
118 | Strategy = "JobsCount",
119 | JobsCount = -1,
120 | };
121 |
122 | Assert.False(setting.Validate());
123 | }
124 |
125 | [Fact]
126 | public void ShouldHaveAtLeastOneProcess()
127 | {
128 | var setting = new OrchestratorSettings()
129 | {
130 | AuthMode = "Basic",
131 | TenancyName = "Default",
132 | UsernameOrEmailAddress = "Test",
133 | Password = "Test",
134 | BaseUrl = "Http://localhost",
135 | Strategy = "JobsCount",
136 | JobsCount = 1,
137 | ProcessKeys = null,
138 | };
139 |
140 | Assert.False(setting.Validate());
141 | }
142 |
143 | [Fact]
144 | public void ProcessKeyShouldBeGuid()
145 | {
146 | var setting = new OrchestratorSettings()
147 | {
148 | AuthMode = "Basic",
149 | TenancyName = "Default",
150 | UsernameOrEmailAddress = "Test",
151 | Password = "Test",
152 | BaseUrl = "Http://localhost",
153 | Strategy = "JobsCount",
154 | JobsCount = 1,
155 | ProcessKeys = new ProcessKey[] { new ProcessKey() { Key = "1234", Process = "test" } },
156 | };
157 |
158 | Assert.False(setting.Validate());
159 | }
160 |
161 | [Fact]
162 | public void ValidBasicAuth()
163 | {
164 | var setting = new OrchestratorSettings()
165 | {
166 | AuthMode = "Basic",
167 | TenancyName = "Default",
168 | UsernameOrEmailAddress = "Test",
169 | Password = "Test",
170 | BaseUrl = "Http://localhost",
171 | Strategy = "JobsCount",
172 | JobsCount = 1,
173 | ProcessKeys = new ProcessKey[] { new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "test" } },
174 | };
175 |
176 | Assert.True(setting.Validate());
177 | }
178 |
179 | [Fact]
180 | public void ValidCloudAuth()
181 | {
182 | var setting = new OrchestratorSettings()
183 | {
184 | AuthMode = "Cloud",
185 | RefreshToken = "randometoken",
186 | ServiceInstanceLogicalName = "test",
187 | AccountLogicalName = "test",
188 | BaseUrl = "Https://platform.uipath.com",
189 | Strategy = "Specific",
190 | RobotIds = new long[] { 1, 2, 3},
191 | ProcessKeys = new ProcessKey[] { new ProcessKey() { Key = Guid.NewGuid().ToString(), Process = "test" } },
192 | };
193 |
194 | Assert.True(setting.Validate());
195 | }
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient.Test/UtilsTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Xunit;
3 |
4 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Test
5 | {
6 | public class UtilsTest
7 | {
8 | [Fact]
9 | public void GetValidUrlWithTrailingBaseUrl()
10 | {
11 | var baseUrl = "http://localhost/";
12 | var jobKey = "123";
13 | Assert.True(Uri.IsWellFormedUriString(Utils.GetBasicAuthUrl(baseUrl), UriKind.Absolute));
14 | Assert.True(Uri.IsWellFormedUriString(Utils.GetJobDetailUrl(baseUrl, jobKey), UriKind.Absolute));
15 | // job status url contains parameter, need to remove those before check
16 | var jobStatusUrl = Utils.GetJobStatusUrl(baseUrl, jobKey);
17 | Assert.True(Uri.IsWellFormedUriString(jobStatusUrl.Substring(0, jobStatusUrl.IndexOf('$')), UriKind.Absolute));
18 | Assert.True(Uri.IsWellFormedUriString(Utils.GetStartjobUrl(baseUrl), UriKind.Absolute));
19 | }
20 |
21 | [Fact]
22 | public void GetValidUrlWithNoneTrailingBaseUrl()
23 | {
24 | var baseUrl = "http://localhost";
25 | var jobKey = "123";
26 |
27 | var authUrl = Utils.GetBasicAuthUrl(baseUrl);
28 | var jobDetailUrl = Utils.GetJobDetailUrl(baseUrl, jobKey);
29 | // job status url contains parameter, need to remove those before check
30 | var jobStatusUrl = Utils.GetJobStatusUrl(baseUrl, jobKey);
31 | var startJobUrl = Utils.GetStartjobUrl(baseUrl);
32 |
33 | Assert.True(Uri.IsWellFormedUriString(authUrl, UriKind.Absolute));
34 | Assert.True(Uri.IsWellFormedUriString(jobDetailUrl, UriKind.Absolute));
35 | Assert.True(Uri.IsWellFormedUriString(jobStatusUrl.Substring(0, jobStatusUrl.IndexOf('$')), UriKind.Absolute));
36 | Assert.True(Uri.IsWellFormedUriString(startJobUrl, UriKind.Absolute));
37 |
38 | var trailedBaseUrl = $"{baseUrl}/";
39 | Assert.StartsWith(trailedBaseUrl, authUrl);
40 | Assert.StartsWith(trailedBaseUrl, jobDetailUrl);
41 | Assert.StartsWith(trailedBaseUrl, jobStatusUrl);
42 | Assert.StartsWith(trailedBaseUrl, startJobUrl);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/Auth/BasicAuthHeadHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http;
2 | using System.Net.Http.Headers;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth
7 | {
8 | public class BasicAuthHeadHandler : DelegatingHandler
9 | {
10 | private readonly ITokenService _tokenService;
11 |
12 | public BasicAuthHeadHandler(ITokenService tokenService)
13 | : base(new HttpClientHandler())
14 | {
15 | _tokenService = tokenService;
16 | }
17 |
18 | public BasicAuthHeadHandler(ITokenService tokenService, HttpMessageHandler innerHandler)
19 | : base(innerHandler)
20 | {
21 | _tokenService = tokenService;
22 | }
23 |
24 | protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
25 | {
26 | var token = await _tokenService.BasicAuthenticateAsync();
27 | request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Result);
28 |
29 | return await base.SendAsync(request, cancellationToken);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/Auth/BasicAuthResponse.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth
2 | {
3 | public class BasicAuthResponse
4 | {
5 | // Do Not change this. It is hard coded on Orchestrator side.
6 | public string Result { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/Auth/BasicAuthSettings.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth
2 | {
3 | public class BasicAuthSettings
4 | {
5 | public string TenancyName { get; set; }
6 | public string UsernameOrEmailAddress { get; set; }
7 | public string Password { get; set; }
8 | }
9 | }
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/Auth/CloudAuthHeadHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http;
2 | using System.Net.Http.Headers;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth
7 | {
8 | public class CloudAuthHeadHandler : DelegatingHandler
9 | {
10 | private readonly ITokenService _tokenService;
11 | private readonly string _serviceInstanceLogicalName;
12 |
13 | public CloudAuthHeadHandler(ITokenService tokenService, string serviceInstanceLogicalName)
14 | : base(new HttpClientHandler())
15 | {
16 | _tokenService = tokenService;
17 | _serviceInstanceLogicalName = serviceInstanceLogicalName;
18 | }
19 |
20 | public CloudAuthHeadHandler(ITokenService tokenService, string serviceInstanceLogicalName, HttpMessageHandler innerHandler)
21 | : base(innerHandler)
22 | {
23 | _tokenService = tokenService;
24 | _serviceInstanceLogicalName = serviceInstanceLogicalName;
25 | }
26 |
27 | protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
28 | {
29 | var token = await _tokenService.CloudAuthenticateAsync();
30 | request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.access_token);
31 | request.Headers.Add("X-UIPATH-TenantName", _serviceInstanceLogicalName);
32 |
33 |
34 | return await base.SendAsync(request, cancellationToken);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/Auth/CloudAuthResponse.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth
2 | {
3 | public class CloudAuthResponse
4 | {
5 | public string access_token { get; set; }
6 |
7 | public string refresh_token { get; set; }
8 |
9 | public string id_token { get; set; }
10 |
11 | public string scope { get; set;}
12 |
13 | public string expires_in { get; set;}
14 |
15 | public string token_type { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/Auth/CloudAuthSettings.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth
2 | {
3 | public class CloudAuthSettings
4 | {
5 | public string grant_type => "refresh_token";
6 |
7 | public string client_id => "5v7PmPJL6FOGu6RB8I1Y4adLBhIwovQN";
8 |
9 | public string refresh_token { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/Auth/ITokenService.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth
4 | {
5 | public interface ITokenService
6 | {
7 | Task BasicAuthenticateAsync();
8 |
9 | Task CloudAuthenticateAsync();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/Auth/TokenService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using System.Net.Http;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using UiPath.ChatbotSamples.BotFramework.Utils;
6 |
7 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth
8 | {
9 | public class TokenService : ITokenService
10 | {
11 | private readonly BasicAuthSettings _basicAuthSettings;
12 | private readonly CloudAuthSettings _cloudAuthSettings;
13 | private readonly string _baseUrl;
14 |
15 | public TokenService(IOptionsMonitor orchestratorSettingAccessor)
16 | {
17 | var orchestratorSettings = orchestratorSettingAccessor.CheckNullReference().CurrentValue;
18 |
19 | _basicAuthSettings = new BasicAuthSettings()
20 | {
21 | TenancyName = orchestratorSettings.TenancyName,
22 | UsernameOrEmailAddress = orchestratorSettings.UsernameOrEmailAddress,
23 | Password = orchestratorSettings.Password,
24 | };
25 |
26 | _cloudAuthSettings = new CloudAuthSettings()
27 | {
28 | refresh_token = orchestratorSettings.RefreshToken,
29 | };
30 |
31 | _baseUrl = orchestratorSettings.BaseUrl;
32 | }
33 |
34 | public async Task BasicAuthenticateAsync()
35 | {
36 | using (HttpClient client = new HttpClient())
37 | {
38 | var tokenResponse = await client.PostAsync(Utils.GetBasicAuthUrl(_baseUrl), Utils.GetPostBody(_basicAuthSettings), new CancellationToken());
39 | return await tokenResponse.Content.ReadAsAsync();
40 | }
41 | }
42 |
43 | public async Task CloudAuthenticateAsync()
44 | {
45 | using (HttpClient client = new HttpClient())
46 | {
47 | var tokenResponse = await client.PostAsync(Utils.CloudAuthUrl, Utils.GetPostBody(_cloudAuthSettings), new CancellationToken());
48 | return await tokenResponse.Content.ReadAsAsync();
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/IOrchestratorClient.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient.JobModels;
3 |
4 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient
5 | {
6 | public interface IOrchestratorClient
7 | {
8 | Task ExecuteJobAsync(StartJobInfo jobInfo);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/JobModels/ODataList.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.JobModels
2 | {
3 | public class ODataList
4 | {
5 | public T[] Value { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/JobModels/StartJobBody.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.JobModels
2 | {
3 | public class StartJobBody
4 | {
5 | // DO NOT Change this name. It is hard coded on Orchestrator side.
6 | public StartJobInfo startInfo { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/JobModels/StartJobInfo.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.JobModels
2 | {
3 | public class StartJobInfo
4 | {
5 | public string ReleaseKey { get; set; }
6 |
7 | public string Strategy { get; set; }
8 |
9 | public int JobsCount { get; set; }
10 |
11 | public long[] RobotIds { get; set; }
12 |
13 | public string InputArguments { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/JobModels/StartJobResponse.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient.JobModels
2 | {
3 | public class StartJobResponse
4 | {
5 | public string Id { get; set; }
6 | public string Key { get; set; }
7 | public string State { get; set; }
8 | public string OutputArguments { get; set; } = null;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/OrchestratorClient.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using System;
3 | using System.Net;
4 | using System.Net.Http;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth;
8 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient.JobModels;
9 | using UiPath.ChatbotSamples.BotFramework.Utils;
10 |
11 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient
12 | {
13 | public class OrchestratorClient : IOrchestratorClient
14 | {
15 | private readonly HttpClient _client;
16 | private readonly string _baseUrl;
17 | private readonly int _statusCheckInterval;
18 | private readonly int _statusMaxRetry;
19 |
20 | public OrchestratorClient(ITokenService tokenService, IOptionsMonitor orchestratorSettingsAccessor)
21 | {
22 | var orchestratorSettings = orchestratorSettingsAccessor.CheckNullReference().CurrentValue;
23 | if (!orchestratorSettings.Validate())
24 | {
25 | throw new ArgumentException("Orchestrator setting invalid");
26 | }
27 |
28 | if (orchestratorSettings.AuthMode.OrdinalEquals("Basic"))
29 | {
30 | _client = new HttpClient(new BasicAuthHeadHandler(tokenService.CheckNullReference()));
31 | }
32 | else
33 | {
34 | _client = new HttpClient(new CloudAuthHeadHandler(tokenService.CheckNullReference(), orchestratorSettings.ServiceInstanceLogicalName));
35 | }
36 |
37 | _baseUrl = orchestratorSettings.CheckNullReference().BaseUrl;
38 | _statusCheckInterval = orchestratorSettings.StatusCheckInterval;
39 | _statusMaxRetry = orchestratorSettings.StatusCheckMaxRetry;
40 | }
41 |
42 | public async Task ExecuteJobAsync(StartJobInfo jobInfo)
43 | {
44 | var jobResponse = await StartJobAsync(jobInfo);
45 | await WaitForJobCompletionAsync(jobResponse.Key);
46 | return await GetJobDetailAsync(jobResponse.Id);
47 | }
48 |
49 | // Depending on user scenario, if the robot is very busy and start job may fail. So a retry will need to be added here.
50 | public async Task StartJobAsync(StartJobInfo jobInfo, HttpClient client = null)
51 | {
52 | StartJobBody body = new StartJobBody() { startInfo = jobInfo };
53 | var startJobResponseList = await HttpCallAsync>(Utils.GetStartjobUrl(_baseUrl), HttpMethod.Post, Utils.GetPostBody(body), client);
54 | return startJobResponseList.Value[0];
55 | }
56 |
57 | public async Task WaitForJobCompletionAsync(string jobKey, HttpClient client = null)
58 | {
59 | int count = 0;
60 | while (count++ < _statusMaxRetry)
61 | {
62 | await Task.Delay(_statusCheckInterval);
63 |
64 | var jobs = await HttpCallAsync>(Utils.GetJobStatusUrl(_baseUrl, jobKey), HttpMethod.Get, null, client);
65 | if (jobs?.Value?.Length == null)
66 | {
67 | continue;
68 | }
69 |
70 | var job = jobs.Value[0];
71 |
72 | if (job.State.OrdinalEquals("Successful"))
73 | {
74 | return;
75 | }
76 | if (job.State.OrdinalEquals("Faulted") || job.State.OrdinalEquals("Stopped"))
77 | {
78 | throw new Exception($"Job {jobKey} completed with {job.State} state.");
79 | }
80 | }
81 | throw new Exception($"Job {jobKey} timedout after {_statusCheckInterval * _statusMaxRetry} ms.");
82 | }
83 |
84 | public async Task GetJobDetailAsync(string jobId, HttpClient client = null)
85 | {
86 | return await HttpCallAsync(Utils.GetJobDetailUrl(_baseUrl, jobId), HttpMethod.Get, null, client);
87 | }
88 |
89 | private void EnsureSuccessStatus(HttpResponseMessage response)
90 | {
91 | if (response?.StatusCode != HttpStatusCode.OK && response?.StatusCode != HttpStatusCode.Created)
92 | {
93 | throw new Exception("Orchestrator call failed");
94 | }
95 | }
96 |
97 | private async Task HttpCallAsync(string url, HttpMethod httpMethod, HttpContent body = null, HttpClient client = null) where T: class
98 | {
99 | client = client ?? _client;
100 |
101 | HttpResponseMessage response = null;
102 |
103 | if (httpMethod == HttpMethod.Get)
104 | {
105 | response = await client.GetAsync(url, new CancellationToken());
106 | }
107 | else if (httpMethod == HttpMethod.Post)
108 | {
109 | response = await client.PostAsync(url, body, new CancellationToken());
110 | }
111 |
112 | EnsureSuccessStatus(response);
113 |
114 | return await (response).Content.ReadAsAsync();
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/OrchestratorClient.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | true
6 | UiPath.ChatbotSamples.BotFramework.OrchestratorClient
7 | UiPath.ChatbotSamples.BotFramework.OrchestratorClient
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/OrchestratorSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UiPath.ChatbotSamples.BotFramework.Utils;
3 |
4 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient
5 | {
6 | public class OrchestratorSettings
7 | {
8 | public string BaseUrl { get; set; }
9 |
10 | public string AuthMode { get; set; }
11 |
12 | public string TenancyName { get; set; }
13 |
14 | public string UsernameOrEmailAddress { get; set; }
15 |
16 | public string Password { get; set; }
17 |
18 | public string RefreshToken { get; set; }
19 |
20 | public string ServiceInstanceLogicalName { get; set; }
21 |
22 | public string AccountLogicalName { get; set; }
23 |
24 | public int StatusCheckMaxRetry { get; set; } = 60;
25 |
26 | public int StatusCheckInterval { get; set; } = 500;
27 |
28 | public string Strategy { get; set; } = "Specific";
29 |
30 | public int JobsCount { get; set; } = 0;
31 |
32 | public long[] RobotIds { get; set; }
33 |
34 | public ProcessKey[] ProcessKeys { get; set; }
35 |
36 | public bool Validate()
37 | {
38 | if (!AuthMode.OrdinalEquals("Basic") && !AuthMode.OrdinalEquals("Cloud"))
39 | {
40 | return false;
41 | }
42 |
43 | if (AuthMode.OrdinalEquals("Basic"))
44 | {
45 | if (string.IsNullOrEmpty(TenancyName) || string.IsNullOrEmpty(UsernameOrEmailAddress) || string.IsNullOrEmpty(Password))
46 | {
47 | return false;
48 | }
49 | }
50 |
51 | if (AuthMode.OrdinalEquals("Cloud"))
52 | {
53 | if (string.IsNullOrEmpty(RefreshToken) || string.IsNullOrEmpty(ServiceInstanceLogicalName) || string.IsNullOrEmpty(AccountLogicalName))
54 | {
55 | return false;
56 | }
57 | }
58 |
59 | bool isUrl = Uri.IsWellFormedUriString(BaseUrl, UriKind.Absolute);
60 | if (!isUrl)
61 | {
62 | return false;
63 | }
64 |
65 | if (!Strategy.OrdinalEquals("Specific") && !Strategy.OrdinalEquals("JobsCount"))
66 | {
67 | return false;
68 | }
69 |
70 | if (Strategy.OrdinalEquals("Specific") && (RobotIds == null || RobotIds.Length == 0))
71 | {
72 | return false;
73 | }
74 |
75 | if (Strategy.OrdinalEquals("JobsCount") && JobsCount <= 0)
76 | {
77 | return false;
78 | }
79 |
80 | if (ProcessKeys == null || ProcessKeys.Length == 0)
81 | {
82 | return false;
83 | }
84 |
85 | foreach (var processKey in ProcessKeys)
86 | {
87 | if (!Guid.TryParse(processKey.Key, out Guid newGuid))
88 | {
89 | return false;
90 | }
91 | }
92 |
93 | return true;
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/ProcessKey.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient
6 | {
7 | public class ProcessKey
8 | {
9 | public string Process { get; set; }
10 |
11 | public string Key { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/BotFramework/OrchestratorClient/Utils.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Net.Http;
4 | using System.Text;
5 |
6 | namespace UiPath.ChatbotSamples.BotFramework.OrchestratorClient
7 | {
8 | public static class Utils
9 | {
10 | public static string GetBasicAuthUrl(string baseUrl)
11 | {
12 | return ConcatUrl(baseUrl, _basicAuthUrl);
13 | }
14 |
15 | public static string CloudAuthUrl => "https://account.uipath.com/oauth/token";
16 |
17 | public static string GetStartjobUrl(string baseUrl)
18 | {
19 | return ConcatUrl(baseUrl, _startJobUrl);
20 | }
21 |
22 | public static string GetJobStatusUrl(string baseUrl, string jobKey)
23 | {
24 | return ConcatUrl(baseUrl, "odata/Jobs?$top=3&$filter=Key eq " + jobKey);
25 | }
26 |
27 | public static string GetJobDetailUrl(string baseUrl, string jobId)
28 | {
29 | return ConcatUrl(baseUrl, "odata/Jobs(" + jobId + @")");
30 | }
31 |
32 | public static StringContent GetPostBody(T t)
33 | {
34 | return new StringContent(SerializePostBody(t), Encoding.UTF8, "application/json");
35 | }
36 |
37 | private static string SerializePostBody(T t)
38 | {
39 | return JsonConvert.SerializeObject(t, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
40 | }
41 |
42 | private static string _basicAuthUrl => "api/account/authenticate";
43 |
44 | private static string _startJobUrl => "odata/Jobs/UiPath.Server.Configuration.OData.StartJobs";
45 |
46 | private static string ConcatUrl(string baseUrl, string routing)
47 | {
48 | if (string.IsNullOrEmpty(baseUrl) || string.IsNullOrEmpty(routing))
49 | {
50 | throw new InvalidOperationException("cannot concat url with null or empty string");
51 | }
52 | var delimiter = '/';
53 |
54 | return $"{baseUrl.TrimEnd(delimiter)}{delimiter}{routing.TrimStart(delimiter)}";
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/BotFramework/README.md:
--------------------------------------------------------------------------------
1 | # SampleBot Solution Code Strucure
2 | SampleBot solution is written to create an implementation reference on how to integrate Microsoft Bot Framework and UiPath Orchestrator to build a virtual agent that can execute tasks using RPA technology.
3 |
4 | This document is a walk through of the code.
5 |
6 | # Prerequisites
7 | Refer to [this link](https://docs.microsoft.com/en-us/azure/bot-service/dotnet/bot-builder-dotnet-sdk-quickstart?view=azure-bot-service-4.0) for prerequisites.
8 | Bot Framework V4 template for C# is not required to run the sample code or create your bot project based on the sample code. It is required when generate a new blank bot project.
9 |
10 | # Entry point - SampleBot project
11 | This project is the entry point of the bot. Majority part of this project is generated from the bot framework template.
12 | What this project do:
13 | - Provides the API endpoint to listen to user input message and send bot response
14 | - Read settings
15 | - Inject the dependencies
16 |
17 | # Common project
18 | This project implements a common multi-turn bot. This bot is focusing on the conversation strategy and it doesn't couple with real life dialog flows. It includes below functionalities:
19 | - Define common models
20 | * EntityState: This is the data strucutre to store and retrieve any extracted entity
21 | * LuisEntity: It provides the ability to post process any entity value that extracted from Luis. For example, normalize names.
22 | * Intent: There are different types of intents defined. Normal intent is user intent for virtual agent to execute some dialog. DetourIntent (for example help) is the intent the makes the bot need to detour to another task (for example provide help text) and come back to resume the last dialog step. TerminationIntent (for example cancel) is the intent that makes the bot stop what it is doing and start like a new conversation.
23 | - Error handling. For any exception uncaught, reply with internal exception and clean up resources.
24 | - Define conversation strategy. For each conversation turn:
25 | * If it is conversation update(user join conversation), then send welcome activity
26 | * If it is message, then do the following:
27 | 1) Recognize intent using Luis
28 | 2) Add extracted entity (if any) to EntityState
29 | 3) If the intent is to terminate or detour, handle the interruption and return
30 | 4) Continue current active dialog with this intent
31 | 5) If no active dialog, then start the dialog mappted to this intent
32 |
33 | # Dialog project
34 | This project defines the customized settings for the sample scenario (My bot that handles replace item and cancel order). It includes
35 | - Intents. MyIntents defines the intent for the bot and the mapping dialog flow
36 | - MyDialogs. Dialogs in this folder defines the conversation flow for each dialog. To get entities from EntityState, inherit from StatefulDialogBase, otherwise DialogBase.
37 | - MyBotSettings. This file defines the LUIS configuration it wants to use and the postprocessing for LUIS entities
38 | - MyBot. This file adds all the dialogs to the dialog set.
39 |
40 | # Actions project
41 | This project is called by Dialog project to execute bot actions. In this sample code, all the actions talk to orchestrator to run a certain process. This project includes:
42 | - Models as interface between Dialog and Actions
43 | - Models as interface between Actions and Orchestrator. Note that the models may not necessarily the same as the models above. GetItemsOutputInternal.cs provides an example of this. It needs to be mapped to the external model for dialog consumption.
44 | - MyRpaClient that is to prepare the input parameter and call the Orchestrator client to run a certain process
45 |
46 | # OrchestratorClient project
47 | This project is to run a job in orchestrator and return the result. The public method it provides is ExecuteJobAsync, which first start job, then wait for job to complete, then get job detail and return.
48 | Note that when all robots are busy and have at least one job pending already, start job may fail. So depending on the user scenario and the robot settings, a retry may be need to add in this project to handle that situation.
49 |
50 |
51 | # Helpers - Utils and Resources project
52 | Utils project provides common functions for other projects to use, such as null check.
53 | Resources project put all the text message in resource file, so it can be easily update externally or extended for multiple lanugage support.
54 |
--------------------------------------------------------------------------------
/BotFramework/Resources/Resource.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace UiPath.ChatbotSamples.BotFramework.Resources {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | public class Resource {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resource() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | public static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("UiPath.ChatbotSamples.BotFramework.Resources.Resource", typeof(Resource).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | public static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized string similar to Is there anything else I can help you with?.
65 | ///
66 | public static string Anything_Else {
67 | get {
68 | return ResourceManager.GetString("Anything_Else", resourceCulture);
69 | }
70 | }
71 |
72 | ///
73 | /// Looks up a localized string similar to I can help to search for your order. Can you provide your customer Id?.
74 | ///
75 | public static string Ask_Customer_Id {
76 | get {
77 | return ResourceManager.GetString("Ask_Customer_Id", resourceCulture);
78 | }
79 | }
80 |
81 | ///
82 | /// Looks up a localized string similar to Bye! Have a good day!.
83 | ///
84 | public static string Bye {
85 | get {
86 | return ResourceManager.GetString("Bye", resourceCulture);
87 | }
88 | }
89 |
90 | ///
91 | /// Looks up a localized string similar to Sorry, I was not helpful..
92 | ///
93 | public static string Bye_With_Active_Dialog {
94 | get {
95 | return ResourceManager.GetString("Bye_With_Active_Dialog", resourceCulture);
96 | }
97 | }
98 |
99 | ///
100 | /// Looks up a localized string similar to Sorry, I don't have anything to cancel..
101 | ///
102 | public static string Cancel_Fail {
103 | get {
104 | return ResourceManager.GetString("Cancel_Fail", resourceCulture);
105 | }
106 | }
107 |
108 | ///
109 | /// Looks up a localized string similar to I have cancelled our last activity..
110 | ///
111 | public static string Cancel_Success {
112 | get {
113 | return ResourceManager.GetString("Cancel_Success", resourceCulture);
114 | }
115 | }
116 |
117 | ///
118 | /// Looks up a localized string similar to Sorry, I didn't understand what you just said to me..
119 | ///
120 | public static string Cannot_Understand {
121 | get {
122 | return ResourceManager.GetString("Cannot_Understand", resourceCulture);
123 | }
124 | }
125 |
126 | ///
127 | /// Looks up a localized string similar to Your order is not delivered because it is {0}. Do you want me to cancel this one and order from another supplier for you with no extra shipping fee? .
128 | ///
129 | public static string Deliver_Status {
130 | get {
131 | return ResourceManager.GetString("Deliver_Status", resourceCulture);
132 | }
133 | }
134 |
135 | ///
136 | /// Looks up a localized string similar to Can you describe the damage?.
137 | ///
138 | public static string Describe_Damage {
139 | get {
140 | return ResourceManager.GetString("Describe_Damage", resourceCulture);
141 | }
142 | }
143 |
144 | ///
145 | /// Looks up a localized string similar to Hi, how can I help you today?.
146 | ///
147 | public static string Greeting {
148 | get {
149 | return ResourceManager.GetString("Greeting", resourceCulture);
150 | }
151 | }
152 |
153 | ///
154 | /// Looks up a localized string similar to You can ask me about delayed shipments, broken items, etc..
155 | ///
156 | public static string Help {
157 | get {
158 | return ResourceManager.GetString("Help", resourceCulture);
159 | }
160 | }
161 |
162 | ///
163 | /// Looks up a localized string similar to Sorry, something went wrong. Please retry later..
164 | ///
165 | public static string Internal_Exception {
166 | get {
167 | return ResourceManager.GetString("Internal_Exception", resourceCulture);
168 | }
169 | }
170 |
171 | ///
172 | /// Looks up a localized string similar to No.
173 | ///
174 | public static string No {
175 | get {
176 | return ResourceManager.GetString("No", resourceCulture);
177 | }
178 | }
179 |
180 | ///
181 | /// Looks up a localized string similar to I don't see any other undelivered orders. Would you like to talk to an agent?.
182 | ///
183 | public static string No_Undelivered_Order {
184 | get {
185 | return ResourceManager.GetString("No_Undelivered_Order", resourceCulture);
186 | }
187 | }
188 |
189 | ///
190 | /// Looks up a localized string similar to None of above.
191 | ///
192 | public static string None_Of_Above {
193 | get {
194 | return ResourceManager.GetString("None_Of_Above", resourceCulture);
195 | }
196 | }
197 |
198 | ///
199 | /// Looks up a localized string similar to Your order with order number {0} has been cancelled. You can print your return label at {1}. Details have been sent to your email..
200 | ///
201 | public static string Order_Cancelled {
202 | get {
203 | return ResourceManager.GetString("Order_Cancelled", resourceCulture);
204 | }
205 | }
206 |
207 | ///
208 | /// Looks up a localized string similar to Your new order has been placed with order number {0}. It is expected to deliver on {1}. Details have been sent to your email..
209 | ///
210 | public static string Order_Created {
211 | get {
212 | return ResourceManager.GetString("Order_Created", resourceCulture);
213 | }
214 | }
215 |
216 | ///
217 | /// Looks up a localized string similar to Replace.
218 | ///
219 | public static string Replace {
220 | get {
221 | return ResourceManager.GetString("Replace", resourceCulture);
222 | }
223 | }
224 |
225 | ///
226 | /// Looks up a localized string similar to Return.
227 | ///
228 | public static string Return {
229 | get {
230 | return ResourceManager.GetString("Return", resourceCulture);
231 | }
232 | }
233 |
234 | ///
235 | /// Looks up a localized string similar to I've made a note of the damage. Do you want me to return or replace this item?.
236 | ///
237 | public static string Return_Or_Replace {
238 | get {
239 | return ResourceManager.GetString("Return_Or_Replace", resourceCulture);
240 | }
241 | }
242 |
243 | ///
244 | /// Looks up a localized string similar to To talk to a human agent, please call (123)456-7890..
245 | ///
246 | public static string Talk_To_Agent {
247 | get {
248 | return ResourceManager.GetString("Talk_To_Agent", resourceCulture);
249 | }
250 | }
251 |
252 | ///
253 | /// Looks up a localized string similar to Thank you!.
254 | ///
255 | public static string Thank_You {
256 | get {
257 | return ResourceManager.GetString("Thank_You", resourceCulture);
258 | }
259 | }
260 |
261 | ///
262 | /// Looks up a localized string similar to I searched for your orders in the past 1 month. Below are the orders that have been delivered to you. Which one are you asking about?.
263 | ///
264 | public static string Which_Delivered {
265 | get {
266 | return ResourceManager.GetString("Which_Delivered", resourceCulture);
267 | }
268 | }
269 |
270 | ///
271 | /// Looks up a localized string similar to I searched for your orders in the past 1 month. Below are the orders that have not been delivered yet. Which one are you asking about?.
272 | ///
273 | public static string Which_Undelivered {
274 | get {
275 | return ResourceManager.GetString("Which_Undelivered", resourceCulture);
276 | }
277 | }
278 |
279 | ///
280 | /// Looks up a localized string similar to Working on it....
281 | ///
282 | public static string Working_On {
283 | get {
284 | return ResourceManager.GetString("Working_On", resourceCulture);
285 | }
286 | }
287 |
288 | ///
289 | /// Looks up a localized string similar to Yes .
290 | ///
291 | public static string Yes {
292 | get {
293 | return ResourceManager.GetString("Yes", resourceCulture);
294 | }
295 | }
296 | }
297 | }
298 |
--------------------------------------------------------------------------------
/BotFramework/Resources/Resource.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Sorry, something went wrong. Please retry later.
122 |
123 |
124 | Sorry, I didn't understand what you just said to me.
125 |
126 |
127 | Hi, how can I help you today?
128 |
129 |
130 | Bye! Have a good day!
131 |
132 |
133 | Sorry, I was not helpful.
134 |
135 |
136 | I have cancelled our last activity.
137 |
138 |
139 | Sorry, I don't have anything to cancel.
140 |
141 |
142 | You can ask me about delayed shipments, broken items, etc.
143 |
144 |
145 | To talk to a human agent, please call (123)456-7890.
146 |
147 |
148 | Is there anything else I can help you with?
149 |
150 |
151 | I can help to search for your order. Can you provide your customer Id?
152 |
153 |
154 | Working on it...
155 |
156 |
157 | I don't see any other undelivered orders. Would you like to talk to an agent?
158 |
159 |
160 | I searched for your orders in the past 1 month. Below are the orders that have not been delivered yet. Which one are you asking about?
161 |
162 |
163 | I searched for your orders in the past 1 month. Below are the orders that have been delivered to you. Which one are you asking about?
164 |
165 |
166 | None of above
167 |
168 |
169 | Your order is not delivered because it is {0}. Do you want me to cancel this one and order from another supplier for you with no extra shipping fee?
170 |
171 |
172 | Yes
173 |
174 |
175 | No
176 |
177 |
178 | Thank you!
179 |
180 |
181 | Your new order has been placed with order number {0}. It is expected to deliver on {1}. Details have been sent to your email.
182 |
183 |
184 | Your order with order number {0} has been cancelled. You can print your return label at {1}. Details have been sent to your email.
185 |
186 |
187 | Can you describe the damage?
188 |
189 |
190 | I've made a note of the damage. Do you want me to return or replace this item?
191 |
192 |
193 | Return
194 |
195 |
196 | Replace
197 |
198 |
--------------------------------------------------------------------------------
/BotFramework/Resources/Resources.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | UiPath.ChatbotSamples.BotFramework.Resources
6 | UiPath.ChatbotSamples.BotFramework.Resources
7 |
8 |
9 |
10 |
11 | True
12 | True
13 | Resource.resx
14 |
15 |
16 |
17 |
18 |
19 | PublicResXFileCodeGenerator
20 | Resource.Designer.cs
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/BotFramework/SampleBot.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.489
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleBot", "SampleBot\SampleBot.csproj", "{42280CCA-E5A4-4603-8A4B-D2716C8F7C7E}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dialogs", "Dialogs\Dialogs.csproj", "{8CE56832-D037-4633-A33A-00ABEBD031AD}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "Common\Common.csproj", "{DB636AB4-2E98-46D7-A252-F8740CAE72F8}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Actions", "Actions\Actions.csproj", "{3FBC4D71-8A16-40A7-82E9-5D5D74F6C8A6}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchestratorClient", "OrchestratorClient\OrchestratorClient.csproj", "{5B70CB3A-BDF0-4FD7-94E0-EC696B1077DF}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils", "Utils\Utils.csproj", "{61FA8EE7-6EB2-4CBA-9E6E-4A0DD3E76031}"
17 | EndProject
18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Resources", "Resources\Resources.csproj", "{F9BF4AF8-A5B2-4832-81DB-FEBED1F32A6E}"
19 | EndProject
20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{99F836B8-C9D3-4E98-BBA1-2821996E9803}"
21 | EndProject
22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils.Test", "Utils.Test\Utils.Test.csproj", "{3C7EEB10-0ECC-4A15-95B6-0EE6D2A0EAE6}"
23 | EndProject
24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchestratorClient.Test", "OrchestratorClient.Test\OrchestratorClient.Test.csproj", "{4111B415-EC6E-4802-B87F-44414FF6B51E}"
25 | EndProject
26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DialogsTest", "DialogsTest\DialogsTest.csproj", "{C2AA898A-3BE0-4A92-A012-8C92A413F50E}"
27 | EndProject
28 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.Common", "Test.Common\Test.Common.csproj", "{01DACA10-1C6F-4BD2-B3A6-83AC5DA7DBC3}"
29 | EndProject
30 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActionsTest", "ActionsTest\ActionsTest.csproj", "{CD291199-F8BE-4D88-AAB3-7A92BCE6081B}"
31 | EndProject
32 | Global
33 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
34 | Debug|Any CPU = Debug|Any CPU
35 | Release|Any CPU = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
38 | {42280CCA-E5A4-4603-8A4B-D2716C8F7C7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {42280CCA-E5A4-4603-8A4B-D2716C8F7C7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {42280CCA-E5A4-4603-8A4B-D2716C8F7C7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {42280CCA-E5A4-4603-8A4B-D2716C8F7C7E}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {8CE56832-D037-4633-A33A-00ABEBD031AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {8CE56832-D037-4633-A33A-00ABEBD031AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {8CE56832-D037-4633-A33A-00ABEBD031AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {8CE56832-D037-4633-A33A-00ABEBD031AD}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {DB636AB4-2E98-46D7-A252-F8740CAE72F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {DB636AB4-2E98-46D7-A252-F8740CAE72F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {DB636AB4-2E98-46D7-A252-F8740CAE72F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {DB636AB4-2E98-46D7-A252-F8740CAE72F8}.Release|Any CPU.Build.0 = Release|Any CPU
50 | {3FBC4D71-8A16-40A7-82E9-5D5D74F6C8A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51 | {3FBC4D71-8A16-40A7-82E9-5D5D74F6C8A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
52 | {3FBC4D71-8A16-40A7-82E9-5D5D74F6C8A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
53 | {3FBC4D71-8A16-40A7-82E9-5D5D74F6C8A6}.Release|Any CPU.Build.0 = Release|Any CPU
54 | {5B70CB3A-BDF0-4FD7-94E0-EC696B1077DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
55 | {5B70CB3A-BDF0-4FD7-94E0-EC696B1077DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
56 | {5B70CB3A-BDF0-4FD7-94E0-EC696B1077DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
57 | {5B70CB3A-BDF0-4FD7-94E0-EC696B1077DF}.Release|Any CPU.Build.0 = Release|Any CPU
58 | {61FA8EE7-6EB2-4CBA-9E6E-4A0DD3E76031}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
59 | {61FA8EE7-6EB2-4CBA-9E6E-4A0DD3E76031}.Debug|Any CPU.Build.0 = Debug|Any CPU
60 | {61FA8EE7-6EB2-4CBA-9E6E-4A0DD3E76031}.Release|Any CPU.ActiveCfg = Release|Any CPU
61 | {61FA8EE7-6EB2-4CBA-9E6E-4A0DD3E76031}.Release|Any CPU.Build.0 = Release|Any CPU
62 | {F9BF4AF8-A5B2-4832-81DB-FEBED1F32A6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
63 | {F9BF4AF8-A5B2-4832-81DB-FEBED1F32A6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
64 | {F9BF4AF8-A5B2-4832-81DB-FEBED1F32A6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
65 | {F9BF4AF8-A5B2-4832-81DB-FEBED1F32A6E}.Release|Any CPU.Build.0 = Release|Any CPU
66 | {3C7EEB10-0ECC-4A15-95B6-0EE6D2A0EAE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
67 | {3C7EEB10-0ECC-4A15-95B6-0EE6D2A0EAE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
68 | {3C7EEB10-0ECC-4A15-95B6-0EE6D2A0EAE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
69 | {3C7EEB10-0ECC-4A15-95B6-0EE6D2A0EAE6}.Release|Any CPU.Build.0 = Release|Any CPU
70 | {4111B415-EC6E-4802-B87F-44414FF6B51E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
71 | {4111B415-EC6E-4802-B87F-44414FF6B51E}.Debug|Any CPU.Build.0 = Debug|Any CPU
72 | {4111B415-EC6E-4802-B87F-44414FF6B51E}.Release|Any CPU.ActiveCfg = Release|Any CPU
73 | {4111B415-EC6E-4802-B87F-44414FF6B51E}.Release|Any CPU.Build.0 = Release|Any CPU
74 | {C2AA898A-3BE0-4A92-A012-8C92A413F50E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
75 | {C2AA898A-3BE0-4A92-A012-8C92A413F50E}.Debug|Any CPU.Build.0 = Debug|Any CPU
76 | {C2AA898A-3BE0-4A92-A012-8C92A413F50E}.Release|Any CPU.ActiveCfg = Release|Any CPU
77 | {C2AA898A-3BE0-4A92-A012-8C92A413F50E}.Release|Any CPU.Build.0 = Release|Any CPU
78 | {01DACA10-1C6F-4BD2-B3A6-83AC5DA7DBC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
79 | {01DACA10-1C6F-4BD2-B3A6-83AC5DA7DBC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
80 | {01DACA10-1C6F-4BD2-B3A6-83AC5DA7DBC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
81 | {01DACA10-1C6F-4BD2-B3A6-83AC5DA7DBC3}.Release|Any CPU.Build.0 = Release|Any CPU
82 | {CD291199-F8BE-4D88-AAB3-7A92BCE6081B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
83 | {CD291199-F8BE-4D88-AAB3-7A92BCE6081B}.Debug|Any CPU.Build.0 = Debug|Any CPU
84 | {CD291199-F8BE-4D88-AAB3-7A92BCE6081B}.Release|Any CPU.ActiveCfg = Release|Any CPU
85 | {CD291199-F8BE-4D88-AAB3-7A92BCE6081B}.Release|Any CPU.Build.0 = Release|Any CPU
86 | EndGlobalSection
87 | GlobalSection(SolutionProperties) = preSolution
88 | HideSolutionNode = FALSE
89 | EndGlobalSection
90 | GlobalSection(NestedProjects) = preSolution
91 | {3C7EEB10-0ECC-4A15-95B6-0EE6D2A0EAE6} = {99F836B8-C9D3-4E98-BBA1-2821996E9803}
92 | {4111B415-EC6E-4802-B87F-44414FF6B51E} = {99F836B8-C9D3-4E98-BBA1-2821996E9803}
93 | {C2AA898A-3BE0-4A92-A012-8C92A413F50E} = {99F836B8-C9D3-4E98-BBA1-2821996E9803}
94 | {01DACA10-1C6F-4BD2-B3A6-83AC5DA7DBC3} = {99F836B8-C9D3-4E98-BBA1-2821996E9803}
95 | {CD291199-F8BE-4D88-AAB3-7A92BCE6081B} = {99F836B8-C9D3-4E98-BBA1-2821996E9803}
96 | EndGlobalSection
97 | GlobalSection(ExtensibilityGlobals) = postSolution
98 | SolutionGuid = {F24F4025-388A-4FB9-954F-B47A559FB2E7}
99 | EndGlobalSection
100 | EndGlobal
101 |
--------------------------------------------------------------------------------
/BotFramework/SampleBot/ConfigurationCredentialProvider.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 | //
4 | // Generated with Bot Builder V4 SDK Template for Visual Studio EmptyBot v4.3.0
5 |
6 | using Microsoft.Bot.Connector.Authentication;
7 | using Microsoft.Extensions.Configuration;
8 |
9 | namespace UiPath.ChatbotSamples.BotFramework.Bot
10 | {
11 | public class ConfigurationCredentialProvider : SimpleCredentialProvider
12 | {
13 | public ConfigurationCredentialProvider(IConfiguration configuration)
14 | : base(configuration["MicrosoftAppId"], configuration["MicrosoftAppPassword"])
15 | {
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/BotFramework/SampleBot/Controllers/BotController.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 | //
4 | // Generated with Bot Builder V4 SDK Template for Visual Studio EmptyBot v4.3.0
5 |
6 | using System.Threading.Tasks;
7 | using Microsoft.AspNetCore.Mvc;
8 | using Microsoft.Bot.Builder;
9 | using Microsoft.Bot.Builder.Integration.AspNet.Core;
10 |
11 | namespace UiPath.ChatbotSamples.BotFramework.Bot.Controllers
12 | {
13 | // This ASP Controller is created to handle a request. Dependency Injection will provide the Adapter and IBot
14 | // implementation at runtime. Multiple different IBot implementations running at different endpoints can be
15 | // achieved by specifying a more specific type for the bot constructor argument.
16 | [Route("api/messages")]
17 | [ApiController]
18 | public class BotController : ControllerBase
19 | {
20 | private readonly IBotFrameworkHttpAdapter Adapter;
21 | private readonly IBot Bot;
22 |
23 | public BotController(IBotFrameworkHttpAdapter adapter, IBot bot)
24 | {
25 | Adapter = adapter;
26 | Bot = bot;
27 | }
28 |
29 | [HttpPost]
30 | public async Task PostAsync()
31 | {
32 | // Delegate the processing of the HTTP POST to the adapter.
33 | // The adapter will invoke the bot.
34 | await Adapter.ProcessAsync(Request, Response, Bot);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/BotFramework/SampleBot/DeploymentTemplates/template-with-new-rg.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "groupLocation": {
6 | "type": "string",
7 | "metadata": {
8 | "description": "Specifies the location of the Resource Group."
9 | }
10 | },
11 | "groupName": {
12 | "type": "string",
13 | "metadata": {
14 | "description": "Specifies the name of the Resource Group."
15 | }
16 | },
17 | "appId": {
18 | "type": "string",
19 | "metadata": {
20 | "description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
21 | }
22 | },
23 | "appSecret": {
24 | "type": "string",
25 | "metadata": {
26 | "description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings."
27 | }
28 | },
29 | "botId": {
30 | "type": "string",
31 | "metadata": {
32 | "description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
33 | }
34 | },
35 | "botSku": {
36 | "type": "string",
37 | "metadata": {
38 | "description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
39 | }
40 | },
41 | "newAppServicePlanName": {
42 | "type": "string",
43 | "metadata": {
44 | "description": "The name of the App Service Plan."
45 | }
46 | },
47 | "newAppServicePlanSku": {
48 | "type": "object",
49 | "defaultValue": {
50 | "name": "S1",
51 | "tier": "Standard",
52 | "size": "S1",
53 | "family": "S",
54 | "capacity": 1
55 | },
56 | "metadata": {
57 | "description": "The SKU of the App Service Plan. Defaults to Standard values."
58 | }
59 | },
60 | "newAppServicePlanLocation": {
61 | "type": "string",
62 | "metadata": {
63 | "description": "The location of the App Service Plan. Defaults to \"westus\"."
64 | }
65 | },
66 | "newWebAppName": {
67 | "type": "string",
68 | "defaultValue": "",
69 | "metadata": {
70 | "description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
71 | }
72 | }
73 | },
74 | "variables": {
75 | "appServicePlanName": "[parameters('newAppServicePlanName')]",
76 | "resourcesLocation": "[parameters('newAppServicePlanLocation')]",
77 | "webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
78 | "siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
79 | "botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
80 | },
81 | "resources": [
82 | {
83 | "name": "[parameters('groupName')]",
84 | "type": "Microsoft.Resources/resourceGroups",
85 | "apiVersion": "2018-05-01",
86 | "location": "[parameters('groupLocation')]",
87 | "properties": {
88 | }
89 | },
90 | {
91 | "type": "Microsoft.Resources/deployments",
92 | "apiVersion": "2018-05-01",
93 | "name": "storageDeployment",
94 | "resourceGroup": "[parameters('groupName')]",
95 | "dependsOn": [
96 | "[resourceId('Microsoft.Resources/resourceGroups/', parameters('groupName'))]"
97 | ],
98 | "properties": {
99 | "mode": "Incremental",
100 | "template": {
101 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
102 | "contentVersion": "1.0.0.0",
103 | "parameters": {},
104 | "variables": {},
105 | "resources": [
106 | {
107 | "comments": "Create a new App Service Plan",
108 | "type": "Microsoft.Web/serverfarms",
109 | "name": "[variables('appServicePlanName')]",
110 | "apiVersion": "2018-02-01",
111 | "location": "[variables('resourcesLocation')]",
112 | "sku": "[parameters('newAppServicePlanSku')]",
113 | "properties": {
114 | "name": "[variables('appServicePlanName')]"
115 | }
116 | },
117 | {
118 | "comments": "Create a Web App using the new App Service Plan",
119 | "type": "Microsoft.Web/sites",
120 | "apiVersion": "2015-08-01",
121 | "location": "[variables('resourcesLocation')]",
122 | "kind": "app",
123 | "dependsOn": [
124 | "[resourceId('Microsoft.Web/serverfarms/', variables('appServicePlanName'))]"
125 | ],
126 | "name": "[variables('webAppName')]",
127 | "properties": {
128 | "name": "[variables('webAppName')]",
129 | "serverFarmId": "[variables('appServicePlanName')]",
130 | "siteConfig": {
131 | "appSettings": [
132 | {
133 | "name": "WEBSITE_NODE_DEFAULT_VERSION",
134 | "value": "10.14.1"
135 | },
136 | {
137 | "name": "MicrosoftAppId",
138 | "value": "[parameters('appId')]"
139 | },
140 | {
141 | "name": "MicrosoftAppPassword",
142 | "value": "[parameters('appSecret')]"
143 | }
144 | ],
145 | "cors": {
146 | "allowedOrigins": [
147 | "https://botservice.hosting.portal.azure.net",
148 | "https://hosting.onecloud.azure-test.net/"
149 | ]
150 | }
151 | }
152 | }
153 | },
154 | {
155 | "apiVersion": "2017-12-01",
156 | "type": "Microsoft.BotService/botServices",
157 | "name": "[parameters('botId')]",
158 | "location": "global",
159 | "kind": "bot",
160 | "sku": {
161 | "name": "[parameters('botSku')]"
162 | },
163 | "properties": {
164 | "name": "[parameters('botId')]",
165 | "displayName": "[parameters('botId')]",
166 | "endpoint": "[variables('botEndpoint')]",
167 | "msaAppId": "[parameters('appId')]",
168 | "developerAppInsightsApplicationId": null,
169 | "developerAppInsightKey": null,
170 | "publishingCredentials": null,
171 | "storageResourceId": null
172 | },
173 | "dependsOn": [
174 | "[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
175 | ]
176 | }
177 | ],
178 | "outputs": {}
179 | }
180 | }
181 | }
182 | ]
183 | }
--------------------------------------------------------------------------------
/BotFramework/SampleBot/DeploymentTemplates/template-with-preexisting-rg.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "appId": {
6 | "type": "string",
7 | "metadata": {
8 | "description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
9 | }
10 | },
11 | "appSecret": {
12 | "type": "string",
13 | "metadata": {
14 | "description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. Defaults to \"\"."
15 | }
16 | },
17 | "botId": {
18 | "type": "string",
19 | "metadata": {
20 | "description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
21 | }
22 | },
23 | "botSku": {
24 | "defaultValue": "F0",
25 | "type": "string",
26 | "metadata": {
27 | "description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
28 | }
29 | },
30 | "newAppServicePlanName": {
31 | "type": "string",
32 | "defaultValue": "",
33 | "metadata": {
34 | "description": "The name of the new App Service Plan."
35 | }
36 | },
37 | "newAppServicePlanSku": {
38 | "type": "object",
39 | "defaultValue": {
40 | "name": "S1",
41 | "tier": "Standard",
42 | "size": "S1",
43 | "family": "S",
44 | "capacity": 1
45 | },
46 | "metadata": {
47 | "description": "The SKU of the App Service Plan. Defaults to Standard values."
48 | }
49 | },
50 | "appServicePlanLocation": {
51 | "type": "string",
52 | "metadata": {
53 | "description": "The location of the App Service Plan."
54 | }
55 | },
56 | "existingAppServicePlan": {
57 | "type": "string",
58 | "defaultValue": "",
59 | "metadata": {
60 | "description": "Name of the existing App Service Plan used to create the Web App for the bot."
61 | }
62 | },
63 | "newWebAppName": {
64 | "type": "string",
65 | "defaultValue": "",
66 | "metadata": {
67 | "description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
68 | }
69 | }
70 | },
71 | "variables": {
72 | "defaultAppServicePlanName": "[if(empty(parameters('existingAppServicePlan')), 'createNewAppServicePlan', parameters('existingAppServicePlan'))]",
73 | "useExistingAppServicePlan": "[not(equals(variables('defaultAppServicePlanName'), 'createNewAppServicePlan'))]",
74 | "servicePlanName": "[if(variables('useExistingAppServicePlan'), parameters('existingAppServicePlan'), parameters('newAppServicePlanName'))]",
75 | "resourcesLocation": "[parameters('appServicePlanLocation')]",
76 | "webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
77 | "siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
78 | "botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
79 | },
80 | "resources": [
81 | {
82 | "comments": "Create a new App Service Plan if no existing App Service Plan name was passed in.",
83 | "type": "Microsoft.Web/serverfarms",
84 | "condition": "[not(variables('useExistingAppServicePlan'))]",
85 | "name": "[variables('servicePlanName')]",
86 | "apiVersion": "2018-02-01",
87 | "location": "[variables('resourcesLocation')]",
88 | "sku": "[parameters('newAppServicePlanSku')]",
89 | "properties": {
90 | "name": "[variables('servicePlanName')]"
91 | }
92 | },
93 | {
94 | "comments": "Create a Web App using an App Service Plan",
95 | "type": "Microsoft.Web/sites",
96 | "apiVersion": "2015-08-01",
97 | "location": "[variables('resourcesLocation')]",
98 | "kind": "app",
99 | "dependsOn": [
100 | "[resourceId('Microsoft.Web/serverfarms/', variables('servicePlanName'))]"
101 | ],
102 | "name": "[variables('webAppName')]",
103 | "properties": {
104 | "name": "[variables('webAppName')]",
105 | "serverFarmId": "[variables('servicePlanName')]",
106 | "siteConfig": {
107 | "appSettings": [
108 | {
109 | "name": "WEBSITE_NODE_DEFAULT_VERSION",
110 | "value": "10.14.1"
111 | },
112 | {
113 | "name": "MicrosoftAppId",
114 | "value": "[parameters('appId')]"
115 | },
116 | {
117 | "name": "MicrosoftAppPassword",
118 | "value": "[parameters('appSecret')]"
119 | }
120 | ],
121 | "cors": {
122 | "allowedOrigins": [
123 | "https://botservice.hosting.portal.azure.net",
124 | "https://hosting.onecloud.azure-test.net/"
125 | ]
126 | }
127 | }
128 | }
129 | },
130 | {
131 | "apiVersion": "2017-12-01",
132 | "type": "Microsoft.BotService/botServices",
133 | "name": "[parameters('botId')]",
134 | "location": "global",
135 | "kind": "bot",
136 | "sku": {
137 | "name": "[parameters('botSku')]"
138 | },
139 | "properties": {
140 | "name": "[parameters('botId')]",
141 | "displayName": "[parameters('botId')]",
142 | "endpoint": "[variables('botEndpoint')]",
143 | "msaAppId": "[parameters('appId')]",
144 | "developerAppInsightsApplicationId": null,
145 | "developerAppInsightKey": null,
146 | "publishingCredentials": null,
147 | "storageResourceId": null
148 | },
149 | "dependsOn": [
150 | "[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
151 | ]
152 | }
153 | ]
154 | }
--------------------------------------------------------------------------------
/BotFramework/SampleBot/Program.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 | //
4 | // Generated with Bot Builder V4 SDK Template for Visual Studio EmptyBot v4.3.0
5 |
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 |
9 | namespace UiPath.ChatbotSamples.BotFramework.Bot
10 | {
11 | public class Program
12 | {
13 | public static void Main(string[] args)
14 | {
15 | CreateWebHostBuilder(args).Build().Run();
16 | }
17 |
18 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
19 | WebHost.CreateDefaultBuilder(args)
20 | .UseStartup();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/BotFramework/SampleBot/SampleBot.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 | UiPath.ChatbotSamples.BotFramework.Bot
6 | UiPath.ChatbotSamples.BotFramework.Bot
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Always
24 |
25 |
26 |
27 |
28 |
29 | Always
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/BotFramework/SampleBot/Startup.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 | //
4 | // Generated with Bot Builder V4 SDK Template for Visual Studio EmptyBot v4.3.0
5 |
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.AspNetCore.Mvc;
9 | using Microsoft.Bot.Builder;
10 | using Microsoft.Bot.Builder.Integration.AspNet.Core;
11 | using Microsoft.Bot.Configuration;
12 | using Microsoft.Bot.Connector.Authentication;
13 | using Microsoft.Extensions.Configuration;
14 | using Microsoft.Extensions.DependencyInjection;
15 | using System;
16 | using System.IO;
17 | using UiPath.ChatbotSamples.BotFramework.Actions;
18 | using UiPath.ChatbotSamples.BotFramework.Bot.Common;
19 | using UiPath.ChatbotSamples.BotFramework.Common;
20 | using UiPath.ChatbotSamples.BotFramework.Dialogs;
21 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient;
22 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient.Auth;
23 |
24 | namespace UiPath.ChatbotSamples.BotFramework.Bot
25 | {
26 | public class Startup
27 | {
28 | public Startup(IHostingEnvironment env)
29 | {
30 | var builder = new ConfigurationBuilder()
31 | .SetBasePath(env.ContentRootPath)
32 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
33 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
34 | .AddEnvironmentVariables();
35 |
36 | Configuration = builder.Build();
37 | }
38 |
39 | public IConfiguration Configuration { get; }
40 |
41 | // This method gets called by the runtime. Use this method to add services to the container.
42 | public void ConfigureServices(IServiceCollection services)
43 | {
44 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
45 |
46 | // Create the credential provider to be used with the Bot Framework Adapter.
47 | services.AddSingleton();
48 |
49 | // Create the Bot Framework Adapter with error handling enabled.
50 | services.AddSingleton();
51 |
52 | // Add Bot configuration.
53 | var botConfig = LoadBotConfiguration();
54 | services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot configuration file could not be loaded."));
55 |
56 | // Add BotServices singleton.
57 | // Create the connected services from .bot file.
58 | services.AddSingleton(sp => new BotServices(botConfig));
59 |
60 | // Memory Storage is for local bot debugging only. When the bot
61 | // is restarted, everything stored in memory will be gone.
62 | // For production bots use the Azure Blob or
63 | // Azure CosmosDB storage providers.
64 | IStorage dataStore = new MemoryStorage();
65 |
66 | // Create and add conversation state.
67 | var conversationState = new ConversationState(dataStore);
68 | services.AddSingleton(conversationState);
69 |
70 | var userState = new UserState(dataStore);
71 | services.AddSingleton(userState);
72 | services.AddOptions();
73 |
74 | //Inject settings and sericies.
75 | services.Configure(Configuration.GetSection("OrchestratorSettings"));
76 | services.AddSingleton();
77 | services.AddSingleton();
78 | services.AddSingleton();
79 |
80 | // Inject bot.
81 | services.AddBot();
82 | }
83 |
84 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
85 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
86 | {
87 | if (env.IsDevelopment())
88 | {
89 | app.UseDeveloperExceptionPage();
90 | }
91 | else
92 | {
93 | app.UseHsts();
94 | }
95 |
96 | app.UseDefaultFiles();
97 | app.UseStaticFiles();
98 |
99 | app.UseMvc();
100 | }
101 |
102 | private BotConfiguration LoadBotConfiguration()
103 | {
104 | var secretKey = Configuration.GetSection("botFileSecret")?.Value;
105 | var botFilePath = Configuration.GetSection("botFilePath")?.Value;
106 | if (!File.Exists(botFilePath))
107 | {
108 | throw new FileNotFoundException($"The .bot configuration file was not found. botFilePath: {botFilePath}");
109 | }
110 |
111 | // Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.
112 | BotConfiguration botConfig = null;
113 | try
114 | {
115 | botConfig = BotConfiguration.Load(botFilePath, secretKey);
116 | }
117 | catch
118 | {
119 | var msg = @"Error reading bot file. Please ensure you have valid botFilePath and botFileSecret set for your environment.
120 | - You can find the botFilePath and botFileSecret in the Azure App Service application settings.
121 | - If you are running this bot locally, consider adding a appsettings.json file with botFilePath and botFileSecret.
122 | - See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration.
123 | ";
124 | throw new InvalidOperationException(msg);
125 | }
126 |
127 | return botConfig;
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/BotFramework/SampleBot/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/BotFramework/SampleBot/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "botFilePath": "samplebot.bot",
3 | "botFileSecret": null,
4 | "OrchestratorSettings": {
5 | "AuthMode": "Cloud",
6 | "RefreshToken": "",
7 | "ServiceInstanceLogicalName": "",
8 | "AccountLogicalName": "",
9 | "BaseUrl": "https://platform.uipath.com",
10 | "StatusCheckMaxRetry": 60,
11 | "StatusCheckInterval": 500,
12 | "Strategy": "Specific",
13 | "RobotIds": [ 123 ],
14 | "ProcessKeys": [
15 | {
16 | "Process": "CreatePurchaseOrder",
17 | "Key": ""
18 | },
19 | {
20 | "Process": "CreateSalesOrder",
21 | "Key": ""
22 | },
23 | {
24 | "Process": "GetItems",
25 | "Key": ""
26 | },
27 | {
28 | "Process": "CancelOrder",
29 | "Key": ""
30 | }
31 | ]
32 | }
33 | }
--------------------------------------------------------------------------------
/BotFramework/SampleBot/samplebot.bot:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sample",
3 | "description": "",
4 | "services": [
5 | {
6 | "type": "endpoint",
7 | "appId": "",
8 | "appPassword": "",
9 | "endpoint": "http://localhost:3979/api/messages",
10 | "id": "23a5a680-87c0-11e9-9c8b-ad4f3822eef1",
11 | "name": "http://localhost:3979/api/messages"
12 | },
13 | {
14 | "type": "luis",
15 | "name": "Sample",
16 | "appId": "44dddc72-a17d-43e6-b972-2fff9098afd8",
17 | "authoringKey": "231bce45531f463bb77c8217e8534661",
18 | "version": "0.1",
19 | "region": "westus"
20 | }
21 | ],
22 | "padlock": "",
23 | "version": "2.0",
24 | "overrides": null
25 | }
26 |
--------------------------------------------------------------------------------
/BotFramework/Test.Common/OrchestratorSettingOption.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using System;
3 | using UiPath.ChatbotSamples.BotFramework.OrchestratorClient;
4 |
5 | namespace UiPath.ChatbotSamples.BotFramework.Test.Common
6 | {
7 | public class OrchestratorSettingOption : IOptionsMonitor
8 | {
9 | public OrchestratorSettingOption(OrchestratorSettings setting)
10 | {
11 | CurrentValue = setting;
12 | }
13 |
14 | public OrchestratorSettings CurrentValue { get; }
15 |
16 | public OrchestratorSettings Get(string name)
17 | {
18 | throw new NotImplementedException();
19 | }
20 |
21 | public IDisposable OnChange(Action listener)
22 | {
23 | throw new NotImplementedException();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/BotFramework/Test.Common/Test.Common.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 | UiPath.ChatbotSamples.BotFramework.Test.Common
6 | UiPath.ChatbotSamples.BotFramework.Test.Common
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/BotFramework/Utils.Test/CheckNullReferenceTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Xunit;
3 |
4 | namespace UiPath.ChatbotSamples.BotFramework.Utils.Test
5 | {
6 | public class CheckNullReferenceTest
7 | {
8 | [Fact]
9 | public void ReturnNullWhenNull()
10 | {
11 | TestType t = null;
12 | Assert.Throws(() => t.CheckNullReference());
13 | }
14 |
15 | [Fact]
16 | public void ReturnValueWhenNotNull()
17 | {
18 | TestType origin = new TestType()
19 | {
20 | Test = "test string",
21 | };
22 | var result = origin.CheckNullReference();
23 | Assert.Equal(origin, result);
24 | Assert.Equal(origin.Test, result.Test);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/BotFramework/Utils.Test/OrdinalEqualTest.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 |
3 | namespace UiPath.ChatbotSamples.BotFramework.Utils.Test
4 | {
5 | public class OrdinalEqualTest
6 | {
7 | [Fact]
8 | public void EqualWhenSame()
9 | {
10 | var testString = "test string";
11 | Assert.True(testString.OrdinalEquals(testString));
12 | }
13 |
14 | [Fact]
15 | public void EqualWhenCaseDifferent()
16 | {
17 | var testString1 = "test string";
18 | var testString2 = "Test String";
19 | Assert.True(testString1.OrdinalEquals(testString2));
20 | }
21 |
22 | [Fact]
23 | public void NotEqualWhenDifferent()
24 | {
25 | var testString1 = "test string 1";
26 | var testString2 = "Test String 2";
27 | Assert.False(testString1.OrdinalEquals(testString2));
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/BotFramework/Utils.Test/TestType.cs:
--------------------------------------------------------------------------------
1 | namespace UiPath.ChatbotSamples.BotFramework.Utils.Test
2 | {
3 | public class TestType
4 | {
5 | public string Test { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/BotFramework/Utils.Test/Utils.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 | UiPath.ChatbotSamples.BotFramework.Utils.Test
6 | UiPath.ChatbotSamples.BotFramework.Utils.Test
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/BotFramework/Utils/CommonExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UiPath.ChatbotSamples.BotFramework.Utils
4 | {
5 | public static class CommonExtensions
6 | {
7 | public static T CheckNullReference(this T t)
8 | {
9 | if (t == null)
10 | {
11 | throw new ArgumentNullException(nameof(t));
12 | }
13 |
14 | return t;
15 | }
16 |
17 | public static bool OrdinalEquals(this string s1, string s2)
18 | {
19 | return string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase);
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/BotFramework/Utils/Utils.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | UiPath.ChatbotSamples.BotFramework.Utils
6 | UiPath.ChatbotSamples.BotFramework.Utils
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Chatbot-Samples
2 | Welcome to the UIPath Chatbot samples repository. Here you will find example of using Microsoft BotFramework to build a chatbot that connects to UiPath RPA.
3 |
--------------------------------------------------------------------------------
/User guide.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UiPath/Chatbot-Samples/6e4fb400456c725070e8d3691ba17827baaac7aa/User guide.pdf
--------------------------------------------------------------------------------