相关文章推荐
踏实的骆驼  ·  htmlunit ...·  8 月前    · 
霸气的煎饼  ·  sqlite row_number() ...·  1 年前    · 

Bot Framework JavaScript、C# 和 Python SDK 将继续受支持,但 Java SDK 即将停用,最终长期支持将于 2023 年 11 月结束。

使用 Java SDK 构建的现有机器人将继续正常运行。

要生成新的机器人,请考虑使用 Microsoft Copilot Studio 并阅读 选择正确的助理解决方案

有关详细信息,请参阅 机器人构建的未来

  • 了解 机器人基础知识 管理状态 对话库 ,以及如何 实现顺序聊天流
  • C# JavaScript Java Python 编写的复杂对话示例的副本。
  • 关于此示例

    本示例演示一个可以注册用户,让其针对列表中的最多两家公司发表评论的机器人。 该机器人使用 3 个组件对话来管理对话流。 每个组件对话包含一个瀑布对话,以及收集用户输入所需的任何提示。 这些对话在以下部分详述。 它使用聊天状态管理其对话,并使用用户状态来保存有关用户及其所要评论的公司的信息。

    此机器人派生自活动处理程序。 与许多示例机器人一样,它会欢迎用户,使用对话处理来自用户的消息,并在该轮聊天结束之前保存用户和聊天状态。

    JavaScript Python

    UserProfile.cs

    /// <summary>Contains information about a user.</summary>
    public class UserProfile
        public string Name { get; set; }
        public int Age { get; set; }
        // The list of companies the user wants to review.
        public List<string> CompaniesToReview { get; set; } = new List<string>();
    

    userProfile.js

    // @ts-check
    class UserProfile {
        constructor(name, age) {
            this.name = name;
            this.age = age;
            // The list of companies the user wants to review.
            this.companiesToReview = [];
    

    UserProfile.java

    您正在寻找的示例似乎已经被移动了! 放心,我们正在努力解决此问题。

    data_models/user_profile.py

    class UserProfile:
        def __init__(
            self, name: str = None, age: int = 0, companies_to_review: List[str] = None
            self.name: str = name
            self.age: int = age
            self.companies_to_review: List[str] = companies_to_review
    

    此机器人包含 3 个对话:

  • 主对话会启动整个进程,并汇总收集的信息。
  • 顶级对话根据用户的年龄收集用户信息并包括分支逻辑。
  • 用户可以通过“评论-选择”对话以迭代方式选择要评论的公司。 它使用循环逻辑来这样做。
  • 主对话有 2 个步骤:

  • 启动顶级对话。
  • 检索并汇总顶级对话框收集的用户资料,将这些信息保存到用户状态,然后标示主对话的结束。
  • Dialogs\MainDialog.cs

    private async Task<DialogTurnResult> InitialStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        return await stepContext.BeginDialogAsync(nameof(TopLevelDialog), null, cancellationToken);
    private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        var userInfo = (UserProfile)stepContext.Result;
        string status = "You are signed up to review "
            + (userInfo.CompaniesToReview.Count is 0 ? "no companies" : string.Join(" and ", userInfo.CompaniesToReview))
            + ".";
        await stepContext.Context.SendActivityAsync(status);
        var accessor = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
        await accessor.SetAsync(stepContext.Context, userInfo, cancellationToken);
        return await stepContext.EndDialogAsync(null, cancellationToken);
    

    dialogs/mainDialog.js

    async initialStep(stepContext) { return await stepContext.beginDialog(TOP_LEVEL_DIALOG); async finalStep(stepContext) { const userInfo = stepContext.result; const status = 'You are signed up to review ' + (userInfo.companiesToReview.length === 0 ? 'no companies' : userInfo.companiesToReview.join(' and ')) + '.'; await stepContext.context.sendActivity(status); await this.userProfileAccessor.set(stepContext.context, userInfo);

    MainDialog.java

    您正在寻找的示例似乎已经被移动了! 放心,我们正在努力解决此问题。

    dialogs\main_dialog.py

    async def initial_step(
        self, step_context: WaterfallStepContext
    ) -> DialogTurnResult:
        return await step_context.begin_dialog(TopLevelDialog.__name__)
    async def final_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        user_info: UserProfile = step_context.result
        companies = (
            "no companies"
            if len(user_info.companies_to_review) == 0
            else " and ".join(user_info.companies_to_review)
        status = f"You are signed up to review {companies}."
        await step_context.context.send_activity(MessageFactory.text(status))
        # store the UserProfile
        accessor = self.user_state.create_property("UserProfile")
        await accessor.set(step_context.context, user_info)
        return await step_context.end_dialog()
    

    顶级对话有 4 个步骤:

  • 询问用户的姓名。
  • 询问用户的年龄
  • 根据用户的年龄,启动“评论-选择”对话或转到下一步。
  • 最后,感谢用户参与并返回收集的信息。
  • 第一步是创建一个空的用户角色,作为会话状态的一部分。 该对话从一个空的个人资料开始,随着交流的进行不断向个人资料中添加信息。 结束时,最后一步会返回收集的信息。

    在第三(开始选择)步中,会根据用户的年龄将聊天流分支。

    JavaScript Python
                stepContext.Values[UserInfo] = new UserProfile();
                var promptOptions = new PromptOptions { Prompt = MessageFactory.Text("Please enter your name.") };
                // Ask the user to enter their name.
                return await stepContext.PromptAsync(nameof(TextPrompt), promptOptions, cancellationToken);
            private async Task<DialogTurnResult> AgeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
                // Set the user's name to what they entered in response to the name prompt.
                var userProfile = (UserProfile)stepContext.Values[UserInfo];
                userProfile.Name = (string)stepContext.Result;
                var promptOptions = new PromptOptions { Prompt = MessageFactory.Text("Please enter your age.") };
                // Ask the user to enter their age.
                return await stepContext.PromptAsync(nameof(NumberPrompt<int>), promptOptions, cancellationToken);
            private async Task<DialogTurnResult> StartSelectionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
                // Set the user's age to what they entered in response to the age prompt.
                var userProfile = (UserProfile)stepContext.Values[UserInfo];
                userProfile.Age = (int)stepContext.Result;
                if (userProfile.Age < 25)
                    // If they are too young, skip the review selection dialog, and pass an empty list to the next step.
                    await stepContext.Context.SendActivityAsync(
                        MessageFactory.Text("You must be 25 or older to participate."),
                        cancellationToken);
                    return await stepContext.NextAsync(new List<string>(), cancellationToken);
                    // Otherwise, start the review selection dialog.
                    return await stepContext.BeginDialogAsync(nameof(ReviewSelectionDialog), null, cancellationToken);
            private async Task<DialogTurnResult> AcknowledgementStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
                // Set the user's company selection to what they entered in the review-selection dialog.
                var userProfile = (UserProfile)stepContext.Values[UserInfo];
                userProfile.CompaniesToReview = stepContext.Result as List<string> ?? new List<string>();
                // Thank them for participating.
                await stepContext.Context.SendActivityAsync(
                    MessageFactory.Text($"Thanks for participating, {((UserProfile)stepContext.Values[UserInfo]).Name}."),
                    cancellationToken);
                // Exit the dialog, returning the collected user information.
                return await stepContext.EndDialogAsync(stepContext.Values[UserInfo], cancellationToken);
    

    dialogs/topLevelDialog.js

    async nameStep(stepContext) { // Create an object in which to collect the user's information within the dialog. stepContext.values.userInfo = new UserProfile(); const promptOptions = { prompt: 'Please enter your name.' }; // Ask the user to enter their name. return await stepContext.prompt(TEXT_PROMPT, promptOptions); async ageStep(stepContext) { // Set the user's name to what they entered in response to the name prompt. stepContext.values.userInfo.name = stepContext.result; const promptOptions = { prompt: 'Please enter your age.' }; // Ask the user to enter their age. return await stepContext.prompt(NUMBER_PROMPT, promptOptions); async startSelectionStep(stepContext) { // Set the user's age to what they entered in response to the age prompt. stepContext.values.userInfo.age = stepContext.result; if (stepContext.result < 25) { // If they are too young, skip the review selection dialog, and pass an empty list to the next step. await stepContext.context.sendActivity('You must be 25 or older to participate.'); return await stepContext.next(); } else { // Otherwise, start the review selection dialog. return await stepContext.beginDialog(REVIEW_SELECTION_DIALOG); async acknowledgementStep(stepContext) { // Set the user's company selection to what they entered in the review-selection dialog. const userProfile = stepContext.values.userInfo; userProfile.companiesToReview = stepContext.result || []; await stepContext.context.sendActivity(`Thanks for participating ${ userProfile.name }`); // Exit the dialog, returning the collected user information.

    TopLevelDialog.java

    您正在寻找的示例似乎已经被移动了! 放心,我们正在努力解决此问题。

    dialogs\top_level_dialog.py

    async def name_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        # Create an object in which to collect the user's information within the dialog.
        step_context.values[self.USER_INFO] = UserProfile()
        # Ask the user to enter their name.
        prompt_options = PromptOptions(
            prompt=MessageFactory.text("Please enter your name.")
        return await step_context.prompt(TextPrompt.__name__, prompt_options)
    async def age_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        # Set the user's name to what they entered in response to the name prompt.
        user_profile = step_context.values[self.USER_INFO]
        user_profile.name = step_context.result
        # Ask the user to enter their age.
        prompt_options = PromptOptions(
            prompt=MessageFactory.text("Please enter your age.")
        return await step_context.prompt(NumberPrompt.__name__, prompt_options)
    async def start_selection_step(
        self, step_context: WaterfallStepContext
    ) -> DialogTurnResult:
        # Set the user's age to what they entered in response to the age prompt.
        user_profile: UserProfile = step_context.values[self.USER_INFO]
        user_profile.age = step_context.result
        if user_profile.age < 25:
            # If they are too young, skip the review selection dialog, and pass an empty list to the next step.
            await step_context.context.send_activity(
                MessageFactory.text("You must be 25 or older to participate.")
            return await step_context.next([])
        # Otherwise, start the review selection dialog.
        return await step_context.begin_dialog(ReviewSelectionDialog.__name__)
    async def acknowledgement_step(
        self, step_context: WaterfallStepContext
    ) -> DialogTurnResult:
        # Set the user's company selection to what they entered in the review-selection dialog.
        user_profile: UserProfile = step_context.values[self.USER_INFO]
        user_profile.companies_to_review = step_context.result
        # Thank them for participating.
        await step_context.context.send_activity(
            MessageFactory.text(f"Thanks for participating, {user_profile.name}.")
        # Exit the dialog, returning the collected user information.
        return await step_context.end_dialog(user_profile)
    

    review-selection 对话

    review-selection 对话包含两个步骤:

  • 请求用户选择要评论的公司,或选择 done 以完成操作。
  • 如果对话是使用任何初始信息启动的,则可通过瀑布步骤上下文的 options 属性获取该信息。 “评论-选择”对话可以自行重启,并使用它来允许用户选择多个要评论的公司。
  • 如果用户已选择要评论的公司,则会从可用的选项中删除该公司。
  • 添加了 done 选项,允许用户早退出循环。
  • 根据情况重复此对话或退出。
  • 如果用户选择了要评论的公司,请将其添加到列表中。
  • 如果用户选择了 2 个公司或选择了退出,请结束对话并返回收集的列表。
  • 否则,请重启对话,并使用列表的内容将其初始化。
  • Dialogs\ReviewSelectionDialog.cs

    private async Task<DialogTurnResult> SelectionStepAsync(
        WaterfallStepContext stepContext,
        CancellationToken cancellationToken)
        // Continue using the same selection list, if any, from the previous iteration of this dialog.
        var list = stepContext.Options as List<string> ?? new List<string>();
        stepContext.Values[CompaniesSelected] = list;
        // Create a prompt message.
        string message;
        if (list.Count is 0)
            message = $"Please choose a company to review, or `{DoneOption}` to finish.";
            message = $"You have selected **{list[0]}**. You can review an additional company, " +
                $"or choose `{DoneOption}` to finish.";
        // Create the list of options to choose from.
        var options = _companyOptions.ToList();
        options.Add(DoneOption);
        if (list.Count > 0)
            options.Remove(list[0]);
        var promptOptions = new PromptOptions
            Prompt = MessageFactory.Text(message),
            RetryPrompt = MessageFactory.Text("Please choose an option from the list."),
            Choices = ChoiceFactory.ToChoices(options),
        // Prompt the user for a choice.
        return await stepContext.PromptAsync(nameof(ChoicePrompt), promptOptions, cancellationToken);
    private async Task<DialogTurnResult> LoopStepAsync(
        WaterfallStepContext stepContext,
        CancellationToken cancellationToken)
        // Retrieve their selection list, the choice they made, and whether they chose to finish.
        var list = stepContext.Values[CompaniesSelected] as List<string>;
        var choice = (FoundChoice)stepContext.Result;
        var done = choice.Value == DoneOption;
        if (!done)
            // If they chose a company, add it to the list.
            list.Add(choice.Value);
        if (done || list.Count >= 2)
            // If they're done, exit and return their list.
            return await stepContext.EndDialogAsync(list, cancellationToken);
            // Otherwise, repeat this dialog, passing in the list from this iteration.
            return await stepContext.ReplaceDialogAsync(InitialDialogId, list, cancellationToken);
    

    dialogs/reviewSelectionDialog.js

    async selectionStep(stepContext) { // Continue using the same selection list, if any, from the previous iteration of this dialog. const list = Array.isArray(stepContext.options) ? stepContext.options : []; stepContext.values[this.companiesSelected] = list; // Create a prompt message. let message = ''; if (list.length === 0) { message = `Please choose a company to review, or \`${ this.doneOption }\` to finish.`; } else { message = `You have selected **${ list[0] }**. You can review an additional company, or choose \`${ this.doneOption }\` to finish.`; // Create the list of options to choose from. const options = list.length > 0 ? this.companyOptions.filter(function(item) { return item !== list[0]; }) : this.companyOptions.slice(); options.push(this.doneOption); // Prompt the user for a choice. return await stepContext.prompt(CHOICE_PROMPT, { prompt: message, retryPrompt: 'Please choose an option from the list.', choices: options async loopStep(stepContext) { // Retrieve their selection list, the choice they made, and whether they chose to finish. const list = stepContext.values[this.companiesSelected]; const choice = stepContext.result; const done = choice.value === this.doneOption; if (!done) { // If they chose a company, add it to the list. list.push(choice.value); if (done || list.length > 1) { // If they're done, exit and return their list. return await stepContext.endDialog(list); } else { // Otherwise, repeat this dialog, passing in the list from this iteration. return await stepContext.replaceDialog(this.initialDialogId, list);

    ReviewSelectionDialog.java

    您正在寻找的示例似乎已经被移动了! 放心,我们正在努力解决此问题。

    dialogs/review_selection_dialog.py

    async def selection_step(
        self, step_context: WaterfallStepContext
    ) -> DialogTurnResult:
        # step_context.options will contains the value passed in begin_dialog or replace_dialog.
        # if this value wasn't provided then start with an emtpy selection list.  This list will
        # eventually be returned to the parent via end_dialog.
        selected: [
        ] = step_context.options if step_context.options is not None else []
        step_context.values[self.COMPANIES_SELECTED] = selected
        if len(selected) == 0:
            message = (
                f"Please choose a company to review, or `{self.DONE_OPTION}` to finish."
        else:
            message = (
                f"You have selected **{selected[0]}**. You can review an additional company, "
                f"or choose `{self.DONE_OPTION}` to finish. "
        # create a list of options to choose, with already selected items removed.
        options = self.company_options.copy()
        options.append(self.DONE_OPTION)
        if len(selected) > 0:
            options.remove(selected[0])
        # prompt with the list of choices
        prompt_options = PromptOptions(
            prompt=MessageFactory.text(message),
            retry_prompt=MessageFactory.text("Please choose an option from the list."),
            choices=self._to_choices(options),
        return await step_context.prompt(ChoicePrompt.__name__, prompt_options)
    def _to_choices(self, choices: [str]) -> List[Choice]:
        choice_list: List[Choice] = []
        for choice in choices:
            choice_list.append(Choice(value=choice))
        return choice_list
    async def loop_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
        selected: List[str] = step_context.values[self.COMPANIES_SELECTED]
        choice: FoundChoice = step_context.result
        done = choice.value == self.DONE_OPTION
        # If they chose a company, add it to the list.
        if not done:
            selected.append(choice.value)
        # If they're done, exit and return their list.
        if done or len(selected) >= 2:
            return await step_context.end_dialog(selected)
        # Otherwise, repeat this dialog, passing in the selections from this iteration.
        return await step_context.replace_dialog(
            self.initial_dialog_id, selected
    

    “对话机器人” 类扩展了活动处理程序,包含用于运行对话的逻辑。 “对话和欢迎机器人” 类扩展了对话机器人,在用户加入聊天时也会欢迎用户。

    机器人的轮次处理程序重复这 3 个对话定义的对话流。 当它收到来自用户的消息时:

  • 它运行主对话。
  • 如果对话堆栈为空,这将启动主对话。
  • 否则,对话仍处于中间进程,这将继续活动对话。
  • 它会保存状态,以持久保存对用户、聊天和对话状态所做的任何更新。
  • Bots\DialogBot.cs

    public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        await base.OnTurnAsync(turnContext, cancellationToken);
        // Save any state changes that might have occurred during the turn.
        await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
        await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
    protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        Logger.LogInformation("Running dialog with Message Activity.");
        // Run the Dialog with the new message Activity.
        await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
    

    bots/dialogBot.js

    this.conversationState = conversationState;
    this.userState = userState;
    this.dialog = dialog;
    this.dialogState = this.conversationState.createProperty('DialogState');
    this.onMessage(async (context, next) => {
        console.log('Running dialog with Message Activity.');
        // Run the Dialog with the new message Activity.
    
            // By calling next() you ensure that the next BotHandler is run.
            await next();
     * Override the ActivityHandler.run() method to save state changes after the bot logic completes.
    async run(context) {
        await super.run(context);
    

    DialogBot.java

    您正在寻找的示例似乎已经被移动了! 放心,我们正在努力解决此问题。

    bots/dialog_bot.py

    async def on_turn(self, turn_context: TurnContext):
        await super().on_turn(turn_context)
        # Save any state changes that might have occurred during the turn.
        await self.conversation_state.save_changes(turn_context, False)
        await self.user_state.save_changes(turn_context, False)
    async def on_message_activity(self, turn_context: TurnContext):
        await DialogHelper.run_dialog(
            self.dialog,
            turn_context,
            self.conversation_state.create_property("DialogState"),
    

    注册机器人的服务

    根据需要创建并注册服务:

  • 机器人的基本服务:适配器和机器人实现。
  • 用于管理状态的服务:存储、用户状态和聊天状态。
  • 机器人将使用的根对话。
  • Startup.cs

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
        services.AddHttpClient().AddControllers().AddNewtonsoftJson(options =>
            options.SerializerSettings.MaxDepth = HttpHelper.BotMessageSerializerSettings.MaxDepth;
        // Create the Bot Framework Authentication to be used with the Bot Adapter.
        services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();
        // Create the Bot Adapter with error handling enabled.
        services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
        // Create the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.)
        services.AddSingleton<IStorage, MemoryStorage>();
        // Create the User state. (Used in this bot's Dialog implementation.)
        services.AddSingleton<UserState>();
    
    const memoryStorage = new MemoryStorage();
    // Create user and conversation state with in-memory storage provider.
    const userState = new UserState(memoryStorage);
    const conversationState = new ConversationState(memoryStorage);
    // Create the main dialog.
    const dialog = new MainDialog(userState);
    const bot = new DialogAndWelcomeBot(conversationState, userState, dialog);
    // Catch-all for errors.
    adapter.onTurnError = async (context, error) => {
        // This check writes out errors to console log .vs. app insights.
        // NOTE: In production environment, you should consider logging this to Azure
        //       application insights. See https://aka.ms/bottelemetry for telemetry
    

    Application.java

    您正在寻找的示例似乎已经被移动了! 放心,我们正在努力解决此问题。

    app.py

    # See https://aka.ms/about-bot-adapter to learn more about how bots work.
    ADAPTER = CloudAdapter(ConfigurationBotFrameworkAuthentication(CONFIG))
    # Catch-all for errors.
    
    CONVERSATION_STATE = ConversationState(MEMORY)
    # Create Dialog and Bot
    DIALOG = MainDialog(USER_STATE)
    BOT = DialogAndWelcomeBot(CONVERSATION_STATE, USER_STATE, DIALOG)
    # Listen for incoming requests on /api/messages.
    

    有关如何实现对话的介绍,请参阅实现有序的对话流,其中使用了单个瀑布对话和一些提示来向用户提出一系列问题。

    “对话”库包含提示的基本验证。 你也可以添加自定义验证。 有关详细信息,请参阅使用对话提示收集用户输入

    若要简化对话代码并将其重复用于多个机器人,可将对话集的某些部分定义为单独的类。 有关详细信息,请参阅重复使用对话

    重复使用对话