首先,
建立一個Score.cs來表達分數
public class Score
{
public Score(string user, int point, DateTime dateTime)
{
User = user;
Point = point;
DateTime = dateTime;
}
public string User { get; set; }
public int Point { get; set; }
public DateTime DateTime { get; set; }
public override string ToString()
{
StringBuilder sb =new StringBuilder();
sb.Append($"User:{User}, Score:{Point}, Date: {DateTime}");
return sb.ToString();
}
}
|
再來, 我們建立Repository 負責資料存取(為了簡化說明所以沒有特意去串DB,而是直接將分數的資料建出來)
建立Service 負責處理較複雜的商業邏輯來獲得最的高分數(這邊_scoRepository 宣告為Interface的目的是想提高程式的可測試性,將來做Unit test的時候我們就可以去Mock Repository)
public interface IRepository<T> where T:class
{
IEnumerable<T> GetAll();
}
public class ScoreRepository:IRepository<Score>
{
public IEnumerable<Score> GetAll()
{
var scores = new List<Score>();
scores.Add(new Score("Andy", 7, DateTime.Now));
scores.Add(new Score("Andy", 20, DateTime.Now.AddDays(-7)));
scores.Add(new Score("Andy", 13, DateTime.Now));
scores.Add(new Score("Bob", 6, DateTime.Now));
scores.Add(new Score("Bob", 19, DateTime.Now));
scores.Add(new Score("Calvin", 35, DateTime.Now.AddDays(-30)));
return scores;
}
}
|
建立Service 負責處理較複雜的商業邏輯來獲得最的高分數(這邊_scoRepository 宣告為Interface的目的是想提高程式的可測試性,將來做Unit test的時候我們就可以去Mock Repository)
public class ScoreService
{
private IRepository<Score> _scoRepository;
public ScoreService(IRepository<Score> scoRepository)
{
this._scoRepository = scoRepository;
}
public string GetHighScore()
{
return _scoRepository.GetAll().OrderByDescending(x => x.Point).FirstOrDefault()?.ToString();
}
public string GetHighScore(DateTime periodOfTime)
{
return _scoRepository.GetAll().Where(t => t.DateTime >= periodOfTime).OrderByDescending(x => x.Point).FirstOrDefault()?.ToString();
}
}
|
建立LUIS Dialog 處理對話
[LuisModel("Your APP ID", "Your secret key")]
[Serializable]
public class LUISDialog: LuisDialog<object>
{
// Implement None Intent
// Implement HighScore Intent
}
|
在 LUIS dialog中為None Intent 新增一個方法
[LuisIntent("")]
[LuisIntent("None")]
public async Task None(IDialogContext context, LuisResult result)
{
// Not a match -- Start a new Game
//context.Call(new NumberGuesserDialog(), null);
var reply = context.MakeMessage();
reply.Text = "Sorry, I didn't get it";
//Make you cortana speak
reply.Speak = "Sorry, I can't understand";
await context.PostAsync(reply);
context.Wait(this.MessageReceived);
}
|
實作回復最得高分的程式碼
private async Task ShowHighScores(IDialogContext context, int paramDays)
{
// Get Yesterday
var ParamYesterday = DateTime.Now.AddDays(paramDays);
ScoreService scoreService=new ScoreService(new ScoreRepository());
var scoreRecord = scoreService.GetHighScore(ParamYesterday);
// Create a reply message
var resultMessage = context.MakeMessage();
resultMessage.Type = "message";
resultMessage.Text = scoreRecord;
resultMessage.Speak = scoreRecord;
// Send Message
await context.PostAsync(resultMessage);
}
|
由於LUIS傳回來的Entity不見得會是數字
(例如:show me the high score for the past two days, 其中two 就是Entity)
所以我們須將英文數字轉成int, 讓我們等一下在做日期加減時能夠正常運算
(例如:show me the high score for the past two days, 其中two 就是Entity)
所以我們須將英文數字轉成int, 讓我們等一下在做日期加減時能夠正常運算
static int ParseEnglish(string number)
{
string[] words = number.ToLower().Split(new char[] {' ', '-', ','}, StringSplitOptions.RemoveEmptyEntries);
string[] ones = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
string[] teens =
{"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"};
string[] tens = {"ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
Dictionary<string, int> modifiers = new Dictionary<string, int>()
{
{"billion", 1000000000},
{"million", 1000000},
{"thousand", 1000},
{"hundred", 100}
};
if (number == "eleventy billion")
return int.MaxValue; // 110,000,000,000 is out of range for an int!
int result = 0;
int currentResult = 0;
int lastModifier = 1;
foreach (string word in words)
{
if (modifiers.ContainsKey(word))
{
lastModifier *= modifiers[word];
}
else
{
int n;
if (lastModifier > 1)
{
result += currentResult * lastModifier;
lastModifier = 1;
currentResult = 0;
}
if ((n = Array.IndexOf(ones, word) + 1) > 0)
{
currentResult += n;
}
else if ((n = Array.IndexOf(teens, word) + 1) > 0)
{
currentResult += n + 10;
}
else if ((n = Array.IndexOf(tens, word) + 1) > 0)
{
currentResult += n * 10;
}
else if (word != "and")
{
throw new ApplicationException("Unrecognized word: " + word);
}
}
}
return result + currentResult * lastModifier;
}
|
在 LUIS dialog中為HighScore Intent 新增一個方法
[LuisIntent("HighScores")]
public async Task GetHighScore(IDialogContext context, LuisResult result)
{
bool isIntentMatch = false;
foreach (var objIntent in result.Intents)
{
if (objIntent.Intent == "HighScores" && objIntent.Score >= .98f)
{
isIntentMatch = true;
}
}
if (!isIntentMatch)
{
var reply = context.MakeMessage();
reply.Type = "message";
reply.Text = "I don't understand";
reply.Speak = "I don't understand";
await context.PostAsync(reply);
context.Wait(this.MessageReceived);
return;
}
// Determine the days in the past
// to search for High Scores
int intDays = -1;
#region PeriodOfTime
EntityRecommendation PeriodOfTime;
if (result.TryFindEntity("PeriodOfTime", out PeriodOfTime))
{
switch (PeriodOfTime.Entity)
{
case "month":
intDays = -30;
break;
case "day":
intDays = -1;
break;
case "week":
intDays = -7;
break;
default:
intDays = -1;
break;
}
}
#endregion
#region Days
EntityRecommendation Days;
if (result.TryFindEntity("Days", out Days))
{
// Set Days
int intTempDays;
if (int.TryParse(Days.Entity, out intTempDays))
{
// A Number was passed
intDays = (Convert.ToInt32(intTempDays) * (-1));
}
else
{
// A number was not passed
// Call ParseEnglish Method
// From: http://stackoverflow.com/questions/11278081/convert-words-string-to-int
intTempDays = ParseEnglish(Days.Entity);
intDays = (Convert.ToInt32(intTempDays) * (-1));
}
// 30 days maximum
if (intDays > 30)
{
intDays = 30;
}
}
#endregion
await ShowHighScores(context, intDays);
context.Wait(this.MessageReceived);
}
|
最後在MessagesController.cs中使用LUISDialog
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
Conversation.SendAsync(activity, ()=> new LUISDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
|
做到這裡差不多可以收工了><
留言
張貼留言