Skip to content

Commit

Permalink
Merge pull request microsoft#1 from mohammed-moussa/newsie-sample
Browse files Browse the repository at this point in the history
Adding Newsie bot sample that utilize both Bing News Search and Bing Summerizer APIs
  • Loading branch information
mohammed-moussa authored Dec 27, 2016
2 parents 2fc58d7 + 462b954 commit 2cc612a
Show file tree
Hide file tree
Showing 44 changed files with 2,212 additions and 0 deletions.
36 changes: 36 additions & 0 deletions CSharp/intelligence-Newsie/App_Start/WebApiConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Web.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace Newsie
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Json settings
config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Formatting = Newtonsoft.Json.Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
};

// Web API configuration and services

// Web API routes
config.MapHttpAttributeRoutes();

config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new
{
id = RouteParameter.Optional
});
}
}
}
87 changes: 87 additions & 0 deletions CSharp/intelligence-Newsie/Controllers/MessagesController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using Autofac;
using Microsoft.Bot.Builder.Dialogs.Internals;
using Microsoft.Bot.Builder.Internals.Fibers;
using Microsoft.Bot.Connector;
using Newsie.Utilities;


namespace Newsie.Controllers
{
[BotAuthentication]
public class MessagesController : ApiController
{
private readonly ILifetimeScope scope;

public MessagesController(ILifetimeScope scope)
{
SetField.NotNull(out this.scope, nameof(scope), scope);
}

public async Task<HttpResponseMessage> Post([FromBody]Activity activity, CancellationToken token)
{
if (activity != null)
{
switch (activity.GetActivityType())
{
case ActivityTypes.Message:
using (var beginLifetimeScope = DialogModule.BeginLifetimeScope(this.scope, activity))
{
var postToBot = beginLifetimeScope.Resolve<IPostToBot>();
await postToBot.PostAsync(activity, token);
}

break;
default:
await this.HandleSystemMessage(activity);
break;
}
}

return new HttpResponseMessage(HttpStatusCode.Accepted);
}

private async Task<Activity> HandleSystemMessage(Activity activity)
{
if (activity.Type != null)
{
if (activity.Type == ActivityTypes.DeleteUserData)
{
}
else if (activity.Type == ActivityTypes.ConversationUpdate)
{
if (activity.MembersAdded.Any(m => m.Id == activity.Recipient.Id))
{
using (var beginLifetimeScope = DialogModule.BeginLifetimeScope(this.scope, activity))
using (var client = beginLifetimeScope.Resolve<IConnectorClient>())
{
var response = activity.CreateReply();

response.Text = string.Format(Strings.GreetWithHiMessage, Emojis.WideSmile, Emojis.News);
await client.Conversations.ReplyToActivityAsync(response);

response.Text = string.Format(Strings.StartGreetingMessage, Emojis.Rocket);
await client.Conversations.ReplyToActivityAsync(response);
}
}
}
else if (activity.Type == ActivityTypes.ContactRelationUpdate)
{
}
else if (activity.Type == ActivityTypes.Typing)
{
}
else if (activity.Type == ActivityTypes.Ping)
{
}
}

return null;
}
}
}
84 changes: 84 additions & 0 deletions CSharp/intelligence-Newsie/Dialogs/MainLuisDialog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Internals.Fibers;
using Microsoft.Bot.Builder.Luis;
using Microsoft.Bot.Builder.Luis.Models;
using Microsoft.Bot.Builder.Scorables;
using Microsoft.Bot.Connector;
using Newsie.Handlers;
using Newsie.Utilities;

namespace Newsie.Dialogs
{
/// <summary>
/// The top-level natural language dialog for sample.
/// </summary>
[Serializable]
[LuisModel("", "")]
internal sealed class MainLuisDialog : DispatchDialog
{
private readonly IHandlerFactory handlerFactory;
private readonly ILuisService luis;

public MainLuisDialog(ILuisService luis, IHandlerFactory handlerFactory)
{
SetField.NotNull(out this.handlerFactory, nameof(handlerFactory), handlerFactory);
SetField.NotNull(out this.luis, nameof(luis), luis);
}

/// <summary>
/// This method process the summarization requests from the client by matching regex pattern on message text
/// this request is sent when the user clicks on "Read Summary" button. A messages is submitted with value
/// contains summary keyword at the beginning and url of article to summarize.
/// Note: HeroCard is created in <see cref="Utilities.CardGenerators.NewsCardGenerator"/>
/// </summary>
/// <param name="context">Dialog context</param>
/// <param name="activity">Message activity containing the message information such as text</param>
/// <param name="result">The regex Match with the Regex pattern</param>
/// <returns>Async Task</returns>
[RegexPattern("^summary.*")]
[ScorableGroup(0)]
public async Task SummarizationRegexHandlerAsync(IDialogContext context, IMessageActivity activity, Match result)
{
await this.handlerFactory.CreateRegexHandler(NewsieStrings.SummarizeActionName).Respond(activity, result);
context.Wait(this.ActivityReceivedAsync);
}

[LuisIntent(NewsieStrings.GreetingIntentName)]
[ScorableGroup(1)]
public async Task GreetingIntentHandlerAsync(IDialogContext context, IMessageActivity activity, LuisResult result)
{
await this.handlerFactory.CreateIntentHandler(NewsieStrings.GreetingIntentName).Respond(activity, result);
context.Wait(this.ActivityReceivedAsync);
}

[LuisIntent(NewsieStrings.NewsIntentName)]
[ScorableGroup(1)]
public async Task FindNewsIntentHandlerAsync(IDialogContext context, IMessageActivity activity, LuisResult result)
{
await this.handlerFactory.CreateIntentHandler(NewsieStrings.NewsIntentName).Respond(activity, result);
context.Wait(this.ActivityReceivedAsync);
}

[LuisIntent("")]
[LuisIntent("None")]
[ScorableGroup(1)]
public async Task FallbackIntentHandlerAsync(IDialogContext context, IMessageActivity activity)
{
await context.PostAsync(string.Format(Strings.FallbackIntentMessage, Emojis.Flushed));
context.Wait(this.ActivityReceivedAsync);
}

protected override ILuisService MakeService(ILuisModel model)
{
return this.luis;
}

protected override Regex MakeRegex(string pattern)
{
return new Regex(pattern, RegexOptions.IgnoreCase);
}
}
}
18 changes: 18 additions & 0 deletions CSharp/intelligence-Newsie/Extensions/CategoriesExtentions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Newsie.Utilities;

namespace Newsie.Extensions
{
internal static class CategoriesExtentions
{
public static string GetDislaplyName(this Categories @enum)
{
switch (@enum)
{
case Categories.ScienceAndTechnology:
return "Science and Technology";
default:
return @enum.ToString();
}
}
}
}
1 change: 1 addition & 0 deletions CSharp/intelligence-Newsie/Global.asax
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%@ Application Codebehind="Global.asax.cs" Inherits="Newsie.WebApiApplication" Language="C#" %>
31 changes: 31 additions & 0 deletions CSharp/intelligence-Newsie/Global.asax.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Reflection;
using System.Web.Http;
using Autofac;
using Autofac.Integration.WebApi;
using Microsoft.Bot.Builder.Dialogs.Internals;
using Newsie.Modules;

namespace Newsie
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
var builder = new ContainerBuilder();

builder.RegisterModule(new DialogModule());
builder.RegisterModule(new MainModule());

var config = GlobalConfiguration.Configuration;

builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(config);

var container = builder.Build();

config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
}
50 changes: 50 additions & 0 deletions CSharp/intelligence-Newsie/Handlers/GreetingIntentHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Internals;
using Microsoft.Bot.Builder.Internals.Fibers;
using Microsoft.Bot.Builder.Luis.Models;
using Microsoft.Bot.Connector;
using Newsie.Extensions;
using Newsie.Utilities;
using Newsie.Utilities.CardGenerators;

namespace Newsie.Handlers
{
internal sealed class GreetingIntentHandler : IIntentHandler
{
private readonly IBotToUser botToUser;

public GreetingIntentHandler(IBotToUser botToUser)
{
SetField.NotNull(out this.botToUser, nameof(botToUser), botToUser);
}

public async Task Respond(IMessageActivity activity, LuisResult result)
{
await this.botToUser.PostAsync(string.Format(Strings.GreetOnDemand, Emojis.WideSmile, Emojis.News));

var reply = this.botToUser.MakeMessage();
var cards = new List<CardAction>();

foreach (var @enum in Enum.GetValues(typeof(Categories)).Cast<Categories>())
{
if (@enum == Categories.None)
{
continue;
}

var cardAction = new CardAction(ActionTypes.ImBack, @enum.GetDislaplyName(), value: @enum.GetDislaplyName());
cards.Add(cardAction);
}

reply.Attachments.Add(CardGenerator.GetHeroCard(cards));

await this.botToUser.PostAsync(reply);

await this.botToUser.PostAsync(string.Format(Strings.GreetOnDemandCont, Emojis.Wink));
}
}
}
25 changes: 25 additions & 0 deletions CSharp/intelligence-Newsie/Handlers/HandlerFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Autofac;
using Microsoft.Bot.Builder.Internals.Fibers;

namespace Newsie.Handlers
{
internal sealed class HandlerFactory : IHandlerFactory
{
private readonly IComponentContext scope;

public HandlerFactory(IComponentContext scope)
{
SetField.NotNull(out this.scope, nameof(scope), scope);
}

public IIntentHandler CreateIntentHandler(string key)
{
return this.scope.ResolveNamed<IIntentHandler>(key);
}

public IRegexHandler CreateRegexHandler(string key)
{
return this.scope.ResolveNamed<IRegexHandler>(key);
}
}
}
9 changes: 9 additions & 0 deletions CSharp/intelligence-Newsie/Handlers/IHandlerFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Newsie.Handlers
{
public interface IHandlerFactory
{
IIntentHandler CreateIntentHandler(string key);

IRegexHandler CreateRegexHandler(string key);
}
}
12 changes: 12 additions & 0 deletions CSharp/intelligence-Newsie/Handlers/IIntentHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Luis.Models;
using Microsoft.Bot.Connector;

namespace Newsie.Handlers
{
public interface IIntentHandler
{
Task Respond(IMessageActivity activity, LuisResult result);
}
}
12 changes: 12 additions & 0 deletions CSharp/intelligence-Newsie/Handlers/IRegexHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;

namespace Newsie.Handlers
{
public interface IRegexHandler
{
Task Respond(IMessageActivity activity, Match result);
}
}
Loading

0 comments on commit 2cc612a

Please sign in to comment.