繁体   English   中英

LUIS Bot框架不会从外部调用调用Intent

[英]LUIS Bot framework won't call Intent from external call

我为我的BOT实现了外部登录。 当外部站点调用Bot CallBack方法时,我需要在PrivateConversationData设置令牌和用户名,然后使用"Welcome back [username]!"等消息继续聊天"Welcome back [username]!"

要显示此消息,我发送一个MessageActivity但此活动从未连接到我的聊天,并且不会触发相应的[LuisIntent("UserIsAuthenticated")]

登录流程之外的其他意图按预期工作。

这是回调方法:

public class OAuthCallbackController : ApiController
{
    [HttpGet]
    [Route("api/OAuthCallback")]
    public async Task OAuthCallback([FromUri] string userId, [FromUri] string botId, [FromUri] string conversationId,
        [FromUri] string channelId, [FromUri] string serviceUrl, [FromUri] string locale,
        [FromUri] CancellationToken cancellationToken, [FromUri] string accessToken, [FromUri] string username)
    {
        var resumptionCookie = new ResumptionCookie(TokenDecoder(userId), TokenDecoder(botId),
            TokenDecoder(conversationId), channelId, TokenDecoder(serviceUrl), locale);

            var container = WebApiApplication.FindContainer();

            var message = resumptionCookie.GetMessage();
            message.Text = "UserIsAuthenticated";

            using (var scope = DialogModule.BeginLifetimeScope(container, message))
            {
                var botData = scope.Resolve<IBotData>();
                await botData.LoadAsync(cancellationToken);

                botData.PrivateConversationData.SetValue("accessToken", accessToken);
                botData.PrivateConversationData.SetValue("username", username);

                ResumptionCookie pending;
                if (botData.PrivateConversationData.TryGetValue("persistedCookie", out pending))
                {
                    botData.PrivateConversationData.RemoveValue("persistedCookie");
                    await botData.FlushAsync(cancellationToken);
                }

                var stack = scope.Resolve<IDialogStack>();
                var child = scope.Resolve<MainDialog>(TypedParameter.From(message));
                var interruption = child.Void<object, IMessageActivity>();

                try
                {
                    stack.Call(interruption, null);

                    await stack.PollAsync(cancellationToken);
                }
                finally
                {
                    await botData.FlushAsync(cancellationToken);
                }
            }
        }
    }   

    public static string TokenDecoder(string token)
    {
        return Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(token));
    }
}

这是控制器:

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 scope = DialogModule.BeginLifetimeScope(this.scope, activity))
                    {
                        var postToBot = scope.Resolve<IPostToBot>();
                        await postToBot.PostAsync(activity, token);
                    }
                    break;
            }
        }

        return new HttpResponseMessage(HttpStatusCode.Accepted);
    }
}

这是我注册组件的方式:

protected override void Load(ContainerBuilder builder)
    {
        base.Load(builder);

        builder.Register(
            c => new LuisModelAttribute("myId", "SubscriptionKey"))
            .AsSelf()
            .AsImplementedInterfaces()
            .SingleInstance();

        builder.RegisterType<MainDialog>().AsSelf().As<IDialog<object>>().InstancePerDependency();

        builder.RegisterType<LuisService>()
            .Keyed<ILuisService>(FiberModule.Key_DoNotSerialize)
            .AsImplementedInterfaces()
            .SingleInstance();
    }

这是对话框:

[Serializable]
public sealed class MainDialog : LuisDialog<object>
{
    public static readonly string AuthTokenKey = "TestToken";
    public readonly ResumptionCookie ResumptionCookie;
    public static readonly Uri CloudocOauthCallback = new Uri("http://localhost:3980/api/OAuthCallback");

    public MainDialog(IMessageActivity activity, ILuisService luis)
        : base(luis)
    {
        ResumptionCookie = new ResumptionCookie(activity);
    }

    [LuisIntent("")]
    public async Task None(IDialogContext context, LuisResult result)
    {
        await context.PostAsync("Sorry cannot understand!");
        context.Wait(MessageReceived);
    }

    [LuisIntent("UserAuthenticated")]
    public async Task UserAuthenticated(IDialogContext context, LuisResult result)
    {
        string username;
        context.PrivateConversationData.TryGetValue("username", out username);

        await context.PostAsync($"Welcome back {username}!");
        context.Wait(MessageReceived);
    }

    [LuisIntent("Login")]
    private async Task LogIn(IDialogContext context, LuisResult result)
    {
        string token;
        if (!context.PrivateConversationData.TryGetValue(AuthTokenKey, out token))
        {
            context.PrivateConversationData.SetValue("persistedCookie", ResumptionCookie);

            var loginUrl = CloudocHelpers.GetLoginURL(ResumptionCookie, OauthCallback.ToString());

            var reply = context.MakeMessage();

            var cardButtons = new List<CardAction>();
            var plButton = new CardAction
            {
                Value = loginUrl,
                Type = ActionTypes.Signin,
                Title = "Connetti a Cloudoc"
            };
            cardButtons.Add(plButton);
            var plCard = new SigninCard("Connect", cardButtons);

            reply.Attachments = new List<Attachment>
            {
                plCard.ToAttachment()
            };

            await context.PostAsync(reply);
            context.Wait(MessageReceived);
        }
        else
        {
            context.Done(token);
        }
    }
}

我想念的是什么?

更新

还在回调方法中尝试使用ResumeAsync

var container = WebApiApplication.FindContainer();

var message = resumptionCookie.GetMessage();
message.Text = "UserIsAuthenticated";

using (var scope = DialogModule.BeginLifetimeScope(container, message))
{
     var botData = scope.Resolve<IBotData>();
     await botData.LoadAsync(cancellationToken);

     botData.PrivateConversationData.SetValue("accessToken", accessToken);
     botData.PrivateConversationData.SetValue("username", username);

     ResumptionCookie pending;
     if (botData.PrivateConversationData.TryGetValue("persistedCookie", out pending))
     {
         botData.PrivateConversationData.RemoveValue("persistedCookie");
         await botData.FlushAsync(cancellationToken);
     }

     await Conversation.ResumeAsync(resumptionCookie, message, cancellationToken);
 }

但它给我错误Operation is not valid due to the current state of the object.

更新2

按照Ezequiel的想法,我改变了我的代码:

    [HttpGet]
    [Route("api/OAuthCallback")]
    public async Task OAuthCallback(string state, [FromUri] string accessToken, [FromUri] string username)
    {
        var resumptionCookie = ResumptionCookie.GZipDeserialize(state);
        var message = resumptionCookie.GetMessage();
        message.Text = "UserIsAuthenticated";

        await Conversation.ResumeAsync(resumptionCookie, message);
    }

resumptionCookie似乎没问题:

在此输入图像描述

await Conversation.ResumeAsync(resumptionCookie, message); 继续给我错误Operation is not valid due to the current state of the object.

您需要恢复与机器人的对话,这就是消息可能无法到达的原因。

不要使用对话框堆栈,请尝试使用

await Conversation.ResumeAsync(resumptionCookie, message);

根据您的身份验证需求,您可能需要考虑AuthBot 您还可以查看库的OAuthCallback控制器上的逻辑 ,以了解它们在身份验证后如何恢复与Bot的对话。

ContosoFlowers示例也使用了恢复会话机制 不是为了auth目的,而是为了展示如何处理一个低估的信用卡付款。

我找到了如何使它工作。

控制器:

public class MessagesController : ApiController
{
    public async Task<HttpResponseMessage> Post([FromBody] Activity activity, CancellationToken token)
    {
        if (activity != null)
        {
            switch (activity.GetActivityType())
            {
                case ActivityTypes.Message:

                    var container = WebApiApplication.FindContainer();

                    using (var scope = DialogModule.BeginLifetimeScope(container, activity))
                    {
                        await Conversation.SendAsync(activity, () => scope.Resolve<IDialog<object>>(), token);
                    }
                    break;
            }
        }
        return new HttpResponseMessage(HttpStatusCode.Accepted);
    }
}

Global.asax中

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);

        var builder = new ContainerBuilder();

        builder.RegisterModule(new DialogModule());

        builder.RegisterModule(new MyModule());

        var config = GlobalConfiguration.Configuration;

        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

        builder.RegisterWebApiFilterProvider(config);

        var container = builder.Build();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    }

    public static ILifetimeScope FindContainer()
    {
        var config = GlobalConfiguration.Configuration;
        var resolver = (AutofacWebApiDependencyResolver)config.DependencyResolver;
        return resolver.Container;
    }
}

MyModule的:

public sealed class MyModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        base.Load(builder);

        builder.Register(
            c => new LuisModelAttribute("MyId", "SubId"))
            .AsSelf()
            .AsImplementedInterfaces()
            .SingleInstance();

        builder.RegisterType<MainDialog>().AsSelf().As<IDialog<object>>().InstancePerDependency();

        builder.RegisterType<LuisService>()
            .Keyed<ILuisService>(FiberModule.Key_DoNotSerialize)
            .AsImplementedInterfaces()
            .SingleInstance();
    }
}

回调方法:

public class OAuthCallbackController : ApiController
{

    [HttpGet]
    [Route("api/OAuthCallback")]
    public async Task OAuthCallback(string state, [FromUri] CancellationToken cancellationToken, [FromUri] string accessToken, [FromUri] string username)
    {
        var resumptionCookie = ResumptionCookie.GZipDeserialize(state);
        var message = resumptionCookie.GetMessage();
        message.Text = "UserIsAuthenticated";

        using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
        {
            var dataBag = scope.Resolve<IBotData>();
            await dataBag.LoadAsync(cancellationToken);

            dataBag.PrivateConversationData.SetValue("accessToken", accessToken);
            dataBag.PrivateConversationData.SetValue("username", username);

            ResumptionCookie pending;
            if (dataBag.PrivateConversationData.TryGetValue("persistedCookie", out pending))
            {
                dataBag.PrivateConversationData.RemoveValue("persistedCookie");
                await dataBag.FlushAsync(cancellationToken);
            }
        }

        await Conversation.ResumeAsync(resumptionCookie, message, cancellationToken);
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM