瀑布式对话框中的C#bot V4文本提示
在得到QnA的回复并从用户那里得到反馈后,我需要添加一个问题“这有帮助吗?”。如果对此没有响应,并且如果下一个输入是一个全新的查询,则流应该从bot.cs重新启动 我尝试使用textprompt,但在emulator中测试时,bot不会在提示后等待用户输入 Bot.cs瀑布式对话框中的C#bot V4文本提示,c#,botframework,C#,Botframework,在得到QnA的回复并从用户那里得到反馈后,我需要添加一个问题“这有帮助吗?”。如果对此没有响应,并且如果下一个输入是一个全新的查询,则流应该从bot.cs重新启动 我尝试使用textprompt,但在emulator中测试时,bot不会在提示后等待用户输入 Bot.cs public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(Cancellation
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
var activity = turnContext.Activity;
var dc = await _dialogs.CreateContextAsync(turnContext);
if (turnContext == null)
{
throw new ArgumentNullException(nameof(turnContext));
}
if (turnContext.Activity.Type == ActivityTypes.Message)
{
if (turnContext.Activity.Text != null)
{
var luisResults = await _services.LuisServices[LuisConfiguration].RecognizeAsync(dc.Context, cancellationToken);
var luisProperties = LuisEntities.FromLuisResults(luisResults);
await _luisEntitiesAccessor.SetAsync(turnContext, luisProperties);
var topScoringIntent = luisResults?.GetTopScoringIntent();
var topIntent = topScoringIntent.Value.intent;
switch (topIntent)
{
case NoneIntent:
await dc.BeginDialogAsync(QnADialog.Name);
break;
case GreetingsIntent:
await dc.BeginDialogAsync(QnAGreetingsDialog.Name);
break;
case CredentialsIntent:
await dc.BeginDialogAsync(CredentialsDialog.Name);
break;
case ContactusIntent:
await dc.BeginDialogAsync(FeedbackDialog.Name);
break;
case FeedbackIntent:
await dc.BeginDialogAsync(FeedbackDialog.Name);
break;
default:
await dc.Context.SendActivityAsync("I didn't understand what you just said to me.");
break;
}
}
else if (string.IsNullOrEmpty(turnContext.Activity.Text))
{
await HandleSubmitActionAsync(turnContext, userProfile);
}
}
else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
{
if (turnContext.Activity.MembersAdded != null)
{
await SendWelcomeMessageAsync(turnContext);
}
}
else if (turnContext.Activity.Type == ActivityTypes.Event)
{
await SendWelcomeMessageAsync(turnContext);
}
else
{
await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected");
}
// Save the dialog state into the conversation state.
await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
}
QnADialog.cs-我希望提示符在其中工作的对话框
public class QnADialog : ComponentDialog
{
public const int QnaNumResults = 1;
public const double QnaConfidenceThreshold = 0.5;
public const string QnaConfiguration = "QnAFaqSubscriptionKey";
private const string QnAFeedbackDialog = "qnaDialog";
public const string Name = "QnA";
public const string TextPrompt = "textPrompt";
private readonly BotServices _services;
private readonly IStatePropertyAccessor<UserProfile> _userProfileAccessor;
Action<string, string, bool, int, int> updateQna;
private int InvalidMessageCount = 0;
string Query = string.Empty;
List<int> qnaIdStorage;
UserProfile userProfile = new UserProfile();
public QnADialog(Action<string, string, bool, int, int> updateQna, bool isCollection, List<int> rotationTemStorage, BotServices services, UserProfile _userProfile, IStatePropertyAccessor<UserProfile> userProfileAccessor, int invalidMessageCount = 0, string dialogId = null)
: base(Name)
{
_services = services ?? throw new ArgumentNullException(nameof(services));
_userProfileAccessor = userProfileAccessor ?? throw new ArgumentNullException(nameof(userProfileAccessor));
userProfile = _userProfile;
this.updateQna = updateQna;
this.InvalidMessageCount = invalidMessageCount;
qnaIdStorage = rotationTemStorage;
var waterfallSteps = new WaterfallStep[]
{
BeginStepAsync,
FetchFAQResultStepAsync,
FeedbackStepAsync,
FeedbackResponseStepAsync,
};
AddDialog(new WaterfallDialog(QnAFeedbackDialog, waterfallSteps));
AddDialog(new TextPrompt("userFeed"));
}
public async Task<DialogTurnResult> BeginStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
{
var messageToForward = stepContext.Context.Activity;
UserProfile.previousQuestion = messageToForward.Text;
string[] supportList = { "HELP", "FEEDBACK", "SUPPORT", "ESCALATE", "AGENT" };
if (messageToForward.Text == null || messageToForward.Text.ToLower() == "no")
{
await stepContext.Context.SendActivityAsync("Sorry, I was not able to help you.");
return await stepContext.EndDialogAsync();
}
else if (messageToForward.Text == null || supportList.Any(x => x == messageToForward.Text.ToUpper()))
{
await stepContext.Context.SendActivityAsync("Please reach out to... ");
return await stepContext.EndDialogAsync();
}
else
{
return await stepContext.NextAsync();
}
}
private async Task<DialogTurnResult> FetchFAQResultStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var message = stepContext.Context.Activity;
var qnaResult = await FaqQnaMakerService.GetQnaResult(_services, stepContext, this.Query);
var qnaIdColl = GetQnaIdColl(this.Query, qnaResult);
int qnaPreviousId = 0;
int qnaNewId = 0;
if (qnaIdColl != null && qnaIdColl.Count > 1)
{
qnaIdColl = qnaIdColl.Distinct().OrderBy(x => x).ToList();
//Compare the previous Qnaid collection and existing collection , if it is matching produce the result.
var matchItem = qnaIdColl.Intersect(qnaIdStorage);
if (matchItem.Count() == 0)
{
//If there is no previous collection Qna id then take the first item from the existing Qna collection
qnaNewId = qnaIdColl.FirstOrDefault();
}
else
{
//If there any previous Qnaid that contain in the existing collection then pick the next value and generate a new qna result.
qnaPreviousId = matchItem.FirstOrDefault();
qnaNewId = GetNextRotationKey(qnaIdColl, qnaPreviousId);
}
//Create a new response based on selected new qna id.
qnaResult = new[] { qnaResult.Where(x => x.Id == qnaNewId).Single() };
}
if (qnaResult.First().Answer.Length > 0)
{
if (qnaResult.First().Score > 0)
{
updateQna(this.Query, qnaResult.First().Answer, false, qnaPreviousId, qnaNewId);
InvalidMessageCount = 0;
var QuestionCollection = TextFormatter.FormattedQuestionColl(qnaResult.First().Answer);
if (QuestionCollection != null)
{
userProfile.IsAswerCollection = true;
updateQna(this.Query, qnaResult.First().Answer, true, qnaPreviousId, qnaNewId);
var replyMessage = stepContext.Context.Activity.CreateReply();
replyMessage.Attachments = new List<Attachment>() { AllAdaptiveCard.QnaAttachment(new Tuple<string, string[]>(QuestionCollection.Item2, QuestionCollection.Item3)) };
if (!string.IsNullOrEmpty(QuestionCollection.Item1))
{
await stepContext.Context.SendActivityAsync(QuestionCollection.Item1);
}
await stepContext.Context.SendActivityAsync(replyMessage);
return await stepContext.EndDialogAsync();
}
else
{
await stepContext.Context.SendActivityAsync(qnaResult.First().Answer);
}
}
else
{
InvalidMessageCount++;
return await stepContext.ContinueDialogAsync();
}
}
return await stepContext.NextAsync();
}
private async Task<DialogTurnResult> FeedbackStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
return await stepContext.PromptAsync("userFeed", new PromptOptions
{
Prompt = stepContext.Context.Activity.CreateReply("Did this help?")
});
}
private async Task<DialogTurnResult> FeedbackResponseStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var message = stepContext.Context.Activity;
var mesgActivity = message as Activity;
string var = userProfile.qnaData;
var qnaResultModel = new { InvalidMessageCount = 0, originalQueryText = string.Empty };
NeedMoreInformation needmoreInfo = NeedMoreInformation.NotSelected;
if (message != null && message.Text == null && message.Value != null)
{
dynamic value = mesgActivity.Value.ToString();
UserReply response = JsonConvert.DeserializeObject<UserReply>(value);
if (!string.IsNullOrEmpty(response.Reply))
{
mesgActivity.Text = response.Reply;
}
}
//This if condition work only the user reply back to the question "Did this help?"
if (userProfile.needMoreInformation == true && message?.Text?.ToLower() != "yes" && message?.Text?.ToLower() != "no")
{
//The response message pass to LUIS service to understand the intention of the conversation is “yes” or “no”
bool? moreInformationYes = await LUISService.GetResultAESChatBotYesNo(message?.Text);
if (moreInformationYes != null && moreInformationYes == true)
{
//Once the LUIS understand the conversation change the original message to yes.
message.Text = "yes";
//needmoreInfo = NeedMoreInformation.Yes;
}
else if (moreInformationYes != null && moreInformationYes == false)
{
////Once the LUIS understand the conversation change the original message to no.
message.Text = "no";
needmoreInfo = NeedMoreInformation.No;
}
else
{
needmoreInfo = NeedMoreInformation.None;
}
}
if (userProfile.needMoreInformation == true && message?.Text?.ToLower() == "yes")
{
userProfile.qnaInvalidMessageCount = 0;
userProfile.needMoreInformation = false;
dynamic value = stepContext.Context.Activity.Value;
var output = JsonConvert.DeserializeObject<UserReply>(stepContext.Context.Activity.Value.ToString());
if (userProfile.feedbackCard == false)
{
var replyMessage = stepContext.Context.Activity.CreateReply();
replyMessage.Attachments = new List<Attachment>() { AllAdaptiveCard.FeedbackAdapativecard() };
await stepContext.Context.SendActivityAsync(replyMessage);
}
if (output.Reply != "yes")
{
await AdaptiveCardReplyAsync(_services, stepContext, userProfile);
}
}
else if (userProfile.needMoreInformation == true && message?.Text?.ToLower() == "no")
{
userProfile.qnaInvalidMessageCount = 0;
userProfile.needMoreInformation = false;
dynamic value = stepContext.Context.Activity.Value;
if (value.Type == "GetMoreContent")
{
await AdaptiveCardGetMoreContent(_services, stepContext, userProfile);
}
else if (value.Type == "GetHelpSubmit")
{
await AdaptiveCardReplyAsync(_services, stepContext, userProfile);
}
else if (userProfile.getMoreContentCard == false)
{
var replyMessage = stepContext.Context.Activity.CreateReply();
replyMessage.Attachments = new List<Attachment>() { AllAdaptiveCard.GetMoreContent() };
await stepContext.Context.SendActivityAsync(replyMessage);
}
// context.Wait(AdaptiveCardGetMoreContent);
}
else
{
await stepContext.BeginDialogAsync(nameof(Bot.cs));
}
return await stepContext.EndDialogAsync();
}
}
公共类QnADialog:ComponentDialog
{
公共const int QnaNumResults=1;
public const double QnaConfidenceThreshold=0.5;
public const string QnaConfiguration=“QnAFaqSubscriptionKey”;
私有常量字符串QnAFeedbackDialog=“qnaDialog”;
public const string Name=“QnA”;
public const string TextPrompt=“TextPrompt”;
专用只读BotServices\u服务;
专用只读IStatePropertyAccessor\u userProfileAccessor;
行动更新qna;
private int InvalidMessageCount=0;
string Query=string.Empty;
列出qnaIdStorage;
UserProfile UserProfile=新的UserProfile();
公共QnADialog(操作更新QNA、bool isCollection、列表轮换temStorage、BotServices服务、UserProfile\u UserProfile、IStatePropertyAccessor userProfileAccessor、int invalidMessageCount=0、string dialogId=null)
:base(名称)
{
_服务=服务??抛出新的ArgumentNullException(服务的名称);
_userProfileAccessor=userProfileAccessor??抛出新的ArgumentNullException(nameof(userProfileAccessor));
userProfile=\u userProfile;
this.updateQna=updateQna;
this.InvalidMessageCount=InvalidMessageCount;
qnaIdStorage=旋转项存储;
var waterwallsteps=新的waterwallstep[]
{
开始同步,
FetchFAQResultStepAsync,
反馈同步,
反馈响应EstePasync,
};
AddDialog(新建WaterWallDialog(QnAFeedbackDialog,WaterWallSteps));
AddDialog(新文本提示(“用户提要”);
}
公共异步任务BeginStepAsync(WaterCallStepContext stepContext,CancellationToken CancellationToken=default(CancellationToken))
{
var messageToForward=stepContext.Context.Activity;
UserProfile.previousQuestion=messageToForward.Text;
string[]supportList={“帮助”、“反馈”、“支持”、“上报”、“代理”};
if(messageToForward.Text==null | | messageToForward.Text.ToLower()=“否”)
{
wait stepContext.Context.SendActivityAsync(“对不起,我无法帮助您。”);
返回wait-stepContext.EndDialogAsync();
}
else if(messageToForward.Text==null | | supportList.Any(x=>x==messageToForward.Text.ToUpper())
{
等待stepContext.Context.SendActivityAsync(“请联系…”);
返回wait-stepContext.EndDialogAsync();
}
其他的
{
返回wait-stepContext.NextAsync();
}
}
专用异步任务FetchFAQResultStepAsync(WaterCallStepContext stepContext,CancellationToken CancellationToken)
{
var message=stepContext.Context.Activity;
var qnaResult=wait faqnamakerservice.GetQnaResult(_services,stepContext,this.Query);
var qnaIdColl=GetQnaIdColl(this.Query,qnaResult);
int qnaPreviousId=0;
int qnaNewId=0;
如果(qnaIdColl!=null&&qnaIdColl.Count>1)
{
qnaIdColl=qnaIdColl.Distinct().OrderBy(x=>x.ToList();
//将以前的Qnaid集合与现有集合进行比较,如果匹配,则生成结果。
var matchItem=qnaIdColl.Intersect(qnaIdStorage);
if(matchItem.Count()==0)
{
//如果没有以前的Qna集合id,则从现有Qna集合中获取第一项
qnaNewId=qnaIdColl.FirstOrDefault();
}
其他的
{
//如果现有集合中包含任何以前的Qnaid,则选择下一个值并生成新的qna结果。
qnaPreviousId=matchItem.FirstOrDefault();
qnaNewId=GetNextRotationKey(qnaIdColl、qnaPreviousId);
}
//基于选定的新qna id创建新响应。
qnaResult=new[]{qnaResult.Where(x=>x.Id==qnaNewId).Single()};
}
如果(qnaResult.First().Answer.Length>0)
{
如果(qnaResult.First().Score>0)
{
updateQna(this.Query,qnaResult.First().Answer,false,qnaPreviousId,qnaNewId);
InvalidMessageCount=0;
var QuestionCollection=TextFormatter.FormattedQuestionColl(qnaResult.First().Answer);
if(QuestionCollection!=null)
{
userProfile.IsAswerCollection=true;
updateQna(this.Query,qnaResult.First().Answer,true,qnaPreviousId,qnaNewId);
var replyMessage=stepContext.Context.Activity.CreateReply();
replyMessage.Attachments=new List(){AllAdaptiveCard.QnaAttachment(新元组(QuestionCollection.Item2,QuestionCollection.Item3));
如果(!string.IsNullOrEmpty(QuestionCollection.Item1))
{
等待stepContext.Context.SendActivityAsync(QuestionCollection.Item1);
}
等待stepContext.Context.SendActivityAsync(replyMessage);
返回wait-stepContext.EndDialogAsync();
}
其他的
{
等待stepContext.Context.SendActivityAsync(qnaResult.First().Answer);
}
var feedback = ((Activity)context.Activity).CreateReply("Did you find what you need?");
feedback.SuggestedActions = new SuggestedActions()
{
Actions = new List<CardAction>()
{
new CardAction(){ Title = "Yes", Type=ActionTypes.PostBack, Value=$"yes-positive-feedback" },
new CardAction(){ Title = "No", Type=ActionTypes.PostBack, Value=$"no-negative-feedback" }
}
};
await context.PostAsync(feedback);
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using System.Threading;
using System.Threading.Tasks;
namespace ChatBot.VirtualAssistant.Dialogs
{
public class RateAnswerDialog : ComponentDialog
{
public RateAnswerDialog()
: base(nameof(RateAnswerDialog))
{
InitialDialogId = nameof(RateAnswerDialog);
var askToRate = new WaterfallStep[]
{
AskRating,
FinishDialog
};
AddDialog(new TextPrompt(nameof(TextPrompt)));
AddDialog(new WaterfallDialog(InitialDialogId, askToRate));
}
private async Task<DialogTurnResult> AskRating(WaterfallStepContext sc, CancellationToken cancellationToken)
{
PromptOptions promptOptions = new PromptOptions
{
Prompt = MessageFactory.Text("Was this helpful?")
};
return await sc.PromptAsync(nameof(TextPrompt), promptOptions);
}
private async Task<DialogTurnResult> FinishDialog(WaterfallStepContext sc, CancellationToken cancellationToken)
{
return await sc.EndDialogAsync(sc);
}
protected override async Task<DialogTurnResult> EndComponentAsync(DialogContext outerDc, object context, CancellationToken cancellationToken)
{
var waterfallContext = (WaterfallStepContext)context;
var userResponse = ((string)waterfallContext.Result).ToLowerInvariant();
if (userResponse == "yes")
{
await waterfallContext.Context.SendActivityAsync("Thank you for your feedback");
}
else if (userResponse == "no")
{
await waterfallContext.Context.SendActivityAsync("Sorry I couldn't help you");
}
else
{
await waterfallContext.Context.SendActivityAsync("The valid answers are 'yes' or 'no'");
// TODO reprompt if required
}
return await outerDc.EndDialogAsync();
}
}
}