Skip to content

Commit

Permalink
CustomActions
Browse files Browse the repository at this point in the history
  • Loading branch information
João Quitério committed Jul 13, 2020
1 parent 3785fca commit c3ef8f4
Show file tree
Hide file tree
Showing 15 changed files with 633 additions and 7 deletions.
62 changes: 62 additions & 0 deletions runtime/dotnet/customaction/Action/CallAzureFunction.cs
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using AdaptiveExpressions;
using AdaptiveExpressions.Properties;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.AI.QnA;
using Microsoft.Bot.Builder.AI.QnA.Dialogs;
using Microsoft.Bot.Builder.AI.QnA.Utils;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Actions;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Input;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Microsoft.BotFramework.Composer.CustomAction
{
/// <summary>
/// Custom command which takes takes 2 data bound arguments (arg1 and arg2) and multiplies them returning that as a databound result.
/// </summary>
public class CallAzureFunction : HttpRequest
{
new public const string Kind = "CallAzureFunction";

[JsonConstructor]
public CallAzureFunction([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) : base(callerPath, callerLine)
{
}

public CallAzureFunction(HttpMethod method, string url, Dictionary<string, StringExpression> headers = null, object body = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) : base(method, url, headers, body, callerPath, callerLine)
{
}

public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default)
{
if (Headers == null)
{
Headers = new Dictionary<string, StringExpression>();
}
if (!Headers.ContainsKey("Authorization"))
{
Headers.Add("Authorization", new StringExpression($"Bearer {await GetAzureTokenAsync(new Uri(this.Url.GetValue(dc)))}"));
}

return await base.BeginDialogAsync(dc, options, cancellationToken);
}

private async Task<string> GetAzureTokenAsync(Uri uri)
{
AzureServiceTokenProvider azureTokenProvider = new AzureServiceTokenProvider();
string tokenPayload = await azureTokenProvider.GetAccessTokenAsync($"{uri.Scheme}://{uri.Host}");
return tokenPayload;
}
}
}
58 changes: 58 additions & 0 deletions runtime/dotnet/customaction/Action/ConnectToChitChatKB.cs
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using AdaptiveExpressions.Properties;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.AI.QnA;
using Microsoft.Bot.Builder.AI.QnA.Dialogs;
using Microsoft.Bot.Builder.AI.QnA.Utils;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Input;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;

namespace Microsoft.BotFramework.Composer.CustomAction
{
/// <summary>
/// Custom command which takes takes 2 data bound arguments (arg1 and arg2) and multiplies them returning that as a databound result.
/// </summary>
public class ConnectToChitChatKB : QnAMakerDialog
{
new public const string Kind = "ConnectToChitChatKB";

[JsonConstructor]
public ConnectToChitChatKB([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) : base(sourceFilePath, sourceLineNumber)
{
}

public ConnectToChitChatKB(string knowledgeBaseId, string endpointKey, string hostName, Activity noAnswer = null, float threshold = 0.3F, string activeLearningCardTitle = "Did you mean:", string cardNoMatchText = "None of the above.", int top = 3, Activity cardNoMatchResponse = null, Metadata[] strictFilters = null, HttpClient httpClient = null, [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) : base(knowledgeBaseId, endpointKey, hostName, noAnswer, threshold, activeLearningCardTitle, cardNoMatchText, top, cardNoMatchResponse, strictFilters, httpClient, sourceFilePath, sourceLineNumber)
{
}

protected override async Task<IQnAMakerClient> GetQnAMakerClientAsync(DialogContext dc)
{
var qnaClient = dc.Context.TurnState.Get<IQnAMakerClient>();
if (qnaClient != null)
{
// return mock client
return qnaClient;
}

var configuration = dc.Context.TurnState.Get<IConfiguration>();
var endpoint = new QnAMakerEndpoint
{
EndpointKey = configuration.GetValue<string>("qna:endpointkey"),
Host = configuration.GetValue<string>("qna:hostname"),
KnowledgeBaseId = configuration.GetValue<string>("qna:chitchat:kbId")
};
var options = await GetQnAMakerOptionsAsync(dc).ConfigureAwait(false);
return new QnAMaker(endpoint, options, HttpClient, this.TelemetryClient, this.LogPersonalInformation.GetValue(dc.State));
}

}
}
43 changes: 43 additions & 0 deletions runtime/dotnet/customaction/Action/EndCall.cs
@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using AdaptiveExpressions.Properties;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.AI.QnA;
using Microsoft.Bot.Builder.AI.QnA.Dialogs;
using Microsoft.Bot.Builder.AI.QnA.Utils;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Input;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;

namespace Microsoft.BotFramework.Composer.CustomAction
{
/// <summary>
/// Custom command which takes takes 2 data bound arguments (arg1 and arg2) and multiplies them returning that as a databound result.
/// </summary>
public class EndCall : Dialog
{
new public const string Kind = "EndCall";

[JsonConstructor]
public EndCall([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
{
}

[JsonProperty("reason")]
public StringExpression Reason { get; set; }

public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default)
{
await dc.Context.SendActivityAsync($"[TODO] - In the future I will end the current call with reason: {Reason.GetValue(dc.State)}");

return await dc.EndDialogAsync(result: true, cancellationToken: cancellationToken);
}
}
}
45 changes: 45 additions & 0 deletions runtime/dotnet/customaction/Action/SetSpeechEndpoint.cs
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using AdaptiveExpressions.Properties;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.AI.QnA;
using Microsoft.Bot.Builder.AI.QnA.Dialogs;
using Microsoft.Bot.Builder.AI.QnA.Utils;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Input;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;

namespace Microsoft.BotFramework.Composer.CustomAction
{
/// <summary>
/// Custom command which takes takes 2 data bound arguments (arg1 and arg2) and multiplies them returning that as a databound result.
/// </summary>
public class SetSpeechEndpoint : Dialog
{
new public const string Kind = "SetSpeechEndpoint";

[JsonConstructor]
public SetSpeechEndpoint([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
{
}

[JsonProperty("endpoint")]
public StringExpression Endpoint { get; set; }

public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default)
{
await dc.Context.SendActivityAsync($"[TODO] - In the future I set the speech endpoint to: {Endpoint.GetValue(dc.State)}. I'm setting converstation.speechEndpoint variable");

dc.State.SetValue("conversation.speechEndpoint", Endpoint.GetValue(dc.State));

return await dc.EndDialogAsync(result: true, cancellationToken: cancellationToken);
}
}
}
45 changes: 45 additions & 0 deletions runtime/dotnet/customaction/Action/SetTTSCaching.cs
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using AdaptiveExpressions.Properties;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.AI.QnA;
using Microsoft.Bot.Builder.AI.QnA.Dialogs;
using Microsoft.Bot.Builder.AI.QnA.Utils;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Input;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;

namespace Microsoft.BotFramework.Composer.CustomAction
{
/// <summary>
/// Custom command which takes takes 2 data bound arguments (arg1 and arg2) and multiplies them returning that as a databound result.
/// </summary>
public class SetTTSCaching : Dialog
{
new public const string Kind = "SetTTSCaching";

[JsonConstructor]
public SetTTSCaching([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
{
}

[JsonProperty("enableCache")]
public bool IsEnabled { get; set; }

public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default)
{
await dc.Context.SendActivityAsync($"[TODO] - In the future I'm goint to toggle the TTS cache. The cache should be set to: {IsEnabled}. I'm setting converstation.ttsCache variable");

dc.State.SetValue("conversation.ttsCache", IsEnabled);

return await dc.EndDialogAsync(result: true, cancellationToken: cancellationToken);
}
}
}
46 changes: 46 additions & 0 deletions runtime/dotnet/customaction/Action/TransferCall.cs
@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using AdaptiveExpressions.Properties;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.AI.QnA;
using Microsoft.Bot.Builder.AI.QnA.Dialogs;
using Microsoft.Bot.Builder.AI.QnA.Utils;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Input;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;

namespace Microsoft.BotFramework.Composer.CustomAction
{
/// <summary>
/// Custom command which takes takes 2 data bound arguments (arg1 and arg2) and multiplies them returning that as a databound result.
/// </summary>
public class TransferCall : Dialog
{
new public const string Kind = "TransferCall";

[JsonConstructor]
public TransferCall([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
{
}

[JsonProperty("reason")]
public StringExpression Reason { get; set; }

[JsonProperty("phoneNumber")]
public StringExpression PhoneNumber { get; set; }

public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default)
{
await dc.Context.SendActivityAsync($"[TODO] - In the future I will transfer the call to {PhoneNumber.GetValue(dc.State)} with the handover reason: {Reason.GetValue(dc.State)}");

return await dc.EndDialogAsync(result: true, cancellationToken: cancellationToken);
}
}
}
2 changes: 1 addition & 1 deletion runtime/dotnet/customaction/CustomAction.sln
Expand Up @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30011.22
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "customaction", "Microsoft.BotFramework.Composer.CustomAction.csproj", "{2B5E9A3A-880D-4DEC-B76E-2AFDA3F05597}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "customaction", "customaction.csproj", "{2B5E9A3A-880D-4DEC-B76E-2AFDA3F05597}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
12 changes: 9 additions & 3 deletions runtime/dotnet/customaction/CustomActionComponentRegistration.cs
@@ -1,4 +1,4 @@
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs.Debugging;
using Microsoft.Bot.Builder.Dialogs.Declarative;
using Microsoft.Bot.Builder.Dialogs.Declarative.Resources;
Expand All @@ -12,12 +12,18 @@ public class CustomActionComponentRegistration : ComponentRegistration, ICompone
public IEnumerable<DeclarativeType> GetDeclarativeTypes(ResourceExplorer resourceExplorer)
{
// Actions
yield return new DeclarativeType<MultiplyDialog>(MultiplyDialog.Kind);
//yield return new DeclarativeType<MultiplyDialog>(MultiplyDialog.Kind);
yield return new DeclarativeType<CallAzureFunction>(CallAzureFunction.Kind);
yield return new DeclarativeType<ConnectToChitChatKB>(ConnectToChitChatKB.Kind);
yield return new DeclarativeType<EndCall>(EndCall.Kind);
yield return new DeclarativeType<SetSpeechEndpoint>(SetSpeechEndpoint.Kind);
yield return new DeclarativeType<SetTTSCaching>(SetTTSCaching.Kind);
yield return new DeclarativeType<TransferCall>(TransferCall.Kind);
}

public IEnumerable<JsonConverter> GetConverters(ResourceExplorer resourceExplorer, SourceContext sourceContext)
{
yield break;
}
}
}
}
Expand Up @@ -6,12 +6,18 @@
</PropertyGroup>

<ItemGroup>
<Folder Include="Action\" />
<Folder Include="Schemas\" />
<None Remove="Schemas\MultiplyDialog.schema" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Bot.Builder.Dialogs.Adaptive" Version="4.9.3" />
<Folder Include="Schema\" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.5.0" />
<PackageReference Include="Microsoft.Bot.Builder" Version="4.9.1" />
<PackageReference Include="Microsoft.Bot.Builder.AI.QnA" Version="4.9.1" />
<PackageReference Include="Microsoft.Bot.Builder.Dialogs.Adaptive" Version="4.9.1" />
</ItemGroup>

</Project>

0 comments on commit c3ef8f4

Please sign in to comment.