diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 9fb85ec49..000000000 --- a/.gitattributes +++ /dev/null @@ -1,14 +0,0 @@ -# Set the default behavior, in case people don't have core.autocrlf set. -* text=auto - -# Explicitly declare text files you want to always be normalized and converted -# to native line endings on checkout. -*.c text -*.h text - -# Declare files that will always have CRLF line endings on checkout. -*.sln text eol=crlf - -# Denote all files that are truly binary and should not be modified. -*.png binary -*.jpg binary \ No newline at end of file diff --git a/.gitignore b/.gitignore index fdfaa1a77..dfcfd56f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,350 @@ -log/ -obj/ -_site/ -.optemp/ -_themes.MSDN.Modern/ -_themes.VS.Modern/ -_themes/ -_samples/ - -.openpublishing.buildcore.ps1 - -.migrationtemp -articles/directories.txt -_themes*/ - -.openpublishing.buildcore.ps1 +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ diff --git a/.openpublishing.build.ps1 b/.openpublishing.build.ps1 deleted file mode 100644 index aadef7620..000000000 --- a/.openpublishing.build.ps1 +++ /dev/null @@ -1,17 +0,0 @@ -param( - [string]$buildCorePowershellUrl = "https://opbuildstorageprod.blob.core.windows.net/opps1container/.openpublishing.buildcore.ps1", - [string]$parameters -) -# Main -$errorActionPreference = 'Stop' - -# Step-1: Download buildcore script to local -echo "download build core script to local with source url: $buildCorePowershellUrl" -$repositoryRoot = Split-Path -Parent $MyInvocation.MyCommand.Definition -$buildCorePowershellDestination = "$repositoryRoot\.openpublishing.buildcore.ps1" -Invoke-WebRequest $buildCorePowershellUrl -OutFile "$buildCorePowershellDestination" - -# Step-2: Run build core -echo "run build core script with parameters: $parameters" -& "$buildCorePowershellDestination" "$parameters" -exit $LASTEXITCODE diff --git a/.openpublishing.publish.config.json b/.openpublishing.publish.config.json deleted file mode 100644 index 2b33ef934..000000000 --- a/.openpublishing.publish.config.json +++ /dev/null @@ -1,154 +0,0 @@ -{ - "docsets_to_publish":[ - { - "docset_name":"bot-framework", - "build_source_folder":"articles", - "build_output_subfolder":"bot-framework", - "locale":"en-us", - "monikers":[], - "moniker_ranges":[ - ">= azure-bot-service-3.0", - ">= botbuilder-3.12.2.4", - ">= skypebotsmedia-1.5.0.1177-alpha", - ">= botconnector-3.11.1" - ], - "open_to_public_contributors":true, - "type_mapping":{ - "Conceptual":"Content", - "ManagedReference":"Content", - "RestApi":"Content" - }, - "build_entry_point":"docs", - "template_folder":"_themes" - }, - { - "docset_name":"bot-framework-rest-api", - "build_source_folder":"rest", - "build_output_subfolder":"bot-framework-rest-api", - "locale":"en-us", - "monikers":[], - "open_to_public_contributors":false, - "type_mapping":{ - "Conceptual":"Content", - "ContextObject":"Toc", - "ManagedReference":"Content", - "RestApi":"Content" - }, - "build_entry_point":"docs", - "template_folder":"_themes", - "version":0 - }, - { - "docset_name":"bot-framework-dotnet-api", - "build_source_folder":"dotnet", - "build_output_subfolder":"bot-framework-dotnet-api", - "locale":"en-us", - "open_to_public_contributors":true, - "type_mapping":{ - "Conceptual":"Content", - "ManagedReference":"Content", - "RestApi":"Content", - "NetEnum":"Content", - "NetDelegate":"Content", - "NetNamespace":"Content", - "NetMember":"Content", - "NetType":"Content" - }, - "build_entry_point":"docs", - "template_folder":"_themes", - "customized_tasks":{ - "docset_postbuild":[ - "_dependentPackages/ECMA2Yaml/tools/PostBuild.ps1" - ], - "docset_prebuild":[ - "_dependentPackages/ECMA2Yaml/tools/Run.ps1", - "_dependentPackages/CommonPlugins/tools/SplitTOC.ps1", - "_dependentPackages/CommonPlugins/tools/DiffFolder.ps1" - ] - } - } - ], - "notification_subscribers":[ - "3b0e6dd6.microsoft.com@amer.teams.ms", - "botframeworkcontentteam@service.microsoft.com" - ], - "sync_notification_subscribers":[], - "branches_to_filter":[], - "git_repository_url_open_to_public_contributors":"https://github.com/MicrosoftDocs/bot-docs", - "git_repository_branch_open_to_public_contributors":"live", - "skip_source_output_uploading":false, - "need_preview_pull_request":true, - "contribution_branch_mappings":{}, - "dependent_repositories":[ - { - "path_to_root":"_themes", - "url":"https://github.com/Microsoft/templates.docs.msft", - "branch":"master", - "branch_mapping":{} - }, - { - "path_to_root":"_themes.pdf", - "url":"https://github.com/Microsoft/templates.docs.msft.pdf", - "branch":"master", - "branch_mapping":{} - }, - { - "path_to_root":"botbuilder-samples", - "url":"https://github.com/Microsoft/BotBuilder-Samples", - "branch":"master", - "branch_mapping":{} - }, - { - "path_to_root":"botbuilder-python", - "url":"https://github.com/microsoft/BotBuilder-Samples", - "branch":"master", - "branch_mapping":{} - } - ], - "branch_target_mapping":{ - "live":[ - "Publish", - "Pdf" - ], - "master":[ - "Publish", - "Pdf" - ] - }, - "need_generate_pdf_url_template":true, - "Targets":{ - "Pdf":{ - "template_folder":"_themes.pdf" - } - }, - "need_generate_intellisense":false, - "template_folder":"_themes", - "dependent_packages":[ - { - "path_to_root":"_dependentPackages/CommonPlugins", - "target_framework":"net45", - "version":"latest", - "id":"Microsoft.OpenPublishing.CommonPlugins", - "nuget_feed":"https://www.myget.org/F/op/api/v2" - }, - { - "id":"Microsoft.DocAsCode.ECMA2Yaml", - "nuget_feed":"https://www.myget.org/F/op/api/v2", - "path_to_root":"_dependentPackages/ECMA2Yaml", - "target_framework":"net45", - "version":"latest" - } - ], - "ECMA2Yaml":{ - "SourceXmlFolder":"dotnet/xml", - "OutputYamlFolder":"dotnet/api", - "Flatten":true, - "SDPMode":true - }, - "DiffFolder":[ - "dotnet/api" - ], - "SplitTOC":[ - "dotnet/api/toc.yml" - ] -} diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json deleted file mode 100644 index 90fbd3048..000000000 --- a/.openpublishing.redirection.json +++ /dev/null @@ -1,704 +0,0 @@ -{ - "redirections": [ - { - "source_path": "articles/bot-service-quickstart.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/abs-quickstart", - "redirect_document_id": true - }, - { - "source_path": "articles/azure-bot-service-build-options.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-build-online-code-editor", - "redirect_document_id": true - }, - { - "source_path": "articles/azure-bot-service-continuous-deployment.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-deploy-az-cli", - "redirect_document_id": false - }, - { - "source_path": "articles/azure-bot-service-continuous-integration.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-deploy-az-cli", - "redirect_document_id": true - }, - { - "source_path": "articles/azure-bot-service-debug-bot.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-debug-bot", - "redirect_document_id": false - }, - { - "source_path": "articles/azure-bot-service-hosting-plan.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-overview-readme#hosting-plans", - "redirect_document_id": true - }, - { - "source_path": "articles/azure-bot-service-migration-plans.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-change-hosting-plan", - "redirect_document_id": true - }, - { - "source_path": "articles/azure-bot-service-overview.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction", - "redirect_document_id": true - }, - { - "source_path": "articles/azure-bot-service-quickstart.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-quickstart", - "redirect_document_id": true - }, - { - "source_path": "articles/azure-bot-service-serverless-template-basic.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-debug-bot", - "redirect_document_id": true - }, - { - "source_path": "articles/azure-bot-service-serverless-template-form.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-debug-bot", - "redirect_document_id": false - }, - { - "source_path": "articles/azure-bot-service-template-language-understanding.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-templates#language-understanding-bot", - "redirect_document_id": false - }, - { - "source_path": "articles/azure-bot-service-template-proactive.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-templates#proactive-bot", - "redirect_document_id": true - }, - { - "source_path": "articles/azure-bot-service-template-question-answer.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-templates#question-and-answer-bot", - "redirect_document_id": false - }, - { - "source_path": "articles/azure-bot-service-templates.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-templates", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-builder-howto-deploy-azure.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-deploy-az-cli", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-builder-overview-getstarted.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-quickstart", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-builder-reference-overview.md", - "redirect_url": "https://aka.ms/botframework-v3-cs-sdk", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-builder-samples.md", - "redirect_url": "https://github.com/Microsoft/BotBuilder-Samples/blob/master/README.md", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-builder-sdk-download.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-quickstart", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-builder-tools-az-cli.md", - "redirect_url": "/azure/bot-service/index", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-builder-tutorial-persist-user-inputs.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-howto-v4-state", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-design-best-practices.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-principles", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-design-conversation-flow.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-conversation-flow", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-design-first-interaction.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-first-interaction", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-design-navigation.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-navigation", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-design-pattern-embed-app.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-pattern-embed-app", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-design-pattern-embed-web-site.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-pattern-embed-web-site", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-design-pattern-handoff-human.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-pattern-handoff-human", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-design-pattern-integrate-browser.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-pattern-integrate-browser", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-design-pattern-knowledge-base.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-pattern-knowledge-base", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-design-pattern-task-automation.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-pattern-task-automation", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-design-principles.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-principles", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-design-user-experience.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-user-experience", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-service-design-best-practices.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-principles", - "redirect_document_id": false - }, - { - "source_path": "articles/channel-connect-bing.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-bing", - "redirect_document_id": true - }, - { - "source_path": "articles/channel-connect-cortana.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-cortana", - "redirect_document_id": true - }, - { - "source_path": "articles/channel-connect-directline.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-directline", - "redirect_document_id": true - }, - { - "source_path": "articles/channel-connect-email.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-email", - "redirect_document_id": true - }, - { - "source_path": "articles/cchannel-connect-facebook.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-facebook", - "redirect_document_id": true - }, - { - "source_path": "articles/channel-connect-groupme.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-groupme", - "redirect_document_id": true - }, - { - "source_path": "articles/channel-connect-kik.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-kik", - "redirect_document_id": true - }, - { - "source_path": "articles/channel-connect-skypeforbusiness.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-skypeforbusiness", - "redirect_document_id": true - }, - { - "source_path": "articles/channel-connect-slack.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-slack", - "redirect_document_id": true - }, - { - "source_path": "articles/intelligent-bots.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-intelligence", - "redirect_document_id": false - }, - { - "source_path": "articles/channel-connect-telegram.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-telegram", - "redirect_document_id": true - }, - { - "source_path": "articles/channel-connect-webchat-speech.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-webchat-speech", - "redirect_document_id": true - }, - { - "source_path": "articles/channel-connect-webchat.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-webchat", - "redirect_document_id": true - }, - { - "source_path": "articles/channel-connect-twilio.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-connect-twilio", - "redirect_document_id": true - }, - { - "source_path": "articles/cognitive-services-add-bot-knowledge.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-intelligence", - "redirect_document_id": false - }, - { - "source_path": "articles/cognitive-services-add-bot-location-control.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-intelligence", - "redirect_document_id": false - }, - { - "source_path": "articles/cognitive-services-add-bot-language.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-intelligence", - "redirect_document_id": false - }, - { - "source_path": "articles/overview-how-bot-framework-works.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-overview-readme", - "redirect_document_id": false - }, - { - "source_path": "articles/ccognitive-services-add-bot-search.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-intelligence", - "redirect_document_id": false - }, - { - "source_path": "articles/cognitive-services-add-bot-speech.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-intelligence", - "redirect_document_id": false - }, - { - "source_path": "articles/cognitive-services-add-bot-vision.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-intelligence", - "redirect_document_id": false - }, - { - "source_path": "articles/cognitive-services-bot-intelligence-overview.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-intelligence", - "redirect_document_id": false - }, - { - "source_path": "articles/debug-bots-cortana-skill-invoke.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-debug-cortana-skill", - "redirect_document_id": true - }, - { - "source_path": "articles/debug-bots-emulator.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-debug-emulator", - "redirect_document_id": true - }, - { - "source_path": "articles/debug-bots-locally-vscode.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-debug-bot", - "redirect_document_id": false - }, - { - "source_path": "articles/deploy-dotnet-bot-visual-studio.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-continuous-deployment", - "redirect_document_id": false - }, - { - "source_path": "articles/deploy-bot-github.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-build-continuous-deployment", - "redirect_document_id": false - }, - { - "source_path": "articles/deploy-bot-overview.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-build-continuous-deployment", - "redirect_document_id": false - }, - { - "source_path": "articles/deploy-bot-verview.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-concept-intelligence", - "redirect_document_id": true - }, - { - "source_path": "articles/deploy-bot-visual-studio.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/deploy-dotnet-bot-visual-studio", - "redirect_document_id": true - }, - { - "source_path": "articles/overview-introduction-bot-framework.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction", - "redirect_document_id": false - }, - { - "source_path": "articles/portal-analytics-overview.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-manage-analytics", - "redirect_document_id": true - }, - { - "source_path": "articles/portal-bot-review-guidelines.md", - "redirect_url": "/azure/bot-service/index", - "redirect_document_id": true - }, - { - "source_path": "articles/portal-channel-inspector.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-channel-inspector", - "redirect_document_id": true - }, - { - "source_path": "articles/portal-configure-channels.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-manage-channels", - "redirect_document_id": true - }, - { - "source_path": "articles/portal-register-bot.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-quickstart-registration", - "redirect_document_id": true - }, - { - "source_path": "articles/deploy-nodejs-bot-visual-studio.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-continuous-deployment", - "redirect_document_id": true - }, - { - "source_path": "articles/embed-chat-control-web-page.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-design-pattern-embed-web-site", - "redirect_document_id": true - }, - { - "source_path": "articles/portal-submit-bot-directory.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-manage-channels", - "redirect_document_id": false - }, - { - "source_path": "articles/publish-bot-overview.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-manage-channels", - "redirect_document_id": false - }, - { - "source_path": "articles/reference-overview.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-reference-overview", - "redirect_document_id": true - }, - { - "source_path": "articles/resources-app-insights-keys.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-resources-app-insights-keys", - "redirect_document_id": true - }, - { - "source_path": "articles/resources-bot-framework-faq.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-reference-overview", - "redirect_document_id": false - }, - { - "source_path": "articles/resources-identifiers-guide.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-servicebot-service-resources-identifiers-guide", - "redirect_document_id": true - }, - { - "source_path": "articles/resources-links-help.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-resources-links-help", - "redirect_document_id": true - }, - { - "source_path": "articles/resources-support.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-resources-links-help", - "redirect_document_id": false - }, - { - "source_path": "articles/resources-tools-downloads.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-quickstart", - "redirect_document_id": false - }, - { - "source_path": "articles/resources-upgrade-to-v3.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-resources-upgrade-to-v3", - "redirect_document_id": true - }, - { - "source_path": "articles/resources-user-agent.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-resources-user-agent", - "redirect_document_id": true - }, - { - "source_path": "articles/rest-api-reference.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference", - "redirect_document_id": true - }, - { - "source_path": "articles/troubleshoot-authentication-problems.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-troubleshoot-authentication-problems", - "redirect_document_id": true - }, - { - "source_path": "articles/azure/azure-bot-service-quickstart.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-quickstart", - "redirect_document_id": false - }, - { - "source_path": "articles/azure/azure-bot-service-serverless-template-basic.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-debug-bot", - "redirect_document_id": false - }, - { - "source_path": "articles/troubleshoot-general-problems.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-troubleshoot-general-problems", - "redirect_document_id": true - }, - { - "source_path": "articles/v4sdk/bot-builder-anatomy.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-basics", - "redirect_document_id": true - }, - { - "source_path": "articles/v4sdk/bot-builder-create-middleware.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-concept-middleware", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-builder-deploy-samples.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-deploy-az-cli", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-builder-tools.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-deploy-az-cli", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-service-activity-spec.md", - "redirect_url": "https://github.com/Microsoft/BotBuilder/tree/master/specs/botframework-activity", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-service-build-download-source-code.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-deploy-az-cli", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-service-channel-inspector.md", - "redirect_url": "https://github.com/microsoft/botbuilder-samples", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-service-continuous-deployment.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-build-continuous-deployment", - "redirect_document_id": true - }, - { - "source_path": "articles/bot-service-manage-test-webchat.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-quickstart", - "redirect_document_id": false - }, - { - "source_path": "articles/dotnet/bot-builder-dotnet-core-authentication.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-tutorial-authentication", - "redirect_document_id": true - }, - { - "source_path": "articles/dotnet/bot-builder-dotnet-quickstart.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/dotnet/bot-builder-dotnet-sdk-quickstart", - "redirect_document_id": true - }, - { - "source_path": "articles/dotnet/bot-builder-dotnet-real-time-audio-video-call-overview.md", - "redirect_url": "https://aka.ms/realTimeMediaCalling-repo", - "redirect_document_id": false - }, - { - "source_path": "articles/dotnet/bot-builder-dotnet-real-time-deploy-visual-studio.md", - "redirect_url": "https://aka.ms/realTimeMediaCalling-repo", - "redirect_document_id": false - }, - { - "source_path": "articles/dotnet/bot-builder-dotnet-real-time-media-concepts.md", - "redirect_url": "https://aka.ms/realTimeMediaCalling-repo", - "redirect_document_id": false - }, - { - "source_path": "articles/dotnet/bot-builder-dotnet-real-time-media-requirements.md", - "redirect_url": "https://aka.ms/realTimeMediaCalling-repo", - "redirect_document_id": false - }, - { - "source_path": "articles/dotnet/bot-builder-dotnet-release-notes.md", - "redirect_url": "https://github.com/Microsoft/BotBuilder/releases", - "redirect_document_id": false - }, - { - "source_path": "articles/dotnet/bot-builder-dotnet-samples.md", - "redirect_url": "https://github.com/Microsoft/BotBuilder-Samples/tree/v3-sdk-samples", - "redirect_document_id": false - }, - { - "source_path": "articles/dotnet/index.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/dotnet/bot-builder-dotnet-overview", - "redirect_document_id": false - }, - { - "source_path": "articles/java/bot-builder-java-quickstart.md", - "redirect_url": "https://github.com/Microsoft/botbuilder-java/wiki", - "redirect_document_id": false - }, - { - "source_path": "articles/nodejs/bot-builder-nodejs-dialog-manage-conversation.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/nodejs/bot-builder-nodejs-dialog-manage-conversation-flow", - "redirect_document_id": true - }, - { - "source_path": "articles/nodejs/bot-builder-nodejs-global-handlers.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/nodejs/bot-builder-nodejs-dialog-actions", - "redirect_document_id": false - }, - { - "source_path": "articles/nodejs/bot-builder-nodejs-manage-complex-conversation.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/nodejs/bot-builder-nodejs-dialog-manage-conversation-flow", - "redirect_document_id": false - }, - { - "source_path": "articles/nodejs/bot-builder-nodejs-manage-conversation-flow.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/nodejs/bot-builder-nodejs-dialog-manage-conversation-flow", - "redirect_document_id": false - }, - { - "source_path": "articles/nodejs/bot-builder-nodejs-prompts.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/nodejs/bot-builder-nodejs-dialog-prompt", - "redirect_document_id": true - }, - { - "source_path": "articles/nodejs/bot-builder-nodejs-quickstart.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/javascript/bot-builder-javascript-quickstart", - "redirect_document_id": true - }, - { - "source_path": "articles/nodejs/bot-builder-nodejs-recognize-intent.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/nodejs/bot-builder-nodejs-recognize-intent-messages", - "redirect_document_id": true - }, - { - "source_path": "articles/nodejs/bot-builder-nodejs-samples.md", - "redirect_url": "https://github.com/Microsoft/BotBuilder-Samples/tree/v3-sdk-samples", - "redirect_document_id": false - }, - { - "source_path": "articles/nodejs/bot-builder-nodejs-save-user-data.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/nodejs/bot-builder-nodejs-state", - "redirect_document_id": true - }, - { - "source_path": "articles/nodejs/bot-builder-nodejs-use-default-message-handler.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/nodejs/bot-builder-nodejs-message-create", - "redirect_document_id": true - }, - { - "source_path": "articles/nodejs/index.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/nodejs/bot-builder-nodejs-overview", - "redirect_document_id": true - }, - { - "source_path": "articles/rest-api/bot-framework-rest-direct-line-concepts.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-concepts", - "redirect_document_id": true - }, - { - "source_path": "articles/rest-api/index.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/rest-api/bot-framework-rest-overview", - "redirect_document_id": true - }, - { - "source_path": "articles/v4sdk/bot-builder-dialog-state.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-concept-state", - "redirect_document_id": true - }, - { - "source_path": "articles/v4sdk/bot-builder-how-to-translation.md", - "redirect_url": "https://github.com/Microsoft/BotBuilder-Samples", - "redirect_document_id": false - }, - { - "source_path": "articles/v4sdk/bot-builder-howto-cosmos-middleware.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-howto-v4-storage", - "redirect_document_id": false - }, - { - "source_path": "articles/v4sdk/bot-builder-howto-classic.md", - "redirect_url": "https://github.com/Microsoft/BotBuilder-Samples", - "redirect_document_id": false - }, - { - "source_path": "articles/v4sdk/bot-builder-howto-direct-line.md", - "redirect_url": "https://github.com/Microsoft/BotBuilder-Samples/tree/v3-sdk-samples", - "redirect_document_id": false - }, - { - "source_path": "articles/v4sdk/bot-builder-howto-event-handlers.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-concept-middleware", - "redirect_document_id": false - }, - { - "source_path": "articles/v4sdk/bot-builder-howto-translation.md", - "redirect_url": "https://github.com/Microsoft/BotBuilder-Samples", - "redirect_document_id": false - }, - { - "source_path": "articles/v4sdk/bot-builder-howto-v4-luisgen.md", - "redirect_url": "https://github.com/Microsoft/botbuilder-tools/blob/master/packages/LUISGen/src/npm/readme.md", - "redirect_document_id": true - }, - { - "source_path": "articles/v4sdk/bot-builder-prompts.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-dialog-manage-conversation-flow", - "redirect_document_id": false - }, - { - "source_path": "articles/v4sdk/bot-builder-proactive-messages.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-howto-proactive-message", - "redirect_document_id": true - }, - { - "source_path": "articles/v4sdk/bot-builder-storage-concept.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-howto-v4-storage", - "redirect_document_id": true - }, - { - "source_path": "articles/v4sdk/bot-builder-welcome-user.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-send-welcome-message", - "redirect_document_id": true - }, - { - "source_path": "articles/v4sdk/bot-concepts.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-service-manage-channels", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-service-build-online-code-editor.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-basics", - "redirect_document_id": false - }, - { - "source_path": "articles/bot-service-change-hosting-plan.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-basics", - "redirect_document_id": false - }, - { - "source_path": "articles/v4sdk/bot-builder-howto-add-input-hints.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-howto-add-suggested-actions", - "redirect_document_id": false - }, - { - "source_path": "articles/v4sdk/bot-builder-enterprise-template-overview.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-virtual-assistant-introduction", - "redirect_document_id": true - }, - { - "source_path": "articles/v4sdk/bot-builder-enterprise-template-getting-started.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-skills-overview", - "redirect_document_id": true - }, - { - "source_path": "articles/v4sdk/bot-builder-enterprise-template-customize.md", - "redirect_url": "https://docs.microsoft.com/azure/bot-service/bot-builder-virtual-assistant-template", - "redirect_document_id": true - } - ] -} diff --git a/.ops.mref.csv b/.ops.mref.csv deleted file mode 100644 index fff918464..000000000 --- a/.ops.mref.csv +++ /dev/null @@ -1,4 +0,0 @@ -botbuilder,Microsoft.Bot.Builder,3.12.2.4 -botconnector,Microsoft.Bot.Connector,3.12.2.4 -botbuilder-rtmcalling,Microsoft.Bot.Builder.RealTimeMediaCalling,1.0.4-alpha -skypebotsmedia,Microsoft.Skype.Bots.Media,1.7.0.26-alpha diff --git a/.ops.mref.yaml b/.ops.mref.yaml deleted file mode 100644 index cf4fee6e9..000000000 --- a/.ops.mref.yaml +++ /dev/null @@ -1,47 +0,0 @@ -queue: - name: Default - demands: DotNetFramework - - -steps: -- task: AzureKeyVault@1 - inputs: - ConnectedServiceName: 'APIDrop-Azure' - KeyVaultName: "APIDrop-DotNet-KeyVault" - -- task: PowerShell@1 - inputs: - scriptType: "inlineScript" - arguments: "-ToolingToken $(ToolingToken)" - inlineScript: 'param ([string]$ToolingToken = "NOT_VALID_TOKEN"); $fullUrl = ("https://" + $ToolingToken + "@apidrop.visualstudio.com/binaries/_git/mrefconfig"); git clone $fullUrl -b tooling _buildtools -q' -- task: PowerShell@1 - inputs: - scriptName: "./_buildtools/scripts/mref-provision.ps1" - arguments: "-ToolingToken $(ToolingToken)" - -- task: ExtractFiles@1 - inputs: - archiveFilePatterns: 'dl\*.zip' - destinationFolder: "$(Build.Repository.LocalPath)\_bin" - -- task: PowerShell@1 - inputs: - scriptName: "./_buildtools/scripts/mref-mdoc-exec.ps1" - arguments: "-CredentialToken $(GitHubToken)" - -- task: PublishBuildArtifacts@1 - inputs: - PathtoPublish: '$(Build.Repository.LocalPath)\mdoc-fw-out' - ArtifactName: "$(Build.BuildNumber)-artifacts" - ArtifactType: "Container" - -- task: PublishBuildArtifacts@1 - inputs: - PathtoPublish: '$(Build.Repository.LocalPath)\nue-out' - ArtifactName: "$(Build.BuildNumber)-artifacts" - ArtifactType: "Container" - -- task: PowerShell@1 - inputs: - scriptName: "scripts/trigger-release.ps1" - arguments: "-GitToken $(GitHubToken) -GitUsername $(GitHubUsername) -GitRepoId $(GitHubLocation) -GitBranch $(GitHubBranch) -GitInRepoLocation $(InRepoLocation) -ArtifactPath $(Build.Repository.LocalPath) -ArtifactName $(ArtifactName) -GitEmail $(GitHubCustomEmail)" diff --git a/.vscode/docfx-assistant/topic-cache.json b/.vscode/docfx-assistant/topic-cache.json deleted file mode 100644 index 0637a088a..000000000 --- a/.vscode/docfx-assistant/topic-cache.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..ed9462b7e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "markdownlint.config": { + "MD028": false, + "MD025": { + "front_matter_title": "" + } + } +} \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..f9ba8cf65 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,9 @@ +# Microsoft Open Source Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). + +Resources: + +- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) +- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) +- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns diff --git a/LICENSE b/LICENSE index 57b3c5b98..a2c95fc15 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Attribution 4.0 International +Attribution 4.0 International ======================================================================= @@ -155,7 +155,6 @@ Section 2 -- Scope. 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications diff --git a/LICENSE-CODE b/LICENSE-CODE index b17b032a4..9e841e7a2 100644 --- a/LICENSE-CODE +++ b/LICENSE-CODE @@ -1,17 +1,21 @@ -The MIT License (MIT) -Copyright (c) Microsoft Corporation + MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: + Copyright (c) Microsoft Corporation. -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/README.md b/README.md index 37bf1cf49..50ad99183 100644 --- a/README.md +++ b/README.md @@ -1,87 +1,31 @@ -# Microsoft Open Source Code of Conduct -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. - -# Bot Framework Technical Documentation Contributor Guide -You've found the GitHub repository that houses the source for the Bot Framework technical documentation that is published on [https://docs.microsoft.com/bot-framework](https://docs.microsoft.com/bot-framework). - -This repository also contains guidance to help you contribute to our technical documentation. For a list of the articles in the contributors' guide, see [the index](contributor-guide/contributor-guide-index.md). - -## Contribute to Bot Framework documentation -Thank you for your interest in Bot Framework documentation! - -* [Ways to contribute](#ways-to-contribute) -* [Code of conduct](#code-of-conduct) -* [About your contributions to Bot Framework content](#about-your-contributions-to-bot-framework-content) -* [Repository organization](#repository-organization) -* [Use GitHub, Git, and this repository](#use-github-git-and-this-repository) -* [How to use markdown to format your topic](#how-to-use-markdown-to-format-your-topic) -* [More resources](#more-resources) -* [Index of all contributors' guide articles](contributor-guide/contributor-guide-index.md) (opens new page) - -## Ways to contribute -You can submit updates to the [Bot Framework documentation](https://docs.microsoft.com/bot-framework) as follows: - -* You can easily contribute to technical articles in the GitHub user interface. Either find the article in this repository, or visit the article on [https://docs.microsoft.com/bot-framework](https://docs.microsoft.com/bot-framework) and click the link in the article that goes to the GitHub source for the article. -* If you are making substantial changes to an existing article, adding or changing images, or contributing a new article, you need to fork this repository, install Git Bash, Markdown Pad, and learn some git commands. - -## About your contributions to Bot Framework content -### Minor corrections -Minor corrections or clarifications you submit for documentation and code examples in this repo are covered by the [docs.microsoft.com Terms of Use](https://docs.microsoft.com/legal/termsofuse). - -### Larger submissions -If you submit a pull request with new or significant changes to documentation and code examples, we'll send a comment in GitHub asking you to submit an online Contribution License Agreement (CLA) if you are not an employee of Microsoft. We need you to complete the online form before we can accept your pull request. - -## Repository organization -The content in the Bot Framework-docs repository follows the organization of documentation on https://docs.microsoft.com/bot-framework. This repository contains two root folders: +# Contributing -### \articles -The *\articles* folder contains the documentation articles formatted as markdown files with an *.md* extension. Articles are typically grouped by Bot Framework service. +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. -Articles need to follow strict file naming guidelines - for details, see [our file naming guidance](contributor-guide/file-names-and-locations.md). +When you submit a pull request, a CLA bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. -The *\articles* folder contains the *\media* folder for root directory article media files, inside which are subfolders with the images for each article. The service folders contain a separate media folder for the articles within each service folder. The article image folders are named identically to the article file, minus the *.md* file extension. - -### \includes -You can create reusable content sections to be included in one or more articles. See [Custom extensions used in our technical content](contributor-guide/custom-markdown-extensions.md). - -### \markdown templates -This folder contains our standard markdown template with the basic markdown formatting you need for an article. - -### \contributor-guide -This folder contains articles that are part of our contributors' guide. - -## Use GitHub, Git, and this repository -For information about how to contribute, how to use the GitHub UI to contribute small changes, and how to fork and clone the repository for more significant contributions, see [Install and set up tools for authoring in GitHub](contributor-guide/tools-and-setup.md). - -If you install GitBash and choose to work locally, the steps for creating a new local working branch, making changes, and submitting the changes back to the main branch are listed in [Git commands for creating a new article or updating an existing article](contributor-guide/git-commands-for-master.md) - -### Branches -We recommend that you create local working branches that target a specific scope of change. Each branch should be limited to a single concept/article both to streamline work flow and reduce the possibility of merge conflicts. The following efforts are of the appropriate scope for a new branch: - -* A new article (and associated images) -* Spelling and grammar edits on an article. -* Applying a single formatting change across a large set of articles (e.g. new copyright footer). - -## How to use markdown to format your topic -All the articles in this repository use GitHub flavored markdown. Here's a list of resources. +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. -* [Markdown basics](https://help.github.com/articles/markdown-basics/) -* [Printable markdown cheatsheet](./contributor-guide/media/documents/markdown-cheatsheet.pdf?raw=true) +# Legal Notices -## Article metadata -Article metadata enables certain functionalities, such as author attribution, contributor attribution, breadcrumbs, article descriptions, and SEO optimizations as well as reporting Microsoft uses to evaluate the performance of the content. So, the metadata is important! [Here's the guidance for making sure your metadata is done right](contributor-guide/article-metadata.md). +Microsoft and any contributors grant you a license to the Microsoft documentation and other content +in this repository under the [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/legalcode), +see the [LICENSE](LICENSE) file, and grant you a license to any code in the repository under the [MIT License](https://opensource.org/licenses/MIT), see the +[LICENSE-CODE](LICENSE-CODE) file. -### Labels -Automated labels are assigned to pull requests to help us manage the pull request workflow and to help let you know what's going on with your pull request: +Microsoft, Windows, Microsoft Azure and/or other Microsoft products and services referenced in the documentation +may be either trademarks or registered trademarks of Microsoft in the United States and/or other countries. +The licenses for this project do not grant you rights to use any Microsoft names, logos, or trademarks. +Microsoft's general trademark guidelines can be found at http://go.microsoft.com/fwlink/?LinkID=254653. -* Contribution License Agreement related - * cla-not-required: The change is relatively minor and does not require that you sign a CLA. - * cla-required: The scope of the change is relatively large and requires that you sign a CLA. - * cla-signed: The contributor signed the CLA, so the pull request can now move forward for review. -* Pillar labels: Labels such as PnP, Modern Apps, and TDC help categorize the pull requests by the internal organization that needs to review the pull request. -* Change sent to author: The author has been notified of the pending pull request. +Privacy information can be found at https://privacy.microsoft.com/en-us/ -## More resources -See the [index of our contributor's guide](contributor-guide/contributor-guide-index.md) for all our guidance topics. +Microsoft and any contributors reserve all other rights, whether under their respective copyrights, patents, +or trademarks, whether by implication, estoppel or otherwise. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..f7b89984f --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). + + \ No newline at end of file diff --git a/ThirdPartyNotices b/ThirdPartyNotices deleted file mode 100644 index faceb5a52..000000000 --- a/ThirdPartyNotices +++ /dev/null @@ -1,15 +0,0 @@ -##Legal Notices -Microsoft and any contributors grant you a license to the Microsoft documentation and other content -in this repository under the [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/legalcode), -see the [LICENSE](LICENSE) file, and grant you a license to any code in the repository under the [MIT License](https://opensource.org/licenses/MIT), see the -[LICENSE-CODE](LICENSE-CODE) file. - -Microsoft, Windows, Microsoft Azure and/or other Microsoft products and services referenced in the documentation -may be either trademarks or registered trademarks of Microsoft in the United States and/or other countries. -The licenses for this project do not grant you rights to use any Microsoft names, logos, or trademarks. -Microsoft's general trademark guidelines can be found at https://go.microsoft.com/fwlink/?LinkID=254653. - -Privacy information can be found at https://privacy.microsoft.com/en-us/ - -Microsoft and any contributors reserve all others rights, whether under their respective copyrights, patents, -or trademarks, whether by implication, estoppel or otherwise. \ No newline at end of file diff --git a/art-source/nomnoml/03.welcome-users.md b/art-source/nomnoml/03.welcome-users.md deleted file mode 100644 index 6140ec4f2..000000000 --- a/art-source/nomnoml/03.welcome-users.md +++ /dev/null @@ -1,60 +0,0 @@ -Flow Diagram for sample 03.welcome-users, used in HowTo \ Develop \ **Send welcome message to users**. - -## JavaScript - -```nomnoml - -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[welcomeBot| - [welcomeBot]->[onMembersAdded] - [onMembersAdded]->[welcomeMessage] - [welcomeMessage]->[infoMessage] - [infoMessage]->[patternMessage] - [welcomeBot]->[onMessage] - [onMessage]->[welcomedUserProperty] - [welcomedUserProperty]->[welcomeMessage] - [welcomedUserProperty]->[sendActivity] - [welcomedUserProperty]->[sendIntroCard] -] - - -``` - -## Python - -```nomnoml - -#font: Segoe UI -#fontSize: 12 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 23 -#fill: #def; #acf - -[WelcomeUserBot| - [WelcomeUserBot]->[on_message_activity()] - [on_message_activity()]->[welcome_user_state] - [welcome_user_state]->[welcome_message] - [welcome_user_state]->False[send_activity()] - [welcome_user_state]->True[__send_intro_card()] - [WelcomeUserBot]->[on_members_added_activity()] - [on_members_added_activity()]--[welcome_message] - [welcome_message]--[info_message] - [info_message]--[pattern_message] - [__send_intro_card()]--[hero_cards] - [send_activity()]--[first_message] -] - -``` \ No newline at end of file diff --git a/art-source/nomnoml/05.multi-turn-prompt.md b/art-source/nomnoml/05.multi-turn-prompt.md deleted file mode 100644 index 3f0678a15..000000000 --- a/art-source/nomnoml/05.multi-turn-prompt.md +++ /dev/null @@ -1,101 +0,0 @@ -Diagrams for sample 05.multi-turn-prompt, used in **Implement sequential conversation flow** and **Reuse dialogs** how-to articles. - -## C\# - -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[DialogBot| - [OnTurnAsync] - [OnMessageActivityAsync] -] - -[UserProfileDialog| - [TransportStepAsync]->[NameStepAsync] - [NameStepAsync]->[NameConfirmStepAsync] - [NameConfirmStepAsync]->[AgeStepAsync] - [AgeStepAsync]->[PictureStepAsync] - [PictureStepAsync]->[ConfirmStepAsync] - [ConfirmStepAsync]->[SummaryStepAsync] - [AgePromptValidatorAsync] - [PicturePromptValidatorAsync] -] - -[DialogBot]->[UserProfileDialog] -``` - -## JavaScript - -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[DialogBot| - [onDialog] - [onMessage] -] - -[UserProfileDialog| - [run] - [transportStep]->[nameStep] - [nameStep]->[nameConfirmStep] - [nameConfirmStep]->[ageStep] - [ageStep]->[pictureStep] - [pictureStep]->[confirmStep] - [confirmStep]->[summaryStep] - [agePromptValidator] - [picturePromptValidator] -] - -[DialogBot]->[UserProfileDialog] -``` - -## Python - -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[DialogHelper| - [run_dialog] -] - -[DialogBot| - [on_turn] - [on_message_activity] -] - -[UserProfileDialog| - [transport_step]->[name_step] - [name_step]->[name_confirm_step] - [name_confirm_step]->[age_step] - [age_step]->[confirm_step] - [confirm_step]->[summary_step] - [age_prompt_validator] -] - -[DialogBot]->[DialogHelper] -[DialogBot]->[UserProfileDialog] -``` diff --git a/art-source/nomnoml/11.qnamaker.md b/art-source/nomnoml/11.qnamaker.md deleted file mode 100644 index 3f1dd2b58..000000000 --- a/art-source/nomnoml/11.qnamaker.md +++ /dev/null @@ -1,62 +0,0 @@ -Flow Diagram for sample 11.qnamaker, used in HowTo \ Develop \ **Use QnA Maker to answer questions**. - -## JavaScript - -```nomnoml - -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - - - - [QnABot| - [onMessage] - [qnamaker| - [getAnswers] - ] - [onMessage]->[qnamaker] - ] - - [qnamaker.ai| - knowledgebase - ] - - [QnABot]->[qnamaker.ai] - - -``` - -## Python - -```nomnoml - -#font: Segoe UI -#fontSize: 14 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - - [QnABot| - [on_message_activity] - [qna_maker| - [get_answers] - ] - [on_message_activity]->[qna_maker] - ] - [qnamaker.ai| - knowledgebase - ] - [QnABot]->[qnamaker.ai] - -``` diff --git a/art-source/nomnoml/13.core-bot.md b/art-source/nomnoml/13.core-bot.md deleted file mode 100644 index e854d0d8b..000000000 --- a/art-source/nomnoml/13.core-bot.md +++ /dev/null @@ -1,95 +0,0 @@ -Diagrams for sample 13.core-bot, used in **Add natural language understanding to your bot** and **Handle user interruptions** how-to articles. - -## JavaScript - -```nomnoml - -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[dialogBot| - conversationState - userState - | - [onMessage] -] - -[mainDialog] - -[bookingDialog] - -[bookingDetails| - destination - origin - travelDate -] - -[FlightBookingRecognizer] - -[dialogAndWelcomeBot| - [onMembersAdded] - [CardFactory] - [onMembersAdded]->[CardFactory] -] - -[dialogBot]->[mainDialog] -[mainDialog]->[FlightBookingRecognizer] -[mainDialog]->[bookingDialog] -[bookingDialog]--[bookingDetails] -[FlightBookingRecognizer]--[bookingDetails] - -``` - -## Python - -```nomnoml -#font: Segoe UI -#fontSize: 8 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 45 -#fill: #def; #acf - -[DialogAndWelcomeBot| - [on_members_added_activity] -] - -[DialogBot| - [on_message_activity] - [on_turn]->[conversation_state] - [on_turn]->[user_state] -] - -[DialogHelper| - [run_dialog]] - -[LuisHelper| - [execute_luis_query] -] - -[BookingDetails| - [destination] - [origin] - [travel_date] -] - -[DialogAndWelcomeBot]->[DialogBot] -[DialogAndWelcomeBot]->[MainDialog] -[MainDialog]->[BookingDialog] -[MainDialog]->[BookingDetails] -[LuisHelper]->[BookingDetails] -[MainDialog]->[LuisHelper] -[BookingDialog]->[BookingDetails] -[DialogBot]->[DialogHelper] - -``` \ No newline at end of file diff --git a/art-source/nomnoml/14.nlp-with-dispatch.md b/art-source/nomnoml/14.nlp-with-dispatch.md deleted file mode 100644 index 51ab9bf0e..000000000 --- a/art-source/nomnoml/14.nlp-with-dispatch.md +++ /dev/null @@ -1,44 +0,0 @@ -Flow Diagram for sample 14.nlp-with-dispatch, used in HowTo \ Develop \ **Use multiple LUIS and QnA models**. - -## JavaScript - -```nomnoml - -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[DialogBot| - [onMessage]->[DispatchToTopIntentAsync] - [DispatchToTopIntentAsync]->[processHomeAutomation] - [DispatchToTopIntentAsync]->[processWeather] - [DispatchToTopIntentAsync]->[processSampleQnA] -] -``` - -## Python - -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[DialogBot| - [on_message_activity]->[_dispatch_to_top_intent] - [_dispatch_to_top_intent]->[_process_home_automation] - [_dispatch_to_top_intent]->[_process_weather] - [_dispatch_to_top_intent]->[_process_sample_qna] -] -``` \ No newline at end of file diff --git a/art-source/nomnoml/18.bot-authentication.md b/art-source/nomnoml/18.bot-authentication.md deleted file mode 100644 index 755c86b45..000000000 --- a/art-source/nomnoml/18.bot-authentication.md +++ /dev/null @@ -1,62 +0,0 @@ -Diagrams for sample 18.bot-authentication, used in **Add authentication to your bot via Azure Bot Service** how-to article. - -## JavaScript - -```nomnoml - -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[DialogBot| - [onDialog] - [onMessage] -] - -[LogoutDialog| - [onBeginDialog]->[interrupt] - [onContinueDialog]->[interrupt] - [interrupt]--[connectionName] -] - -[AuthBot]-:>[DialogBot] -[AuthBot]->[MainDialog] -[MainDialog]-:>[LogoutDialog] - -``` - -## Python - -```nomnoml - -#font: Segoe UI -#fontSize: 12 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[DialogBot| - [on_turn] - [on_message_activity] -] - -[LogoutDialog| - [on_begin_dialog]->[_interrupt] - [on_continue_dialog]->[_interrupt] - [_interrupt]--[connectionName] -] -[AuthBot]-:>[DialogBot] -[AuthBot]->[MainDialog] -[MainDialog]-:>[LogoutDialog] - -``` \ No newline at end of file diff --git a/art-source/nomnoml/43.complex-dialog.md b/art-source/nomnoml/43.complex-dialog.md deleted file mode 100644 index 85619cdee..000000000 --- a/art-source/nomnoml/43.complex-dialog.md +++ /dev/null @@ -1,141 +0,0 @@ -Diagrams for sample 43.complex-dialog, used in *Create advanced conversation flow using branches and loops** how-to article. - -## C\# - -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[DialogExtensions| - [Run] -] - -[DialogBot| - [OnTurnAsync] - [OnMessageActivityAsync] -] - -[DialogAndWelcomeBot| - [OnMembersAddedAsync] -] - -[MainDialog| - [InitialStepAsync]->[FinalStepAsync] -] - -[TopLevelDialog| - [NameStepAsync]->[AgeStepAsync] - [AgeStepAsync]->[StartSelectionStepAsync] - [StartSelectionStepAsync]->[AcknowledgementStepAsync] -] - -[ReviewSelectionDialog| - [SelectionStepAsync]->[LoopStepAsync] - [SelectionStepAsync]--[_companyOptions] -] - -[DialogAndWelcomeBot]-:>[DialogBot] -[DialogBot]->[DialogExtensions] -[DialogBot]->[MainDialog] -[MainDialog]->[TopLevelDialog] -[TopLevelDialog]->[ReviewSelectionDialog] -``` - -## JavaScript - -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[DialogBot| - [onDialog] - [onMessage] -] - -[DialogAndWelcomeBot| - [onMembersAdded] -] - -[MainDialog| - [run] - [initialStep]->[finalStep] -] - -[TopLevelDialog| - [nameStep]->[ageStep] - [ageStep]->[startSelectionStep] - [startSelectionStep]->[acknowledgementStep] -] - -[ReviewSelectionDialog| - [selectionStep]->[loopStep] - [selectionStep]--[companyOptions] -] - -[DialogAndWelcomeBot]-:>[DialogBot] -[DialogBot]->[MainDialog] -[MainDialog]->[TopLevelDialog] -[TopLevelDialog]->[ReviewSelectionDialog] -``` - -## Python - -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[DialogHelper| - [run_dialog] -] - -[DialogBot| - [on_turn] - [on_message_activity] -] - -[DialogAndWelcomeBot| - [on_members_added_activity] -] - -[MainDialog| - [initial_step]->[final_step] -] - -[TopLevelDialog| - [name_step]->[age_step] - [age_step]->[start_selection_step] - [start_selection_step]->[acknowledgement_step] -] - -[ReviewSelectionDialog| - [selection_step]->[loop_step] - [selection_step]--[company_options] -] - -[DialogAndWelcomeBot]-:>[DialogBot] -[DialogBot]->[DialogHelper] -[DialogBot]->[MainDialog] -[MainDialog]->[TopLevelDialog] -[TopLevelDialog]->[ReviewSelectionDialog] -``` \ No newline at end of file diff --git a/art-source/nomnoml/44.bot-builder-primitive-prompts.md b/art-source/nomnoml/44.bot-builder-primitive-prompts.md deleted file mode 100644 index e0c30ad3d..000000000 --- a/art-source/nomnoml/44.bot-builder-primitive-prompts.md +++ /dev/null @@ -1,66 +0,0 @@ -Flow Diagram for sample 44.prompt-users-for-input, used in HowTo \ Develop \ **Create your own prompts**. - -## JavaScript - -```nomnoml - -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[customPromptBot| - - [userProfile| - name - age - date - ] - - [conversationFlow| - [lastQuestionAsked] - - [question| - name - age - date - ] - ] - - [onMessage]->[userProfile] - [onMessage]->[conversationFlow] - [lastQuestionAsked]->[question] -] - -``` -## Python - -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[CustomPromptBot]->[UserProfile] -[CustomPromptBot]->[ConversationFlow] -[UserProfile| - [name] - [age] - [date]] -[ConversationFlow| -[last_question_asked]->[Question| -[NAME] -[AGE] -[DATE] -[NONE]]] -``` diff --git a/art-source/nomnoml/45.state-management.md b/art-source/nomnoml/45.state-management.md deleted file mode 100644 index f54b81a77..000000000 --- a/art-source/nomnoml/45.state-management.md +++ /dev/null @@ -1,65 +0,0 @@ -Flow Diagram for sample 45.state-management, used in HowTo \ Develop \ **Save user and conversation data**. - -## JavaScript - -```nomnoml - -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[stateManagementBot| - - [userProfile| - name - ] - - [conversationData| - timeStamp - channelId - promptedForUserName - ] - - [onMessage]->[userProfile] - [onMessage]->[conversationData] -] - -``` - -## Python - -```nomnoml - -#font: Segoe UI -#fontSize: 16 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf - -[StateManagementBot| - - [UserProfile| - name - ] - - [ConversationData| - timestamp - channel_id - prompted_for_user_name - ] - - [on_message_activity]->[UserProfile] - [on_message_activity]->[ConversationData] -] - -``` diff --git a/art-source/nomnoml/80.skills-simple-bot-to-bot.md b/art-source/nomnoml/80.skills-simple-bot-to-bot.md deleted file mode 100644 index fbe63283c..000000000 --- a/art-source/nomnoml/80.skills-simple-bot-to-bot.md +++ /dev/null @@ -1,188 +0,0 @@ -Flow diagrams for sample 80.skills-simple-bot-to-bot, used for articles in the HowTo \ Develop \ Skills section. - -## For [Implement a skill](/articles/v4sdk/skill-implement-skill.md) - -### JavaScript - -```nomnoml - -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf -#direction: right -#.package: direction=down - -[ EchoSkillBot | - [echoBot]-[adapter] - [adapter]+->[AuthenticationConfiguration] - [AuthenticationConfiguration]-->[allowedCallersClaimsValidator] -] - -[SimpleRootBot]-[EchoSkillBot] - -``` - -### Python - -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf -#direction: right -#.package: direction=down - -[ EchoSkillBot | - [EchoBot]->[ADAPTER] - [ADAPTER]->[AuthenticationConfiguration] - [AuthenticationConfiguration]->[AllowedCallersClaimsValidator] -] - -[RootBot]-[EchoSkillBot] -``` - -## For [Implement a skill consumer](/articles/v4sdk/skill-implement-consumer.md) - -### Python -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf -#direction: right -#.package: direction=down - -[ RootBot | -[SkillHandler] -> [ADAPTER] - [ADAPTER]-> [AuthenticationConfiguration] - [AuthenticationConfiguration] -> [AllowedSkillsClaimsValidator] -[SkillHandler] -> [BOT] - [BOT] -> [SkillConfiguration] - [BOT] -> [SkillHttpClient] - - -[SkillHttpClient]->[SkillConversationIdFactory] -[SkillHttpClient]->[SimpleCredentialProvider] - -[SkillHandler] -> [SkillConversationIdFactory] -[SkillHandler] -> [SimpleCredentialProvider] -[SkillHandler] -> [AuthenticationConfiguration] -] - -[RootBot]-[EchoSkillBot] -``` - -### Python - take 2 - -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf -#direction: right -#.package: direction=down - -[ simple-root-bot | - [SkillConfiguration]<--[BOT] - [BOT]-[ADAPTER] - [ADAPTER]+->[AuthenticationConfiguration] - [SKILL_HANDLER]+->[AuthenticationConfiguration] - [AuthenticationConfiguration]-->[AllowedSkillsClaimsValidator] - - [BOT]->[CLIENT] - [SkillConfiguration]<--[CLIENT] - [ADAPTER]<-[SKILL_HANDLER] - [BOT]<--[SKILL_HANDLER] - - [CLIENT]-[ID_FACTORY] - [ID_FACTORY]-[SKILL_HANDLER] -] - -[simple-root-bot]-[echo-skill-bot] -``` - -### JavaScript - -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf -#direction: right -#.package: direction=down - -[ SimpleRootBot | - [botFrameworkSkill]<--[bot] - [bot]-[adapter] - [adapter]+->[AuthenticationConfiguration] - [handler]+->[AuthenticationConfiguration] - [AuthenticationConfiguration]-->[allowedSkillsClaimsValidator] - - [bot]->[skillClient] - [botFrameworkSkill]<--[skillClient] - [adapter]<-[handler] - [bot]<--[handler] - - [skillClient]-[conversationIdFactory] - [conversationIdFactory]-[handler] -] - -[SimpleRootBot]-[EchoSkillBot] -``` - -## For [Add claims validation](/articles/v4sdk/skill-add-claims-validation.md) - -### JavaScript - -```nomnoml -#font: Segoe UI -#fontSize: 9 -#lineWidth: 1 -#arrowSize: 1 -#bendSize:0.3 -#edges: rounded -#padding: 8 -#spacing: 16 -#fill: #def; #acf -#direction: right -#.package: direction=down - -[ SimpleRootBot | - [rootBot]-[adapterWithErrorHandler] - [adapterWithErrorHandler]-->[authenticationConfiguration] - [skillHandler]-->[authenticationConfiguration] -] - -[ EchoSkillBot | - [echoBot]-[skillAdapterWithErrorHandler] - [skillAdapterWithErrorHandler]-->[authenticationConfiguration] -] - -[SimpleRootBot]-[EchoSkillBot] -``` diff --git a/art-source/power-point/JS-logic-flow-images.pptx b/art-source/power-point/JS-logic-flow-images.pptx deleted file mode 100644 index 9cb545ef3..000000000 Binary files a/art-source/power-point/JS-logic-flow-images.pptx and /dev/null differ diff --git a/art-source/power-point/bot-concepts-art.pptx b/art-source/power-point/bot-concepts-art.pptx deleted file mode 100644 index 6a90602fa..000000000 Binary files a/art-source/power-point/bot-concepts-art.pptx and /dev/null differ diff --git a/art-source/power-point/bot-skills-art.pptx b/art-source/power-point/bot-skills-art.pptx deleted file mode 100644 index 05a39f589..000000000 Binary files a/art-source/power-point/bot-skills-art.pptx and /dev/null differ diff --git a/articles/TOC.md b/articles/TOC.md deleted file mode 100644 index 8dbfea1e8..000000000 --- a/articles/TOC.md +++ /dev/null @@ -1,89 +0,0 @@ -# [Azure Bot Service Documentation](index.yml) -# Overview -## [About Azure Bot Service](bot-service-overview-introduction.md) -## [What's new](what-is-new.md) -# Quickstart -## [Create a bot using .NET](dotnet/bot-builder-dotnet-sdk-quickstart.md) -## [Create a bot using JavaScript](javascript/bot-builder-javascript-quickstart.md) -## [Create a bot using Python](python/bot-builder-python-quickstart.md) -## [Create a bot using Azure Bot Service](v4sdk/abs-quickstart.md) -# Tutorials -## [1. Create and deploy a basic bot](v4sdk/bot-builder-tutorial-basic-deploy.md) -## [2. Add QnA Maker and redeploy a bot](v4sdk/bot-builder-tutorial-add-qna.md) -## [Add authentication to your bot](bot-builder-tutorial-authentication.md) -# Samples -## [Bot Framework samples repo on GitHub](https://github.com/Microsoft/BotBuilder-Samples/blob/master/README.md) -# Concepts -## [How bots work](v4sdk/bot-builder-basics.md) -## [Managing state](v4sdk/bot-builder-concept-state.md) -## [Dialogs library](v4sdk/bot-builder-concept-dialog.md) -## [Middleware](v4sdk/bot-builder-concept-middleware.md) -## [User authentication](v4sdk/bot-builder-concept-authentication.md) -## [Manage bot resources](v4sdk/bot-file-basics.md) -## [How bots for Microsoft Teams work](v4sdk/bot-builder-basics-teams.md) -## [About skills](v4sdk/skills-conceptual.md) - -## [Bot Service templates](bot-service-concept-templates.md) -## [Cognitive Services](bot-service-concept-intelligence.md) -## [Key scenarios for bots](bot-service-scenario-overview.md) -### [Commerce bot](bot-service-scenario-commerce.md) -### [Cortana Skill bot](bot-service-scenario-cortana-skill.md) -### [Enterprise Productivity bot](bot-service-scenario-enterprise-productivity.md) -### [Information bot](bot-service-scenario-informational.md) -### [Internet of Things bot](bot-service-scenario-internet-things.md) -# How-To -## [Design](design/TOC.md) -## Develop - -### [Send and receive text message](v4sdk/bot-builder-howto-send-messages.md) -### [Add media to messages](v4sdk/bot-builder-howto-add-media-attachments.md) -### [Add buttons to guide user action](v4sdk/bot-builder-howto-add-suggested-actions.md) -### [Save user and conversation data](v4sdk/bot-builder-howto-v4-state.md) -### [Prompt users for input](v4sdk/bot-builder-primitive-prompts.md) -### [Send welcome message to users](v4sdk/bot-builder-send-welcome-message.md) -### [Send proactive notifications to users](v4sdk/bot-builder-howto-proactive-message.md) -### [Implement sequential conversation flow](v4sdk/bot-builder-dialog-manage-conversation-flow.md) -### [Add natural language understanding to your bot](v4sdk/bot-builder-howto-v4-luis.md) -### [Answer user's questions using QnA Maker](v4sdk/bot-builder-howto-qna.md) -### [Use multiple LUIS and QnA models](v4sdk/bot-builder-tutorial-dispatch.md) -### [Create advanced conversation flow using branches and loops](v4sdk/bot-builder-dialog-manage-complex-conversation-flow.md) -### [Reuse dialogs](v4sdk/bot-builder-compositcontrol.md) - -### [Handle user interruptions](v4sdk/bot-builder-howto-handle-user-interrupt.md) -### [Write directly to storage](v4sdk/bot-builder-howto-v4-storage.md) -### [Add authentication to your bot](v4sdk/bot-builder-authentication.md) -### [Implement custom storage for your bot](v4sdk/bot-builder-custom-storage.md) -### Skills -#### [Implement a skill](v4sdk/skill-implement-skill.md) -#### [Implement a skill consumer](v4sdk/skill-implement-consumer.md) - -### [Add telemetry to your bot](v4sdk/bot-builder-telemetry.md) -### [Add telemetry to your QnA bot](v4sdk/bot-builder-telemetry-QnAMaker.md) -### [Analyze your bot's telemetry data](v4sdk/bot-builder-telemetry-analytics-queries.md) -### [Use Direct Line Speech in your bot](directline-speech-bot.md) -### [.NET](dotnet/TOC.md) -### [Node.js](nodejs/TOC.md) -## Test -### [Unit testing bots](v4sdk/unit-test-bots.md) -### [Add trace activities to your bot](v4sdk/using-trace-activities.md) -## [Debug](debug/TOC.md) -## Deploy -### [Deploy your bot to Azure](bot-builder-deploy-az-cli.md) -### [Set up continuous deployment](bot-service-build-continuous-deployment.md) -## [Manage](manage/TOC.md) -## [Migrate](v4sdk/migration/TOC.md) -# Reference -## [.NET SDK v4](https://aka.ms/botframework-v4-cs-sdk) -## [JavaScript SDK v4](https://aka.ms/bot-jssdk-v4) -## [Python SDK v4](https://aka.ms/botframework-v4-python-sdk) -## [REST](rest-api/TOC.md) -## [.NET SDK v3](https://aka.ms/botframework-v3-cs-sdk) -## [Node.js SDK v3](https://aka.ms/bot-jssdk-v3) -## BF CLI tool reference -### [BF CLI overview](v4sdk/bf-cli-overview.md) -### [BF CLI reference](v4sdk/bf-cli-reference.md) -## [Entities and activity types](bot-service-activities-entities.md) -# [Resources](resources/TOC.md) diff --git a/articles/bot-builder-deploy-az-cli.md b/articles/bot-builder-deploy-az-cli.md deleted file mode 100644 index f26d75279..000000000 --- a/articles/bot-builder-deploy-az-cli.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: Deploy your bot - Bot Service -description: Deploy your bot to the Azure cloud -keywords: deploy bot, azure deploy bot, publish bot -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: conceptual -ms.service: bot-service -ms.date: 08/06/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Deploy your bot - -[!INCLUDE [applies-to](./includes/applies-to.md)] - -In this article we will show you how to deploy a basic bot to Azure. We will explain how to prepare your bot for deployment, deploy your bot to Azure, and test your bot in Web Chat. It would be useful to read this article before following the steps, so that you fully understand what is involved in deploying a bot. - -## Prerequisites - -[!INCLUDE [deploy prerequisite](~/includes/deploy/snippet-prerequisite.md)] - -## Prepare for deployment - -[!INCLUDE [deploy prepare intro](~/includes/deploy/snippet-prepare-deploy-intro.md)] - -### 1. Login to Azure - -[!INCLUDE [deploy az login](~/includes/deploy/snippet-az-login.md)] - -### 2. Set the subscription - -[!INCLUDE [deploy az subscription](~/includes/deploy/snippet-az-set-subscription.md)] - - -### 3. Create the application registration - -[!INCLUDE [deploy create app registration](~/includes/deploy/snippet-create-app-registration.md)] - - -### 4. Create the bot application service - -When creating the bot application service, you can deploy your bot in a new or in an existing resource group. Choose the option that works best for you. - -Make sure that you have the correct path to your bot project ARM deployment templates directory `DeploymentTemplates`, you need it to assign the value to `template-file`. - - -> [!NOTE] -> Python bots cannot be deployed to a resource group that contains Windows services/bots. Multiple Python bots can be deployed to the same resource group, but create other services (LUIS, QnA, etc.) in another resource group. - - -#### **Deploy via ARM template (with **new** Resource Group)** - - -[!INCLUDE [ARM with new resourece group](~/includes/deploy/snippet-ARM-new-resource-group.md)] - - -#### **Deploy via ARM template (with **existing** Resource Group)** - -[!INCLUDE [ARM with existing resourece group](~/includes/deploy/snippet-ARM-existing-resource-group.md)] - ---- - -### 5. Prepare your code for deployment - -#### 5.1 Retrieve or create necessary IIS/Kudu files - -[!INCLUDE [retrieve or create IIS/Kudu files](~/includes/deploy/snippet-IIS-Kudu-files.md)] - - -#### 5.2 Zip up the code directory manually - -[!INCLUDE [zip up code](~/includes/deploy/snippet-zip-code.md)] - - -## Deploy code to Azure - -[!INCLUDE [deploy code to Azure](~/includes/deploy/snippet-deploy-code-to-az.md)] - - -## Test in Web Chat - -[!INCLUDE [test in web chat](~/includes/deploy/snippet-test-in-web-chat.md)] - - -## Additional information - -Deploying your bot to Azure will involve paying for the services you use. The [billing and cost management](https://docs.microsoft.com/azure/billing/) article helps you understand Azure billing, monitor usage and costs, and manage your account and subscriptions. - -## Next steps - -> [!div class="nextstepaction"] -> [Set up continuous deployment](bot-service-build-continuous-deployment.md) - - diff --git a/articles/bot-builder-tutorial-authentication.md b/articles/bot-builder-tutorial-authentication.md deleted file mode 100644 index 9715a79f5..000000000 --- a/articles/bot-builder-tutorial-authentication.md +++ /dev/null @@ -1,361 +0,0 @@ ---- -title: Add authentication to your bot via Azure Bot Service - Bot Service -description: Learn how to use the Azure Bot Service authentication features to add SSO to your bot. -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ROBOTS: NOINDEX -ms.date: 11/14/2019 -monikerRange: 'azure-bot-service-3.0' ---- - -# Add authentication to your bot via Azure Bot Service - -[!INCLUDE [pre-release-label](includes/pre-release-label-v3.md)] - -This tutorial uses new bot authentication capabilities in Azure Bot Service, providing features to make it easier to develop a bot that authenticates users to various identity providers such as Azure AD (Azure Active Directory), GitHub, Uber, and so on. These updates also take steps towards an improved user experience by eliminating the _magic code verification_ for some clients. - -Prior to this, your bot needed to include OAuth controllers and login links, store the target client IDs and secrets, and perform user token management. - - -Now, bot developers no longer need to host OAuth controllers or manage the token life-cycle, as all of this can now be done by the Azure Bot Service. - -The features include: - -- Improvements to the channels to support new authentication features, such as new WebChat and DirectLineJS libraries to eliminate the need for the 6-digit magic code verification. -- Improvements to the Azure Portal to add, delete, and configure connection settings to various OAuth identity providers. -- Support for a variety of out-of-the-box identity providers including Azure AD (both v1 and v2 endpoints), GitHub, and others. -- Updates to the C# and Node.js Bot Framework SDKs to be able to retrieve tokens, create OAuthCards and handle TokenResponse events. -- Samples for how to make a bot that authenticates to Azure AD (v1 and v2 endpoints) and to GitHub. - -You can extrapolate from the steps in this article to add such features to an existing bot. The following are sample bots that demonstrate the new authentication features - -| Sample | BotBuilder version | Description | -|:---|:---:|:---| -| [AadV1Bot](https://aka.ms/AadV1Bot) | v3 | Demonstrates OAuthCard support in the v3 C# SDK, using the Azure AD v1 endpoint | -| [AadV2Bot](https://aka.ms/AadV2Bot) | v3 | Demonstrates OAuthCard support in the v3 C# SDK, using the Azure AD v2 endpoint | -| [GitHubBot](https://aka.ms/GitHubBot) | v3 | Demonstrates OAuthCard support in the v3 C# SDK, using GitHub | -| [BasicOAuth](https://aka.ms/BasicOAuth) | v3 | Demonstrates OAuth 2.0 support in the v3 C# SDK | - -> [!NOTE] -> The authentication features also work with Node.js with BotBuilder v3. However, this article covers just sample C# code. - -For additional information and support, refer to [Bot Framework additional resources](https://docs.microsoft.com/azure/bot-service/bot-service-resources-links-help). - -## Overview - -This tutorial creates a sample bot that connects to the Microsoft Graph using an Azure AD v1 or v2 token. As part of this process, you'll use code from a GitHub repo, and this tutorial describes how to set that up, including the bot application. - -- [Create your bot and an authentication application](#create-your-bot-and-an-authentication-application) -- [Prepare the bot sample code](#prepare-the-bot-sample-code) -- [Use the Emulator to test your bot](#use-the-emulator-to-test-your-bot) - -To complete these steps, you will need Visual Studio 2017, npm, node, and git installed. You should also have some familiarity with Azure, OAuth 2.0, and bot development. - -Once you finish, you will have a bot that can respond to a few simple tasks against an Azure AD application, such as checking and sending an email, or displaying who you are and who your manager is. To do this, your bot will use a token from an Azure AD application against the Microsoft.Graph library. - -The final section breaks down some of the bot code - -- [Notes on the token retrieval flow](#notes-on-the-token-retrieval-flow) - -## Create your bot and an authentication application - -You need to create a registration bot where you'll set the messaging endpoint to your deployed bot's code, and you need to create an Azure AD (either v1 or v2) application to allow your bot to access Office 365. - -> [!NOTE] -> These authentication features work with other types of bots. However this tutorial uses a registration only bot. - -### Register an application in Azure AD - -You need an Azure AD application that your bot can use as an identity provider to connect to the Microsoft Graph API. - -For this bot you can use Azure AD v1 or v2 endpoints. -For information about the differences between the v1 and v2 endpoints, see the [v1-v2 comparison](https://docs.microsoft.com/azure/active-directory/develop/active-directory-v2-compare) and the [Azure AD v2.0 endpoint overview](https://docs.microsoft.com/azure/active-directory/develop/active-directory-appmodel-v2-overview). - -#### Create an Azure AD identity provider application - -Use these steps to create a new Azure AD application. You can use the v1 or v2 endpoints with the app that you create. - -> [!TIP] -> You will need to create and register the Azure AD application in a tenant -> in which you can consent to delegate permissions requested by an application. - -1. Open the [Azure Active Directory][azure-aad-blade] panel in the Azure portal. - If you are not in the correct tenant, click **Switch directory** to switch to the correct tenant. (For instruction on creating a tenant, see [Access the portal and create a tenant](https://docs.microsoft.com/azure/active-directory/fundamentals/active-directory-access-create-new-tenant).) -1. Open the **App registrations** panel. -1. In the **App registrations** panel, click **New registration**. -1. Fill in the required fields and create the app registration. - - 1. Name your application. - 1. Select the **Supported account types** for your application. - 1. For the **Redirect URI** - 1. Select **Web**. - 1. Set the URL to `https://token.botframework.com/.auth/web/redirect`. - 1. Click **Register**. - - - Once it is created, Azure displays the **Overview** page for the app. - - Record the **Application (client) ID** value. You will use this value later as the _Client id_ when you register your Azure AD application with your bot. - - Also record the **Directory (tenant) ID** value. You will also use this to register this application with your bot. - - > [!NOTE] - > When the supported account types is set to single tenant, if you use a personal subscription instead of a Microsoft account, the emulator would issue the error: *The bot's Microsoft App ID or Microsoft App Password is incorrect..* - > In this case, the supported account types must be set to *Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)*. - -1. In the navigation pane, click **Certificates & secrets** to create a secret for your application. - - 1. Under **Client secrets**, click **New client secret**. - 1. Add a description to identify this secret from others you might need to create for this app, such as `bot login`. - 1. Set **Expires** to **Never**. - 1. Click **Add**. - 1. Before leaving this page, record the secret. You will use this value later as the _Client secret_ when you register your Azure AD application with your bot. - -1. In the navigation pane, click **API permissions** to open the **API permissions** panel. It is a best practice to explicitly set the API permissions for the app. - - 1. Click **Add a permission** to show the **Request API permissions** pane. - 1. For this sample, select **Microsoft APIs** and **Microsoft Graph**. - 1. Choose **Delegated permissions** and make sure the permissions you need are selected. This sample requires theses permissions. - - > [!NOTE] - > Any permission marked as **ADMIN CONSENT REQUIRED** will require both a user and a tenant admin to login, so for your bot tend to stay away from these. - - - **openid** - - **profile** - - **Mail.Read** - - **Mail.Send** - - **User.Read** - - **User.ReadBasic.All** - - 1. Click **Add permissions**. (The first time a user accesses this app through the bot, they will need to grant consent.) - -You now have an Azure AD application configured. - -### Create your bot on Azure - -Create a **Bot Channels Registration** using the [Azure Portal](https://portal.azure.com/). - -### Register your Azure AD application with your bot - -The next step is to register with your bot the Azure AD application that you just created. - -# [Azure AD v1](#tab/aadv1) - -1. Navigate to your bot's resource page on the [Azure Portal](https://portal.azure.com/). -1. Click **Settings**. -1. Under **OAuth Connection Settings** near the bottom of the page, click **Add Setting**. -1. Fill in the form as follows: - - 1. For **Name**, enter a name for your connection. You'll use this name in your bot code. - 1. For **Service Provider**, select **Azure Active Directory**. Once you select this, the Azure AD-specific fields will be displayed. - 1. For **Client id**, enter the application (client) ID that you recorded for your Azure AD v1 application. - 1. For **Client secret**, enter the secret that you created to grant the bot access to the Azure AD app. - 1. For **Grant Type**, enter `authorization_code`. - 1. For **Login URL**, enter `https://login.microsoftonline.com`. - 1. For **Tenant ID**, enter the directory (tenant) ID that your recorded earlier for your Azure AD app. - - This will be the tenant associated with the users who can be authenticated. - - 1. For **Resource URL**, enter `https://graph.microsoft.com/`. - 1. Leave **Scopes** blank. - -1. Click **Save**. - -> [!NOTE] -> These values enable your application to access Office 365 data via the Microsoft Graph API. - -# [Azure AD v2](#tab/aadv2) - -1. Navigate to your bot's Bot Channels Registration page on the [Azure Portal](https://portal.azure.com/). -1. Click **Settings**. -1. Under **OAuth Connection Settings** near the bottom of the page, click **Add Setting**. -1. Fill in the form as follows: - - 1. For **Name**, enter a name for your connection. You'll use it in your bot code. - 1. For **Service Provider**, select **Azure Active Directory v2**. Once you select this, the Azure AD-specific fields will be displayed. - 1. For **Client id**, enter the application (client) ID that you recorded for your Azure AD v1 application. - 1. For **Client secret**, enter the secret that you created to grant the bot access to the Azure AD app. - 1. For **Tenant ID**, enter the directory (tenant) ID that your recorded earlier for your Azure AD app. - - This will be the tenant associated with the users who can be authenticated. - - 1. For **Scopes**, enter the names of the permission you chose from application registration: - `Mail.Read Mail.Send openid profile User.Read User.ReadBasic.All`. - - > [!NOTE] - > For Azure AD v2, **Scopes** takes a case-sensitive, space-separated list of values. - -1. Click **Save**. - -> [!NOTE] -> These values enable your application to access Office 365 data via the Microsoft Graph API. - ---- - -#### To test your connection - -1. Open the connection you just created. -1. Click **Test Connection** at the top of the **Service Provider Connection Setting** pane. -1. The first time, this should open a new browser tab listing the permissions your app is requesting and prompt you to accept. -1. Click **Accept**. -1. This should then redirect you to a **Test Connection to `' Succeeded** page. - -## Prepare the bot sample code - -1. Clone the github repository at https://github.com/Microsoft/BotBuilder. -1. Open and build the solution, `BotBuilder\CSharp\Microsoft.Bot.Builder.sln`. -1. Close that solution and open, `BotBuilder\CSharp\Samples\Microsoft.Bot.Builder.Samples.sln`. -1. Set the start up project. - - For a bot that uses the v1 Azure AD application, use the `Microsoft.Bot.Sample.AadV1Bot` project. - - For a bot that uses the v2 Azure AD application, use the `Microsoft.Bot.Sample.AadV2Bot` project. -1. Open the `Web.config` file, and modify the app settings as follows: - 1. Set the `ConnectionName` to the value you used when you configured your bot's OAuth 2.0 connection setting. - 1. Set the `MicrosoftAppId` value to your bot's app ID. - 1. Set the `MicosoftAppPassword` value to your bot's secret. - - > [!IMPORTANT] - > Depending on the characters in your secret, you may need to XML escape the password. For example, any ampersands (&) will need to be encoded as `&`. - - ```xml - - - - - - ``` - - If you do not know how to get your **Microsoft app ID** and **Microsoft app password** values, you can either create a new password as described here: - [bot-channels-registration-password](bot-service-quickstart-registration.md#get-registration-password) - Or retrieve the **Microsoft app ID** and **Microsoft app password** provisioned with the **Bot Channels Registration** from the deployement described here: - [find-your-azure-bots-appid-and-appsecret](https://blog.botframework.com/2018/07/03/find-your-azure-bots-appid-and-appsecret) - - > [!NOTE] - > You could now publish this bot code to your Azure subscription (right-click on the project and choose **Publish**), but it is not necessary for this tutorial. You would need to set up a publishing configuration that uses the application and hosting plan that you used when configuration the bot in the Azure Portal. - -## Use the Emulator to test your bot - -You will need to install the [Bot Emulator](https://github.com/Microsoft/BotFramework-Emulator) to test your bot locally. You can use the v3 or v4 Emulator. - -1. Start your bot (with or without debugging). -1. Note the localhost port number for the page. You will need this information to interact with your bot. -1. Start the Emulator. -1. Connect to your bot. - - If you haven't configured the connection already, provide the address and your bot's Microsoft app ID and password. Add `/api/messages` to the bot's URL. Your URL will look something like `http://localhost:portNumber/api/messages`. - -1. Type `help` to see a list of available commands for the bot, and test the authentication features. -1. Once you've signed in, you don't need to provide your credentials again until you sign out. -1. To sign out, and cancel your authentication, type `signout`. - - - -> [!NOTE] -> Bot authentication requires use of the Bot Connector Service. The service accesses the bot channels registration information for your bot, which is why you need to set your bot's messaging endpoint on the portal. Authentication also requires the use of HTTPS, which is why you needed to create an HTTPS forwarding address for your bot running locally. - - - -## Notes on the token retrieval flow - -When a user asks the bot to do something that requires the bot to have the user logged in, the bot can use the `Microsoft.Bot.Builder.Dialogs.GetTokenDialog` to initiate retrieving a token for a given connection. The next couple of snippets are taken from the `GetTokenDialog` class. - -### Check for a cached token - -In this code, first the bot does a quick check to determine if the Azure Bot Service already has a token for the user (which is identified by the current Activity sender) and the given ConnectionName (which is the connection name used in configuration). Azure Bot Service will either already have a token cached or it will not. The call to GetUserTokenAsync performs this ‘quick check'. If Azure Bot Service has a token and returns it, the token can immediately be used. If Azure Bot Service does not have a token, this method will return null. In this case, the bot can send a customized OAuthCard for the user to login. - -```csharp -// First ask Bot Service if it already has a token for this user -var token = await context.GetUserTokenAsync(ConnectionName).ConfigureAwait(false); -if (token != null) -{ - // use the token to do exciting things! -} -else -{ - // If Bot Service does not have a token, send an OAuth card to sign in - await SendOAuthCardAsync(context, (Activity)context.Activity); -} -``` - -### Send an OAuthCard to the user - -You can customize the OAuthCard with whatever text and button text you want. The important pieces are: - -- Set the `ContentType` to `OAuthCard.ContentType`. -- Set the `ConnectionName` property to the name of the connection you want to use. -- Include one button with a `CardAction` of `Type` `ActionTypes.Signin`; note that you do not need to specify any value for the sign in link. - -At the end of this call, the bot needs to "wait for the token" to come back. This waiting takes place on the main Activity stream because there could be a lot the user needs to do to sign-in. - -```csharp -private async Task SendOAuthCardAsync(IDialogContext context, Activity activity) -{ - await context.PostAsync($"To do this, you'll first need to sign in."); - - var reply = await context.Activity.CreateOAuthReplyAsync(_connectionName, _signInMessage, _buttonLabel).ConfigureAwait(false); - await context.PostAsync(reply); - - context.Wait(WaitForToken); -} -``` - -### Wait for a TokenResponseEvent - -In this code the Bot's dialog class is waiting for a `TokenResponseEvent` (more about how this is routed to the Dialog stack is below). The `WaitForToken` method first determines if this event was sent. If it was sent, it can be used by the bot. If it was not, the `WaitForToken` method takes whatever text was sent to the bot and passes it to `GetUserTokenAsync`. The reason for this is that some clients (like WebChat) do not need the Magic Code verification code and can directly send the Token in the `TokenResponseEvent`. Other clients still require the magic code (like Facebook or Slack). The Azure Bot Service will present these clients with a six digit magic code and ask the user to type this into the chat window. While not ideal, this is the 'fall back' behavior and so if `WaitForToken` receives a code, the bot can send this code to the Azure Bot Service and get a token back. If this call also fails, then you can decide to report an error, or do something else. In most cases though, the bot will now have a user token. - -If you look in the **MessageController.cs** file, you'll see that `Event` activities of this type are also routed to the dialog stack. - -```csharp -private async Task WaitForToken(IDialogContext context, IAwaitable result) -{ - var activity = await result as Activity; - - var tokenResponse = activity.ReadTokenResponseContent(); - if (tokenResponse != null) - { - // Use the token to do exciting things! - } - else - { - if (!string.IsNullOrEmpty(activity.Text)) - { - tokenResponse = await context.GetUserTokenAsync(ConnectionName, - activity.Text); - if (tokenResponse != null) - { - // Use the token to do exciting things! - return; - } - } - await context.PostAsync($"Hmm. Something went wrong. Let's try again."); - await SendOAuthCardAsync(context, activity); - } -} -``` - -### Message controller - -On subsequent calls to the bot, notice that the token is never cached by this sample bot. This is because the bot can always ask the Azure Bot Service for the token. This avoids the bot needing to manage the token life-cycle, refresh the token, etc, as Azure Bot Service does all of this for you. - -```csharp -else if(message.Type == ActivityTypes.Event) -{ - if(message.IsTokenResponseEvent()) - { - await Conversation.SendAsync(message, () => new Dialogs.RootDialog()); - } -} -``` -## Additional resources -[Bot Framework SDK](https://github.com/microsoft/botbuilder) diff --git a/articles/bot-service-activities-entities.md b/articles/bot-service-activities-entities.md deleted file mode 100644 index 38a1c1bb4..000000000 --- a/articles/bot-service-activities-entities.md +++ /dev/null @@ -1,167 +0,0 @@ ---- -title: Entities and activity types - Bot Service -description: Entities and activity types. -keywords: mention entities, activity types, consume entities -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 03/01/2018 ---- -# Entities and activity types - -Entities are a part of an activity, and provide additional information about the activity or conversation. - -[!include[Entity boilerplate](includes/snippet-entity-boilerplate.md)] - -## Entities - -The *entities* property of a message is an array of open-ended schema.org -objects which allows the exchange of common contextual metadata between the channel and bot. - -### Mention entities - -Many channels support the ability for a bot or user to "mention" someone within the context of a conversation. -To mention a user in a message, populate the message's entities property with a *mention* object. -The mention object contains these properties: - -| Property | Description | -|----|----| -| Type | type of the entity ("mention") | -| Mentioned | channel account object that indicates which user was mentioned | -| Text | text within the *activity.text* property that represents the mention itself (may be empty or null) | - -This code example shows how to add a mention entity to the entities collection. - -# [C#](#tab/cs) -[!code-csharp[set Mention](includes/code/dotnet-create-messages.cs#setMention)] - -> [!TIP] -> When attempting to determine user intent, the bot may want to ignore that portion -> of the message where it is mentioned. Call the `GetMentions` method and evaluate -> the `Mention` objects returned in the response. - -# [JavaScript](#tab/js) -```javascript -var entity = context.activity.entities; - -const mention = { - type: "Mention", - text: "@johndoe", - mentioned: { - name: "John Doe", - id: "UV341235" - } -} - -entity = [mention]; -``` - ---- - -### Place objects - -Location-related information can be conveyed -within a message by populating the message's entities property with either -a *Place* object or a *GeoCoordinates* object. - -The place object contains these properties: - -| Property | Description | -|----|----| -| Type | type of the entity ("Place") | -| Address | description or postal address object (future) | -| Geo | GeoCoordinates | -| HasMap | URL to a map or map object (future) | -| Name | name of the place | - -The geoCoordinates object contains these properties: - -| Property | Description | -|----|----| -| Type | type of the entity ("GeoCoordinates") | -| Name | name of the place | -| Longitude | longitude of the location (WGS 84) | -| Latitude | latitude of the location (WGS 84) | -| Elevation | elevation of the location (WGS 84) | - -This code example shows how to add a place entity to the entities collection: - -# [C#](#tab/cs) -[!code-csharp[set GeoCoordinates](includes/code/dotnet-create-messages.cs#setGeoCoord)] - -# [JavaScript](#tab/js) -```javascript -var entity = context.activity.entities; - -const place = { - elavation: 100, - type: "GeoCoordinates", - name : "myPlace", - latitude: 123, - longitude: 234 -}; - -entity = [place]; - -``` - ---- - -### Consume entities - -# [C#](#tab/cs) - -To consume entities, use either the `dynamic` keyword or strongly-typed classes. - -This code example shows how to use the `dynamic` keyword to process an entity within the `Entities` property of a message: - -[!code-csharp[examine entity using dynamic keyword](includes/code/dotnet-create-messages.cs#examineEntity1)] - -This code example shows how to use a strongly-typed class to process an entity within the `Entities` property of a message: - -[!code-csharp[examine entity using typed class](includes/code/dotnet-create-messages.cs#examineEntity2)] - -# [JavaScript](#tab/js) - -This code example shows how to process an entity within the `entity` property of a message: - -```javascript -if (entity[0].type === "GeoCoordinates" && entity[0].latitude > 34) { - // do something -} -``` - ---- - -## Activity types - - -Activities can be of several different types past the most common **message**. Explanations and further details on different activity types can be found in the [Bot Framework Activity schema](https://aka.ms/botSpecs-activitySchema). - -::: moniker range="azure-bot-service-3.0" - -## Additional resources - -- Activity class -::: moniker-end diff --git a/articles/bot-service-adapter-connect-webex.md b/articles/bot-service-adapter-connect-webex.md deleted file mode 100644 index 67f88daaa..000000000 --- a/articles/bot-service-adapter-connect-webex.md +++ /dev/null @@ -1,190 +0,0 @@ ---- -title: Connect a bot to Webex Teams | Microsoft Docs -description: Learn how to configure a bot's connection to Webex via the Webex adapter. -keywords: bot adapter, Webex, Webex bot -author: garypretty -manager: kamrani -ms.topic: article -ms.author: gapretty -ms.service: bot-service -ms.date: 01/21/2020 ---- - -# Connect a bot to Webex Teams using the Webex adapter - -In this article you will learn how to connect a bot to Webex using the adapter available in the SDK. This article will walk you through modifying the EchoBot sample to connect it to a Webex app. - -> [!NOTE] -> The instructions below cover the C# implementation of the Webex adapter. For instructions on using the JavaScript implementation, part of the BotKit libraries, [see the BotKit Webex documentation](https://botkit.ai/docs/v4/platforms/webex.html). - -## Prerequisites - -* The [EchoBot sample code](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/02.echo-bot) - -* Access to a Webex team with sufficient permissions to login to create / manage applications at [https://developer.webex.com/my-apps](https://developer.webex.com/my-apps). If you do not have access to a Webex team you can create an account for free at [www.webex.com](https://www.webex.com). - -## Create a Webex bot app - -1. Log into the [Webex developer dashboard](https://developer.webex.com/my-apps) and then click the 'Create a new app' button. - -2. On the next screen choose to create a Webex Bot by clicking 'Create a bot'. - -3. On the next screen, enter an appropriate name, username and description for your bot, as well as choosing an icon or uploading an image of your own. - - ![Set up bot](~/media/bot-service-adapter-connect-webex/create-bot.png) - - Click the 'Add bot' button. - -4. On the next page you will be provided with an access token for your new Webex app, please make a note of this token as you will require it when configuring your bot. - - ![Set up bot](~/media/bot-service-adapter-connect-webex/create-bot-settings.png) - -## Wiring up the Webex adapter in your bot - -Before you can complete the configuration of our Webex app, you need to wire up the Webex adapter into your bot. - -### Install the Webex adapter NuGet package - -Add the [Microsoft.Bot.Builder.Adapters.Webex](https://www.nuget.org/packages/Microsoft.Bot.Builder.Adapters.Webex/) NuGet package. For more information on using NuGet, see [Install and manage packages in Visual Studio](https://aka.ms/install-manage-packages-vs) - -### Create a Webex adapter class - -Create a new class that inherits from the ***WebexAdapter*** class. This class will act as our adapter for the Webex channel. It includes error handling capabilities (much like the ***BotFrameworkAdapterWithErrorHandler*** class already in the sample, used for handling requests from Azure Bot Service). - -```csharp -public class WebexAdapterWithErrorHandler : WebexAdapter -{ - public WebexAdapterWithErrorHandler(IConfiguration configuration, ILogger logger) - : base(configuration, logger) - { - OnTurnError = async (turnContext, exception) => - { - // Log any leaked exception from the application. - logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}"); - - // Send a message to the user - await turnContext.SendActivityAsync("The bot encountered an error or bug."); - await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code."); - - // Send a trace activity, which will be displayed in the Bot Framework Emulator - await turnContext.TraceActivityAsync("OnTurnError Trace", exception.Message, "https://www.botframework.com/schemas/error", "TurnError"); - }; - } -} -``` - -### Create a new controller for handling Webex requests - -We create a new controller which will handle requests from your Webex app, on a new endpoint 'api/webex' instead of the default 'api/messages' used for requests from Azure Bot Service Channels. By adding an additional endpoint to your bot, you can accept requests from Bot Service channels (or additional adapters), as well as from Webex, using the same bot. - -```csharp -[Route("api/webex")] -[ApiController] -public class WebexController : ControllerBase -{ - private readonly WebexAdapter _adapter; - private readonly IBot _bot; - - public WebexController(WebexAdapter adapter, IBot bot) - { - _adapter = adapter; - _bot = bot; - } - - [HttpPost] - public async Task PostAsync() - { - // Delegate the processing of the HTTP POST to the adapter. - // The adapter will invoke the bot. - await _adapter.ProcessAsync(Request, Response, _bot); - } -} -``` - -### Inject Webex Adapter In Your Bot Startup.cs - -Add the following line into the ***ConfigureServices*** method within your Startup.cs file, which will register your Webex adapter and make it available for your new controller class. The configuration settings, described in the next step, will be automatically used by the adapter. - -```csharp -services.AddSingleton(); -``` - -Once added, your ***ConfigureServices*** method shold look like this. - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); - - // Create the default Bot Framework Adapter (used for Azure Bot Service channels and emulator). - services.AddSingleton(); - - // Create the Webex Adapter - services.AddSingleton(); - - // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. - services.AddTransient(); -} -``` - -### Add Webex adapter settings to your bot's configuration file - -1. Add the 4 settings shown below to your appSettings.json file in your bot project. - - ```json - "WebexAccessToken": "", - "WebexPublicAddress": "", - "WebexSecret": "", - "WebexWebhookName": "" - ``` - -2. Populate the **WebexAccessToken** setting within the Webex Bot Access Token, that was generated when creating your Webex bot app in the earlier steps. Leave the other 3 settings empty at this time, until we gather the information needed for them in later steps. - -## Complete configuration of your Webex app and bot - -### Create and update a Webex webhook - -Now that you have created a Webex app and wired up the adapter in your bot project, the final steps are to configure a Webex webhook, point it to the correct endpoint on your bot, and subscribe your app to ensure your bot receives messages and attachments. To do this your bot must be running, so that Webex can verify the URL to the endpoint is valid. - -1. To complete this step, [deploy your bot to Azure](https://aka.ms/bot-builder-deploy-az-cli) and make a note of the URL to your deployed bot. Your Webex messaging endpoint is the URL for your bot, which will be the URL of your deployed application (or ngrok endpoint), plus '/api/webex' (for example, `https://yourbotapp.azurewebsites.net/api/webex`). - - > [!NOTE] - > If you are not ready to deploy your bot to Azure, or wish to debug your bot when using the Webex adapter, you can use a tool such as [ngrok](https://www.ngrok.com) (which you will likely already have installed if you have used the Bot Framework emulator previously) to tunnel through to your bot running locally and provide you with a publicly accessible URL for this. - > - > If you wish create an ngrok tunnel and obtain a URL to your bot, use the following command in a terminal window (this assumes your local bot is running on port 3978, alter the port numbers in the command if your bot is not). - > - > ```cmd - > ngrok.exe http 3978 -host-header="localhost:3978" - > ``` - -2. Navigate to [https://developer.webex.com/docs/api/v1/webhooks](https://developer.webex.com/docs/api/v1/webhooks). - -3. Click the link for the PUT method `https://api.ciscospark.com/v1/webhooks/{webhookId}` (with the description "Update a Webhook"). This will expand a form allowing you to send a request to the endpoint. - - ![Set up bot](~/media/bot-service-adapter-connect-webex/webex-webhook-put-endpoint.png) - -4. Populate the form with the following details; - - * Name (provide a name for your webhook, such as "Messages Webhook") - * Target URL (the full URL to your bot's Webex endpoint, such as `https://yourbotapp.azurewebsites.net/api/webex`) - * Secret (here you should provide a secret of your choice to secure your webhook) - * Status (leave this as the default setting of 'active') - - ![Set up bot](~/media/bot-service-adapter-connect-webex/webex-webhook-form.png) - -5. Click **Run**, which should create your webhook and provide you with a success message. - -### Complete the remaining settings in your bot application - -Complete the remaining 3 settings in your bot's appsettings.json file (you already populated **WebexAccessToken** in an earlier step). - -* WebexPublicAddress (the full URL to your bot's Webex endpoint) -* WebexSecret (the secret you provided when creating your webhook in the previous step) -* WebexWebhookName (the name for your webhook you provided in the previous step) - -## Re-deploy your bot in your Webex team - -Now that you have completed the configuration of your bot's settings in appsettings.json, you should re-deploy your bot (or restart your bot if you are tunnelling to a local endpoint using ngrok). Configuration of you Webex app and bot are now complete. -You can now login to your Webex team at [https://www.webex.com](https://www.webex.com) and chat with your bot by sending it a message, in the same way you would contact another person. - -![Set up bot](~/media/bot-service-adapter-connect-webex/webex-contact-person.png) diff --git a/articles/bot-service-build-continuous-deployment.md b/articles/bot-service-build-continuous-deployment.md deleted file mode 100644 index 4d5dc9e91..000000000 --- a/articles/bot-service-build-continuous-deployment.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: Configure continuous deployment for Bot Service - Bot Service -description: Learn how to setup continuous deployment from source control for a Bot Service. -keywords: continuous deployment, publish, deploy, azure portal -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/10/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Set up continuous deployment - -[!INCLUDE [applies-to](./includes/applies-to.md)] - -This article shows you how to configure continuous deployment for your bot. You can enable continuous deployment to automatically deploy code changes from your source repository to Azure. In this topic, we'll cover setting up continuous deployment for GitHub. For information on setting up continuous deployment with other source control systems, see the additional resource section at the bottom of this page. - -## Prerequisites -- If you don't have an Azure subscription, create a [free account](https://portal.azure.com) before you begin. -- You **must** [deploy your bot to Azure](bot-builder-deploy-az-cli.md) before enabling continuous deployment. - -## Prepare your repository -Make sure that your repository root has the correct files in your project. This will allow you to get automatic builds from the Azure App Service Kudu build server. - -|Runtime | Root directory files | -|:-------|:---------------------| -| ASP.NET Core | .sln or .csproj | -| Node.js | server.js, app.js, or package.json with a start script | -| Python | app.py | - - -## Continuous deployment using GitHub -To enable continuous deployment with GitHub, navigate to the **App Service** page for your bot in the Azure portal. - -Click **Deployment Center** > **GitHub** > **Authorize**. - -![Continous deployment](~/media/azure-bot-build/azure-deployment.png) - -In the browser window that opens up, click **Authorize AzureAppService**. - -![Azure Github Permission](~/media/azure-bot-build/azure-deployment-github.png) - -After authorizing the **AzureAppService**, go back to **Deployment Center** in the Azure portal. - -1. Click **Continue**. - -1. Select **App Service build service**. - -1. Click **Continue**. - -1. Select **Organization**, **Repository**, and **Branch**. - -1. Click **Continue**, and then **Finish** to complete the setup. - -At this point, continuous deployment with GitHub is set up. Whenever you commit to the source code repository, your changes will automatically be deployed to the Azure Bot Service. - -## Disable continuous deployment - -While your bot is configured for continuous deployment, you may not use the online code editor to make changes to your bot. If you want to use the online code editor, you can temporarily disable continuous deployment. - -To disable continuous deployment, do the following: -1. In the [Azure portal](https://portal.azure.com), go to your bot's **All App Service settings** blade and click **Deployment Center**. -1. Click **Disconnect** to disable continuous deployment. To re-enable continuous deployment, repeat the steps from the appropriate sections above. - -## Additional resources -- To enable continuous deployment from BitBucket and Azure DevOps Services, see [continous deployment using Azure App Service](https://docs.microsoft.com/azure/app-service/deploy-continuous-deployment). - - diff --git a/articles/bot-service-channel-additional-channels.md b/articles/bot-service-channel-additional-channels.md deleted file mode 100644 index a35a7cc2d..000000000 --- a/articles/bot-service-channel-additional-channels.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Additional channels - Bot Service -description: Learn how to configure additional channels for your bot. -keywords: bot channels, hangouts, Twilio, facebook, azure portal -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 02/08/2019 ---- - -# Additional channels - -Besides the channels listed in within these docs, there are a few additional channels available as an adapter, both through our [provided platforms](https://botkit.ai/docs/v4/platforms/) via Botkit, or accessible through the [community repositories](https://github.com/BotBuilderCommunity/). Below are the additional channels provided: - -- [Webex Teams](https://botkit.ai/docs/v4/platforms/webex.html) -- [Websocket and Webhooks](https://botkit.ai/docs/v4/platforms/web.html) -- [Google Hangouts and Google Assistant](https://github.com/BotBuilderCommunity/) (available through community) -- [Amazon Alexa](https://github.com/BotBuilderCommunity/) (available through community) - -## Currently available adapters - -A complete list of available adapters can be [found here](https://botkit.ai/docs/v4/platforms/). You'll notice some channels are available also as an adapter, and it's up to you when to use a channel versus an adapter. - -### When to use an adapter - -1. The service does not support the channel you want -2. Security and compliance requirements of your deployment dictate that you cannot rely on an outside service -3. Depth of features that you need in a particular channel may not be supported - -### When to use a channel - -1. You require cross-channel compatibility: your bot should work on more than one of the available channels -2. Built in support: Microsoft maintains, patches, and seamlessly services each channel for you each time a third-party makes updates -3. Allows access to additional exclusive Microsoft channels, like quickly growing Microsoft Teams -4. If you want to rely on a GUI interface to enable additional channels for your bot diff --git a/articles/bot-service-channel-connect-cortana.md b/articles/bot-service-channel-connect-cortana.md deleted file mode 100644 index 4ab4b43fd..000000000 --- a/articles/bot-service-channel-connect-cortana.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -title: Connect a bot to Cortana - Bot Service -description: Learn how to configure a bot for access through the Cortana interface. -keywords: cortana, bot channel, configure cortana -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/22/2019 ---- -# Connect a bot to Cortana - -Cortana is a speech-enabled channel that can send and receive voice messages in addition to textual conversation. A bot intended to connect to Cortana should be designed for speech as well as text. A Cortana *skill* is a bot that can be invoked using a Cortana client. Publishing a bot adds the bot to the list of available skills. - -To add the Cortana channel, open the bot in the [Azure Portal](https://portal.azure.com/), click the **Channels** blade, and then click **Cortana**. - -![Add Cortana channel](~/media/channels/cortana-addchannel.png) - -## Configure Cortana - -When connecting your bot with the Cortana channel, some basic information about your bot will be pre-filled into the registration form. Review this information carefully. This form consists of the following fields. - -| Field | Description | -|------|------| -| **Skill icon** | An icon that is displayed in the Cortana canvas when your skill is invoked. This is also used where skills are discoverable (like the Microsoft store). (32KB max, PNG only).| -| **Display name** | The name of your Cortana skill is displayed to the user at the top of the visual UI. (30 character limit) | -| **Invocation name** | This is the name users say when invoking a skill. It should be no more than three words and easy to pronounce. See the [Invocation Name Guidelines][invocation] for more information on how to choose this name.| - -![Default settings](~/media/channels/cortana-defaultsettings.png) - ->!NOTE: Cortana does not currently support the use of Azure Active Directory (AAD) Account authentication. You will need to use a Microsoft Account (MSA) to successfully publish your bot to Cortana. - -## General bot information - -Under the **Manage user identity through connected services section** press the option to enable it. Fill in the form. - -All fields marked with an asterisk (*) are required. A Bot must be published to Azure before it can be connected to Cortana. - -![Manage user identity, part 1](~/media/channels/cortana-manageidentity-1.png) -![Manage user identity, part 2](~/media/channels/cortana-manageidentity-2.png) - -### When should Cortana prompt for a user to sign in - -Select **Sign in at invocation** if you want Cortana to sign in the user at the time they invoke your skill. - -Select **Sign in when required** if you use a Bot Service sign-in card to sign in the user. Typically, you use this option if you want to sign in the user only if they will use a feature that requires authentication. When your skill sends a message that includes the sign-in card as an attachment, Cortana ignores the sign-in card and performs the authorization flow using the Connect Account settings. - -### Account name - -The name of your skill that you want displayed when the user signs in to your skill. - -### Client ID for third-party services - -Your bot's application ID. You received the ID when you registered your bot. - -### Space-separated list of scopes - -Specify the scopes that the service requires (see the service's documentation). - -### Authorization URL - -Set to `https://login.microsoftonline.com/common/oauth2/v2.0/authorize`. - -### Token options - -Select **POST**. - -### Grant type - -Select **Authorization code** to use the code grant flow, or select **Implicit** to use the implicit flow. - -### Token URL - -For the **Authorization code** grant type, set to `https://login.microsoftonline.com/common/oauth2/v2.0/token`. - -### Client secret/password for third party services - -The bot's password. You received the password when you registered your bot. - -### Client authentication scheme - -Select **HTTP Basic**. - -### Internet access required to authenticate users - -Leave this unchecked. - -### Request user profile data (optional) - -Cortana provides access to several different types of user profile information, that you can use to customize the bot for the user. For example, if a skill has access to the user's name and location then the skill can have custom response such as "Hello Kamran, I hope you are having a pleasant day in Bellevue, Washington." - -Click **Add a user profile request**, then select the user profile information you want from the drop-down list. Add a friendly name to use to access this information from your bot's code. - -### Deploy on Cortana - -When you are done filling out the registration form for your Cortana skill, click **Deploy on Cortana** to complete the connection. This brings you back to your bot's Channels blade and you should see that it is now connected to Cortana. - -At this point your bot is deployed as a Cortana skill to your account. - -Next, you need to enable and authorize the Bot skill to connect to your account. In your Cortana app, say or type "ask *Invocation Name*" where the "Invocation Name" is what you configured in the Cortana Channel in the Azure portal. Cortana will then prompt you to allow your Bot Skill to connect. If you choose "Yes" to allow this, the skill will now work and show up in Cortana's skill list. - -## Next steps - -* [Cortana Skills Kit](https://aka.ms/CortanaSkillsKitOverview) -* [Enable debugging](bot-service-debug-cortana-skill.md) -* [Publish a Cortana skill][publish] - -[invocation]: https://docs.microsoft.com/cortana/skills/cortana-invocation-guidelines -[publish]: https://docs.microsoft.com/cortana/skills/publish-skill -[CortanaEntity]: https://aka.ms/cortana-channel-data diff --git a/articles/bot-service-channel-connect-directline.md b/articles/bot-service-channel-connect-directline.md deleted file mode 100644 index d3aa58f63..000000000 --- a/articles/bot-service-channel-connect-directline.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Connect a bot to Direct Line - Bot Service -description: Learn how to configure a bot's connection to Direct Line. -keywords: direct line, bot channels, custom client, connect to channels, configure -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 08/7/2019 ---- - -# Connect a bot to Direct Line - -You can enable your own client application to communicate with your bot by using the Direct Line channel. - -## Add the Direct Line channel - -To add the Direct Line channel, open the bot in the [Azure Portal](https://portal.azure.com/), click the **Channels** blade, and then click **Direct Line**. - -![Add Direct Line channel](media/bot-service-channel-connect-directline/directline-addchannel.png) - -## Add new site - -Next, add a new site that represents the client application that you want to connect to your bot. Click **Add new site**, enter a name for your site, and click **Done**. - -![Add Direct Line site](media/bot-service-channel-connect-directline/directline-addsite.png) - -## Manage secret keys - -When your site is created, the Bot Framework generates secret keys that your client application can use to [authenticate](~/rest-api/bot-framework-rest-direct-line-3-0-authentication.md) the Direct Line API requests that it issues to communicate with your bot. To view a key in plain text, click **Show** for the corresponding key. - -![Show Direct Line key](media/bot-service-channel-connect-directline/directline-showkey.png) - -Copy and securely store the key that is shown. Then use the key to [authenticate](~/rest-api/bot-framework-rest-direct-line-3-0-authentication.md) the Direct Line API requests that your client issues to communicate with your bot. -Alternatively, use the Direct Line API to [exchange the key for a token](~/rest-api/bot-framework-rest-direct-line-3-0-authentication.md#generate-token) that your client can use to authenticate its subsequent requests within the scope of a single conversation. - -![Copy Direct Line key](media/bot-service-channel-connect-directline/directline-copykey.png) - -## Configure settings - -Finally, configure settings for the site. - -- Select the Direct Line protocol version that your client application will use to communicate with your bot. - -> [!TIP] -> If you are creating a new connection between your client application and bot, use Direct Line API 3.0. - -When finished, click **Done** to save the site configuration. You can repeat this process, beginning with [Add new site](#add-new-site), for each client application that you want to connect to your bot. - -When you have the **enhanced authentication enabled**, you will see the following behavior for which trusted origins are used: - -- If you configure trusted origins as part of the configuration UI page, then these will **always** be used as the only set. Sending no or additional trusted origins when generating a token or starting a conversation will be ignored (i.e. they are **not appended** to the list or cross validated). -- If you have not configured trusted origins as part of the configuration UI, then any value you send as part of the API calls will be used. \ No newline at end of file diff --git a/articles/bot-service-channel-connect-directlinespeech.md b/articles/bot-service-channel-connect-directlinespeech.md deleted file mode 100644 index 14f03c659..000000000 --- a/articles/bot-service-channel-connect-directlinespeech.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: Connect a bot to Direct Line Speech -titleSuffix: Bot Service -description: Overview and steps required to connect an existing Bot Framework bot to the Direct Line Speech channel for voice in, voice out interaction with high reliability and low latency. -services: bot-service -author: trrwilson -manager: nitinme -ms.service: bot-service -ms.topic: conceptual -ms.date: 11/02/2019 -ms.author: travisw ---- - -# Connect a bot to Direct Line Speech - -[!INCLUDE[applies-to-v4](includes/applies-to.md)] - -You can configure your bot to allow client applications to communicate with it through the Direct Line Speech channel. - -Once you have built your bot, onboarding it with Direct Line Speech will enable low latency, high reliability connection with client applications using the [Speech SDK](https://aka.ms/speech/sdk). These connections are optimized for voice in, voice out conversational experiences. For more information on Direct Line Speech and how to build client applications, visit the [custom voice-first virtual assistant](https://aka.ms/bots/speech/va) page. - -## Add the Direct Line Speech channel - -1. To add the Direct Line Speech Channel, first open the bot in the [Azure Portal](https://portal.azure.com), From your resources, select your **Bot Channel Registration** resource. Click on **Channels** in the configuration blade. - - ![highlight of the location for selecting channels to connect to](media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-selectchannel.png "selecting channels") - -1. In the channel selection page, find and click `Direct Line Speech` to choose the channel. - - ![selecting direct line speech channel](media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-connectspeechchannel.png "connecting Direct Line Speech") - -1. Direct Line Speech Channel requires a Cognitive Services resource. You can either use an existing resource or create a new Cognitive Services resource following the [instructions](https://docs.microsoft.com/azure/cognitive-services/cognitive-services-apis-create-account). - - ![selecting direct line speech channel](media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-cognitivesericesaccount-selection.png "selecting Cogntive Services resource") - -1. Once you've reviewed the terms of use, click `Save` to confirm your channel selection. - - ![saving the enablement of Direct Line Speech channel](media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-savechannel.png "Save the channel configuration") - -## Enable the Bot Framework Protocol Streaming Extensions - -With the Direct Line Speech channel connected to your bot, you now need to enable Bot Framework Protocol Streaming Extensions support for optimal, low-latency interaction. - -1. If you haven't already, open the blade for your bot in the [Azure Portal](https://portal.azure.com). - -1. Click on **Settings** under the **Bot Management** category (right below **Channels**). Click the checkbox for **Enable Streaming Endpoint**. - - ![enable the streaming protocol](media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-enablestreamingsupport.png "enable streaming extension support") - -1. At the top of the page, click **Save**. - -1. On the same blade, under the **App Service Settings** category, click **Configuration**. - - ![navigate to app service settings](media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-configureappservice.png "configure the app service") - -1. Click on `General settings` and then select the option to enable `Web socket` support. - - ![enable websockets for the app service](media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-enablewebsockets.png "enable websockets") - -1. Click `Save` at the top of the configuration page. - -1. The Bot Framework Protocol Streaming Extensions are now enabled for your bot. You are now ready to update your bot code and [integrate Streaming Extensions support](https://aka.ms/botframework/addstreamingprotocolsupport) to an existing bot project. - -## Adding protocol support to your bot - -With the Direct Line Speech channel connected and support for the Bot Framework Protocol Streaming Extensions enabled, all that's left is to add code to your bot to support the optimized communication. Follow the instructions on [adding Streaming Extensions support to your bot](https://aka.ms/botframework/addstreamingprotocolsupport) to ensure full compatibility with Direct Line Speech. - - diff --git a/articles/bot-service-channel-connect-email.md b/articles/bot-service-channel-connect-email.md deleted file mode 100644 index bb2ad2b76..000000000 --- a/articles/bot-service-channel-connect-email.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: Connect a bot to Office 365 email - Bot Service -description: Learn how to configure a bot to send and receive email with Office 365. -keywords: Office 365, bot channels, email, email credentials, azure portal, custom email -author: kamrani -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/15/2019 ---- -# Connect a bot to Office 365 email - -Bots can communicate with users via Office 365 email in addition to other [channels](~/bot-service-manage-channels.md). When a bot is configured to access an email account, it receives a message when a new email arrives. The bot can then respond as indicated by its business logic. For example, the bot could send an email reply acknowledging an email was received with the message, "Hi! Thanks for your order! We will begin processing it immediately." - -> [!WARNING] -> It is a violation of the Bot Framework [Code of Conduct](https://www.botframework.com/Content/Microsoft-Bot-Framework-Preview-Online-Services-Agreement.htm) to create "spambots", including bots that send unwanted or unsolicited bulk email. - -> [!NOTE] -> If you are using Microsoft Exchange Server, make sure you have enabled [Autodiscover](https://docs.microsoft.com/exchange/client-developer/exchange-web-services/autodiscover-for-exchange) first before configuring email channel. - -## Configure email credentials - -You can connect a bot to the Email channel by entering Office 365 credentials in the Email channel configuration. -Federated authentication using any vendor that replaces AAD is not supported. - -> [!NOTE] -> You should not use your own personal email accounts for bots, as every message sent to that email account will be forwarded to the bot. This can result in the bot inappropriately sending a response to a sender. For this reason, bots should only use dedicated O365 email accounts. - -To add the Email channel, open the bot in the [Azure Portal](https://portal.azure.com/), click the **Channels** blade, and then click **Email**. Enter your valid email credentials and click **Save**. - -![Enter email credentials](~/media/bot-service-channel-connect-email/bot-service-channel-connect-email-credentials.png) - -The Email channel currently works with Office 365 only. Other email services are not currently supported. - -## Customize emails - -The Email channel supports sending custom properties to create more advanced, customized emails using the `channelData` property. - -[!INCLUDE [Email channelData table](~/includes/snippet-channelData-email.md)] - -The following example message shows a JSON file that includes these `channelData` properties. - -```json -{ - "type": "message", - "locale": "en-Us", - "channelID": "email", - "from": { "id": "mybot@mydomain.com", "name": "My bot"}, - "recipient": { "id": "joe@otherdomain.com", "name": "Joe Doe"}, - "conversation": { "id": "123123123123", "topic": "awesome chat" }, - "channelData": - { - "htmlBody": "This is more than awesome.", - "subject": "Super awesome message subject", - "importance": "high", - "ccRecipients": "Yasemin@adatum.com;Temel@adventure-works.com" - } -} -``` - -::: moniker range="azure-bot-service-3.0" -For more information about using `channelData`, see the [Node.js](https://github.com/Microsoft/BotBuilder-Samples/tree/master/Node/core-ChannelData) sample or [.NET](~/dotnet/bot-builder-dotnet-channeldata.md) documentation. -::: moniker-end - -::: moniker range="azure-bot-service-4.0" -For more information about using `channelData`, -see [how to implement channel-specific functionality](~/v4sdk/bot-builder-channeldata.md). -::: moniker-end - -## Other considerations - -If your bot does not return a 200 OK HTTP status code within 15 seconds in response to an incoming email message, the email channel will try to resend the message, and your bot may receive the same email message activity a few times. For more information, see the [HTTP details](v4sdk/bot-builder-basics.md#http-details) section in **How bots work** and the how to [troubleshooting timeout errors](https://github.com/daveta/analytics/blob/master/troubleshooting_timeout.md) article. - -> [!NOTE] -> If you are using an Office 365 account with MFA enabled on it, make sure you disable MFA for the specified account first, then you can configure the account for the email channel. Otherwise, the connection will fail. - -## Additional resources - - -::: moniker range="azure-bot-service-3.0" -* Connect a bot to [channels](~/bot-service-manage-channels.md) -* [Implement channel-specific functionality](dotnet/bot-builder-dotnet-channeldata.md) with the Bot Framework SDK for .NET -* Read the [channels reference](bot-service-channels-reference.md) article for more information about which features are supported on each channel -::: moniker-end -::: moniker range="azure-bot-service-4.0" -* Connect a bot to [channels](~/bot-service-manage-channels.md) -* [Implement channel-specific functionality](~/v4sdk/bot-builder-channeldata.md) with the Bot Framework SDK for .NET -* Read the [channels reference](bot-service-channels-reference.md) article for more information about which features are supported on each channel -::: moniker-end - diff --git a/articles/bot-service-channel-connect-facebook.md b/articles/bot-service-channel-connect-facebook.md deleted file mode 100644 index 191e2cece..000000000 --- a/articles/bot-service-channel-connect-facebook.md +++ /dev/null @@ -1,402 +0,0 @@ ---- -title: Connect a bot to Facebook Messenger - Bot Service -description: Learn how to configure a bot's connection to Facebook Messenger. -keywords: Facebook Messenger, bot channel, Facebook App, App ID, App Secret, Facebook bot, credentials -manager: kamrani -ms.topic: article -ms.author: kamrani -ms.service: bot-service -ms.date: 01/16/2020 ---- - -# Connect a bot to Facebook - -Your bot can be connected to both Facebook Messenger and Facebook Workplace, so that it can communicate with users on both platforms. The following tutorial shows how to connect a bot to these two channels. - -> [!NOTE] -> The Facebook UI may appear slightly different depending on which version you are using. - -## Connect a bot to Facebook Messenger - -To learn more about developing for Facebook Messenger, see the [Messenger platform documentation](https://developers.facebook.com/docs/messenger-platform). You may wish to review Facebook's [pre-launch guidelines](https://developers.facebook.com/docs/messenger-platform/product-overview/launch#app_public), [quick start](https://developers.facebook.com/docs/messenger-platform/guides/quick-start), and [setup guide](https://developers.facebook.com/docs/messenger-platform/guides/setup). - -To configure a bot to communicate using Facebook Messenger, enable Facebook Messenger on a Facebook page and then connect the bot. - -### Copy the Page ID - -The bot is accessed through a Facebook Page. - -1. [Create a new Facebook Page](https://www.facebook.com/bookmarks/pages) or go to an existing Page. - -1. Open the Facebook Page's **About** page and then copy and save the **Page ID**. - -### Create a Facebook app - -1. In your browser, navigate to [Create a new Facebook App](https://developers.facebook.com/quickstarts/?platform=web). -1. Enter the name of your app and click the **Create New Facebook App ID** button. - - ![Create App](media/channels/fb-create-messenger-bot-app.png) - -1. In the displayed dialog, enter your email address and click the **Create App ID** button. - - ![Create an App ID](media/channels/fb-create-messenger-bot-app-id.png) - -1. Go through the wizard steps. - -1. Enter the required check information, then click the **Skip Quick Start** button in the upper right. - -1. In the left pane of the next displayed window, expand *Settings* and click **Basic**. - -1. In the right pane, copy and save the **App ID** and **App Secret**. - - ![Copy App ID and App Secret](media/channels/fb-messenger-bot-get-appid-secret.png) - -1. In the left pane, under *Settings*, click **Advanced**. - -1. In the right pane, set **Allow API Access to App Settings** slider to **Yes**. - - ![Copy App ID and App Secret](media/channels/fb-messenger-bot-api-settings.png) - -1. In the page bottom right, click the **Save Changes** button. - -### Enable messenger - -1. In the left pane, click **Dashboard**. -1. In the right pane, scroll down and in the **Messenger** box, click the **Set Up** button. The Messenger entry is displayed under the *PRODUCTS* section in the left pane. - - ![Enable messenger](media/channels/fb-messenger-bot-enable-messenger.png) - -### Generate a Page Access Token - -1. In the left pane, under the Messenger entry, click **Settings**. -1. In the right pane, scroll down and in the **Token Generation** section, select the target page. - - ![Enable messenger](media/channels/fb-messenger-bot-select-messenger-page.png) - -1. Click the **Edit Permissions** button to grant the app pages_messaging in order to generate an access token. -1. Follow the wizard steps. In the last step accept the default settings and click the **Done** button. At the end a **page access token** is generated. - - ![Messenger permissions](media/channels/fb-messenger-bot-permissions.png) - -1. Copy and save the **Page Access Token**. - -### Enable webhooks - -In order to send messages and other events from your bot to Facebook Messenger, you must enable webhooks integration. At this point, let's leave the Facebook setting steps pending; will come back to them. - -1. In your browser open a new window and navigate to the [Azure portal](https://portal.azure.com/). - -1. In the Resource list, click on the bot resource registration and in the related blade click **Channels**. - -1. In the right pane, click the **Facebook** icon. - -1. In the wizard enter the Facebook information stored in the previous steps. If the information is correct, at the bottom of the wizard, you should see the **callback URL** and the **verify token**. Copy and store them. - - ![fb messenger channel config](media/channels/fb-messenger-bot-config-channel.PNG) - -1. Click the **Save** button. - -1. Let's go back to the Facebook settings. In the right pane, scroll down and in the **Webhooks** section, click the **Subscribe To Events** button. This is to forward messaging events from Facebook Messenger to the bot. - - ![Enable webhooks](media/channels/fb-messenger-bot-webhooks.PNG) - -1. In the displayed dialog, enter the **Callback URL** and **Verify Token** values stored previously. Under **Subscription Fields**, select *message\_deliveries*, *messages*, *messaging\_optins*, and *messaging\_postbacks*. - - ![Config webhooks](media/channels/fb-messenger-bot-config-webhooks.png) - -1. Click the **Verify and Save** button. - -1. Select the Facebook page to subscribe the webhook. Click the **Subscribe** button. - - ![Config webhooks page](media/channels/fb-messenger-bot-config-webhooks-page.PNG) - -### Submit for review - -Facebook requires a Privacy Policy URL and Terms of Service URL on its basic app settings page. The [Code of Conduct](https://investor.fb.com/corporate-governance/code-of-conduct/default.aspx) page contains third party resource links to help create a privacy policy. The [Terms of Use](https://www.facebook.com/terms.php) page contains sample terms to help create an appropriate Terms of Service document. - -After the bot is finished, Facebook has its own [review process](https://developers.facebook.com/docs/messenger-platform/app-review) for apps that are published to Messenger. The bot will be tested to ensure it is compliant with Facebook's [Platform Policies](https://developers.facebook.com/docs/messenger-platform/policy-overview). - -### Make the App public and publish the Page - -> [!NOTE] -> Until an app is published, it is in [Development Mode](https://developers.facebook.com/docs/apps/managing-development-cycle). Plugin and API functionality will only work for admins, developers, and testers. - -After the review is successful, in the App Dashboard under App Review, set the app to Public. -Ensure that the Facebook Page associated with this bot is published. Status appears in Pages settings. - -## Connect a bot to Facebook Workplace - -> [!NOTE] -> On December 16, 2019, Workplace by Facebook changed its security model for custom integrations. Prior integrations built using Microsoft Bot Framework v4 need to be updated to use the Bot Framework Facebook adapters per the instructions below prior to February 28, 2020. -> -> Facebook will only consider integrations with limited access to Workplace data (low sensitivity permissions) eligible for continued use until December 31, 2020 if such integrations have completed and passed Security RFI and if the developer reaches out before January 15, 2020 via [Direct Support](https://my.workplace.com/work/admin/direct_support) to request continued use of the app. -> -> Bot Framework adapters are available for [JavaScript/Node.js](https://aka.ms/botframework-workplace-adapter) and [C#/.NET](https://aka.ms/bf-workplace-csharp) bots. - -Facebook Workplace is a business-oriented version of Facebook, which allows employees to easily connect and collaborate. It contains live videos, news feeds, groups, messenger, reactions, search, and trending posts. It also supports: - -- Analytics and integrations. A dashboard with analytics, integration, single sign-on, and identity providers that companies use to integrate Workplace with their existing IT systems. -- Multi-company groups. Shared spaces in which employees from different organizations can work together and collaborate. - -See the [Workplace Help Center](https://workplace.facebook.com/help/work/) to learn more about Facebook Workplace and [Workplace Developer Documentation](https://developers.facebook.com/docs/workplace) for guidelines about developing for Facebook Workplace. - -To use Facebook Workplace with your bot, you must create a Workplace account and a custom integration to connect the bot. - -### Create a Workplace Premium account - -1. Submit an application to [workplace](https://www.facebook.com/workplace) on behalf of your company. -1. Once your application has been approved, you will receive an email inviting you to join. The response may take a while. -1. From the e-mail invitation, click **Get Started**. -1. Enter your profile information. - > [!TIP] - > Set yourself as the system administrator. Remember that only system administrators can create custom integrations. -1. Click **Preview Profile** and verify the information is correct. -1. Access *Free Trial*. -1. Create **password**. -1. Click **Invite Coworkers** to invite employees to sign-in. The employees you invited will become members as soon as they sign. They will go through a similar sign-in process as described in these steps. - -### Create a custom integration - -Create a [custom integration](https://developers.facebook.com/docs/workplace/custom-integrations-new) for your Workplace following the steps described below. When you create a custom integration, an app with defined permissions and a page of type 'Bot' only visible within your Workplace community are created. - -1. In the **Admin Panel**, open the **Integrations** tab. -1. Click on the **Create your own custom App** button. - - ![Workplace Integration](media/channels/fb-integration.png) - -1. Choose a display name and a profile picture for the app. Such information will be shared with the page of type 'Bot'. -1. Set the **Allow API Access to App Settings** to "Yes". -1. Copy and safely store the App ID, App Secret and App Token that's shown to you. - - ![Workplace Keys](media/channels/fb-keys.png) - -1. Now you have finished creating a custom integration. You can find the page of type 'Bot' in your Workplace community,as shown below. - - ![Workplace page](media/channels/fb-page.png) - -### Update your bot code with Facebook adapter - -Your bot's source code needs to be updated to include an adapter to communicate with Workplace by Facebook. Adapters are available for [JavaScript/Node.js](https://aka.ms/botframework-workplace-adapter) and [C#/.NET](https://aka.ms/bf-workplace-csharp) bots. - -### Provide Facebook credentials - -You will need to update appsettings.json of your bot with **Facebook App ID**, **Facebook App Secret** and **Page Access Token** values copied from the Facebook Workplace previously. Instead of a traditional pageID, use the numbers following the integrations name on its **About** page. Follow these instructions to update your bot source code in [JavaScript/Node.js](https://aka.ms/botframework-workplace-adapter) or [C#/.NET](https://aka.ms/bf-workplace-csharp). - -### Submit for review - -Please refer to the **Connect a bot to Facebook Messenger** section and [Workplace Developer Documentation](https://developers.facebook.com/docs/workplace) for details. - -### Make the App public and publish the Page - -Please refer to the **Connect a bot to Facebook Messenger** section for details. - -### Setting the API version - -If you receive a notification from Facebook about deprecation of a certain version of the Graph API, go to [Facebook developers page](https://developers.facebook.com). Navigate to your bot’s **App Settings** and go to **Settings > Advanced > Upgrade API version**, then switch **Upgrade All Calls** to 3.0. - -![API version upgrade](media/channels/fb-version-upgrade.png) - -## Connect a bot to Facebook using the Facebook adapter - -Use the Bot Framework Facebook adapter to connect your bot with Facebook Workplace. To connect to Facebook messenger, you can use the Facebook channel or the Facebook adapter. -Facebook adapters are available for [JavaScript/Node.js](https://aka.ms/botframework-workplace-adapter) and [C#/.NET](https://aka.ms/bf-workplace-csharp) bots. - -In this article you will learn how to connect a bot to Facebook using the adapter. This article will walk you through modifying the EchoBot sample to connect it to Facebook. - -The instructions below cover the C# implementation of the Facebook adapter. For instructions on using the JavaScript adapter, part of the BotKit libraries, [see the BotKit Facebook documentation](https://botkit.ai/docs/v4/platforms/facebook.html). - -### Prerequisites - -- The [EchoBot sample code](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/02.echo-bot) -- A Facebook for Developers account. If you do not have an account, you can [create one here](https://developers.facebook.com). - -### Create a Facebook app, page and gather credentials - -1. Log into [https://developers.facebook.com](https://developers.facebook.com). Click **My Apps** in the main menu and click **Create App** from the drop down menu. - -![Create app](media/bot-service-channel-connect-facebook/create-app-button.png) - -1. In the pop-up window that appears, enter a name for your new app and then click **Create App ID**. - -![Define app name](media/bot-service-channel-connect-facebook/app-name.png) - -#### Set up Messenger and associate a Facebook page - -1. Once your app has been created, you will see a list of products available to set up. Click the **Set Up** button next to the **Messenger** product. - -1. You now need to associate your new app with a Facebook page (if you do not have an existing page you want to use, you can create one by clicking **Create New Page** in the **Access Tokens** section). Click **Add or Remove Pages**, select the page you want to associated with your app and click **Next**. Leave the **Manage and access Page conversations on Messenger** setting enabled and click **Done**. - -![Set up messenger](media/bot-service-channel-connect-facebook/app-page-permissions.png) - -1. Once you have associated your page, click the **Generate Token** button to generate a page access token. Make a note of this token as you will need it in a later step when configuring your bot application. - -#### Obtain your app secret - -1. In the left hand menu, click **Settings** and then click **Basic** to navigate to the basic setting page for your app. - -1. On the basic settings page, click the **Show** button next to your **App Secret**. Make a note of this secret as you will need it in a later step when configuring your bot application. - -### Wiring up the Facebook adapter in your bot - -Now that you have your Facebook app, page and credentials, you need to configure your bot application. - -#### Install the Facebook adapter NuGet package - -Add the [Microsoft.Bot.Builder.Adapters.Facebook](https://www.nuget.org/packages/Microsoft.Bot.Builder.Adapters.Facebook/) NuGet package. For more information on using NuGet, see [Install and manage packages in Visual Studio](https://aka.ms/install-manage-packages-vs). - -#### Create a Facebook adapter class - -Create a new class that inherits from the ***FacebookAdapter*** class. This class will act as our adapter for the Facebook channel and include error handling capabilities (similar to the ***BotFrameworkAdapterWithErrorHandler*** class already in the sample, used for handling other requests from Azure Bot Service). - -```csharp -public class FacebookAdapterWithErrorHandler : FacebookAdapter -{ - public FacebookAdapterWithErrorHandler(IConfiguration configuration, ILogger logger) - : base(configuration, logger) - { - OnTurnError = async (turnContext, exception) => - { - // Log any leaked exception from the application. - logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}"); - - // Send a message to the user - await turnContext.SendActivityAsync("The bot encountered an error or bug."); - await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code."); - - // Send a trace activity, which will be displayed in the Bot Framework Emulator - await turnContext.TraceActivityAsync("OnTurnError Trace", exception.Message, "https://www.botframework.com/schemas/error", "TurnError"); - }; - } -} -``` - -#### Create a new controller for handling Facebook requests - -Create a new controller which will handle requests from Facebook, on a new endpoing 'api/facebook' instead of the default 'api/messages' used for requests from Azure Bot Service Channels. By adding an additional endpoint to your bot, you can accept requests from Bot Service channels, as well as from Facebook, using the same bot. - -```csharp -[Route("api/facebook")] -[ApiController] -public class FacebookController : ControllerBase -{ - private readonly FacebookAdapter _adapter; - private readonly IBot _bot; - - public FacebookController(FacebookAdapter adapter, IBot bot) - { - _adapter = adapter; - _bot = bot; - } - - [HttpPost] - [HttpGet] - public async Task PostAsync() - { - // Delegate the processing of the HTTP POST to the adapter. - // The adapter will invoke the bot. - await _adapter.ProcessAsync(Request, Response, _bot); - } -} -``` - -#### Inject the Facebook adapter in your bot startup.cs - -Add the following line to the ***ConfigureServices*** method within your startup.cs file. This will register your Facebook adapter and make it available for your new controller class. The configuration settings you added in the previous step will be automatically used by the adapter. - -```csharp -services.AddSingleton(); -``` - -Once added, your ***ConfigureServices*** method shold look like this. - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); - - // Create the default Bot Framework Adapter (used for Azure Bot Service channels and emulator). - services.AddSingleton(); - - // Create the Facebook Adapter - services.AddSingleton(); - - // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. - services.AddTransient(); -} -``` - -#### Obtain a URL for your bot - -Now that you have wired up the adapter in your bot project, you need to provide to Facebook the correct endpoint for your application, so that your bot will receive messages. You also need this URL to complete configuration of your bot application. - -To complete this step, [deploy your bot to Azure](https://aka.ms/bot-builder-deploy-az-cli) and make a note of the URL of your deployed bot. - -> [!NOTE] -> If you are not ready to deploy your bot to Azure, or wish to debug your bot when using the Facebook adapter, you can use a tool such as [ngrok](https://www.ngrok.com) (which you will likely already have installed if you have used the Bot Framework emulator previously) to tunnel through to your bot running locally and provide you with a publicly accessible URL for this. -> -> If you wish create an ngrok tunnel and obtain a URL to your bot, use the following command in a terminal window (this assumes your local bot is running on port 3978, alter the port numbers in the command if your bot is not). -> -> ```cmd -> ngrok.exe http 3978 -host-header="localhost:3978" -> ``` - -#### Add Facebook app settings to your bot's configuration file - -Add the settings shown below to your appSettings.json file in your bot project. You populate **FacebookAppSecret** and **FacebookAccessToken** using the values you gathered when creating and configuring your Facebook App. **FacebookVerifyToken** should be a random string that you create and will be used to ensure your bot's endpoint is authenitic when called by Facebook. - -```json - "FacebookVerifyToken": "", - "FacebookAppSecret": "", - "FacebookAccessToken": "" -``` - -Once you have populated the settings above, you should redeploy (or restart if running locally with ngrok) your bot. - -### Complete configuration of your Facebook app - -The final step is to configure your new Facebook app's Messenger endpoint, to ensure your bot receives messages. - -1. Within the dashboard for your app, click **Messenger** in the left hand menu and then click **Settings**. - -1. In the **Webhooks** section click **Add Callback URL**. - -1. In the **Callback URL** text box enter your bot's URL, plus the `api/facebook` endpoint you specified in your newly created controller. For example, `https://yourboturl.com/api/facebook`. In the **Verify Token** text box enter the verify token you created earlier and used in your bot application's appSettings.json file. - - ![Edit callback url](media/bot-service-channel-connect-facebook/edit-callback-url.png) - -1. Click **Verify and Save**. Ensure you bot is running, as Facebook will make a request to your application's endpoint and verify it using your **Verify Token**. - -1. Once your callback URL has been verified, click the **Add Subscriptions** button that is now shown. In the pop-up window, select the following subscriptions and click **Save**. - - - **messages** - - **messaging_postbacks** - - **messaging_optins** - - **messaging_deliveries** - - ![Webhook subscriptions](media/bot-service-channel-connect-facebook/webhook-subscriptions.png) - -### Test your bot with adapter in Facebook - -You can now test whether your bot is connected to Facebook correctly by sending a message via the Facebook Page you associated with your new Facebook app. - -1. Navigate to your Facebook Page. - -1. Click **Add a Button** button. - - ![Add a button](media/bot-service-channel-connect-facebook/add-button.png) - -1. Select **Contact You** and **Send Message** and click **Next**. - - ![Add a button](media/bot-service-channel-connect-facebook/button-settings.png) - -1. When asked **Where would you like this button to send people to?** select **Messenger** and click **Finish**. - - ![Add a button](media/bot-service-channel-connect-facebook/button-settings-2.png) - -1. Hover over the new **Send Message** button that is now shown on your Facebook Page and click **Test Button** from the pop-up menu. This will start a new conversation with your app via Facebook Messenger, which you can use to test messaging your bot. Once the message is received by your bot, it will send a message back to you, echoing the text from your message. - -You can also test this feature using the [sample bot for the Facebook adapter](https://aka.ms/csharp-61-facebook-adapter-sample) by populating the appSettings.json file with the same values described in the steps above. - -## See also - -- **Sample code**. Use the [Facebook-events](https://aka.ms/facebook-events) sample bot to explore the bot communication with Facebook Messenger. diff --git a/articles/bot-service-channel-connect-groupme.md b/articles/bot-service-channel-connect-groupme.md deleted file mode 100644 index ab8931142..000000000 --- a/articles/bot-service-channel-connect-groupme.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Connect a bot to GroupMe - Bot Service -description: Learn how to configure a bot's connection to GroupMe. -keywords: bot channel, GroupMe, create GroupMe, credentials -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Connect a bot to GroupMe - -You can configure a bot to communicate with people using the GroupMe group messaging app. - -[!INCLUDE [Channel Inspector intro](~/includes/snippet-channel-inspector.md)] - -## Sign up for a GroupMe account - -If you don't have a GroupMe account, [sign up for a new account](https://web.groupme.com/signup). - -## Create a GroupMe application - -[Create a GroupMe application](https://dev.groupme.com/applications/new) for your bot. - -Use this callback URL: `https://groupme.botframework.com/Home/Login` - -![Create app](~/media/channels/GM-StepApp.png) - -## Gather credentials - -1. In the **Redirect URL** field, copy the value after **client_id=**. -2. Copy the **Access Token** value. - -![Copy client ID and access token](~/media/channels/GM-StepClientId.png) - - -## Submit credentials - -1. On dev.botframework.com, paste the **client_id** value you just copied into the **Client ID** field. -2. Paste the **Access Token** value into the **Access Token** field. -2. Click **Save**. - -![Enter credentials](~/media/channels/GM-StepClientIDToken.png) diff --git a/articles/bot-service-channel-connect-kik.md b/articles/bot-service-channel-connect-kik.md deleted file mode 100644 index 9d1368d1e..000000000 --- a/articles/bot-service-channel-connect-kik.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Connect a bot to Kik - Bot Service -description: Learn how to configure a bot's connection to Kik. -keywords: connect a bot, bot channel, Kik bot, credentials, configure, phone -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Connect a bot to Kik - -You can configure your bot to communicate with people using the Kik messaging app. - -## Install Kik on your phone - -If you don't have Kik installed on your phone, install it via your phone's app store or at the Kik website. You'll need to use an existing Kik user account or sign up for an new account. - -![Kik sign up](./media/channels/kik-signup.png) - -## Log into the dev portal with your mobile phone - -Use your mobile phone to log into the Kik portal. When prompted, _Open this page in "Kik"?_ select **Open**. - -![Kik dev portal](./media/channels/kik-dev-portal.png) - -## Follow the bot setup process - -Give your bot a name. - -![Set up bot](./media/channels/kik-phone.png) - -## Gather credentials - -On the Configuration tab, copy the **Name** and **API key**. - -![Copy bot information](./media/channels/kik-configure.png) - -## Submit credentials - -![Paste credentials](./media/channels/kik-creds.png) - -Click **Submit Kik Credentials**. - -## Enable the bot - -Check **Enable this bot on Kik**. Then click **I'm done configuring Kik**. - -When you have completed these steps, your bot will be successfully configured to communicate with users in Kik. diff --git a/articles/bot-service-channel-connect-line.md b/articles/bot-service-channel-connect-line.md deleted file mode 100644 index 7f9327766..000000000 --- a/articles/bot-service-channel-connect-line.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: Connect a bot to LINE - Bot Service -description: Learn how to configure a bot's connection to LINE. -keywords: connect a bot, bot channel, LINE bot, credentials, configure, phone -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 1/7/2019 ---- - -# Connect a bot to LINE - -You can configure your bot to communicate with people through the LINE app. - -## Log into the LINE console - -Log into the [LINE developer console](https://developers.line.biz/console/register/messaging-api/provider/) of your LINE account, using *Log in with Line*. - -> [!NOTE] -> If you haven't already, [download LINE](https://line.me/), then go to your settings to register your email address. - -### Register as a developer - -If this is your first time on the LINE developer console, enter your name and email address to create a developer account. - -![LINE screenshot register developer](./media/channels/LINE-screenshot-1.png) - -## Create a new provider - -First, create a provider for your bot if you don't already have one set up. The provider is the entity (individual or company) that offers your app. - -![LINE screenshot create provider](./media/channels/LINE-screenshot-2.png) - -## Create a Messaging API channel - -Next, create a new Messaging API channel. - -![LINE screenshot channel type](./media/channels/LINE-channel-type-selection.png) - -Create a new Messaging API channel by clicking on the green square. - -![LINE screenshot create channel](./media/channels/LINE-create-channel.png) - -The name cannot include "LINE" or some similar string. Fill out the required fields and confirm your channel settings. - -![LINE screenshot channel settings](./media/channels/LINE-screenshot-4.png) - -## Get necessary values from your channel settings - -Once you've confirmed your channel settings, you'll be directed to a page similar to this. - -![LINE screenshot channel page](./media/channels/LINE-screenshot-5.png) - -Click on the channel you created to access your channel settings, and scroll down to find the **Basic information > Channel secret**. Save that somewhere for a moment. Verify the Available features include `PUSH_MESSAGE`. - -![LINE screenshot channel secret](./media/channels/LINE-screenshot-6.png) - -Then, scroll farther to **Messaging settings**. There, you will see a **Channel access token** field, with an *issue* button. Click that button to get your access token, and save that for the moment as well. - -![LINE screenshot channel token](./media/channels/LINE-screenshot-8.png) - -## Connect your LINE channel to your Azure bot - -Log in to the [Azure portal](https://portal.azure.com/) and find your bot, and click on **Channels**. - -![LINE screenshot azure settings](./media/channels/LINE-channel-setting-2.png) - -There, select the LINE channel and paste the channel secret and access token from above into the appropriate fields. Be sure to save your changes. - -Copy the custom webhook URL that Azure gives you. - -![LINE screenshot azure settings](./media/channels/LINE-channel-setting-1.png) - -## Configure LINE webhook settings - -Next, go back to the LINE developer console and paste the webhook URL from Azure into the **Message settings > Webhook URL**, and click **Verify** to verify the connection. If you just created the channel in Azure, it may take a few minutes to take effect. - -Then, enable **Message settings > Use webhooks**. - -> [!IMPORTANT] -> In LINE Developer Console, you must first set the webhook URL, and only then set **Use webhooks = Enabled**. First enabling webhooks with an empty URL will not set the enabled status, even though the UI may say otherwise. - -After you added a webhook URL and then enabled webhooks, make sure to reload this page and verify that these changes were set correctly. - -![LINE screenshot webhooks](./media/channels/LINE-screenshot-9.png) - -## Test your bot - -Once you have completed these steps, your bot will be successfully configured to communicate with users on LINE and is ready to test. - -### Add your bot to your LINE mobile app - -In the LINE developer console, navigate to the settings page and you will see a QR code of your bot. - -In the Mobile LINE app, go to the right most navigation tab with three dots [**...**] and tap on the QR code icon. - -![LINE screenshot mobile app](./media/channels/LINE-screenshot-12.jpg) - -Point the QR code reader at the QR code in your developer console. You should now be able to interact with your bot in your mobile LINE app and test your bot. - -### Automatic messages - -When you start testing your bot, you may notice the bot sends unexpected messages that are not the ones you specified in the `conversationUpdate` activity. Your dialog may look something like this: - -![LINE screenshot conversation](./media/channels/LINE-screenshot-conversation.jpg) - -To avoid sending these messages, you need to switch off the Auto-response messages. - -![LINE screenshot auto response](./media/channels/LINE-screenshot-10.png) - -Alternatively, you can choose to keep these messages. In this case, it may be a good idea to click “Set message” and edit it. - -![LINE screenshot set auto response](./media/channels/LINE-screenshot-11.png) - -## Troubleshooting - -* In case your bot is not responding to any of your messages at all, navigate to your bot in Azure portal, and choose Test in Web Chat. - * If the bot works there, but does not respond in LINE, reload your LINE Developer Console page and repeat the webhook instructions above. Be sure you set the **Webhook URL** before enabling webhooks. - * If the bot doesn't work in Web Chat, debug the issue for your bot then come back and finish configuring your LINE channel. - diff --git a/articles/bot-service-channel-connect-skype.md b/articles/bot-service-channel-connect-skype.md deleted file mode 100644 index ab7ceb86f..000000000 --- a/articles/bot-service-channel-connect-skype.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: Connect a bot to Skype - Bot Service -description: Learn how to configure a bot for access through the Skype interface. -keywords: skype, bot channels, configure skype, publish, connect to channels -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 10/11/2018 ---- - -# Connect a bot to Skype - -Skype keeps you connected with users through instant messaging, phone, and video calls. Extend this functionality by building bots that users can discover and interact with through the Skype interface. - ->[!NOTE] -> As of October 31, 2019 the Skype channel no longer accepts new Bot publishing requests. This means that you can continue to develop bots using the Skype channel, but your bot will be limited to 100 users. You will not be able to publish your bot to a larger audience. Current Skype bots will continue to run uninterrupted. Read more about [why some features are not available in Skype anymore](https://support.skype.com/faq/fa12091/why-are-some-features-not-available-in-skype-anymore). - -To add the Skype channel, open the bot in the [Azure Portal](https://portal.azure.com/), click the **Channels** blade, and then click **Skype**. - -![Add Skype channel](~/media/channels/skype-addchannel.png) - -This will take you to the **Configure Skype** settings page. - -![Configure Skype channel](~/media/channels/skype_configure.png) - -You need to configure settings in **Web control**, **Messaging**, **Calling**, **Groups** and **Publish**. Let's go over them one by one. - -## Web control - -To embed the bot into your website, click the **Get embed code** button from the **Web control** section. This will direct you to the Skype for Developers page. Follow the instructions there to get the embed code. - -## Messaging - -This section configures how your bot sends and receives messages in Skype. - -## Calling - -This section configures the calling feature of Skype in your bot. You can specify whether **Calling** is enabled for your bot and if enabled, whether IVR functionality or Real Time Media functionality is to be used. - -## Groups - -This section configures whether your bot can be added to a group and how it behaves in a group for messaging and is also used to enable Group Video Calls for Calling bots. - -## Publish - -This section configures the publish settings of your bot. All fields labeled with a * are required fields. - -Bots in **Preview** are limited to 100 contacts. If you need more than 100 contacts, submit your bot for review. Clicking **Submit for Review** will automatically make your bot searchable in Skype if accepted. If your request cannot be approved, you will be notified as to what you need to change before it can be approved. - -> [!TIP] -> If you are wanting to submit your bot for review, keep in mind it must meet the [skype certification checklist](https://github.com/Microsoft/skype-dev-bots/blob/master/certification/CHECKLIST.md) before it will be accepted. - -After finishing configuration, click **Save** and accept the **Terms of Service**. The Skype channel is now added to your bot. - -## Next steps - -* [Skype for Business](bot-service-channel-connect-skypeforbusiness.md) diff --git a/articles/bot-service-channel-connect-skypeforbusiness.md b/articles/bot-service-channel-connect-skypeforbusiness.md deleted file mode 100644 index 775695fc0..000000000 --- a/articles/bot-service-channel-connect-skypeforbusiness.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: Connect a bot to Skype for Business - Bot Service -description: Learn how to connect a bot with the Skype for Business tenant. -keywords: skype for business, bot channels -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Connect a bot to Skype for Business (Preview) - -Skype for Business Online keeps you connected with co-workers and business partners through instant messaging, phone, and video calls. Extend this functionality by building bots that users can discover and interact with through the Skype for Business interface. - -> [!IMPORTANT] -> **Skype for Business channel of Bot Framework was deprecated on June 30, 2019.** -> -> Skype for Business channel stopped accepting new bots on June 30, 2019. Existing bots continued operating through October 31, 2019. The channel is currently being deprecated, and no production loads should be using it. Microsoft Teams is the preferred communication tool from Microsoft. Learn how to [connect your bot to Microsoft Teams](https://msdn.microsoft.com/microsoft-teams/bots). diff --git a/articles/bot-service-channel-connect-slack.md b/articles/bot-service-channel-connect-slack.md deleted file mode 100644 index a51265443..000000000 --- a/articles/bot-service-channel-connect-slack.md +++ /dev/null @@ -1,314 +0,0 @@ ---- -title: Connect a bot to Slack - Bot Service -description: Learn how to configure a bot's connection to Slack. -keywords: connect a bot, bot channel, Slack bot, Slack messaging app, slack adapter -author: JonathanFingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/09/2019 ---- - -# Connect a bot to Slack - -There are two ways in which you can confgure Slack messaging app: -- Use Azure Bot Service portal to connect your bot -- Use the Slack adapter - -## [Azure Bot Service Portal](#tab/abs) -## Create a Slack application for your bot - -Log into [Slack](https://slack.com/signin) and then go to [create a Slack application](https://api.slack.com/apps) channel. - -![Set up bot](~/media/channels/slack-NewApp.png) - -## Create an app and assign a Development Slack team - -Enter an App Name and select a Development Slack Team. If you are not already a member of a Development Slack Team, [create or join one](https://slack.com/). - -![Create app](~/media/channels/slack-CreateApp.png) - -Click **Create App**. Slack will create your app and generate a Client ID and Client Secret. - -## Add a new Redirect URL - -Next you will add a new Redirect URL. - -1. Select the **OAuth & Permissions** tab. -2. Click **Add a new Redirect URL**. -3. Enter [https://slack.botframework.com](https://slack.botframework.com). -4. Click **Add**. -5. Click **Save URLs**. - -![Add Redirect URL](~/media/channels/slack-RedirectURL.png) - -## Create a Slack Bot User - -Adding a Bot User allows you to assign a username for your bot and choose whether it is always shown as online. - -1. Select the **Bot Users** tab. -2. Click **Add a Bot User**. - -![Create bot](~/media/channels/slack-CreateBot.png) - -Click **Add Bot User** to validate your settings, click **Always Show My Bot as Online** to **On**, and then click **Save Changes**. - -![Create bot](~/media/channels/slack-CreateApp-AddBotUser.png) - -## Subscribe to Bot Events - -Follow these steps to subscribe to six particular bot events. By subscribing to bot events, your app will be notified of user activities at the URL you specify. - -> [!TIP] -> Your bot handle is the name of your bot. To find a bot's handle, -> visit [https://dev.botframework.com/bots](https://dev.botframework.com/bots), -> choose a bot, and record the name of the bot. - -1. Select the **Event Subscriptions** tab. -2. Click **Enable Events** to **On**. -3. In **Request URL**, enter `https://slack.botframework.com/api/Events/{YourBotHandle}`, where `{YourBotHandle}` is your bot handle, without the braces. The bot handle used in this example is **ContosoBot**. - - ![Subscribe Events: top](~/media/channels/slack-SubscribeEvents-a.png) - -4. In **Subscribe to Bot Events**, click **Add Bot User Event**. -5. In the list of events, select these six event types: - * `member_joined_channel` - * `member_left_channel` - * `message.channels` - * `message.groups` - * `message.im` - * `message.mpim` - - ![Subscribe Events: middle](~/media/channels/slack-SubscribeEvents-b.png) - -6. Click **Save Changes**. - - ![Subscribe Events: bottom](~/media/channels/slack-SubscribeEvents-c.png) - -## Add and Configure Interactive Messages (optional) - -If your bot will use Slack-specific functionality such as buttons, follow these steps: - -1. Select the **Interactive Components** tab and click **Enable Interactive Components**. -2. Enter `https://slack.botframework.com/api/Actions` as the **Request URL**. -3. Click the **Save changes** button. - -![Enable messages](~/media/channels/slack-MessageURL.png) - -## Gather credentials - -Select the **Basic Information** tab and scroll to the **App Credentials** section. -The Client ID, Client Secret, and Verification Token required for configuration of your Slack bot are displayed. - -![Gather credentials](~/media/channels/slack-AppCredentials.png) - -## Submit credentials - -In a separate browser window, return to the Bot Framework site at `https://dev.botframework.com/`. - -1. Select **My bots** and choose the Bot that you want to connect to Slack. -2. In the **Channels** section, click the Slack icon. -3. In the **Enter your Slack credentials** section, paste the App Credentials from the Slack website into the appropriate fields. -4. The **Landing Page URL** is optional. You may omit or change it. -5. Click **Save**. - -![Submit credentials](~/media/channels/slack-SubmitCredentials.png) - -Follow the instructions to authorize your Slack app's access to your Development Slack Team. - -## Enable the bot - -On the Configure Slack page, confirm the slider by the Save button is set to **Enabled**. -Your bot is configured to communicate with users in Slack. - -## Create an Add to Slack button - -Slack provides HTML you can use to help Slack users find your bot in the -*Add the Slack button* section of [this page](https://api.slack.com/docs/slack-button). -To use this HTML with your bot, replace the href value (begins with `https://`) with the URL found in your bot's Slack channel settings. -Follow these steps to get the replacement URL. - -1. On [https://dev.botframework.com/bots](https://dev.botframework.com/bots), click your bot. -2. Click **Channels**, right-click the entry named **Slack**, and click **Copy link**. This URL is now in your clipboard. -3. Paste this URL from your clipboard into the HTML provided for the Slack button. This URL replaces the href value provided by Slack for this bot. - -Authorized users can click the **Add to Slack** button provided by this modified HTML to reach your bot on Slack. - -## [Slack adapter](#tab/adapter) -## Connect a bot to Slack using the Slack adapter - -As well as the channel available in the Azure Bot Service to connect your bot with Slack, you can also use the Slack adapter. In this article you will learn how to connect a bot to Slack using the adapter. This article will walk you through modifying the EchoBot sample to connect it to a Slack app. - -> [!NOTE] -> The instructions below cover the C# implementation of the Slack adapter. For instructions on using the JS adapter, part of the BotKit libraries, [see the BotKit Slack documentation](https://botkit.ai/docs/v4/platforms/slack.html). - -## Prerequisites - -* The [EchoBot sample code](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/02.echo-bot) - -* Access to a Slack workspace with sufficient permissions to create and manage applications at [https://api.slack.com/apps](https://api.slack.com/apps). If you do not have access to a Slack environment you can create a workspace for [free](https://www.slack.com). - -## Create a Slack application for your bot - -Log into [Slack](https://slack.com/signin) and then go to [create a Slack application](https://api.slack.com/apps) channel. - -![Set up bot](~/media/channels/slack-NewApp.png) - -Click the 'Create new app' button. - -### Create an app and assign a development Slack team - -Enter an **App Name** and select a **Development Slack Workspace**. If you are not already a member of a development Slack team, [create or join one](https://slack.com/). - -![Create app](~/media/channels/slack-CreateApp.png) - -Click **Create App**. Slack will create your app and generate a client ID and client secret. - -### Gather required configuration settings for your bot - -Once your app is created, collect the following information. You will need this to connect your bot to Slack. - -1. Note the **Verification Token** and the **Signing Secret** from the **Basic Information** tab and keep them for later to configure your bot settings. - -![Slack tokens](~/media/bot-service-adapter-connect-slack/slack-tokens.png) - -2. Navigate to the **Install App** page under the **Settings** menu and follow the instructions to install your app into a Slack team. Once installed, copy the **Bot User OAuth Access Token** and, again, keep this for later to configure your bot settings. - -## Wiring up the Slack adapter in your bot - -### Install the Slack adapter NuGet package - -Add the [Microsoft.Bot.Builder.Adapters.Slack](https://www.nuget.org/packages/Microsoft.Bot.Builder.Adapters.Slack/) NuGet package. For more information on using NuGet, see [Install and manage packages in Visual Studio](https://aka.ms/install-manage-packages-vs) - -### Create a Slack adapter class - -Create a new class that inherits from the ***SlackAdapter*** class. This class will act as our adapter for the Slack channel and include error handling capabilities (similar to the ***BotFrameworkAdapterWithErrorHandler*** class already in the sample, used for handling other requests from Azure Bot Service). - -```csharp -public class SlackAdapterWithErrorHandler : SlackAdapter -{ - public SlackAdapterWithErrorHandler(IConfiguration configuration, ILogger logger) - : base(configuration, logger) - { - OnTurnError = async (turnContext, exception) => - { - // Log any leaked exception from the application. - logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}"); - - // Send a message to the user - await turnContext.SendActivityAsync("The bot encountered an error or bug."); - await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code."); - - // Send a trace activity, which will be displayed in the Bot Framework Emulator - await turnContext.TraceActivityAsync("OnTurnError Trace", exception.Message, "https://www.botframework.com/schemas/error", "TurnError"); - }; - } -} -``` - -### Create a new controller for handling Slack requests - -We create a new controller which will handle requests from your slack app, on a new endpoing 'api/slack' instead of the default 'api/messages' used for requests from Azure Bot Service Channels. By adding an additional endpoint to your bot, you can accept requests from Bot Service channels, as well as from Slack, using the same bot. - -```csharp -[Route("api/slack")] -[ApiController] -public class SlackController : ControllerBase -{ - private readonly SlackAdapter _adapter; - private readonly IBot _bot; - - public SlackController(SlackAdapter adapter, IBot bot) - { - _adapter = adapter; - _bot = bot; - } - - [HttpPost] - [HttpGet] - public async Task PostAsync() - { - // Delegate the processing of the HTTP POST to the adapter. - // The adapter will invoke the bot. - await _adapter.ProcessAsync(Request, Response, _bot); - } -} -``` - -### Add Slack app settings to your bot's configuration file - -Add the 3 settings shown below to your appSettings.json file in your bot project, populating each one with the values gathered earlier when creating your Slack app. - -```json - "SlackVerificationToken": "", - "SlackBotToken": "", - "SlackClientSigningSecret": "" -``` - -### Inject the Slack adapter In your bot startup.cs - -Add the following line to the ***ConfigureServices*** method within your startup.cs file. This will register your Slack adapter and make it available for your new controller class. The configuration settings you added in the previous step will be automatically used by the adapter. - -```csharp -services.AddSingleton(); -``` - -Once added, your ***ConfigureServices*** method shold look like this. - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); - - // Create the default Bot Framework Adapter (used for Azure Bot Service channels and emulator). - services.AddSingleton(); - - // Create the Slack Adapter - services.AddSingleton(); - - // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. - services.AddTransient(); -} -``` - -## Complete configuration of your Slack app - -### Obtain a URL for your bot - -Now that you have created a Slack app and wired up the adapter in your bot project, the final step is to point the Slack app to the correct endpoint on your bot and subscribe your app to ensure your bot receives messages. To do this your bot must be running, so that Slack can verify the URL to the endpoint is valid. - -To complete this step, [deploy your bot to Azure](https://aka.ms/bot-builder-deploy-az-cli) and make a note of the URL to your deployed bot. - -> [!NOTE] -> If you are not ready to deploy your bot to Azure, or wish to debug your bot when using the Slack adapter, you can use a tool such as [ngrok](https://www.ngrok.com) (which you will likely already have installed if you have used the Bot Framework emulator previously) to tunnel through to your bot running locally and provide you with a publicly accessible URL for this. -> -> If you wish create an ngrok tunnel and obtain a URL to your bot, use the following command in a terminal window (this assumes your local bot is running on port 3978, alter the port numbers in the command if your bot is not). -> -> ``` -> ngrok.exe http 3978 -host-header="localhost:3978" -> ``` - -### Update your Slack app - -Navigate back to the [Slack API dashboard]([https://api.slack.com/apps]) and select your app. You now need to configure 2 URLs for your app and subscribe to the appropriate events. - -1. In the **OAuth & Permissions** tab, the **Redirect URL** should be your bot's URL, plus the `api/slack` endpoint you specified in your newly created controller. For example, `https://yourboturl.com/api/slack`. - -![Slack redirect URL](~/media/bot-service-adapter-connect-slack/redirect-url.png) - -2. In the **Event Subscriptions** tab, fill in the **Request URL** with the same URL you used in step 1. - -3. Enable events using the toggle at the top of the page. - -4. Expand the **Subscribe to bot events** section and use the **Add Bot User Event** button to subscribe to the **im_created** and **message.im** events. - -![Slack event subscriptions](~/media/bot-service-adapter-connect-slack/event-subscriptions.png) - -## Test your bot with adapter in Slack - -Your Slack app is now configured and you can now login to the Slack workspace you installed your app into. (You will see it listed under the 'Apps' section of the left hand menu.) Select your app and try sending a message. You should see it echoed back to you in the IM window. - -You can also test this feature using the [sample bot for the Slack adapter](https://aka.ms/csharp-60-slack-adapter-sample) by populating the appSettings.json file with the same values described in the steps above. This sample has additional steps described in the README file to show examples of link sharing, receiving attachments, and sending interactive messages. - ---- diff --git a/articles/bot-service-channel-connect-telegram.md b/articles/bot-service-channel-connect-telegram.md deleted file mode 100644 index 175e5ede0..000000000 --- a/articles/bot-service-channel-connect-telegram.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Create a bot for Telegram - Bot Service -description: Learn how to configure a bot's connection to Telegram. -keywords: configure bot, Telegram, bot channel, Telegram bot, access token -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Connect a bot to Telegram - -You can configure your bot to communicate with people using the Telegram messaging app. - -[!INCLUDE [Channel Inspector intro](~/includes/snippet-channel-inspector.md)] - -## Visit the Bot Father to create a new Telegram bot - -Create a new Telegram bot using the Bot Father. - -![Visit Bot Father](~/media/channels/tg-StepVisitBotFather.png) - -## Create a new Telegram bot -To create a new Telegram bot, send command `/newbot`. - -![Create new bot](~/media/channels/tg-StepNewBot.png) - -### Specify a friendly name - -Give the Telegram bot a friendly name. - -![Give bot a friendly name](~/media/channels/tg-StepNameBot.png) - -### Specify a username - -Give the Telegram bot a unique username. - -![Give bot a unique name](~/media/channels/tg-StepUsername.png) - -### Copy the access token - -Copy the Telegram bot's access token. - -![Copy access token](~/media/channels/tg-StepBotCreated.png) - -## Enter the Telegram bot's access token - -Go to your bot's **Channels** section in the Azure portal and click the **Telegram** button. - -> [!NOTE] -> The Azure portal UI will look slightly different if you have already connected your bot to Telegram. - -![Select Telegram in channels](~/media/channels/tg-connectBot-Azure.png) - -Paste the token you copied previously into the **Access Token** field and click **Save**. - -![Telegram access token](~/media/channels/tg-accessToken-Azure.png) - -Your bot is now successfully configured to communicate with users in Telegram. - -![Telegram bot enabled](~/media/channels/tg-botEnabled-Azure.png) diff --git a/articles/bot-service-channel-connect-twilio.md b/articles/bot-service-channel-connect-twilio.md deleted file mode 100644 index b64561ce5..000000000 --- a/articles/bot-service-channel-connect-twilio.md +++ /dev/null @@ -1,225 +0,0 @@ ---- -title: Connect a bot to Twilio - Bot Service -description: Learn how to configure a bot's connection to Twilio. -keywords: Twilio, bot channels, SMS, App, phone, configure Twilio, cloud communication, text -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 10/9/2018 ---- - -# Connect a bot to Twilio - -You can configure your bot to communicate with people using the Twilio cloud communication platform. - -## Log in to or create a Twilio account for sending and receiving SMS messages - -If you don't have a Twilio account, create a new account. - -## Create a TwiML Application - -Create a TwiML application following the instructions. - -![Create app](~/media/channels/twi-StepTwiml.png) - -Under **Properties**, enter a **FRIENDLY NAME**. In this tutorial we use "My TwiML app" as an example. The **REQUEST URL** under Voice can be left empty. Under **Messaging**, the **Request URL** should be `https://sms.botframework.com/api/sms`. - -## Select or add a phone number - -Follow the instructions here to add a verified caller ID via the console site. After you finish, you will see your verified number in **Active Numbers** under **Manage Numbers**. - -![Set phone number](~/media/channels/twi-StepPhone.png) - -## Specify application to use for Voice and Messaging - -Click the number and go to **Configure**. Under both Voice and Messaging, set **CONFIGURE WITH** to be TwiML App and set **TWIML APP** to be My TwiML app. After you finish, click **Save**. - -![Specify application](~/media/channels/twi-StepPhone2.png) - -Go back to **Manage Numbers**, you will see the configuration of both Voice and Messaging are changed to TwiML App. - -![Specified number](~/media/channels/twi-StepPhone3.png) - - -## Gather credentials - -Go back to the [console homepage](https://www.twilio.com/console/), you will see your Account SID and Auth Token on the project dashboard, as shown below. - -![Gather app credentials](~/media/channels/twi-StepAuth.png) - -## Submit credentials - -In a separate window, return to the Bot Framework site at https://dev.botframework.com/. - -- Select **My bots** and choose the Bot that you want to connect to Twilio. This will direct you to the Azure portal. -- Select **Channels** under **Bot Management**. Click the Twilio (SMS) icon. -- Enter the Phone Number, Account SID, and Auth Token you record earlier. After you finish, click **Save**. - -![Submit credentials](~/media/channels/twi-StepSubmit.png) - -When you have completed these steps, your bot will be successfully configured to communicate with users using Twilio. - -## Connect a bot to Twilio using the Twilio adapter - -As well as the channel available in the Azure Bot Service to connect your bot with Twilio, you can also use the Twilio adapter. In this article you will learn how to connect a bot to Twilio using the adapter. This article will walk you through modifying the EchoBot sample to connect it to Twilio. - -> [!NOTE] -> The instructions below cover the C# implementation of the Twilio adapter. For instructions on using the JS adapter, part of the BotKit libraries, [see the BotKit Twilio documentation](https://botkit.ai/docs/v4/platforms/twilio.html). - -### Prerequisites - -* The [EchoBot sample code](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/02.echo-bot) - -* A Twilio account. If you do not have a Twilio account, you can [create one here](https://www.twilio.com/try-twilio). - -### Get a Twilio number and gather account credentials - -1. Log into [Twilio](https://twilio.com/console). On the right hand side of the page you will see the **ACCOUNT SID** and **AUTH TOKEN** for your account, make a note of these as you will need them later when configuring your bot application. - -2. Choose **Programmable Voice** from the options under **Get Started with Twilio**. - -![Get started with Programmable Voice](~/media/bot-service-channel-connect-twilio/get-started-voice.png) - -3. On the next page, click the **Get your first Twilio number** button. A pop-up window will show you a new number, which you can accept by clicking **Choose this number** (alternatively you can search for a different number by following the on screen instructions). - -4. Once you have chosen your number, make a note of it, as you will need this when configuring your bot application in a later step. - -### Wiring up the Twilio adapter in your bot - -Now that you have your Twilio number and account credentials, you need to configure your bot application. - -#### Install the Twilio adapter NuGet package - -Add the [Microsoft.Bot.Builder.Adapters.Twilio](https://www.nuget.org/packages/Microsoft.Bot.Builder.Adapters.Twilio/) NuGet package. For more information on using NuGet, see [Install and manage packages in Visual Studio](https://aka.ms/install-manage-packages-vs). - -#### Create a Twilio adapter class - -Create a new class that inherits from the ***TwilioAdapter*** class. This class will act as our adapter for the Twilio channel and include error handling capabilities (similar to the ***BotFrameworkAdapterWithErrorHandler*** class already in the sample, used for handling other requests from Azure Bot Service). - -```csharp -public class TwilioAdapterWithErrorHandler : TwilioAdapter -{ - public TwilioAdapterWithErrorHandler(IConfiguration configuration, ILogger logger) - : base(configuration, logger) - { - OnTurnError = async (turnContext, exception) => - { - // Log any leaked exception from the application. - logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}"); - - // Send a message to the user - await turnContext.SendActivityAsync("The bot encountered an error or bug."); - await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code."); - - // Send a trace activity, which will be displayed in the Bot Framework Emulator - await turnContext.TraceActivityAsync("OnTurnError Trace", exception.Message, "https://www.botframework.com/schemas/error", "TurnError"); - }; - } -} -``` - -#### Create a new controller for handling Twilio requests - -Create a new controller which will handle requests from Twilio, on a new endpoing 'api/twilio' instead of the default 'api/messages' used for requests from Azure Bot Service Channels. By adding an additional endpoint to your bot, you can accept requests from Bot Service channels, as well as from Twilio, using the same bot. - -```csharp -[Route("api/twilio")] -[ApiController] -public class TwilioController : ControllerBase -{ - private readonly TwilioAdapter _adapter; - private readonly IBot _bot; - - public TwilioController(TwilioAdapter adapter, IBot bot) - { - _adapter = adapter; - _bot = bot; - } - - [HttpPost] - [HttpGet] - public async Task PostAsync() - { - // Delegate the processing of the HTTP POST to the adapter. - // The adapter will invoke the bot. - await _adapter.ProcessAsync(Request, Response, _bot); - } -} -``` - -#### Inject the Twilio adapter in your bot startup.cs - -Add the following line to the ***ConfigureServices*** method within your startup.cs file. This will register your Twilio adapter and make it available for your new controller class. The configuration settings you added in the previous step will be automatically used by the adapter. - -```csharp -services.AddSingleton(); -``` - -Once added, your ***ConfigureServices*** method shold look like this. - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); - - // Create the default Bot Framework Adapter (used for Azure Bot Service channels and emulator). - services.AddSingleton(); - - // Create the Twilio Adapter - services.AddSingleton(); - - // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. - services.AddTransient(); -} -``` - -#### Obtain a URL for your bot - -Now that you have wired up the adapter in your bot project, you need to identify the correct endpoint to provide to Twilio in order to ensure your bot receives messages. You also require this URL to complete configuration of your bot application. - -To complete this step, [deploy your bot to Azure](https://aka.ms/bot-builder-deploy-az-cli) and make a note of the URL of your deployed bot. - -> [!NOTE] -> If you are not ready to deploy your bot to Azure, or wish to debug your bot when using the Twilio adapter, you can use a tool such as [ngrok](https://www.ngrok.com) (which you will likely already have installed if you have used the Bot Framework emulator previously) to tunnel through to your bot running locally and provide you with a publicly accessible URL for this. -> -> If you wish create an ngrok tunnel and obtain a URL to your bot, use the following command in a terminal window (this assumes your local bot is running on port 3978, alter the port numbers in the command if your bot is not). -> -> ``` -> ngrok.exe http 3978 -host-header="localhost:3978" -> ``` - -#### Add Twilio app settings to your bot's configuration file - -Add the settings shown below to your appSettings.json file in your bot project. You populate **TwilioNumber**, **TwilioAccountSid** and **TwilioAuthToken** using the values you gathered when creating your Twilio number. **TwilioValidationUrl** should be your bot's URL, plus the `api/twilio` endpoint you specified in your newly created controller. For example, `https://yourboturl.com/api/twilio`. - - -```json - "TwilioNumber": "", - "TwilioAccountSid": "", - "TwilioAuthToken": "", - "TwilioValidationUrl", "" -``` - -Once you have populated the settings above, you should redeploy (or restart if running locally with ngrok) your bot. - -### Complete configuration of your Twilio number - -The final step is to configure your new Twilio number's messaging endpoint, to ensure your bot receives messages. - -1. Navigate to the Twilio [Active Numbers page](https://www.twilio.com/console/phone-numbers/incoming). - -2. Click the phone number you created in the earlier step. - -3. Within the **Messaging** section, complete the **A MESSAGE COMES IN** section by chooisng **Webhook** from the drop down and populating the text box with your bot's endpoint that you used to populate the **TwilioValidationUrl** setting in the previous step, such as `https://yourboturl.com/api/twilio`. - -![Configure Twilio number webhook](~/media/bot-service-channel-connect-twilio/twilio-number-messaging-settings.png) - -4. Click the **Save** button. - -### Test your bot with adapter in Twilio - -You can now test whether your bot is connected to Twilio correctly by sending an SMS message to your Twilio number. Once the message is received by your bot it will send a message back to you, echoing the text from your message. - -You can also test this feature using the [sample bot for the Twilio adapter](https://aka.ms/csharp-63-twilio-adapter-sample) by populating the appSettings.json with the same values described in the steps above. diff --git a/articles/bot-service-channel-connect-webchat-speech.md b/articles/bot-service-channel-connect-webchat-speech.md deleted file mode 100644 index e26ea1f6a..000000000 --- a/articles/bot-service-channel-connect-webchat-speech.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: Enable speech in Web Chat - Bot Service -description: Learn how to enable speech in the web chat control for a bot connected to the Web Chat channel. -keywords: speech, web chat, voice, microphone, audio -author: DeniseMak -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Enable speech in Web Chat -You can enable a voice interface in the Web Chat control. Users interact with the voice interface by using the microphone in the Web Chat control. - -![Web chat speech sample](~/media/bot-service-channel-webchat/webchat-sample-speech.png) - -If the user types instead of speaking a response, Web Chat turns off the speech functionality and the bot gives only a textual response instead of speaking out loud. To re-enable the spoken response, the user can use the microphone to respond to the bot the next time. If the microphone is accepting input, it appears dark or filled-in. If it's grayed out, the user clicks on it to enable it. - -## Prerequisites - - Before you run the sample, you need to have a Direct Line secret or token for the bot that you want to run using the Web Chat control. - * See [Connect a bot to Direct Line](bot-service-channel-connect-directline.md) for information on getting a Direct Line secret associated with your bot. - * See [Generate a Direct Line token](rest-api/bot-framework-rest-direct-line-3-0-authentication.md) for information on exchanging the secret for a token. - -## Customizing Web Chat for speech -To enable the speech functionality in Web Chat, you need to customize the JavaScript code that invokes the Web Chat control. You can try out voice-enabled Web Chat locally using the following steps. - -1. Download the [sample index.html](https://aka.ms/web-chat-speech-sample). -2. Edit the code in `index.html` according to the type of speech support you want to add. The types of speech implementations are described in [Enable speech services](#enable-speech-services). -3. Start a web server. One way to do so is to use `npm http-server` at a Node.js command prompt. - - * To install `http-server` globally so it can be run from the command line, run this command: - - ``` - npm install http-server -g - ``` - - * To start a web server using port 8000, from the directory that contains `index.html`, run this command: - - ``` - http-server -p 8000 - ``` -4. Aim your browser at `http://localhost:8000/samples?parameters`. For example, `http://localhost:8000/samples?s=YOURDIRECTLINESECRET` invokes the bot using a Direct Line secret. The parameters that can be set in the query string are described in the following table: - - | Parameter | Description | - |-----------|-------------| - | s | Direct Line secret. See [Connect a bot to Direct Line](bot-service-channel-connect-directline.md) for information on getting a Direct Line secret. | - | t | Direct Line token. See [Generate a Direct Line token](rest-api/bot-framework-rest-direct-line-3-0-authentication.md) for info on how to generate this token. | - | domain | Optional. The URL of an alternate Direct Line endpoint. | - | webSocket | Optional. Set to 'true' to use WebSocket to receive messages. Default is `false`. | - | userid | Optional. The ID of the bot user. | - | username | Optional. The user name of the bot's user. | - | botid | Optional. ID of the bot. | - | botname | Optional. Name of the bot. | - - -## Enable speech services -The customization allows you to add speech functionality in any of the following ways: - -* **Browser-provided speech** - Use speech functionality built into the web browser. At this time, this functionality is only available on the Chrome browser. - -* **Create a custom speech service** - You can create your own custom speech recognition and voice synthesis components. - -### Browser-provided speech - -The following code instantiates speech recognizer and speech synthesis components that come with the browser. This method of adding speech is not supported by all browsers. - -> [!NOTE] -> Google Chrome supports the browser speech recognizer. However, Chrome may block the microphone in the following cases: -> * If the URL of the page that contains Web Chat begins with `http://` instead of `https://`. -> * If the URL is a local file using the `file://` protocol instead of `http://localhost:8000`. - -[!code-js[Specify speech options to use in-browser speech (JavaScript)](./includes/code/bot-service-channel-connect-webchat-speech.js#BrowserSpeech)] - - -### Custom Speech service - -You can also provide your own custom speech recognition that implements ISpeechRecognizer or speech synthesis that implements ISpeechSynthesis. - -[!code-js[Fetch a token to use with a custom speech service (JavaScript)](./includes/code/bot-service-channel-connect-webchat-speech.js#CustomSpeechService)] - -### Pass the speech options to Web Chat - -The following code passes the speech options to the Web Chat control: - -[!code-js[Pass speech options to Web Chat (JavaScript)](./includes/code/bot-service-channel-connect-webchat-speech.js#PassSpeechOptionsToWebChat)] - -## Next steps -Now that you can enable voice interaction with Web Chat, learn how your bot constructs spoken messages and adjusts the state of the microphone: -* [Add speech to messages (C#)](dotnet/bot-builder-dotnet-text-to-speech.md) -* [Add speech to messages (Node.js)](nodejs/bot-builder-nodejs-text-to-speech.md) - -## Additional resources - -* You can [download the source code](https://github.com/Microsoft/BotFramework-WebChat) for the web chat control on GitHub. -* The [Bing Speech API documentation](https://docs.microsoft.com/azure/cognitive-services/speech/home) provides more information on the Bing Speech API. - diff --git a/articles/bot-service-channel-connect-webchat.md b/articles/bot-service-channel-connect-webchat.md deleted file mode 100644 index 22687385e..000000000 --- a/articles/bot-service-channel-connect-webchat.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -title: Connect a bot to the Web Chat channel - Bot Service -description: Learn how to use the web chat control in your web page for a bot connected to the Web Chat channel. -keywords: web chat, bot channel, web page, secret key, iframe, HTML -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 08/22/2019 ---- - -# Connect a bot to Web Chat - -[!INCLUDE [pre-release-label](./includes/pre-release-label.md)] - -When you [create a bot](bot-service-quickstart.md) with Bot Service, the Web Chat channel is automatically configured for you. The Web Chat channel includes the web chat control, which provides the ability for users to interact with your bot directly in a web page. - -![Web chat sample](./media/bot-service-channel-webchat/create-a-bot.png) - -The Web Chat channel in the Bot Framework Portal contains everything you need to embed the web chat control in a web page. All you have to do to use the web chat control is get your bot's secret key and embed the control in a web page. - -## Web Chat and Direct Line considerations - -> [!IMPORTANT] -> Please, keep in mind these important [Security considerations](rest-api/bot-framework-rest-direct-line-3-0-authentication.md#security-considerations). - -## Get your bot secret key - -1. Open your bot in the [Azure Portal](https://portal.azure.com) and click **Channels** blade. - -2. Click **Edit** for the **Web Chat** channel. -![Web chat channel](./media/bot-service-channel-webchat/bot-service-channel-list.png) - -3. Under **Secret keys**, click **Show** for the first key. -![Secret key](./media/bot-service-channel-webchat/secret-key.png) - -4. Copy the **Secret key** and the **Embed code**. - -5. Click **Done**. - -## Embed the web chat control in your website - -You can embed the web chat control in your website by using one of two options. - -### Option 1 - Keep your secret hidden, exchange your secret for a token, and generate the embed - -Use this option if you can execute a server-to-server request to exchange your web chat secret for a temporary token, -and if you want to make it difficult for other developers to embed your bot in their websites. -Although using this option will not absolutely prevent other developers from embedding your bot in their websites, -it does make it difficult for them to do so. - -To exchange your secret for a token and generate the embed: - -1. Issue a **GET** request to `https://webchat.botframework.com/api/tokens` and pass your web chat secret via the `Authorization` header. The `Authorization` header uses the `BotConnector` scheme and includes your secret, as shown in the example request below. - -2. The response to your **GET** request will contain the token (surrounded with quotation marks) that can be used to start a conversation by rendering the web chat control within an **iframe**. A token is valid for one conversation only; to start another conversation, you must generate a new token. - -3. Within the `iframe` **Embed code** that you copied from the Web Chat channel within the Bot Framework Portal (as described in [Get your bot secret key](#get-your-bot-secret-key) above), change the `s=` parameter to `t=` and replace "YOUR_SECRET_HERE" with your token. - -> [!NOTE] -> Tokens will automatically be renewed before they expire. - -##### Example request - -``` -requestGET https://webchat.botframework.com/api/tokens -Authorization: BotConnector YOUR_SECRET_HERE -``` - -##### Example response - -```response -"IIbSpLnn8sA.dBB.MQBhAFMAZwBXAHoANgBQAGcAZABKAEcAMwB2ADQASABjAFMAegBuAHYANwA.bbguxyOv0gE.cccJjH-TFDs.ruXQyivVZIcgvosGaFs_4jRj1AyPnDt1wk1HMBb5Fuw" -``` - -##### Example iframe (using token) - -```html - -``` - -##### Example html code -```html - - - - - - - -``` - -### Option 2 - Embed the web chat control in your website using the secret - -Use this option if you want to allow other developers to easily embed your bot into their websites. - -> [!WARNING] -> If you use this option, other developers can embed your bot into their websites -> by simply copying your embed code. - -To embed your bot in your website by specifying the secret within the `iframe` tag: - -1. Copy the `iframe` **Embed code** from the Web Chat channel within the Bot Framework Portal (as described in [Get your bot secret key](#get-your-bot-secret-key) above). - -2. Within that **Embed code**, replace "YOUR_SECRET_HERE" with the **Secret key** value that you copied from the same page. - -##### Example iframe (using secret) - -```html - -``` - -## Style the web chat control - -You may change the size of the web chat control by using the `style` attribute of the `iframe` to specify `height` and `width`. - -```html - -``` - -![Chat control Client](./media/chatwidget-client.png) - -## Additional resources - -You can [download the source code](https://aka.ms/BotFramework-WebChat-V4) for the web chat control on GitHub. diff --git a/articles/bot-service-channel-connect-wechat.md b/articles/bot-service-channel-connect-wechat.md deleted file mode 100644 index 20bf79e95..000000000 --- a/articles/bot-service-channel-connect-wechat.md +++ /dev/null @@ -1,161 +0,0 @@ ---- -title: Connect a bot to WeChat - Bot Service -description: Learn how to configure a bot's connection to WeChat. -keywords: WeChat, Tencent, bot channel, WeChat App, WeChat bot, App ID, App Secret, credentials -author: seaen -manager: kamrani -ms.topic: article -ms.author: egorn -ms.service: bot-service -ms.date: 11/01/2019 ---- - -# Connect a bot to WeChat - -You can configure your bot to communicate with people using the WeChat Official Accounts Platform. - -## Download WeChat Adapter for Bot Framework - -WeChat adapter for Microsoft Bot Framework is an open source adapter on GitHub. [Download WeChat Adapter for Bot Framework](https://github.com/microsoft/BotFramework-WeChat/). - -## Create a WeChat Account - -To configure a bot to communicate using WeChat, you need to create a WeChat official account on [WeChat Official Account Platform](https://mp.weixin.qq.com/?lang=en_US) and then connect the bot to the app. Currently we only support Service Account. - -### Change Your Prefer Language - -You can change the display language you prefer before login. - - ![change_language](./media/channels/wechat-change-language.png) - -### Register A Service Account - -A real service account must be verified by WeChat, you can’t enable webhook before account is verified. To create your own service account, please follow the instruction [Here](https://kf.qq.com/product/weixinmp.html#hid=87). -For short, just click the Register Now on the top, select the Service Account and follow the instruction. - - ![register_account](./media/channels/wechat-register-account.png) - -### Sandbox Account - -If you just want to test the WeChat and bot integration, you can use a sandbox account instead of creating the service account. Learn more about creating a [sandbox account](https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login). - -## Enable WeChat Adapter To Bot - -The Bot Project is a regular Bot Framework SDK V4 project. Before you can launch it, you need to make sure you can run the bot. Download [WeChat Adapter for Bot Framework](https://github.com/microsoft/BotFramework-WeChat/). - -### Prerequisites - - .NET Core SDK (version 2.2.x) - -### Add Reference To WeChat Adapter Source - -Please directly reference the WeChat adapter project or add ~/BotFramework-WeChat/libraries/csharp_dotnetcore/outputpackages as local NuGet source. - -### Inject WeChat Adapter In Your Bot Startup.cs - -```csharp -public void ConfigureServices(IServiceCollection services) -{ - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); - - // Create the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.) - services.AddSingleton(); - - // Create the User state. (Used in this bot's Dialog implementation.) - services.AddSingleton(); - - // Create the Conversation state. (Used by the Dialog system itself.) - services.AddSingleton(); - - // Load WeChat settings. - var wechatSettings = new WeChatSettings(); - Configuration.Bind("WeChatSettings", wechatSettings); - services.AddSingleton(wechatSettings); - - // Configure hosted serivce. - services.AddSingleton(); - services.AddHostedService(); - services.AddSingleton(); - - // The Dialog that will be run by the bot. - services.AddSingleton(); - - // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. - services.AddTransient(); -} -``` - -### Update Your Bot Controller - -```csharp -[Route("api/messages")] -[ApiController] -public class BotController : ControllerBase -{ - private readonly IBot _bot; - private readonly WeChatHttpAdapter _weChatHttpAdapter; - private readonly string Token; - public BotController(IBot bot, WeChatHttpAdapter weChatAdapter) - { - _bot = bot; - _weChatHttpAdapter = weChatAdapter; - } - - [HttpPost("/WeChat")] - [HttpGet("/WeChat")] - public async Task PostWeChatAsync([FromQuery] SecretInfo secretInfo) - { - // Delegate the processing of the HTTP POST to the adapter. - // The adapter will invoke the bot. - await _weChatHttpAdapter.ProcessAsync(Request, Response, _bot, secretInfo); - } -} -``` - -### Setup appsettings.json - -You will need to set up appsettings.json before start up the bot, you can find what you need below. - -```json -"WeChatSettings": { - "UploadTemporaryMedia": true, - "PassiveResponseMode": false, - "Token": "", - "EncodingAESKey": "", - "AppId": "", - "AppSecret": "" -} -``` - -#### Service Account - -If you already have a service account and ready to deploy, then you can find **AppID** , **AppSecret** , **EncodingAESKey** and **Token** in the basic configurations on the left nav bar, like below. - -Don't forgot you need to set up the IP white list, otherwise WeChat won't accept your request. - - ![serviceaccount_console](./media/channels/wechat-serviceaccount-console.png) - -#### Sandbox Account - -Sandbox account don't have **EncodingAESKey** , message from WeChat was not encrypted just leave EncodingAESKey blank. You only have three parameters here, **appID** , **appsecret** and **Token**. - - ![sandbox_account](./media/channels/wechat-sandbox-account.png) - -### Start Bot And Set Endpoint URL - -Now you can set your bot backend. Before you are doing this, you have to start the bot before you save the settings, WeChat will send you a request to verify the URL. -Please set the endpoint in such pattern: **https://your_end_point/WeChat**, or set your personal settings the same with what you have done in BotController.cs - - ![sandbox_account2](./media/channels/wechat-sandbox-account-2.png) - -### Subscribe Your Official Account - -You can find a QR code to subscribe your test account as in WeChat. - - ![subscribe](./media/channels/wechat-subscribe.png) - -## Test Through WeChat - -Everything is done, you can try it in your WeChat client. You can try our sample bot under tests folder. This sample bot includes wechat adapter and integrated with echo bot and Cards bot. - - ![chat](./media/channels/wechat-chat.png) diff --git a/articles/bot-service-channel-directline-extension-net-bot.md b/articles/bot-service-channel-directline-extension-net-bot.md deleted file mode 100644 index bb05343b5..000000000 --- a/articles/bot-service-channel-directline-extension-net-bot.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: .NET bot with direct line app service extension -titleSuffix: Bot Service -description: Enable .NET bot to work with direct line app service extension -services: bot-service -manager: kamrani -ms.service: bot-service -ms.topic: conceptual -ms.author: kamrani -ms.date: 01/16/2020 ---- - -# Configure .NET bot for extension - -[!INCLUDE[applies-to-v4](includes/applies-to.md)] - -This article describes how to update a bot to work with **named pipes**, and how to enable the direct line app service extension in the **Azure App Service** resource where the bot is hosted. - -## Prerequisites - -In order to perform the steps described next, you must have **Azure App Service** resource and related **App Service** in Azure. - -## Enable Direct Line App Service Extension - -This section describes how to enable the direct line app service extension using keys from your bot’s channel configuration and the **Azure App Service** resource where your bot is hosted. - -## Update .NET Bot to use Direct Line App Service Extension - -> [!NOTE] -> `Microsoft.Bot.Builder.StreamingExtensions` are preview packages and will not be updated. The SDK v4.7 contains the [streaming code](https://github.com/microsoft/botbuilder-dotnet/tree/master/libraries/Microsoft.Bot.Builder/Streaming) and you do not need to install the Streaming Packages separately. - -1. In Visual Studio, open your bot project. -2. Add the **Streaming Extension NuGet** package to your project: - 1. In your project, right click on **Dependencies** and select **Manage NuGet Packages**. - 2. Under the *Browse* tab, click **Include prerelease** to show the preview packages. - 3. Select the package **Microsoft.Bot.Builder.StreamingExtensions**. - 4. Click the **Install** button to install the package; read and agree to the license agreement. -3. Allow your app to use the **Bot Framework NamedPipe**: - - Open the `Startup.cs` file. - - In the ``Configure`` method, add code to ``UseBotFrameworkNamedPipe`` - - ```csharp - - public void Configure(IApplicationBuilder app, IHostingEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseHsts(); - } - - app.UseDefaultFiles(); - app.UseStaticFiles(); - - // Allow the bot to use named pipes. - app.UseNamedPipes(); - - app.UseMvc(); - } - ``` - -4. Save the `Startup.cs` file. -5. Open the `appsettings.json` file and enter the following values: - 1. `"MicrosoftAppId": ""` - 2. `"MicrosoftAppPassword": ""` - - The values are the **appid** and the **appSecret** associated with the service registration group. - -6. **Publish** the bot to your Azure App Service. - -### Gather your Direct Line Extension keys - -1. In your browser, navigate to the [Azure portal](https://portal.azure.com/) -1. In the Azure portal, locate your **Azure Bot Service** resource -1. Click on **Channels** to configure the bot’s channels -1. If it is not already enabled, click on the **Direct Line** channel to enable it. -1. If it is already enabled, in the Connect to channels table click on the **Edit** link on the Direct Line row. -1. Scroll down to the App Service Extension Keys section. -1. Click on the **Show link** to reveal one of the keys, then copy its value. - -![App service extension keys](./media/channels/direct-line-extension-extension-keys.png) - -### Enable the Direct Line App Service Extension - -1. In your browser, navigate to the [Azure portal](https://portal.azure.com/) -1. In the Azure portal, locate the **Azure App Service** resource page for the Web App where your bot is or will be hosted -1. Click on **Configuration**. Under the *Application settings* section, add the following new settings: - - |Name|Value| - |---|---| - |DirectLineExtensionKey|| - |DIRECTLINE_EXTENSION_VERSION|latest| - -1. Within the *Configuration* section, click on the **General** settings section and turn on **Web sockets** -1. Click on **Save** to save the settings. This restarts the Azure App Service. - -## Confirm Direct Line App Extension and the Bot are Initialized - -In your browser, navigate to https://.azurewebsites.net/.bot. -If everything is correct, the page will return this JSON content: `{"k":true,"ib":true,"ob":true,"initialized":true}`. This is the information you obtain when **everything works correctly**, where - -- **k** determines whether Direct Line App Service Extension (ASE) can read an App Service Extension Key from its configuration. -- **initialized** determines whether Direct Line ASE can use the App Service Extension Key to download the bot metadata from Azure Bot Service -- **ib** determines whether Direct Line ASE can establish an inbound connection with the bot. -- **ob** determines whether Direct Line ASE can establish an outbound connection with the bot. diff --git a/articles/bot-service-channel-directline-extension-net-client.md b/articles/bot-service-channel-directline-extension-net-client.md deleted file mode 100644 index 0cdbd4203..000000000 --- a/articles/bot-service-channel-directline-extension-net-client.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -title: Create .NET client for direct line app service extension -titleSuffix: Bot Service -description: .NET client C# to connect to direct line app service extension -services: bot-service -manager: kamrani -ms.service: bot-service -ms.topic: conceptual -ms.author: kamrani -ms.date: 07/25/2019 ---- - -# Create .NET Client to Connect to Direct Line App Service Extension - -This article describes how to create a .NET client in C# which connects to the direct line app service extension. - -## Gather your Direct Line Extension keys - -1. In your browser, navigate to the [Azure portal](https://portal.azure.com/) -1. In the Azure portal, locate your **Azure Bot Service** resource -1. Click on **Channels** to configure the bot’s channels -1. If it is not already enabled, click on the **Direct Line** channel to enable it. -1. If it is already enabled, in the Connect to channels table click on the **Edit** link on the Direct Line row. -1. Scroll to the Sites section. There is typically a Default Site unless you have deleted or renamed it. -1. Click on the **Show link** to reveal one of the keys, then copy its value. - - ![App service extension keys](./media/channels/direct-line-extension-extension-keys-net-client.png) - -> [!NOTE] -> This value is your direct line client secret used to connect to direct -line app service extension. You can create additional sites if you’d like and use -those secret values as well. - -## Add the Preview Nuget Package Source - -The preview NuGet packages needed to create a C# Direct line client can be found in a NuGet feed. - -1. In Visual Studio navigate to the **Tools->Options** menu item. -1. Select the **NuGet Package Manager->Package Sources** item. -1. Click on the + button to add a new package source with these values: - - Name: DL ASE Preview - - Source: https://botbuilder.myget.org/F/experimental/api/v3/index.json -1. Click on the **Update** button to save the values. -1. Click **OK** to exit the Package Sources configuration. - -## Create a C# Direct Line Client - -Interactions with the direct line app service extension happen differently than traditional Direct Line becuase most communication happens over a *WebSocket*. The updated direct line client includes helper classes for opening and closing a *WebSocket*, sending commands through the WebSocket, and receiving Activities back from the bot. This section describes how to create a simple C# client to interact with a bot. - -1. Create a new .NET Core 2.2 console application project in Visual Studio. -1. Add the **DirectLine client NuGet** to your project - - Click on Dependencies in the Solution tree - - Select **Manage Nuget Packages...** - - Change the Package source to the one you defined from above (DL ASE Preview) - - Find the package *Microsoft.Bot.Connector.Directline* version v3.0.3-Preview1 or later. - - Click on **Install Package**. -1. Create a client and generate a token using a secret. This step is the same as building any other C# Direct Line client except the endpoint you need use in your bot,appended with the **.bot/** path as shown next. Do not forget the ending **/**. - - ```csharp - string endpoint = "https://.azurewebsites.net/.bot/"; - string secret = ""; - - var tokenClient = new DirectLineClient( - new Uri(endpoint), - new DirectLineClientCredentials(secret)); - var conversation = await tokenClient.Tokens.GenerateTokenForNewConversationAsync(); - ``` - -1. Once you have a conversation reference from generating a token, you can use this conversation ID to open a WebSocket with the new `StreamingConversations` property on the `DirectLineClient`. To do this you need to create a callback that will be invoked when the bot wants to send `ActivitySets` to the client: - - ```csharp - public static void ReceiveActivities(ActivitySet activitySet) - { - if (activitySet != null) - { - foreach (var a in activitySet.Activities) - { - if (a.Type == ActivityTypes.Message && a.From.Id.Contains("bot")) - { - Console.WriteLine($": {a.Text}"); - } - } - } - } - ``` - -1. Now you are ready to open the WebSocket on the `StreamingConversations` property using the conversation’s token, `conversationId`, and your `ReceiveActivities` callback: - - ```csharp - var client = new DirectLineClient( - new Uri(endpoint), - new DirectLineClientCredentials(conversation.Token)); - - await client.StreamingConversations.ConnectAsync( - conversation.ConversationId, - ReceiveActivities); - ``` - -1. The client can now be used to start a conversation and send `Activities` to the bot: - - ```csharp - - var startConversation = await client.StreamingConversations.StartConversationAsync(); - var from = new ChannelAccount() { Id = "123", Name = "Fred" }; - var message = Console.ReadLine(); - - while (message != "end") - { - try - { - var response = await client.StreamingConversations.PostActivityAsync( - startConversation.ConversationId, - new Activity() - { - Type = "message", - Text = message, - From = from - }); - } - catch (OperationException ex) - { - Console.WriteLine( - $"OperationException when calling PostActivityAsync: ({ex.StatusCode})"); - } - message = Console.ReadLine(); - } - ``` diff --git a/articles/bot-service-channel-directline-extension-node-bot.md b/articles/bot-service-channel-directline-extension-node-bot.md deleted file mode 100644 index 8120a5789..000000000 --- a/articles/bot-service-channel-directline-extension-node-bot.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: Node.js bot with direct line app service extension -titleSuffix: Bot Service -description: Enable Node.js bot to work with direct line app service extension -services: bot-service -manager: kamrani -ms.service: bot-service -ms.topic: conceptual -ms.author: dev -ms.date: 01/15/2020 ---- - -# Configure Node.js bot for extension - -[!INCLUDE[applies-to-v4](includes/applies-to.md)] - -This article describes how to update a bot to work with **named pipes**, and how to enable the direct line app service extension in the **Azure App Service** resource where the bot is hosted. - -## Prerequisites - -In order to perform the steps described next, you must have **Azure App Service** resource and related **App Service** in Azure. - -## Enable Direct Line App Service Extension - -This section describes how to enable the direct line app service extension using keys from your bot’s channel configuration and the **Azure App Service** resource where your bot is hosted. - -## Update Node.js Bot to use Direct Line App Service Extension - -1. BotBuilder v4.7.0 or higher is required to use a Node.js bot with Direct Line App Service Extension. -1. To update an existing bot using v4.x of the SDK - 1. In the root directory of your bot run `npm install --save botbuilder` to update to the latest packages. -1. Allow your app to use the **Direct Line App Service Extension Named Pipe**: - - Update the bot's index.js (below the assignment of the adapter and bot) to include: - - ```Node.js - - adapter.useNamedPipe(async (context) => { - await myBot.run(context); - }); - ``` - -1. Save the `index.js` file. -1. Update the default `Web.Config` file to add the `AspNetCore` handler needed by Direct Line App Service Extension to service requests: - - Locate the `Web.Config` file in the `wwwroot` directory of your bot and replace the default contents with: - - ```XML - - - - - - - - - - - ``` - -1. Open the `appsettings.json` file and enter the following values: - 1. `"MicrosoftAppId": ""` - 1. `"MicrosoftAppPassword": ""` - - The values are the **appid** and the **appSecret** associated with the service registration group. - -1. **Publish** the bot to your Azure App Service. - -### Gather your Direct Line App Service Extension keys - -1. In your browser, navigate to the [Azure portal](https://portal.azure.com/) -1. In the Azure portal, locate your **Azure Bot Service** resource -1. Click on **Channels** to configure the bot’s channels -1. If it is not already enabled, click on the **Direct Line** channel to enable it. -1. If it is already enabled, in the Connect to channels table click on the **Edit** link on the Direct Line row. -1. Scroll down to the **App Service Extension Keys** section. -1. Click on the **Show link** to reveal one of the keys, then copy its value. - -![App service extension keys](./media/channels/direct-line-extension-extension-keys.png) - -### Enable the Direct Line App Service Extension - -1. In your browser, navigate to the [Azure portal](https://portal.azure.com/) -1. In the Azure portal, locate the **Azure App Service** resource page for the Web App where your bot is or will be hosted -1. Click on **Configuration**. Under the *Application settings* section, add the following new settings: - - |Name|Value| - |---|---| - |DirectLineExtensionKey|| - |DIRECTLINE_EXTENSION_VERSION|latest| - -1. Within the *Configuration* section, click on the **General** settings section and turn on **Web sockets** -1. Click on **Save** to save the settings. This restarts the Azure App Service. - -### Confirm Direct Line App Extension and the Bot are Initialized - -1. In your browser, navigate to https://.azurewebsites.net/.bot. -If everything is correct, the page will return this JSON content: `{"k":true,"ib":true,"ob":true,"initialized":true}`. This is the information you obtain when **everything works correctly**, where - - - **k** determines whether Direct Line App Service Extension (ASE) can read an App Service Extension Key from its configuration. - - **initialized** determines whether Direct Line ASE can use the App Service Extension Key to download the bot metadata from Azure Bot Service - - **ib** determines whether Direct Line ASE can establish an inbound connection with the bot. - - **ob** determines whether Direct Line ASE can establish an outbound connection with the bot. diff --git a/articles/bot-service-channel-directline-extension-vnet.md b/articles/bot-service-channel-directline-extension-vnet.md deleted file mode 100644 index b92002120..000000000 --- a/articles/bot-service-channel-directline-extension-vnet.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: Use direct line app service extension within a VNET -titleSuffix: Bot Service -description: Use direct line app service extension within a VNET -services: bot-service -manager: kamrani -ms.service: bot-service -ms.topic: conceptual -ms.author: kamrani -ms.date: 07/25/2019 ---- - -# Use direct line app service extension within a VNET - -This article describes how to use the Direct Line App Service Extension with an Azure Virtual Network (VNET). - -## Create an App Service Environment and other Azure resources - -1. Direct line app service extension is available on all **Azure App Services**, including those hosted within an **Azure App Service Environment**. An Azure App Service Environment provides isolation and is ideal for working within a VNET. - - Instructions for creating an external App Service Environment can be found in [Create an External App Service environment](https://docs.microsoft.com/azure/app-service/environment/create-external-ase) article. - - Instructions for creating an internal App Service Environment can be found in [Create and use an Internal Load Balancer App Service Environment](https://docs.microsoft.com/azure/app-service/environment/create-ilb-ase) article. -1. Once you have created your App Service Environment, you need to add an App Service Plan inside of it where you can deploy your bots (and thus run Direct Line App Service Extension). To do this: - - Go to https://portal.azure.com/ - - Create a new “App Service Plan” resource. - - Under Region, select your App Service Environment - - Finish creating your App Service Plan - -## Configure the VNET Network Security Groups (NSG) - -1. Direct Line App Service Extension requires an outbound connection so that it can issue HTTP requests. This can be configured as an outbound rule in your VNET NSG that is associated with the App Service Environment’s subnet. The rule that required is as follows: - -|Source|Any| -|---|---| -|Source Port|*| -|Destination|IP Addresses| -|Destination IP addresses|20.38.80.64, 40.82.248.64| -|Destination port ranges|443| -|Protocol|Any| -|Action|Allow| - - -![Direct line extension architecture](./media/channels/direct-line-extension-vnet.png) - ->[!NOTE] -> The IP addresses provided are explicitly for the preview. We will be moving to a Service Tag for Azure Bot Service later in the year which will change this configuration. - -### Configure your bot’s App Service - -For the preview, you will need to change how your Direct line app service extension communicates with Azure. This can be done by adding a new **App Service Application Setting** to your application using the portal, or the `applicationsettings.json` file: - -- Property: DirectLineExtensionABSEndpoint -- Value: https://st-directline.botframework.com/v3/extension - ->[!NOTE] -> This will only be required for the preview of Direct line app service extension. diff --git a/articles/bot-service-channel-directline-extension-webchat-client.md b/articles/bot-service-channel-directline-extension-webchat-client.md deleted file mode 100644 index e423d89e8..000000000 --- a/articles/bot-service-channel-directline-extension-webchat-client.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Use WebChat with the direct line app service extension -titleSuffix: Bot Service -description: Use WebChat with the direct line app service extension -services: bot-service -manager: kamrani -ms.service: bot-service -ms.topic: conceptual -ms.author: kamrani -ms.date: 07/25/2019 ---- - -# Use WebChat with the direct line app service extension - -This article describes how to use WebChat with the direct line app service extension. - -## Get Your Direct Line Secret - -The first step is to find your direct line secret. You can do this by following the instructions described in [Connect a bot to Direct Line](bot-service-channel-connect-directline.md) article. - -## Get the preview version of DirectLineJS -The preview version of DirectLineJS can be found here: -https://github.com/Jeffders/DirectLineAppServiceExtensionPreview/tree/master/libraries - -## Integrate WebChat client - -Generally speaking, the approach is the same as before. With the exception that a new version of **WebChat** has been created that supports two-way **WebSocket** traffic, which instead of connecting to https://directline.botframework.com/ connects directly to your hosted bot. -The direct line URL for your bot will be `https://.azurewebsites.net/.bot/`, where the `/.bot/` extension is the Direct Line **endpoint** on your App Service. -If you can configure your own domain name you still must append the `/.bot/` path to access the direct line REST APIs. - -1. Exchange the secret for a token by following the instructions in the [Authentication](https://docs.microsoft.com/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-authentication?view=azure-bot-service-4.0) article. But, instead of obtaining a token at this location: `https://directline.botframework.com/v3/directline/tokens/generate`, you generate the token directly from your Direct Line App Service Extension at this location: `https://.azurewebsites.net/.bot/v3/directline/tokens/generate`. - -1. Once you have a token, you can update the webpage that uses WebChat with these changes: - -```html - - - - Direct Line Streaming Sample - - - - - - -
- - - - -``` diff --git a/articles/bot-service-channel-directline-extension.md b/articles/bot-service-channel-directline-extension.md deleted file mode 100644 index fa90e350b..000000000 --- a/articles/bot-service-channel-directline-extension.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Direct line app service extension -titleSuffix: Bot Service -description: Direct line app service extension features -services: bot-service -manager: kamrani -ms.service: bot-service -ms.topic: conceptual -ms.author: kamrani -ms.date: 07/09/2019 ---- - -# Direct Line App Service Extension - -[!INCLUDE[applies-to-v4](includes/applies-to.md)] - -> [!WARNING] -> The **Direct Line App Service Extension** is in public **preview**. - -The direct line app service extension allows clients to connect directly with the host, where the bot is located. This provides workload isolation and, in some cases, improved performance. The following picture shows the overall architecture: - -![Direct line extension architecture](./media/channels/direct-line-extension-architecture.png) - -The direct line app service extension adds a new set of streaming extensions to the Bot Framework protocol, which replace HTTP for exchanging messages with a transport that allows bidirectional requests to be sent over a **persistent WebSocket**. - -Before streaming extensions, the Direct Line API offered one way for a client to send Activities to Direct Line and two ways for a client to retrieve Activities from Direct Line. The messages were sent via an HTTP POST, and received by either an HTTP GET (polling) or by opening a WebSocket to receive ActivitySets. -Streaming extensions expand on the use of the WebSocket an allows **all messaging communication** to be sent on that WebSocket. Streaming extensions can also be used between channel services and the bot. - -The direct line app service extension is pre-installed on all instances of Azure App Services in every data center around the world. It is maintained and managed by Microsoft without additional deployment work for the customer. It is disabled on Azure App Services by default, but it can be easily turned on so that it can connect to your hosted bot. - - -## See Also - -|Name|Description| -|---|---| -|[Configure .NET bot for extension](bot-service-channel-directline-extension-net-bot.md)|Update a .NET bot to work with **named pipes**, and enable the Direct Line App Service Extension in the **Azure App Service** resource where the bot is hosted. | -|[Configure Node.js bot for extension](bot-service-channel-directline-extension-node-bot.md)|Update a Node.js bot to work with **named pipes** and enable the Direct Line App Service Extension in the **Azure App Service** resource where the bot is hosted. | -|[Create .NET client with Extension](bot-service-channel-directline-extension-net-client.md)|Create a .NET client in C# which connects to the direct line app service extension| -|[Use extension with WebChat](bot-service-channel-directline-extension-webchat-client.md)|Use WebChat with the direct line app service extension| -|[Use extension within VNET](bot-service-channel-directline-extension-vnet.md)|Use the direct line app service extension with an Azure Virtual Network (VNET)| - -## Additional resources - -- [Connect a bot to Direct Line](bot-service-channel-connect-directline.md) -- [Connect a bot to Direct Line Speech](bot-service-channel-connect-directlinespeech.md) diff --git a/articles/bot-service-channel-directline.md b/articles/bot-service-channel-directline.md deleted file mode 100644 index 0b891a443..000000000 --- a/articles/bot-service-channel-directline.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: About Direct Line channel -titleSuffix: Bot Service -description: Direct Line channel features -services: bot-service -author: ivorb -manager: kamrani -ms.service: bot-service -ms.topic: conceptual -ms.date: 11/01/2019 -ms.author: kamrani ---- - -# About Direct Line - -The Bot Framework Direct Line channel is an easy way to integrate your bot into your mobile app, webpage, or other application. -Direct Line is available in three forms: -- Direct Line service – a global, robust service for most developers -- Direct Line App Service Extensions – dedicated Direct Line functionality for security and performance (available in public preview) -- Direct Line Speech – optimized for high-performance speech (GA) - -You can choose which offering of Direct Line is best for you by evaluating the features each offers and the needs of your solution. -Over time these offerings will be simplified. - -| | Direct Line | Direct Line App Service Extension | Direct Line Speech | -|----------------------------|-------------|-----------------------------------|--------------------| -| Availability and Licensing | General availability | Public preview, no SLA | GA | -| Speech recognition and text-to-speech performance | Standard | Standard | High performance | -| Supports legacy web browsers | Yes | At GA | Yes | -| Bot Framework SDK support | All v3, v4 | v4.63+ required | v4.63+ required | -| Client SDK support | JS, C# | JS, C# | C++, C#, Unity, JS| -| Works with Web Chat | Yes | Yes | No| -| VNET | No | Preview | No | - - -## Additional resources -- [Connect a bot to Direct Line](bot-service-channel-connect-directline.md) -- [Connect a bot to Direct Line Speech](bot-service-channel-connect-directlinespeech.md) diff --git a/articles/bot-service-channels-reference.md b/articles/bot-service-channels-reference.md deleted file mode 100644 index 52a87605c..000000000 --- a/articles/bot-service-channels-reference.md +++ /dev/null @@ -1,288 +0,0 @@ ---- -title: Channels reference -description: Bot Framework Channels reference -keywords: channels reference, bot builder channels, bot framework channels -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/03/2019 ---- - -# Categorized activities by channel - -The following tables show what events (Activities on the wire) can come from which channels. - -This is the key for the tables: - -Symbol | Meaning -:------------------:|:------------------------------------------------ -:white_check_mark: |The Bot should expect to receive this Activity -:x: |The Bot should **never** expect to receive this Activity -:white_large_square:|Currently undetermined whether the Bot can receive this - -Activities can meaningfully be split into separate categories. For each category we have a table of possible Activities. - -Conversational --------------- - - \ | Cortana | Direct Line | Direct Line (Web Chat) | Email | Facebook | GroupMe | Kik | Teams | Slack | Skype | Skype Business | Telegram | Twilio -:---------------------- | :-----: | :----------------: | :--------------------: |:----: | :------: | :-----: | :-----: | :---: | :---: | :---: | :------------: | :------: | :----: -Message | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: -MessageReaction | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: - -- All Channels send Message Activities. -- When using a Dialog, Message Activities should generally always be passed onto the Dialog. -- This is probably not true of the MessageReaction although they are very much part of the conversation. -- There are logically two types of MessageReaction: Added and Removed - - -> [!TIP] -> "Message Reactions" are things like a "thumbs up" on a previous comment. They can happen out of order, so they can be thought of as similar to buttons. This Activity is currently sent by the Teams Channel. - - -Welcome -------- - - \ | Cortana | Direct Line | Direct Line (Web Chat) | Email | Facebook | GroupMe | Kik | Teams | Slack | Skype | Skype Business | Telegram | Twilio -:---------------------- | :-----: | :---------: | :--------------------: |:----: | :------: | :-----: | :-----: | :---: | :---: | :---: | :------------: | :------: | :----: -ConversationUpdate | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_large_square: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: -ContactRelationUpdate | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: - -- It is common for Channels to send ConversationUpdate Activities. -- There are logically two types of MessageReaction: Added and Removed -- It is very tempting to assume bot "Welcome" behavior can be simply implemented by wiring up ConversationUpdate.Added and this sometimes works. -- However, this is a simplification, in order to produce a reliable "Welcome" behavior the bot implementation may also need to use state. - - -Application Extensibility -------------------------- - - \ | Cortana | Direct Line | Direct Line (Web Chat) | Email | Facebook | GroupMe | Kik | Teams | Slack | Skype | Skype Business | Telegram | Twilio -:---------------------- | :-----: | :---------: | :--------------------: |:----: | :------: | :-----: | :-----: | :---: | :---: | :---: | :------------: | :------: | :----: -Event.* | :white_large_square: | :white_check_mark: | :white_check_mark: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: -Event.CreateConversation | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: -Event.ContinueConversation | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: - -- Event Activities are an extensibility mechanism in Direct Line (_aka Web Chat_). -- An application that owns both the client and server may chose to tunnel their own events through the service using this Event Activity. - - -Microsoft Teams ------------------- - - \ | Cortana | Direct Line | Direct Line (Web Chat) | Email | Facebook | GroupMe | Kik | Teams | Slack | Skype | Skype Business | Telegram | Twilio -:---------------------- | :-----: | :---------: | :--------------------: |:----: | :------: | :-----: | :-----: | :---: | :---: | :---: | :------------: | :------: | :----: -Invoke.TeamsVerification | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: -Invoke.ComposeResponse | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: - -- Along with a number of the other typed Activities, Microsoft Teams defines a few Teams specific Invoke Activities. -- Invoke Activities are specific to an application and not something a client would define. -- There is no general notion of Invoke specific subtypes of the activity. -- Invoke is currently the only Activity that triggers a request-reply behavior on the bot. - -This is very important: if using Dialogs for the OAuth Prompt to work the Invoke.TeamsVerification Activity must be forwarded to the Dialog. - - -Message Update --------------- - - \ | Cortana | Direct Line | Direct Line (Web Chat) | Email | Facebook | GroupMe | Kik | Teams | Slack | Skype | Skype Business | Telegram | Twilio -:---------------------- | :-----: | :---------: | :--------------------: |:----: | :------: | :-----: | :-----: | :---: | :---: | :---: | :------------: | :------: | :----: -MessageUpdate | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :white_large_square: | :x: | :x: | :x: | :x: -MessageDelete | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :white_large_square: | :x: | :x: | :x: | :x: - -- Message Update is currently supported by Teams. - - -OAuth -------- - - \ | Cortana | Direct Line | Direct Line (Web Chat) | Email | Facebook | GroupMe | Kik | Teams | Slack | Skype | Skype Business | Telegram | Twilio -:---------------------- | :-----: | :---------: | :--------------------: |:----: | :------: | :-----: | :-----: | :---: | :---: | :---: | :------------: | :------: | :----: -Event.TokenResponse| :white_large_square: | :white_check_mark: | :white_check_mark: | :x: | :white_large_square: | :white_large_square: | :white_large_square: | :x: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: - -This is very important: if using Dialogs for the OAuth Prompt to work the Event.TokenResponse Activity must be forwarded to the Dialog. - - -Uncategorized -------------- - - \ | Cortana | Direct Line | Direct Line (Web Chat) | Email | Facebook | GroupMe | Kik | Teams | Slack | Skype | Skype Business | Telegram | Twilio -:---------------------- | :-----: | :---------: | :--------------------: |:----: | :------: | :-----: | :-----: | :---: | :---: | :---: | :------------: | :------: | :----: -EndOfConversation | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: -InstallationUpdate | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: -Typing | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: -Handoff | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: - - -Out of Use (includes Payment specific Invoke) ---------------------------------------------- -- DeleteUserData -- Invoke.PaymentRequest -- Invoke.Address -- Ping - ---- - -## Summary of Activities supported per Channel - -Cortana -------- -- Message -- ConversationUpdate -- _Event.TokenResponse_ -- _EndOfConversation (when the window closes?)_ - -Direct Line --------- -- Message -- ConversationUpdate -- Event.TokenResponse -- Event.* -- _Event.CreateConversation_ -- _Event.ContinueConversation_ - -Email ------ -- Message - -Facebook --------- -- Message -- _Event.TokenResponse_ - -GroupMe -------- -- Message -- ConversationUpdate -- _Event.TokenResponse_ - -Kik ---- -- Message -- ConversationUpdate -- _Event.TokenResponse_ - -Teams ------ -- Message -- ConversationUpdate -- MessageReaction -- MessageUpdate -- MessageDelete -- Invoke.TeamsVerification -- Invoke.ComposeResponse - - -Slack ------ -- Message -- ConversationUpdate -- _Event.TokenResponse_ - - -Skype ------ -- Message -- ContactRelationUpdate -- _Event.TokenResponse_ - - -Skype Business --------------- -- Message -- ContactRelationUpdate -- _Event.TokenResponse_ - - -Telegram --------- -- Message -- ConversationUpdate -- _Event.TokenResponse_ - - -Twilio ------- -- Message - -## Summary Table All Activities to All Channels - - \ | Cortana | Direct Line | Direct Line (Web Chat) | Email | Facebook | GroupMe | Kik | Teams | Slack | Skype | Skype Business | Telegram | Twilio -:---------------------- | :-----: | :---------: | :--------------------: |:----: | :------: | :-----: | :-----: | :---: | :---: | :---: | :------------: | :------: | :----: -Message | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: -MessageReaction | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: -ConversationUpdate | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_large_square: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: -ContactRelationUpdate | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: -Event.* | :white_large_square: | :white_check_mark: | :white_check_mark: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: -Event.CreateConversation | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: -Event.ContinueConversation | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: -Invoke.TeamsVerification | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: -Invoke.ComposeResponse | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: -MessageUpdate | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :white_large_square: | :x: | :x: | :x: | :x: -MessageDelete | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :white_large_square: | :x: | :x: | :x: | :x: -Event.TokenResponse | :white_large_square: | :white_check_mark: | :white_check_mark: | :x: | :white_large_square: | :white_large_square: | :white_large_square: | :x: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: -EndOfConversation | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: -InstallationUpdate | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: -Typing | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: -Handoff | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: - -## Web Chat -Web Chat will send: -- "message": with "text" and/or "attachments" -- "event": with "name" and "value" (as JSON/string) -- "typing": if the user set an option, namely "sendTypingIndicator" -Web Chat will not send "contactRelationUpdate". And Web Chat do not support "messageReaction", no one explicitly ask us to support this feature. - -By default, Web Chat will render: -- "message": will render as either carousel or stacked, depends on the option in the activity -- "typing": will render for 5s and hide it, or until next activity come in -- "conversationUpdate": will hide -- "event": will hide -- Others: will show a warning box (we never see it in production) -You can modify this render pipeline to add, remove, or replace any custom render. - -You can use Web Chat to send any activity type and payload, we neither document nor recommend this feature. -You should use "event" activity instead. - -## Action support by channel - -The following table shows the maximum number of Suggested Actions and Card Actions that are supported in each channel. The :x: indicates that the action is not supported at all in the specified channel. - -| \ | Cortana | Direct Line | Direct Line (Web Chat) | Email | Facebook | GroupMe | Kik | Line | Teams | Slack | Skype | Skype Business | Telegram | Twilio | -| :---------------- | :-----: | :---------: | :--------------------: |:----: | :------: | :-----: | :-----: | :---: | :---: | :---: | :---: | :------------: | :------: | :----: | -| Suggested Actions | :x: | 100 | 100 | :x: | 10 | :x: | 20 | 13 | :x: | 100 | 10 | :x: | 100 | :x: | -| Card Actions | 100 | 100 | 100 | :x: | 3 | :x: | 20 | 99 | 3 | 100 | 3 | :x: | :x: | :x: | - -For more information about the numbers shown in the above table, refer to channel support code listed [here](https://aka.ms/channelactions). - -For more information on _Suggested Actions_, refer to the [Use button for input](https://aka.ms/howto-add-buttons) article. - -For more information on _Card Actions_, refer to the [Send a hero card](https://aka.ms/howto-add-media#send-a-hero-card) section of the _Add media to messages_ article. - -## Card Support by Channel - -| Channel | Adaptive Card | Animation Card | Audio Card | Hero Card | Receipt Card | Signin Card | Thumbnail Card | Video Card | -|:-------:|:-------------:|:--------------:|:----------:|:---------:|:------------:|:-----------:|:--------------:|:----------:| -|Cortana|✔|❌|❌|❌|✔|✔|✔|❌| -|Email|🔶|🌐|🌐|✔|✔|✔|✔|🌐| -|Facebook|⚠🔶|✔|❌|✔|✔|✔|✔|❌| -|GroupMe|🔶|🌐|🌐|🌐|🌐|🌐|🌐|🌐| -|Kik|🔶|✔|✔|❌|🌐|❌|✔|🌐| -|Line|⚠🔶|✔|🌐|✔|✔|✔|✔|🌐| -|Microsoft Teams|✔|❌|❌|✔|✔|✔|✔|❌| -|Skype|❌|✔|✔|✔|✔|✔|✔|✔| -|Slack|🔶|✔|🌐|🌐|✔|✔|🌐|🌐| -|Telegram|⚠🔶|✔|🌐|✔|✔|✔|✔|✔| -|Twilio|🔶|🌐|❌|🌐|🌐|🌐|🌐|❌| -|Web Chat|✔|✔|✔|✔|✔|✔|✔|✔| - -*Note: The Direct Line channel technically supports all cards, but it's up to the client to implement them* - -* ✔: Full Support -* ⚠: Partial Support - Card May Not Send if it Contains Inputs/Buttons. Varies by Channel. -* ❌: No Support -* 🔶: Card is Converted to Image -* 🌐: Card is Converted to Unformatted Text With Links and/or Images and/or Media Does Not Play in Client diff --git a/articles/bot-service-concept-intelligence.md b/articles/bot-service-concept-intelligence.md deleted file mode 100644 index 21e4487bf..000000000 --- a/articles/bot-service-concept-intelligence.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: Cognitive Services - Bot Service -description: Learn how to add artificial intelligence to your bots with Microsoft Cognitive Services to make them more useful and engaging. -keywords: language understanding, knowledge extraction, speech recognition, web search -author: RobStand -ms.author: rstand -manager: rstand -ms.topic: article -ms.service: bot-service -ms.date: 12/17/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Cognitive Services - -Microsoft Cognitive Services let you tap into a growing collection of powerful AI algorithms developed by experts in the fields of computer vision, speech, natural language processing, knowledge extraction, and web search. The services simplify a variety of AI-based tasks, giving you a quick way to add state-of-the-art intelligence technologies to your bots with just a few lines of code. The APIs integrate into most modern languages and platforms. The APIs are also constantly improving, learning, and getting smarter, so experiences are always up to date. - -Intelligent bots respond as if they can see the world as people see it. They discover information and extract knowledge from different sources to provide useful answers, and, best of all, they learn as they acquire more experience to continuously improve their capabilities. - -## Language understanding - -The interaction between users and bots is mostly free-form, so bots need to understand language naturally and contextually. The Cognitive Service Language APIs provide powerful language models to determine what users want, to identify concepts and entities in a given sentence, and ultimately to allow your bots to respond with the appropriate action. The five APIs support several text analytics capabilities, such as spell checking, sentiment detection, language modeling, and extraction of accurate and rich insights from text. - -Cognitive Services provides these APIs for language understanding: - -- The Language Understanding Intelligent Service (LUIS) is able to process natural language using pre-built or custom-trained language models. More details can be found on [Language understanding for bots](v4sdk/bot-builder-concept-luis.md) - -- The Text Analytics API detects sentiment, key phrases, topics, and language from text. - -- The Bing Spell Check API provides powerful spell check capabilities, and is able to recognize the difference between names, brand names, and slang. - -- The Text Analytics Models in Azure Machine Learning Studio allows you to build and operationalize text analytics models such as lemmatization and text-preprocessing. These models can help you address issues such as document classification or sentiment analysis problems. - -Learn more about [language understanding][language] with Microsoft Cognitive Services. - -## Knowledge extraction - -Cognitive Services provides four knowledge APIs that enable you to identify named entities or phrases in unstructured text, add personalized recommendations, provide auto-complete suggestions based on natural interpretation of user queries, and search academic papers and other research like a personalized FAQ service. - -- The Entity Linking Intelligence Service annotates unstructured text with the relevant entities mentioned in the text. Depending on the context, the same word or phrase may refer to different things. This service understands the context of the supplied text and will identify each entity in your text. - -- The Knowledge Exploration Service provides natural language interpretation of user queries and returns annotated interpretations to enable rich search and auto-completion experiences that anticipate what the user is typing. Instant query completion suggestions and predictive query refinements are based on your own data and application-specific grammars to enable your users to perform fast queries. - -- The Academic Knowledge API returns academic research papers, authors, journals, conferences, topics, and universities from the Microsoft Academic Graph. Built as a domain-specific example of the Knowledge Exploration Service, the Academic Knowledge API provides a knowledge base using a graph-like dialog with search capabilities over hundreds of millions of research-related entities. Search for a topic, a professor, a university, or a conference, and the API will provide relevant publications and related entities. The grammar also supports natural queries like "Papers by Michael Jordan about machine learning after 2010". - -- The QnA Maker is an easy-to-use REST API and web-based service that trains AI to respond to users’ questions in a natural, conversational way. With optimized machine learning logic and the ability to integrate industry-leading language processing, QnA Maker distills semi-structured data like question and answer pairs into distinct, helpful answers. - -Learn more about [knowledge extraction][knowledge] with Microsoft Cognitive Services. - -## Speech recognition and conversion - -Use the Speech APIs to add advanced speech skills to your bot that leverage industry-leading algorithms for speech-to-text and text-to-speech conversion, as well as speaker recognition. The Speech APIs use built-in language and acoustic models that cover a wide range of scenarios with high accuracy. - -For applications that require further customization, you can use the Custom Recognition Intelligent Service (CRIS). This allows you to calibrate the language and acoustic models of the speech recognizer by tailoring it to the vocabulary of the application, or even to the speaking style of your users. - -There are three Speech APIs available in Cognitive Services to process or synthesize speech: - -- The Bing Speech API provides speech-to-text and text-to-speech conversion capabilities. -- The Custom Recognition Intelligent Service (CRIS) allows you to create custom speech recognition models to tailor the speech-to-text conversion to an application's vocabulary or user's speaking style. -- The Speaker Recognition API enables speaker identification and verification through voice. - -The following resources provide additional information about adding speech recognition to your bot. - -* [Bot Conversations for Apps video overview](https://channel9.msdn.com/events/Build/2017/P4114) -* [Microsoft.Bot.Client library for UWP or Xamarin apps](https://aka.ms/bot-client) -* [Bot Client Library Sample](https://aka.ms/trivia-bot-speech-sample) -* [Speech-enabled WebChat Client](https://aka.ms/BotFramework-WebChat) - -Learn more about [speech recognition and conversion][speech] with Microsoft Cognitive Services. - -## Web search - -The Bing Search APIs enable you to add intelligent web search capabilities to your bots. With a few lines of code, you can access billions of webpages, images, videos, news, and other result types. You can configure the APIs to return results by geographical location, market, or language for better relevance. You can further customize your search using the supported search parameters, such as Safesearch to filter out adult content, and Freshness to return results according to a specific date. - -There are five Bing Search APIs available in Cognitive Services. - -- The Web Search API provides web, image, video, news and related search results with a single API call. - -- The Image Search API returns image results with enhanced metadata (dominant color, image kind, etc.) and supports several image filters to customize the results. - -- The Video Search API retrieves video results with rich metadata (video size, quality, price, etc.), video previews, and supports several video filters to customize the results. - -- The News Search API finds news articles around the world that match your search query or are currently trending on the Internet. - -- The Autosuggest API offers instant query completion suggestions to complete your search query faster and with less typing. - -Learn more about [web search][search] with Microsoft Cognitive Services. - -## Image and video understanding - -The Vision APIs bring advanced image and video understanding skills to your bots. -State-of-the-art algorithms allow you to process images or videos and get back information you can transform into actions. For example, you can use them to recognize objects, people's faces, age, gender or even feelings. - -The Vision APIs support a variety of image understanding features. They can identify mature or explicit content, estimate and accent colors, categorize the content of images, perform optical character recognition, and describe an image with complete English sentences. The Vision APIs also support several image and video processing capabilities, such as intelligently generating image or video thumbnails, or stabilizing the output of a video. - -Cognitive Services provide four APIs you can use to process images or videos: - -- The Computer Vision API extracts rich information about images (such as objects or people), determines if the image contains mature or explicit content, and processes text (using OCR) in images. - -- The Emotion API analyzes human faces and recognizes their emotion across eight possible categories of human emotions. - -- The Face API detects human faces, compares them to similar faces, and can even organize people into groups according to visual similarity. - -- The Video API analyzes and processes video to stabilize video output, detects motion, tracks faces, and can generate a motion thumbnail summary of the video. - -Learn more about [image and video understanding][vision] with Microsoft Cognitive Services. - -## Additional resources - -You can find comprehensive documentation of each product and their corresponding API references in the Cognitive Services documentation. - -[language]: https://docs.microsoft.com/azure/cognitive-services/luis/home -[search]: https://docs.microsoft.com/azure/cognitive-services/bing-web-search/search-the-web -[vision]: https://docs.microsoft.com/azure/cognitive-services/computer-vision/home -[knowledge]: https://docs.microsoft.com/azure/cognitive-services/kes/overview -[speech]: https://docs.microsoft.com/azure/cognitive-services/speech/home -[location]: https://docs.microsoft.com/azure/cognitive-services/ diff --git a/articles/bot-service-concept-templates.md b/articles/bot-service-concept-templates.md deleted file mode 100644 index 7c3818790..000000000 --- a/articles/bot-service-concept-templates.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: Bot Service templates - Bot Service -description: Learn about the different templates you can use when you create a bot with Bot Service. -author: robstand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Bot Service templates - -[!INCLUDE [pre-release-label](includes/pre-release-label-v3.md)] - -Bot Service includes five templates to help you get started with building bots. These templates provide a fully functional bot out of the box to help you get started quickly. When you [create a bot](bot-service-quickstart.md), you choose a template and the SDK language for your bot. - -Each template provides a starting point that is based on a core capability for a bot. - -## Basic bot -To create a bot that uses dialogs to respond to user input, choose the Basic template. The **Basic** template creates a bot that has the minimum set of files and code to get started. The bot echoes back to the user whatever they type in. You can use this template to get started building conversation flow in your bot. - -## Form bot -To create a bot that collects input from a user via a guided conversation, choose the **Form** template. A form bot is designed to collect a specific set of information from the user. For example, a bot that is designed to obtain a user's sandwich order would need to collect information such as type of bread, choice of toppings, size of sandwich, and so on. - -Bots created with the Form template in the C# language use [FormFlow](dotnet/bot-builder-dotnet-formflow.md) to manage forms, and bots created with the Form template in the Node.js language use [waterfalls](nodejs/bot-builder-nodejs-dialog-waterfall.md) to manage forms. - -## Language Understanding bot -To create a bot that uses natural language models to understand user intent, choose the **Language understanding** template. This template leverages Language Understanding (LUIS) to provide natural language understanding. - -If a user sends a message such as "get news about virtual reality companies," your bot can use LUIS to interpret the meaning of the message. Using LUIS, you can quickly deploy an HTTP endpoint that will interpret user input in terms of the intention that it conveys (find news) and the key entities that are present (virtual reality companies). LUIS enables you to specify the set of intents and entities that are relevant to your application, and then guides you through the process of building a language understanding application. - -When you create a bot using the Language understanding template, Bot Service creates a corresponding LUIS application that is empty (i.e., that always returns `None`). To update your LUIS application model so that it is capable of interpreting user input, you must sign-in to LUIS, click **My applications**, select the application that the service created for you, and then create intents, specify entities, and train the application. - -## Question and Answer bot -To create a bot that distills semi-structured data like question and answer pairs into distinct, helpful answers, choose the **Question and Answer** template. This template leverages the QnA Maker service to parse questions and provide answers. - -When you create a bot with the Question and Answer template, you must sign-in to QnA Maker and create a new QnA service. This QnA service will give you the knowledge base ID and subscription key that you can use to update your [App Settings](bot-service-manage-settings.md) values for **QnAKnowldegebasedId** and **QnASubscriptionKey**. Once those values are set, your bot can answer any questions that the QnA service has in its knowledge base. - -## Proactive bot -To create a bot that can send proactive messages to the user, choose the **Proactive template**. Typically, each message that a bot sends to the user directly relates to the user's prior input. In some cases though, a bot may need to send the user information that is not directly related to the user's most recent message. These types of messages are called **proactive messages**. Proactive messages can be useful in a variety of scenarios. For example, if a bot sets a timer or reminder, it may need to notify the user when the time arrives. Or, if a bot receives a notification about an external event, it may need to communicate that information to the user. - -When you create a bot by using the Proactive template, several Azure resources are automatically created and added to your resource group. By default, these Azure resources are already configured to enable a very simple proactive messaging scenario. - -| Resource | Description | -|----|----| -| Azure Storage | Used to create the queue. | -| Azure Function App | A `queueTrigger` Azure Function that is triggered whenever there is a message in the queue. It communicates to Bot Service by using [Direct Line](https://docs.microsoft.com/bot-framework/rest-api/bot-framework-rest-direct-line-3-0-concepts). This function uses bot binding to send the message as part of the trigger’s payload. Our example function forwards the user’s message as-is from the queue. -| Bot Service | Your bot. Contains the logic that receives the message from user, adds the message to the Azure queue, receives triggers from Azure Function, and sends back the message it received via trigger's payload. | - -The following diagram shows how triggered events work when you create a bot using the Proactive template. - -![Overview of example Proactive Bot](~/media/bot-proactive-diagram.png) - -The process begins when the user sends a message to your bot via Bot Framework servers (step 1). - -## Next steps -Now that you know about the different templates, learn about Cognitive Services for use within bots. - -> [!div class="nextstepaction"] -> [Cognitive Services for bots](bot-service-concept-intelligence.md) diff --git a/articles/bot-service-debug-bot.md b/articles/bot-service-debug-bot.md deleted file mode 100644 index 7a5531931..000000000 --- a/articles/bot-service-debug-bot.md +++ /dev/null @@ -1,158 +0,0 @@ ---- -title: Debug a bot - Bot Service -description: Learn how to debug a bot built using Bot Service. -author: v-ducvo -ms.author: kamrani -keywords: Bot Framework SDK, debug bot, test bot, bot emulator, emulator -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 2/26/2019 ---- - -# Debug a bot - -This article describes how to debug your bot using an integrated development environment (IDE) such as Visual Studio or Visual Studio Code and the Bot Framework Emulator. While you can use these methods to debug any bot locally, this article uses a [C# bot](~/dotnet/bot-builder-dotnet-sdk-quickstart.md) or [Javascript bot](~/javascript/bot-builder-javascript-quickstart.md) created in the quickstart. - -> [!NOTE] -> In this article, we use the Bot Framework Emulator to send and receive messages from the bot during debugging. If you are looking for other ways to debug your bot using the Bot Framework Emulator, please read the [Debug with the Bot Framework Emulator](https://docs.microsoft.com/azure/bot-service/bot-service-debug-emulator) article. - -## Prerequisites -- Download and install the [Bot Framework Emulator](https://aka.ms/Emulator-wiki-getting-started). -- Download and install [Visual Studio Code](https://code.visualstudio.com) or [Visual Studio](https://www.visualstudio.com/downloads) (Community Edition or above). - - - -## Debug a JavaScript bot using breakpoints in Visual Studio Code - -In Visual Studio Code, you can set breakpoints and run the bot in debug mode to step through your code. To set breakpoints in VS Code, do the following: - -1. Launch VS Code and open your bot project folder. -2. From the menu bar, click **Debug** and click **Start Debugging**. If you are prompted to select a runtime engine to run your code, select **Node.js**. At this point, the bot is running locally. -3. Click the **.js** file and set breakpoints as necessary. In VS Code, you can set breakpoints by hovering your mouse over the column to the left of the line numbers. A small red dot will appear. If you click on the dot, the breakpoint is set. If you click the dot again, the breakpoint is removed. - - ![Set breakpoint in VS Code](~/media/bot-service-debug-bot/breakpoint-set.png) - -4. Start the Bot Framework Emulator and connect to your bot as described in the [Debug with the Bot Framework Emulator](https://docs.microsoft.com/azure/bot-service/bot-service-debug-emulator) article. -5. From the emulator, send your bot a message (for example, send the message "Hi"). Execution will stop at the line where you place the breakpoint. - - ![Debug in VS Code](~/media/bot-service-debug-bot/breakpoint-caught.png) - -## Debug a C# bot using breakpoints in Visual Studio - -In Visual Studio (VS), you can set breakpoints and run the bot in debug mode to step through your code. To set breakpoints in VS, do the following: - -1. Navigate to your bot folder and open the **.sln** file. This will open the solution in VS. -2. From the menu bar, click **Build** and click **Build Solution**. -3. In the **Solution Explorer**, click the **.cs** file and set breakpoints as necessary. This file defines your main bot logic. In VS, you can set breakpoints by hovering your mouse over the column to the left of the line numbers. A small red dot will appear. If you click on the dot the breakpoint is set. If you click the dot again the breakpoint is removed. -4. From the menu, click **Debug** and click **Start Debugging**. At this point, the bot is running locally. - - ![Set breakpoint in VS](~/media/bot-service-debug-bot/breakpoint-set-vs.png) - - - -5. Start the Bot Framework Emulator and connect to your bot as described in the section above. -6. From the emulator, send your bot a message (e.g.: send the message "Hi"). Execution will stop at the line where you place the breakpoint. - - ![Debug in VS](~/media/bot-service-debug-bot/breakpoint-caught-vs.png) - -::: moniker range="azure-bot-service-3.0" - -## Debug a Consumption plan C\# Functions bot - -The Consumption plan serverless C\# environment in Bot Service has more in common with Node.js than a typical C\# application because it requires a runtime host, much like the Node engine. In Azure, the runtime is part of the hosting environment in the cloud, but you must replicate that environment locally on your desktop. - -### Prerequisites - -Before you can debug your Consumption plan C# bot, you must complete these tasks. - -- Download the source code for your bot (from Azure), as described in [Set up continuous deployment](bot-service-continuous-deployment.md). -- Download and install the [Bot Framework Emulator](https://aka.ms/Emulator-wiki-getting-started). -- Install the Azure Functions CLI. -- Install the DotNet CLI. - -If you want to be able to debug your code by using breakpoints in Visual Studio 2017, you must also complete these tasks. - -- Download and install Visual Studio 2017 (Community Edition or above). -- Download and install the Command Task Runner Visual Studio Extension. - -> [!NOTE] -> Visual Studio Code is not currently supported. - -### Debug a Consumption plan C# Functions bot using the emulator - -The simplest way to debug your bot locally is to start the bot and then connect to it from Bot Framework Emulator. -First, open a command prompt and navigate to the folder where the **project.json** file is located in your repository. Then, run the command `dotnet restore` to restore the various packages that are referenced in your bot. - -> [!NOTE] -> Visual Studio 2017 changes how Visual Studio handles dependencies. -> While Visual Studio 2015 uses **project.json** to handle dependencies, -> Visual Studio 2017 uses a **.csproj** model when loading in Visual Studio. -> If you are using Visual Studio 2017, download this **.csproj** file -> to the **/messages** folder in your repository before you run the `dotnet restore` command. - -![Command prompt](~/media/bot-service-debug-bot/csharp-azureservice-debug-envconfig.png) - -Next, run `debughost.cmd` to load and start your bot. - -![Command prompt run debughost.cmd](~/media/bot-service-debug-bot/csharp-azureservice-debug-debughost.png) - -At this point, the bot is running locally. From the console window, copy the endpoint that debughost is listening on (in this example, `http://localhost:3978`). Then, start the Bot Framework Emulator and paste the endpoint into the address bar of the emulator. For this example, you must also append `/api/messages` to the endpoint. Since you do not need security for local debugging, you can leave the **Microsoft App ID** and **Microsoft App Password** fields blank. Click **Connect** to establish a connection to your bot using the specified endpoint. - -![Configure emulator](~/media/bot-service-debug-bot/mac-azureservice-emulator-config.png) - -After you have connected the emulator to your bot, send a message to your bot by typing some text into the textbox that is located at the bottom of the emulator window (i.e., where **Type your message...** appears in the lower-left corner). By using the **Log** and **Inspector** panels on the right side of the emulator window, you can view the requests and responses as messages are exchanged between the emulator and the bot. - -![test via emulator](~/media/bot-service-debug-bot/mac-azureservice-debug-emulator.png) - -Additionally, you can view log details in the console window. - -![Console window](~/media/bot-service-debug-bot/csharp-azureservice-debug-debughostlogging.png) - -::: moniker-end - -## Debug a Python bot using breakpoints in Visual Studio Code - -In Visual Studio Code, you can set breakpoints and run the bot in debug mode to step through your code. See also [Create a bot with the Bot Framework SDK for Python](~/python/bot-builder-python-quickstart.md). - -1. Launch VS Code and open your bot project folder. -1. Set breakpoints as necessary. You can set breakpoints by hovering your mouse over the column to the left of the line numbers. A small red dot will appear. If you click on the dot, the breakpoint is set. If you click the dot again, the breakpoint is removed. -1. Select the `app.py`. -1. From the menu bar, click **Debug** and click **Start Debugging**. -1. Select **Python File** to debug the currently selected file. - - ![Set breakpoints](~/media/bot-service-debug-bot/bot-debug-python-breakpoints.png) - -1. Start the Bot Framework Emulator and connect to your bot as described in the [Debug with the Bot Framework Emulator](https://docs.microsoft.com/azure/bot-service/bot-service-debug-emulator) article. -1. From the emulator, send your bot a message (for example, send the message "Hi"). Execution will stop at the line where you place the breakpoint. - - ![Debug in VS Code](~/media/bot-service-debug-bot/bot-debug-python-breakpoint-caught.png) - -For more information, see [Debug your Python code](https://aka.ms/bot-debug-python). - -## Additional resources - -- See [troubleshoot general problems](bot-service-troubleshoot-bot-configuration.md) and the other troubleshooting articles in that section. -- See the how to [Debug with the Emulator](bot-service-debug-emulator.md). - -## Next steps - -> [!div class="nextstepaction"] -> [Debug your bot using transcript files](v4sdk/bot-builder-debug-transcript.md). diff --git a/articles/bot-service-debug-cortana-skill.md b/articles/bot-service-debug-cortana-skill.md deleted file mode 100644 index 9116e9928..000000000 --- a/articles/bot-service-debug-cortana-skill.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: Test a Cortana skill - Bot Service -description: Learn how to test a Cortana bot by invoking a Cortana skill. -keywords: Bot Framework SDK, register your bot, cortana -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/01/2018 -monikerRange: 'azure-bot-service-3.0' ---- - -# Test a Cortana skill - -[!INCLUDE [pre-release-label](includes/pre-release-label-v3.md)] - -If you've built a Cortana skill using the Bot Framework SDK, you can test it by invoking it from Cortana. The following instructions walk you through the steps required to try out your Cortana skill. - -## Register your bot -If you [created your bot](~/bot-service-quickstart.md) using Bot Service in Azure, then your bot is already registered and you can skip this step. - -If you have deployed your bot elsewhere or if you want to test your bot locally, then you must [register](bot-service-quickstart-registration.md) your bot so that you can connect it to Cortana. During the registration process, you will need to provide your bot's **Messaging endpoint**. If you choose to test your bot locally, you will need to run a tunneling software such as [ngrok](http://ngrok.com) to get an endpoint for your local bot. - -## Get messaging endpoint using ngrok - -If you are running the bot locally, you can get an endpoint to use for testing by running tunneling software, such as [ngrok](https://ngrok.com). To use ngrok to get an endpoint, from a console window type: - -```cmd - ngrok.exe http 3979 -host-header="localhost:3979" -``` - -This configures and displays an ngrok forwarding link that forwards requests to your bot, which is running on port 3978. The URL to the forwarding link should look something like this: `https://0d6c4024.ngrok.io`. Append `/api/messages` to the link, to form a messaging endpoint URL in this format: `https://0d6c4024.ngrok.io/api/messages`. - -Enter this endpoint URL in the **Configuration** section of your bot's [Settings](~/bot-service-manage-settings.md) blade. - -## Enable speech recognition priming -If your bot uses a Language Understanding (LUIS) app, make sure you associate the LUIS application ID with your registered bot service. This helps your bot recognize spoken utterances that are defined in your LUIS model. For more information, see [Speech priming](~/bot-service-manage-speech-priming.md). - -## Add the Cortana channel -To add Cortana as a channel, follow steps listed in [Connect a bot to Cortana](bot-service-channel-connect-cortana.md). - -## Test using Web Chat control - -To test your bot using the integrated web chat control in Bot Service, click **Test in Web Chat** and type a message to verify that your bot is working. - -## Test using emulator - -To test your bot using the [emulator](~/bot-service-debug-emulator.md), do the following: - -1. Run the bot. -2. Open the emulator and fill in the necessary information. To find your bot's **AppID** and **AppPassword**, see [MicrosoftAppID and MicrosoftAppPassword](bot-service-manage-overview.md#microsoftappid-and-microsoftapppassword). -3. Click **Connect** to connect the emulator to your bot. -4. Type a message to verify that your bot is working. - -## Test using Cortana -You can invoke your Cortana skill by speaking an invocation phrase to Cortana. -1. Open Cortana. -2. Open the Notebook within Cortana and click **About me** to see which account you're using for Cortana. Make sure you are signed in with the same Microsoft account that you used to register your bot. - ![Sign in to Cortana's notebook](~/media/cortana/cortana-notebook.png) -2. Click on the microphone button in the Cortana app or in the "Ask me anything" search box in Windows, and say your bot's [invocation phrase][InvocationNameGuidelines]. The invocation phrase includes an *invocation name*, which uniquely identifies the skill to invoke. For example, if a skill's invocation name is "Northwind Photo", a proper invocation phrase could include "Ask Northwind Photo to..." or "Tell Northwind Photo that...". - - You specify your bot's *Invocation Name* when you configure it for Cortana. - ![Enter the invocation name when you configure the Cortana channel](~/media/cortana/cortana-invocation-name-callout.png) - -3. If Cortana recognizes your invocation phrase, your bot launches in Cortana's canvas. - -## Troubleshoot - -If your Cortana skill fails to launch, check the following: -* Make sure you are signed in to Cortana using the same Microsoft account that you used to register your bot in the Bot Framework Portal. -* Check if the bot is working by clicking **Test in Web chat** to open the **Chat** window and typing a message to it. -* Check if your invocation name meets the [guidelines][InvocationNameGuidelines]. If your invocation name is longer than three words, hard to pronounce, or sounds like other words, Cortana might have difficulty recognizing it. -* If your skill uses a LUIS model, make sure you [enable speech recognition priming](~/bot-service-manage-speech-priming.md). - -See the [Enable Debugging of Cortana skills][Cortana-TestBestPractice] for additional troubleshooting tips and information on how to enable debugging of your skill in the Cortana dashboard. - - -## Next steps - -Once you have tested your Cortana skill and verified that it works the way you'd like it to, you can deploy it to a group of beta testers or release it to the public. See [Publishing Cortana Skills][Cortana-Publish] for more information. - -## Additional resources -* [The Cortana Skills Kit][CortanaGetStarted] - -[CortanaGetStarted]: /cortana/getstarted - -[BFPortal]: https://dev.botframework.com/ -[CortanaDevCenter]: https://developer.microsoft.com/cortana - -[CortanaSpecificEntities]: https://aka.ms/cortana-channel-data -[CortanaAuth]: https://aka.ms/add-auth-cortana-skill - -[InvocationNameGuidelines]: https://aka.ms/cortana-invocation-guidelines - - -[Cortana-Debug]: https://aka.ms/cortana-enable-debug -[Cortana-TestBestPractice]: https://aka.ms/cortana-test-best-practice -[Cortana-Publish]: /cortana/skills/publish-skill diff --git a/articles/bot-service-debug-emulator.md b/articles/bot-service-debug-emulator.md deleted file mode 100644 index 7d402f332..000000000 --- a/articles/bot-service-debug-emulator.md +++ /dev/null @@ -1,236 +0,0 @@ ---- -title: Test and debug bots using the Bot Framework Emulator - Bot Service -description: Learn how to inspect, test, and debug bots using the Bot Framework Emulator desktop application. -keywords: transcript, msbot tool, language services, speech recognition -author: DeniseMak -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 2/26/2019 ---- - -# Debug with the emulator - -The Bot Framework Emulator is a desktop application that allows bot developers to test and debug their bots, either locally or remotely. Using the emulator, you can chat with your bot and inspect the messages that your bot sends and receives. The emulator displays messages as they would appear in a web chat UI and logs JSON requests and responses as you exchange messages with your bot. Before you deploy your bot to the cloud, run it locally and test it using the emulator. You can test your bot using the emulator even if you have not yet [created](./bot-service-quickstart.md) it with Azure Bot Service or configured it to run on any channels. - -## Prerequisites -- Install [Bot Framework Emulator](https://aka.ms/Emulator-wiki-getting-started) - -## Run a bot locally -Before connecting your bot to the Bot Framework Emulator, you need to run your bot locally. You can use Visual Studio or Visual Studio Code to run your bot, or use command line. -To run a bot using command line, do the following: - - -# [C#](#tab/csharp) - -* Go to the command prompt and change directory to your bot project directory. -* Start the bot by running the following command: - ``` - dotnet run - ``` -* Copy the port number in the line before *Application started. Press CTRL+C to shut down.* - - ![C# Port Number](media/bot-service-debug-emulator/csharp_port_number.png) - - -# [JavaScript](#tab/javascript) - -* Go to the command prompt and change directory to your bot project directory. -* Start the bot by running the following command: - ``` - node index.js - ``` -* Copy the port number that restify is listening on. - - ![JS Port Number](media/bot-service-debug-emulator/js_port_number.png) - -# [Python](#tab/python) -* Go to the command prompt and change directory to your bot project directory. -* Start the bot by running the following command: - ``` - python app.py - ``` -* Copy the port number that restify is listening on. - - ![JS Port Number](media/bot-service-debug-emulator/js_port_number.png) - ---- - -At this point, your bot should be running locally. - - -## Connect to a bot running on localhost - - -### Configure the emulator for authentication - -If a bot requires authentication, displaying a login dialog, you must configure the emulator as shown below. - -#### Using sign-in verification code - -1. Start the emulator. -1. In the emulator, click the gear icon in the bottom left, or the **Emulator Settings** tab in the upper right. -1. Check the box by **Use a sign-in verification code for OAuthCards**. -1. Check the box by **Bypass ngrok for local address** -1. Click the **Save** button. - -When you click the login button displayed by the bot, a validation code will be generated. -You wil enter the code in the bot input chat box for the authentication to take place. -After that you can perform the allowed operations. - -Alternatively, you can perform the steps described below. - -#### Using authentication tokens - -1. Start the emulator. -1. In the emulator, click the gear icon in the bottom left, or the **Emulator Settings** tab in the upper right. -1. Check the box by **Use version1.0 authentication tokens**. -1. Enter the local path to the **ngrok** tool. For more the tool information, see [ngrok](https://ngrok.com/). -1. Check the box by **Run ngrok when the Emulator starts up**. -1. Click the **Save** button. - -When you click the login button displayed by the bot, you will be asked to enter your credentials. An authentication token is generated. After that you can perform the allowed operations. - - -![Emulator UI](media/emulator-v4/emulator-welcome.png) - -To connect to a bot running locally and click **Open bot**. Add the port number your copied earlier into the following URL and paste the updated URL in the Bot URL bar: - -*http://localhost:**port number**/api/messages* - -![Emulator UI](media/bot-service-debug-emulator/open_bot_emulator.png) - -If your bot is running with [Microsoft Account (MSA) credentials](#use-bot-credentials), enter these credentials too. - -### Use bot credentials - -When you open the bot, set the **Microsoft App ID** and **Microsoft App password** if your bot is running with credentials. If you created your bot with the Azure Bot Service, the credentials are available on the bot's App Service, under the **Settings -> Configuration** section. If you do not know the values, you can remove those from the locally running bot's configuration file, then run the bot in the Emulator. If the bot isn't running with these settings, you don't need to run the emulator with the settings either. - -When creating an AD identity provider application, remember the following: - -- When the supported account types is set to single tenant, if you use a personal subscription instead of a Microsoft account, the emulator would issue the error: *The bot's Microsoft App ID or Microsoft App Password is incorrect..* -- In this case, the supported account types must be set to *Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)*. - -For more information, see [Create an Azure AD identity provider application](bot-builder-tutorial-authentication.md#create-an-azure-ad-identity-provider-application). - -## View detailed Message Activity with the Inspector - -Send a message to your bot and the bot should respond back. You can click on the message bubble within the conversation window and inspect the raw JSON activity using the **INSPECTOR** feature to the right side of the window. When selected, the message bubble will turn yellow and the activity JSON object will be displayed to the left of the chat window. The JSON information includes key metadata, including the channel ID, activity type, conversation ID, the text message, endpoint URL, and so on. You can inspect activities sent from the user, as well as activities the bot responds with. - -![Emulator Message Activity](media/emulator-v4/emulator-view-message-activity-03.png) - -> [!TIP] -> You can debug state changes in a bot connected to a channel by adding [Inspection Middleware](bot-service-debug-inspection-middleware.md) to the bot. - - - - -## Inspect services - -With the new v4 emulator you can also inspect the JSON responses from LUIS and QnA. Using a bot with a connected language service, you can select **trace** in the LOG window to the bottom right. This new tool also provides features to update your language services directly from the emulator. - -![LUIS Inspector](media/emulator-v4/emulator-luis-inspector.png) - -With a connected LUIS service, you'll notice that the trace link specifies **Luis Trace**. When selected, you'll see the raw response from your LUIS service, which includes intents, entities along with their specified scores. You also have the option to re-assign intents for your user utterances. - -![QnA Inspector](media/emulator-v4/emulator-qna-inspector.png) - -With a connected QnA service, the log will display **QnA Trace**, and when selected you can preview the question and answer pair associated with that activity, along with a confidence score. From here, you can add alternative question phrasing for an answer. - - - - - -### Login to Azure -You can use Emulator to login in to your Azure account. This is particularly helpful for you to add and manage services your bot depends on. Log into Azure by following these steps: -- Click on File -> Sign in with Azure -![Azure login](media/emulator-v4/emulator-azure-login.png) -- On the welcome screen click on Sign in with your Azure account -You can optionally have Emulator keep you signed in across Emulator application restarts. -![Azure login](media/emulator-v4/emulator-azure-login-success.png) - -## Disabling data collection - -If you decide that you no longer want to allow the Emulator to collect usage data, you can easily disable data collection by following these steps: - -1. Navigate to the Emulator's settings page by clicking on the Settings button (gear icon) in the nav bar on the left side. - - ![disable data collection](media/emulator-v4/emulator-disable-data-1.png) - -2. Uncheck the checkbox labeled *Help improve the Emulator by allowing us to collect usage data* under the **Data Collection** section. - - ![disable data collection](media/emulator-v4/emulator-disable-data-2.png) - -3. Click the "Save" button. - - ![disable data collection](media/emulator-v4/emulator-disable-data-3.png) - -If you change your mind, you can always enable it by re-checking the checkbox. - -## Additional resources - -The Bot Framework Emulator is open source. You can [contribute][EmulatorGithubContribute] to the development and [submit bugs and suggestions][EmulatorGithubBugs]. - -For troubleshooting, see [troubleshoot general problems](bot-service-troubleshoot-bot-configuration.md) and the other troubleshooting articles in that section. - -## Next steps - -Use inspection middleware to debug a bot connected to a channel. - -> [!div class="nextstepaction"] -> [Debug your bot using transcript files](bot-service-debug-inspection-middleware.md) - - - - - -[EmulatorGithubContribute]: https://github.com/Microsoft/BotFramework-Emulator/wiki/How-to-Contribute -[EmulatorGithubBugs]: https://github.com/Microsoft/BotFramework-Emulator/wiki/Submitting-Bugs-%26-Suggestions - -[ngrokDownload]: https://ngrok.com/ -[inconshreveable]: https://inconshreveable.com/ diff --git a/articles/bot-service-debug-inspection-middleware.md b/articles/bot-service-debug-inspection-middleware.md deleted file mode 100644 index b92d0f045..000000000 --- a/articles/bot-service-debug-inspection-middleware.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -title: Debug a bot with inspection middleware - Bot Service -description: Learn how to debug a bot with inspection middleware -author: zxyanliu -ms.author: v-liyan -keywords: Bot Framework SDK, debug bot, inspection middleware, bot emulator, Azure Bot Channels Registration -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/01/2019 ---- - -# Debug a bot with inspection middleware -This article describes how to debug your bot using inspection middleware. This feature allows the Bot Framework Emulator to debug traffic into and out of the bot in addition to looking at the current state of the bot. You can use a trace message to send data to the emulator and then inspect the state of your bot in any given turn of the conversation. - -We use an EchoBot built locally using the Bot Framework v4 ([C#](https://docs.microsoft.com/azure/bot-service/dotnet/bot-builder-dotnet-sdk-quickstart?view=azure-bot-service-4.0) | [JavaScript](https://docs.microsoft.com/azure/bot-service/javascript/bot-builder-javascript-quickstart?view=azure-bot-service-4.0) | [Python](https://docs.microsoft.com/azure/bot-service/python/bot-builder-python-quickstart?view=azure-bot-service-4.0)) to show how to debug and inspect the bot's message state. You can also [Debug a bot using IDE](./bot-service-debug-bot.md) or [Debug with the Bot Framework Emulator](./bot-service-debug-emulator.md), but to debug state you need to add inspection middleware to your bot. The Inspection bot samples are available here: [C#](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/47.inspection), [JavaScript](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/javascript_nodejs/47.inspection) and [Python](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/python/47.inspection). - -## Prerequisites -- Download and install the [Bot Framework Emulator](https://aka.ms/Emulator-wiki-getting-started) -- Knowledge of bot [Middleware](https://docs.microsoft.com/azure/bot-service/bot-builder-concept-middleware?view=azure-bot-service-4.0) -- knowledge of bot [Managing state](https://docs.microsoft.com/azure/bot-service/bot-builder-concept-state?view=azure-bot-service-4.0) -- Download and install [ngrok](https://ngrok.com/) (if you want to debug a bot configured in Azure to use additional channels) - -## Update your emulator to the latest version -Before using the bot inspection middleware to debug your bot, you need to update your emulator to be version 4.5 or newer. Check the [latest version](https://github.com/Microsoft/BotFramework-Emulator/releases) for updates. - -To check the version of your emulator, select **Help** -> **About** in the menu. You will see the current version of your emulator. - -![current-version](./media/bot-debug-inspection-middleware/bot-debug-check-emulator-version.png) - -## Update your bot's code - -# [C#](#tab/csharp) -Set up the inspection state in the **Startup** file. Add the inspection middleware to the adapter. The inspection state is provided through dependency injection. See the code update below or refer to the inspection sample here: [C#](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/47.inspection). - -**Startup.cs** -[!code-csharp [inspection bot sample](~/../botbuilder-samples/samples/csharp_dotnetcore/47.inspection/Startup.cs?range=17-37)] - -**AdapterWithInspection.cs** -[!code-csharp [inspection bot sample](~/../botbuilder-samples/samples/csharp_dotnetcore/47.inspection/AdapterwithInspection.cs?range=11-37)] - -**EchoBot.cs** -[!code-csharp [inspection bot sample](~/../botbuilder-samples/samples/csharp_dotnetcore/47.inspection/Bots/EchoBot.cs?range=14-43)] - -# [JavaScript](#tab/javascript) -Before updating your bot's code you should update its packages to the latest versions by executing the following command in your terminal: -```cmd -npm install --save botbuilder@latest -``` -Then you need to update the code of your JavaScript bot as follows. You can read more here: [Update your bot's code](https://github.com/Microsoft/BotFramework-Emulator/blob/master/content/CHANNELS.md#1-update-your-bots-code) or refer to the inspection sample here: [JavaScript](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/javascript_nodejs/47.inspection). - -**index.js** - -Set up the inspection state and add the inspection middleware to the adapter in the **index.js** file. - -[!code-javascript [inspection bot sample](~/../botbuilder-samples/samples/javascript_nodejs/47.inspection/index.js?range=10-43)] - -**bot.js** - -Update the bot class in the **bot.js** file. - -[!code-javascript [inspection bot sample](~/../botbuilder-samples/samples/javascript_nodejs/47.inspection/bot.js?range=6-50)] - -# [Python](#tab/python) -Before updating your bot's code run install the necessary PyPI packages by running the following commands in a terminal: -```cmd -pip install aiohttp -pip install botbuilder-core>=4.7.0 -``` -Set up the inspection state in the **app.py** file by adding a middleware to the adapter. - -**app.py** - -[!code-python [inspection bot sample](~/../botbuilder-samples/samples/python/47.inspection/app.py?range=75-84)] - -Update the bot class in the **echo_bot.py** file. - -**bots/echo_bot.py** - -[!code-python [inspection bot sample](~/../botbuilder-samples/samples/python/47.inspection/bots/echo_bot.py?range=16-64)] - ---- - -## Test your bot locally -After updating the code you can run your bot locally and test the debugging feature using two emulators: one to send and receive messages, and the other to inspect the state of messages in debugging mode. To test your bot locally take the following steps: - -1. Navigate to your bot's directory in a terminal and execute the following command to run your bot locally: - -# [C#](#tab/csharp) - -```cmd -dotnet run -``` - -# [JavaScript](#tab/javascript) - -```cmd -npm start -``` - -# [Python](#tab/python) -```cmd -python app.py -``` - ---- - -2. Open your emulator. Click **Open Bot**. Fill in Bot URL with http://localhost:3978/api/messages and the **MicrosoftAppId** and **MicrosoftAppPassword** values. If you have a JavaScript bot you can find these values in your bot's **.env** file. If you have a C# bot you can find these values in the **appsettings.json** file. Click **Connect**. - -3. Now open another emulator. This second emulator will work as a debugger. Follow the instructions as described in the previous step. Check **Open in debug mode** and then click **Connect**. - -4. At this point you will see a UUID (`/INSPECT attach `) in your debugging emulator. Copy the UUID and paste it to the chat box of the first emulator. - -> [!NOTE] -> A universally unique identifier (UUID) is a unique ID for identifying information. A UUID is generated every time when the emulator is launched in debug mode after you add the inspection middleware in your bot's code. - -5. Now you can send messages in the chat box of your first emulator and inspect the messages in the debugging emulator. To inspect the state of the messages click **Bot State** in the debugging emulator and unfold **values** on the right **JSON** window. You will be able to see the state of your bot as follows: -![bot state](./media/bot-debug-inspection-middleware/bot-debug-bot-state.png) - -## Inspect the state of a bot configured in Azure -If you want to inspect the state of your bot configured in Azure and connected to channels (like Teams) you will need to install and run [ngrok](https://ngrok.com/). - -### Run ngrok -At this point you have updated your emulator to the latest version and added the inspection middleware in your bot's code. The next step is to run ngrok and configure your local bot to your Azure Bot Channels Registration. Before running ngrok you need to run your bot locally. - -To run your bot locally do the following: -1. Navigate to your bot's folder in a terminal and set your npm registration to use the [latest builds](https://botbuilder.myget.org/feed/botbuilder-v4-js-daily/package/npm/botbuilder-azure) - -2. Run your bot locally. You will see your bot expose a port number like 3978. - -3. Open another command prompt and navigate to your bot's project folder. Run the following command: -``` -ngrok http 3978 -``` -4. ngrok is now connected to your locally running bot. Copy the public IP address. -![ngrok-success](./media/bot-debug-inspection-middleware/bot-debug-ngrok.png) - -### Update channel registrations for your bot -Now that your local bot is connected to ngrok you can configure your local bot to your Bot Channels Registration in Azure. - -1. Go to your Bot Channels Registration in Azure. Click **Settings** on the left menu and set the **Messaging endpoint** with your ngrok IP. If necessary add **/api/messages** after the IP address. (For example, https://e58549b6.ngrok.io/api/messages). Check **Enable Streaming Endpoint** and **Save**. -![endpoint](./media/bot-debug-inspection-middleware/bot-debug-channels-setting-ngrok.png) -> [!TIP] -> If **Save** is not enabled, you can uncheck **Enable Streaming Endpoint** and click **Save**, then check **Enable Streaming Endpoint** and click **Save** again. You need to make sure that **Enable Streaming Endpoint** is checked and the configuration of the endpoint is saved. - -2. Go to your bot's resource group, click **Deployment**, and select your Bot Channels Registration that previously deployed successfully. Click **Inputs** on the left side to get the **appId** and **appSecret**. Update your bot's **.env** file (or **appsettings.json** file if you have a C# bot) with the **appId** and **appSecret**. -![get-inputs](./media/bot-debug-inspection-middleware/bot-debug-get-inputs-id-secret.png) - -3. Start your emulator, click **Open Bot**, and put http://localhost:3978/api/messages in the **Bot URL**. Fill **Microsoft App ID** and **Microsoft App password** with the same **appId** and **appSecret** you added to our bot's **.env** (**appsettings.json**) file. Then click **Connect**. - -4. Your running bot is now connected to your Bot Channels Registration in Azure. You can test the web chat by clicking **Test in Web Chat** and sending messages in the chat box. -![test-web-chat](./media/bot-debug-inspection-middleware/bot-debug-test-webchat.png) - -5. Now let's enable the debugging mode in the emulator. In your emulator select **Debug** -> **Start Debugging**. Fill the ngrok IP address (don't forget to add **/api/messages**) in the **Bot URL** (for example, https://e58549b6.ngrok.io/api/messages). Fill **Microsoft App ID** with **appId** and **Microsoft App password** with **appSecret**. Make sure **Open in debug mode** is checked as well. Click **Connect**. - -6. When the debugging mode is enabled a UUID will be generated in your emulator. A UUID is a unique ID generated every time you start the debugging mode in your emulator. Copy and paste the UUID to the **Test in Web Chat** chat box or your channel's chat box. You will see the message "Attached to session, all traffic is being replicated for inspection" in the chat box. - - You can start debugging your bot by sending messages in the configured channel's chat box. Your local emulator will automatically update the messages with all the details for debugging. To inspect your bot's state of messages click **Bot State** and unfold the **values** in the right JSON window. - - ![debug-inspection-middleware](./media/bot-debug-inspection-middleware/debug-state-inspection-channel-chat.gif) - -## Additional resources -- Try the new inspection bot samples here: [C#](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/47.inspection) and [JavaScript](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/javascript_nodejs/47.inspection). -- Read [troubleshoot general problems](bot-service-troubleshoot-bot-configuration.md) and the other troubleshooting articles in that section. -- Read the how to [Debug with the Emulator](bot-service-debug-emulator.md) article. diff --git a/articles/bot-service-design-conversation-flow.md b/articles/bot-service-design-conversation-flow.md deleted file mode 100644 index 7a5bd0696..000000000 --- a/articles/bot-service-design-conversation-flow.md +++ /dev/null @@ -1,143 +0,0 @@ ---- -title: Design and control conversation flow - Bot Service -description: Learn how to design and control conversation flow in your bot to provide a good user experience. -keywords: design, control, conversation flow, handle interruptions, overview -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/19/2019 ---- - - -# Design and control conversation flow - -::: moniker range="azure-bot-service-3.0" - -[!INCLUDE [pre-release-label](./includes/pre-release-label-v3.md)] - -In a traditional application, the user interface (UI) is a series of screens. -A single app or website can use one or more screens as needed to exchange information with the user. -Most applications start with a main screen where users initially land and provide navigation that leads to other screens for various functions like starting a new order, browsing products, or looking for help. - -Like apps and websites, bots have a UI, but it is made up of **dialogs**, rather than screens. Dialogs help preserve your place within a conversation, prompt users when needed, and execute input validation. They are useful for managing multi-turn conversations and simple "forms-based" collections of information to accomplish activities such as booking a flight. - -Dialogs enable the bot developer to logically separate various areas of bot functionality and guide conversational flow. For example, you may design one dialog to contain the logic that helps the user browse for products and a separate dialog to contain the logic that helps the user create a new order. - -Dialogs may or may not have graphical interfaces. They may contain buttons, text, and other elements, or be entirely speech-based. Dialogs also contain actions to perform tasks such as invoking other dialogs or processing user input. - -## Using dialogs to manage conversation flow - -[!INCLUDE [Dialog flow example](./includes/snippet-dotnet-manage-conversation-flow-intro.md)] - -For a detailed walkthrough of managing conversation flow using dialogs and the Bot Framework SDK, see: - -- [Manage conversation flow with dialogs (.NET)](./dotnet/bot-builder-dotnet-manage-conversation-flow.md) -- [Manage conversation flow with dialogs (Node.js)](./nodejs/bot-builder-nodejs-manage-conversation-flow.md) - -## Dialog stack - -When one dialog invokes another, the Bot Builder adds the new dialog to the top of the dialog stack. -The dialog that is on top of the stack is in control of the conversation. -Every new message sent by the user will be subject to processing by that dialog until it either closes or redirects to another dialog. -When a dialog closes, it's removed from the stack, and the previous dialog in the stack assumes control of the conversation. - -> [!IMPORTANT] -> Understanding the concept of how the dialog stack is constructed and deconstructed -> by the Bot Builder as dialogs invoke one another, close, and so on -> is critical to being able to effectively design the conversation flow of a bot. - -## Dialogs, stacks and humans - -It may be tempting to assume that users will navigate across dialogs, creating a dialog stack, -and at some point will navigate back in the direction they came from, unstacking the dialogs one by one in a neat and orderly way. -For example, the user will start at root dialog, invoke the new order dialog from there, and then invoke the product search dialog. -Then the user will select a product and confirm, exiting the product search dialog, complete the order, exiting the new order dialog, and arrive back at the root dialog. - -Although it would be great if users always traveled such a linear, logical path, it seldom occurs. -Humans do not communicate in "stacks." They tend to frequently change their minds. -Consider the following example: - -![bot](./media/bot-service-design-conversation-flow/stack-issue.png) - -While your bot may have logically constructed a stack of dialogs, - the user may decide to do something entirely different or ask a question that may be unrelated to the current topic. -In the example, the user asks a question rather than providing the yes/no response that the dialog expects. -How should your dialog respond? - -- Insist that the user answer the question first. -- Disregard everything that the user had done previously, reset the whole dialog stack, and start from the beginning by attempting to answer the user's question. -- Attempt to answer the user's question and then return to that yes/no question and try to resume from there. - -There is no one *right* answer to this question, as the best solution will depend upon the specifics of your scenario and how the user would reasonably expect the bot to respond. However, as your conversation complexity increases **dialogs** become harder to manage. For complex branchings situations, it may be easier to create your own flow of control logic to keep track of your user's conversation. - -## Next steps - -Managing the user's navigation across dialogs and designing conversation flow in a manner that enables -users to achieve their goals (even in a non-linear fashion) is a fundamental challenge of bot design. -The [next article](./bot-service-design-navigation.md) reviews some common pitfalls of poorly designed navigation and discusses strategies for avoiding those traps. - -::: moniker-end - -::: moniker range="azure-bot-service-4.0" - -In a traditional application, the user interface (UI) consists of a series of screens, and a single app or website can use one or more screens as needed to exchange information with the user. -Most applications start with a main screen where users initially land, and that screen provides navigation that leads to other screens for various functions like starting a new order, browsing products, or looking for help. - -Like apps and websites, bots have a UI, but it is made up of **messages** rather than screens. Messages may contain buttons, text, and other elements, or be entirely speech-based. - -While a traditional application or website can request multiple pieces of information on a screen all at once, a bot will gather the same amount of information using multiple messages. In this way, the process of gathering information from the user is an active experience; one where the user is having an active conversation with the bot. - -A well designed bot will have a conversation flow that feels natural. The bot should be able to handle the core conversation seamlessly, and be able to handle interruptions or switching topic of conversations gracefully. - -## Procedural conversation flow - -Conversation with a bot is generally focused around the task a bot is trying to achieve, which is called a procedural flow. This is where the bot asks the user a series of questions to gather all the information it needs before processing the task. - -In a procedural conversation flow, you define the order of the questions and the bot will ask the questions in the order you defined. You can organize the questions into logical *modules* to keep the code centralized while staying focused on guiding the conversational. For example, you may design one module to contain the logic that helps the user browse for products and a separate module to contain the logic that helps the user create a new order. - -You can structure these modules to flow in any way you like, ranging from free form to sequential. The Bot Framework SDK provides several libraries that allows you to construct any conversational flow your bot needs. For example, the `prompts` library allows you to ask users for input, the `waterfall` library allows you to define a sequence of question/answer pair, the `dialog control` library allows you to modularized your conversational flow logic, etc. All of these libraries are tied together through a `dialogs` object. Let's take a closer look at how modules are implemented as `dialogs` to design and manage conversation flows and see how that flow is similar to the traditional application flow. - -![bot](./media/designing-bots/core/dialogs-screens.png) - -In a traditional application, everything begins with the **main screen**. -The **main screen** invokes the **new order screen**. -The **new order screen** remains in control until it either closes or invokes other screens, such as the **product search screen**. -If the **new order screen** closes, the user is returned to the **main screen**. - -In a bot, everything begins with the **root dialog**. -The **root dialog** invokes the **new order dialog**. -At that point, the **new order dialog** takes control of the conversation and remains in control until it either closes or invokes other dialogs, such as the **product search dialog**. -If the **new order dialog** closes, control of the conversation is returned back to the **root dialog**. - -For examples of how implement conversation flow, see how to [create your own prompts to gather user input](./v4sdk/bot-builder-primitive-prompts.md) and use dialogs to [implement sequential conversation flow](./v4sdk/bot-builder-dialog-manage-conversation-flow.md). - -## Handle interruptions - -It may be tempting to assume that users will perform procedural tasks one by one in a neat and orderly way. -For example, in a procedural conversation flow using `dialogs`, the user will start at root dialog, invoke the new order dialog from there, and then invoke the product search dialog. Then the user will select a product and confirm, exiting the product search dialog, complete the order, exiting the new order dialog, and arrive back at the root dialog. - -Although it would be great if users always traveled such a linear, logical path, it seldom occurs. -Humans do not communicate in sequential `dialogs`. They tend to frequently change their minds. -Consider the following example: - -![bot](./media/bot-service-design-conversation-flow/stack-issue.png) - -While your bot may be procedural centric, the user may decide to do something entirely different or ask a question that may be unrelated to the current topic. -In the example above, the user asks a question rather than providing the yes/no response that the bot expects. -How should your bot respond? - -- Insist that the user answer the question first. -- Disregard everything that the user had done previously, reset the whole dialog stack, and start from the beginning by attempting to answer the user's question. -- Attempt to answer the user's question and then return to that yes/no question and try to resume from there. - -There is no *right* answer to this question, as the best solution will depend upon the specifics of your scenario and how the user would reasonably expect the bot to respond. For more information see [Handle user interruption](v4sdk/bot-builder-howto-handle-user-interrupt.md). - -## Next steps - -Managing the user's navigation across dialogs and designing conversation flow in a manner that enables -users to achieve their goals (even in a non-linear fashion) is a fundamental challenge of bot design. -The [next article](~/bot-service-design-navigation.md) reviews some common pitfalls of poorly designed navigation and discusses strategies for avoiding those traps. - -::: moniker-end diff --git a/articles/bot-service-design-first-interaction.md b/articles/bot-service-design-first-interaction.md deleted file mode 100644 index a66e1fff8..000000000 --- a/articles/bot-service-design-first-interaction.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Design a bot's first user interaction - Bot Service -description: Learn what makes a great first user experience and how to design your bots for success. -keywords: first impression, beginning, language vs menu -author: matvelloso -ms.author: mateusv -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Design a bot's first user interaction - -## First impressions matter - -The very first interaction between the user and bot is critical to the user experience. When designing your bot, keep in mind that there is more to that first message than just saying "hi." When you build an app, you design the first screen to provide important [navigation](bot-service-design-navigation.md) cues. Users should intuitively understand things such as where the menu is located and how it works, where to go for help, what the privacy policy is, and so on. When you design a bot, the user's first interaction with the bot should provide that same type of information. - -## Language versus menus - -Consider the following two designs: - -### Design 1 - -![bot](~/media/bot-service-design-first-interaction/hello1.png) - - -### Design 2 - -![bot](~/media/bot-service-design-first-interaction/hello2.png) - -Starting the bot with an open-ended question such as "How can I help you?" is generally not recommended. If your bot has a hundred different things it can do, chances are users won’t be able to guess most of them. Your bot didn’t tell them what it can do, so how can they possibly know? - -Menus provide a simple solution to that problem. First, by listing the available options, your bot is conveying its capabilities to the user. Second, menus spare the user from having to type too much, instead they can just click. Finally, the use of menus can significantly simplify your natural language models by narrowing the scope of input that the bot could receive from the user. - -> [!TIP] -> Menus are a valuable tool when designing bots for a great user experience; don’t dismiss them as not being "smart enough." -> You can design your bot to use menus while still supporting free form input. -> If a user responds to the initial menu by typing rather than selecting a menu option, your bot could attempt to parse the user's text input. - -Alternatively, you can ask more pointed questions to lead the user if the bot has a specific function. For example, if your bot is responsible for taking sandwich orders, your first interaction could be "Hi! I'm here to take your sandwich order. What kind of bread would you like? We have white, wheat, or rye." That way, the user knows how to respond and is given navigational cues through the conversation. - -## Other considerations - -In addition to providing an intuitive and easily navigated first interaction, -a well-designed bot provides the user with access to information about its privacy policy and terms of use. - -> [!TIP] -> If your bot collects personal data from the user, it's important to convey that and to describe what will be done with the data. - -## Next steps - -Now that you're familiar with some basic principles for designing the first interaction between user and bot, -learn more about [designing the flow of conversation](~/bot-service-design-conversation-flow.md). diff --git a/articles/bot-service-design-navigation.md b/articles/bot-service-design-navigation.md deleted file mode 100644 index b75245286..000000000 --- a/articles/bot-service-design-navigation.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: Design bot navigation - Bot Service -description: Learn how to design a good navigation structure for your bot and how to avoid the most common navigation design errors. -keywords: navigation, overview, stubborn bot, clueless bot, mysterious bot, captain obvious bot, bot that can't forget -author: matvelloso -ms.author: mateusv -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 - ---- - -# Design bot navigation - -Users can navigate websites using breadcrumbs, apps using menus, and web browsers using buttons like **forward** and **back**. However, none of these well-established navigation techniques entirely address navigation requirements within a bot. As discussed [previously](~/bot-service-design-conversation-flow.md#handle-interruptions), users often interact with bots in a non-linear fashion, making it challenging to design bot navigation that consistently delivers a great user experience. - -Consider the following dilemmas: - -- How do you ensure that a user doesn't get lost in a conversation with a bot? -- Can a user navigate "back" in a conversation with a bot? -- How does a user navigate to the "main menu" during a conversation with a bot? -- How does a user "cancel" an operation during a conversation with a bot? - -The specifics of your bot's navigation design will depend largely upon the features and functionality that your bot supports. Regardless of the type of bot you're developing, you'll want to avoid the common pitfalls of poorly designed conversational interfaces. This article describes these pitfalls in terms of five personalities: the "stubborn bot", the "clueless bot", the "mysterious bot", the "captain obvious bot", and the "bot that can't forget." - -> [!TIP] -> Mitigating each type of these personalities for your bot can often be done by correctly [handling user interruptions](v4sdk/bot-builder-howto-handle-user-interrupt.md). - -## The "stubborn bot" - -The stubborn bot insists upon maintaining the current course of conversation, -even when the user attempts to steer things in a different direction. - -Consider the following scenario: - -![bot](~/media/bot-service-design-navigation/stubborn-bot-new.png) - -Users often change their minds, decide to cancel or sometimes they want to start over altogether. - -> [!TIP] -> Do: Design your bot to consider that a user might attempt to change the course of the conversation at any time. -> -> Don't: Design your bot to ignore user input and keep repeating the same question in an endless loop. - -There are many methods of avoiding this pitfall, but perhaps the easiest way to prevent a bot from asking the same question endlessly is to simply specify a maximum number of retry attempts for each question. If designed in this manner, the bot is not doing anything "smart" to understand the user's input and respond appropriately but will at least avoid asking the same question in an endless loop. - -## The "clueless bot" - -The clueless bot responds in a nonsensical manner when it doesn't understand a user's attempt to access certain functionality. A user may try common keyword commands like "help" or "cancel" with reasonable expectations that the bot will respond appropriately. - -Consider the following scenario: - -![bot](~/media/bot-service-design-navigation/clueless-bot.png) - -Although you may be tempted to design every dialog within your bot to listen for, and respond appropriately to, certain keywords, this approach is not recommended. - -> [!TIP] -> Do: Implement [middleware](v4sdk/bot-builder-create-middleware.md) that will examine user input for the keywords that you specify (ex: "help", "cancel", "start over", etc.) and respond appropriately. -> -> Don't: Design every dialog to examine user input for a list of keywords. - -By defining the logic in your **middleware**, you're making it accessible to every exchange with the user. Using this approach, individual dialogs and prompts can be made to safely ignore the keywords, if necessary. - -## The "mysterious bot" - -The mysterious bot fails to immediately acknowledge the user's input in any way. - -Consider the following scenario: - -![bot](~/media/bot-service-design-navigation/mysterious-bot.png) - -In some cases, this situation might be an indication that the bot is having an outage. -However, it could just be that the bot is busy processing the user's input and hasn't yet finished compiling its response. - -> [!TIP] -> Do: Design your bot to immediately acknowledge user input, even in cases where the bot may take some time to compile its response. -> -> Don't: Design your bot to postpone acknowledgement of user input until the bot finishes compiling its response. - -By immediately acknowledging the user's input, you eliminate any potential for confusion as to the state of the bot. If your response takes a long time to compile, consider sending a "typing" message to indicate your bot is working, and then following up with a [proactive message](v4sdk/bot-builder-howto-proactive-message.md) - -## The "captain obvious bot" - -The captain obvious bot provides unsolicited information that is completely obvious and therefore useless to the user. - -Consider the following scenario: - -![bot](~/media/bot-service-design-navigation/captainobvious-bot.png) - -> [!TIP] -> Do: Design your bot to provide information that will be useful to the user. -> -> Don't: Design your bot to provide unsolicited information that is unlikely to be useful to the user. - -By designing your bot to provide useful information, you're increasing the odds that the user will engage with your bot. - -## The "bot that can't forget" - -The bot that can't forget inappropriately integrates information from past conversations into the current conversation. - -Consider the following scenario: - -![bot](~/media/bot-service-design-navigation/rememberall-bot.png) - -> [!TIP] -> Do: Design your bot to maintain the current topic of conversation, unless/until the user expresses a desire to revisit a prior topic. -> -> Don't: Design your bot to interject information from past conversations when it is not relevant to the current conversation. - -By maintaining the current topic of conversation, you reduce the potential for confusion and frustration as well as increasing the odds that the user will continue to engage with your bot. - -## Next steps - -By designing your bot to avoid these common pitfalls of poorly designed conversational interfaces, you're taking an important step toward ensuring a great user experience. - -Next, learn more about the [UX elements](~/bot-service-design-user-experience.md) that bots most typically rely upon to exchange information with users. diff --git a/articles/bot-service-design-pattern-embed-app.md b/articles/bot-service-design-pattern-embed-app.md deleted file mode 100644 index 382d40f99..000000000 --- a/articles/bot-service-design-pattern-embed-app.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Embed a bot in an app - Bot Service -description: Learn how to design a bot that will be embedded within another app. -author: matvelloso -ms.author: mateusv -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 08/15/2018 - ---- - -# Embed a bot in an app - -Although bots most commonly exist outside of apps, they can also be integrated with apps. For example, you could embed a [knowledge bot](~/bot-service-design-pattern-knowledge-base.md) within an app -to help users find information that might otherwise be challenging to locate within complex app structures. -You could embed a bot within a help desk app to act as the first responder to incoming user requests. -The bot could independently resolve simple issues and [hand off](~/bot-service-design-pattern-handoff-human.md) more complex issues to a human agent. - -## Integrating bot with app - -The way to integrate a bot with an app varies depending on the type of app. - -### Native mobile app - -An app that is created in native code can communicate with the Bot Framework by using -the [Direct Line API][directLineAPI], -either via REST or websockets. - -### Web-based mobile app - -A mobile app that is built by using web language and frameworks such as Cordova -may communicate with the Bot Framework by using the same components that a -[bot embedded within a website](~/bot-service-design-pattern-embed-web-site.md) would use, -just encapsulated within a native app's shell. - -### IoT app - -An IoT app can communicate with the Bot Framework by using -the [Direct Line API][directLineAPI]. -In some scenarios, it may also use Microsoft Cognitive Services -to enable capabilities such as image recognition and speech. - -### Other types of apps and games - -Other types of apps and games can communicate with the Bot Framework by using -the [Direct Line API][directLineAPI]. - -## Creating a cross-platform mobile app that runs a bot - -This example of creating a mobile app that runs a bot uses Xamarin, a popular tool -for building cross-platform mobile applications. - -First, create a simple web view component and use it to host a -web chat control. -Then, using Azure portal, add the Web Chat channel. - -Next, specify the registered web chat URL as the source for the web view control in the Xamarin app: - -```cs -public class WebPage : ContentPage -{ - public WebPage() - { - var browser = new WebView(); - browser.Source = "https://webchat.botframework.com/embed/"; - this.Content = browser; - } -} -``` - -Using this process, you can create a cross-platform mobile application -that renders the embedded web view with the web chat control. - -![Back-channel](~/media/bot-service-design-pattern-embed-app/xamarin-apps.png) - - - -## Additional resources - -- [Direct Line API][directLineAPI] -- Microsoft Cognitive Services - -[directLineAPI]: https://docs.microsoft.com/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-concepts diff --git a/articles/bot-service-design-pattern-embed-web-site.md b/articles/bot-service-design-pattern-embed-web-site.md deleted file mode 100644 index e5a3207e6..000000000 --- a/articles/bot-service-design-pattern-embed-web-site.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Embed a bot in a website - Bot Service -description: Learn how to design a bot that will be embedded within a website. -author: matvelloso -ms.author: mateusv -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 - ---- - -# Embed a bot in a website - -Although bots commonly exist outside of websites, they can also be embedded within a website. -For example, you may embed a [knowledge bot](~/bot-service-design-pattern-knowledge-base.md) within a website -to enable users to quickly find information that might otherwise be challenging to locate within complex website structures. -Or you might embed a bot within a help desk website to act as the first responder to incoming user requests. -The bot could independently resolve simple issues and [handoff](~/bot-service-design-pattern-handoff-human.md) more complex issues to a human agent. - -This article explores integrating bots with websites and the process of using the *backchannel* mechanism to facilitate private communication between a web page and a bot. - -Microsoft provides two different ways to integrate a bot in a website: -the Skype web control and an open source web control. - -## Skype web control - -The [Skype web control](https://aka.ms/bot-skype-web-control) is essentially a Skype client in a web-enabled control. Built-in Skype authentication enables the bot to authenticate and recognize users, without requiring the -developer to write any custom code. Skype will automatically recognize Microsoft Accounts used in its web client. - -Because the Skype web control simply acts as a front-end for Skype, -the user's Skype client automatically has access to the full context of any conversation that the web control facilitates. -Even after the web browser is closed, the user may continue to interact with the bot using the Skype client. - -## Open source web control - -The open source web chat control -is based upon ReactJS and uses the -[Direct Line API][directLineAPI] -to communicate with the Bot Framework. The web chat control provides a blank canvas for implementing the web chat, -giving you full control over its behaviors and the user experience that it delivers. - -The *backchannel* mechanism enables the web page that is hosting the control -to communicate directly with the bot in a manner that is entirely invisible to the user. -This capability enables a number of useful scenarios: - -- The web page can send relevant data to the bot (e.g., GPS location). -- The web page can advise the bot about user actions (e.g., "user just selected Option A from the dropdown"). -- The web page can send the bot the auth token for a logged-in user. -- The bot can send relevant data to the web page (e.g., current value of user's portfolio). -- The bot can send "commands" to the web page (e.g., change background color). - -## Using the backchannel mechanism - -[!INCLUDE [Introduction to backchannel mechanism](~/includes/snippet-backchannel.md)] - -## Sample code - -The open source web chat control is available via GitHub. For details about how you can implement the backchannel mechanism using the open source web chat control and the Bot Framework SDK for Node.js, see [Use the backchannel mechanism](~/nodejs/bot-builder-nodejs-backchannel.md). - -## Additional resources - -- [Direct Line API][directLineAPI] -- [Open source web chat control](https://github.com/Microsoft/BotFramework-WebChat) -- [Use the backchannel mechanism](~/nodejs/bot-builder-nodejs-backchannel.md) - -[directLineAPI]: https://docs.botframework.com/restapi/directline3/#navtitle diff --git a/articles/bot-service-design-pattern-handoff-human.md b/articles/bot-service-design-pattern-handoff-human.md deleted file mode 100644 index 22aba32c3..000000000 --- a/articles/bot-service-design-pattern-handoff-human.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -title: Transition conversations from bot to human - Bot Service -description: Learn how to design for situations where a user starts a conversation with a bot and then must be handed off to a human. -author: matvelloso -ms.author: mateusv -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 5/2/2019 - ---- - -# Transition conversations from bot to human - -Regardless of how much artificial intelligence a bot possesses, there may still be times when it needs to hand off the conversation to a human being. The bot should recognize when it needs to hand off and provide the user with a clear, smooth transition. - -## Scenarios that require human involvement - -A wide variety of scenarios may require that a bot transition control of the conversation to a human. A few of those scenarios are *triage*, *escalation*, and *supervision*. - -### Triage - -A typical help desk call starts with some very basic questions that can easily be answered by a bot. As the first responder to inbound requests from users, a bot could collect the user's name, address, description of the problem, or any other pertinent information and then transition control of the conversation to an agent. Using a bot to triage incoming requests allows agents to devote their time to solving the problem instead of collecting information. - -### Escalation - -In the help desk scenario, a bot may be able to answer basic questions and resolve simple issues in addition to collecting information, such as resetting a user's password. However, if a conversation indicates that a user's issue is complex enough to require human involvement, the bot will need to escalate the issue to a human agent. To implement this type of scenario, a bot must be capable of differentiating between issues it can resolve independently and issues that must be escalated to a human. There are many ways that a bot may determine that it needs to transfer control of the conversation to a human. - -#### User-driven menus - -Perhaps the simplest way for a bot to handle this dilemma is to present the user with a menu of options. Tasks that the bot can handle independently appear in the menu above a link labeled "Chat with an agent." This type of implementation requires no advanced machine learning or natural language understanding. The bot simply transfers control of the conversation to a human agent when the user selects the "Chat with an agent" option. - -#### Scenario-driven - -The bot may decide whether or not to transfer control based upon whether or not it determines that it is capable of handling the scenario at hand. The bot collects some information about the user's request and then queries its internal list of capabilities to determine if it is capable of addressing that request. If the bot determines that it is capable of addressing the request, it does so, but if the bot determines that the request is beyond the scope of issues it can resolve it transfers control of the conversation to a human agent. - -#### Natural language - -Natural language understanding and sentiment analysis help the bot decide when to transfer control of the conversation to a human agent. This is particularly valuable when attempting to determine when the user is frustrated or wants to speak with a human agent. - -The bot analyzes the content of the user's messages -by using the Text Analytics API -to infer sentiment -or by using the LUIS API. - - -> [!TIP] -> Natural language understanding may not always be the best method for determining when a bot -> should transfer conversation control to a human being. Bots, like humans, don't always guess -> correctly, and invalid responses will frustrate the user. If the user selects from a menu of -> valid choices, however, the bot will always respond appropriately to that input. - -### Supervision - -In some cases, the human agent will want to monitor the conversation instead of taking control. - -For example, consider a help desk scenario where a bot is communicating with a user to diagnose computer problems. A machine learning model helps the bot determine the most likely cause of the issue, however before advising the user to take a specific course of action, the bot can privately confirm the diagnosis and remedy with the human agent and request authorization to proceed. The agent then clicks a button, the bot presents the solution to the user, and the problem is solved. The bot is still performing the majority of the work, but the agent retains control the final decision. - -## Transitioning control of the conversation - -When a bot decides to transfer control of a conversation to a human, it can inform the user that she is being transferred and put the conversation into a 'waiting' state until it confirms that an agent is available. - -When the bot is waiting for a human, it may automatically answer all incoming user messages with a default response such as "waiting in queue". Furthermore, you could have the bot remove the conversation from the 'waiting' state if the user sent certain messages such as "never mind" or "cancel". - -You specify how agents will be assigned to waiting users when you design your bot. For example, the bot may implement a simple queue system: first in, first out. More complex logic would assign users to agents based upon geography, language, or some other factor. The bot could also present some type of UI to the agent that they can use to select a user. When an agent becomes available, she connects to the bot and joins the conversation. - -> [!IMPORTANT] -> Even after an agent is engaged, the bot remains the behind-the-scenes facilitator of the conversation. -> The user and agent never communicate directly with each other; they just route messages through the bot. - -## Routing messages between user and agent - -After the agent connects to the bot, the bot begins to route messages between user and agent. Although it may appear to the user and the agent that they are chatting directly with each other, they are actually exchanging messages via the bot. The bot receives messages from the user and sends those messages to the agent, and in turn receives messages from the agent and sends those messages to the user. - -> [!NOTE] -> In more advanced scenarios, the bot can assume responsibility beyond merely routing messages -> between user and agent. For example, the bot may decide which response is appropriate -> and simply ask the agent for confirmation to proceed. - -## Additional resources - -::: moniker range="azure-bot-service-4.0" - -- [Dialogs](v4sdk/bot-builder-dialog-manage-conversation-flow.md) -- Text Analytics API - -::: moniker-end - -::: moniker range="azure-bot-service-3.0" - -- [Manage conversation flow with dialogs (.NET)](~/dotnet/bot-builder-dotnet-manage-conversation-flow.md) -- [Manage conversation flow with dialogs (Node.js)](~/nodejs/bot-builder-nodejs-manage-conversation-flow.md) -- Text Analytics API - - -::: moniker-end - diff --git a/articles/bot-service-design-pattern-integrate-browser.md b/articles/bot-service-design-pattern-integrate-browser.md deleted file mode 100644 index 5bab7abf5..000000000 --- a/articles/bot-service-design-pattern-integrate-browser.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: Integrate your bot with a web browser - Bot Service -description: Learn how to design a smooth user transition from bot to web browser and back again. -author: matvelloso -ms.author: mateusv -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Integrate your bot with a web browser - -Some scenarios require more than just a bot to fulfill a requirement. -A bot may need to send the user to a web browser to complete a task and then resume the conversation with the user after the task has been completed. - -## Authentication and authorization -If a bot wants the ability to read the user's calendar in Office 365, or perhaps -even create appointments on behalf of that user, the user must first authenticate with Microsoft Azure Active Directory and -authorize the bot to access the user's calendar data. The bot will redirect the user to a web browser to complete the -authentication and authorization tasks, and then will subsequently resume the conversation with the user. - -## Security and compliance -Security and compliance requirements often restrict the type of information that a bot -can exchange with a user. In some cases, it may be necessary for the user to send/receive data -outside of the current conversation. -For example, if a user wants to execute a payment using a third-party payment provider, a credit card number should not -be specified within the context of the conversation. -Instead, the bot will direct the user to a web browser to complete the payment process, -and then will subsequently resume the conversation with the user. - -This article explores the process of facilitating a user's transition from -bot to web browser, and back again. - -> [!NOTE] -> Transitioning from chat to web browser and back is not ideal, as switching between -> applications can easily confuse a user. To provide a better experience, many channels -> offer built-in HTML windows that a bot can use to present applications would otherwise -> appear in a web browser. This technique allows the user to remain within the conversation -> while still accessing external resources. This approach is conceptually similar to mobile -> applications managing authorization flows using OAuth within embedded web views. - -## Bot to web browser, and back again - -This diagram shows the high-level flow for integration between bot and web browser. - -![Bot to web interaction](~/media/bot-service-design-pattern-integrate-browser/bot-to-web1.png) - -Consider each step of the flow: - -1. The bot generates and displays a hyperlink that will redirect the user to a website. - The hyperlink typically includes data via querystring parameters on the target URL that specify information about the context of the current conversation, such as conversation ID, channel ID, and user ID in the channel. - -2. The user clicks the hyperlink and is redirected to the target URL within a web browser. - -3. The bot enters a state awaiting communication from the website to indicate that the website flow is complete. - > [!TIP] - > Design this flow so that the bot will not permanently remain in the 'waiting' state if - > the user never completes the website flow. In other words, if the user abandons the web - > browser and starts communicating with the bot again, the bot should acknowledge, not [ignore](~/bot-service-design-navigation.md#the-mysterious-bot) - > that input. - -4. The user completes the necessary task(s) via the web browser. - This could be an OAuth flow or any sequence of events required by the scenario at hand. - -5. When the user completes the website flow, the website generates a '[magic number](#verify-identity)' - and instructs the user to copy the value and paste it back into the conversation with the bot. - -6. The website [signals to the bot](#website-signal-to-bot) that the user has completed the website flow. - It communicates the 'magic number' to the bot and provides any other relevant data. - For example, in the case of an OAuth flow, the website would provide an access token to the bot. - -7. The user returns to the bot and pastes the 'magic number' into the chat. - The bot validates that 'magic number' provided by the user matches the expected value, verifying that the current user is the same user who previously clicked the hyperlink to initiate the website flow. - -### Verifying user identity using the 'magic number' - -The generation of a 'magic number' during the bot-to-website flow ([step 5](#generate-magic-number) above) enables the bot to subsequently verify that the user who initiated the website flow is indeed the user -for whom it was intended. -For example, if a bot is conducting a group chat with multiple users, any one of them -could have clicked the hyperlink to initiate the website flow. Without the 'magic number' validation process, -the bot has no way of knowing which user completed the flow. -One user could authenticate and inject access tokens in another user's session. - -> [!WARNING] -> This isn't just a risk within group chats. Without the 'magic number' validation process, anyone who obtains the hyperlink to launch the website flow can spoof a user's identity. - -The magic number should be a random number generated using a strong cryptography library. -For an example of the generation process in C#, see -this code -within the BotAuth library. -BotAuth enables bots that are built in Microsoft Bot Framework to implement -the bot-to-website flow to authenticate a user in a website and then to subsequently use the access token -that was generated from the authentication process. -Since BotAuth does not make any assumptions about the channel's capabilities, such flows should function well with most channels. - -> [!NOTE] -> The need for the 'magic number' validation process should be deprecated as channels build their own embedded web views. - -### How does the website 'signal' the bot? - -When the bot [generates the hyperlink](#generate-hyperlink) that the user will click to initiate the website flow, -it includes information via querystring parameters in the target URL about the context of the current conversation, such as conversation ID, channel ID, and user ID in the channel. The website can subsequently use this information to read and write state variables for that user or conversation using the Bot Framework SDK or REST APIs. See [step 6](#signal-to-bot) above for an example of how the website 'signals' to the bot that the website flow is complete. - -## Sample code - -As described in this article, the BotAuth library enables OAuth flows to be bound to bots that are built using .NET and Node in the Microsoft Bot Framework. - -## Additional resources - -- [Dialogs](~/dotnet/bot-builder-dotnet-dialogs.md) -- [Manage conversation flow with dialogs (.NET)](~/dotnet/bot-builder-dotnet-manage-conversation-flow.md) -- [Manage conversation flow with dialogs (Node.js)](~/nodejs/bot-builder-nodejs-manage-conversation-flow.md) diff --git a/articles/bot-service-design-pattern-knowledge-base.md b/articles/bot-service-design-pattern-knowledge-base.md deleted file mode 100644 index 8553095bd..000000000 --- a/articles/bot-service-design-pattern-knowledge-base.md +++ /dev/null @@ -1,192 +0,0 @@ ---- -title: Design knowledge bots - Bot Service -description: Learn about different ways to design a knowledge bot that finds and returns information in response to the user's input or query. -author: matvelloso -ms.author: mateusv -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 - ---- - -# Design knowledge bots - -A knowledge bot can be designed to provide information about virtually any topic. -For example, one knowledge bot might answer questions about events such as, "What bot events are there at this conference?", "When is the next Reggae show?", or "Who is Tame Impala?" -Another might answer IT-related questions such as "How do I update my operating system?" or "Where do I go to reset my password?" -Yet another might answer questions about contacts such as "Who is John Doe?" or "What is Jane Doe's email address?" - -Regardless of the use case for which a knowledge bot is designed, its basic objective is always the same: find and return the information that the user has requested -by leveraging a body of data, such as relational data in a SQL database, -JSON data in a non-relational store, or PDFs in a document store. - -## Search - -Search functionality can be a valuable tool within a bot. - -First, "fuzzy search" enables a bot to return information that's likely to be relevant to the user's question, without requiring that the user provide precise input. -For example, if the user asks a music knowledge bot for information about "impala" (instead of "Tame Impala"), the bot can respond with information that's most likely to be relevant to that input. - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/fuzzySearch2.png) - -Search scores indicate the level of confidence for the results of a specific search, -enabling a bot to order its results accordingly, or even tailor its communication based upon confidence level. -For example, if confidence level is high, the bot may respond with "Here is the event that best matches your search:". - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/searchScore2.png) - -If confidence level is low, the bot may respond with "Hmm... were you looking for any of these events?" - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/searchScore1.png) - -### Using Search to Guide a Conversation - -If your motivation for building a bot is to enable basic search engine functionality, -then you may not need a bot at all. What does a conversational interface offer that users can't get from a typical search engine in a web browser? - -Knowledge bots are generally most effective when they are designed to guide the conversation. -A conversation is composed of a back-and-forth exchange between user and bot, which presents the bot -with opportunities to ask clarifying questions, present options, and validate outcomes -in a way that a basic search is incapable of doing. -For example, the following bot guides a user through a conversation that facets and filters a dataset until it -locates the information that the user is seeking. - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/guidedConvo1.png) - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/guidedConvo2.png) - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/guidedConvo3.png) - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/guidedConvo4.png) - -By processing the user's input in each step and presenting the relevant options, the bot guides the user to the information that they're seeking. Once the bot delivers that information, it can even provide guidance about more efficient ways to find similar information in the future. - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/Training.png) - -### Azure Search - -By using Azure Search, -you can create an efficient search index that a bot can easily search, facet, and filter. -Consider a search index that is created using the Azure portal. - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/search3.PNG) - -You want to be able to access all properties of the data store, so you set each property as "retrievable." -You want to be able to find musicians by name, so you set the **Name** property as "searchable." -Finally, you want to be able to facet filter over musicians' eras, so you mark the **Eras** property as both "facetable" and "filterable." - -Faceting determines the values that exist in the data store for a given property, along with the magnitude of each value. -For example, this screenshot shows that there are 5 distinct eras in the data store: - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/facet.png) - -Filtering, in turn, selects only the specified instances of a certain property. -For example, you could filter the result set above to contain only items where **Era** is equal to "Romantic." - -> [!NOTE] -> See a sample bot -> for a complete example of a knowledge bot that is created using Azure Document DB, Azure Search, and the -> Microsoft Bot Framework. -> -> For the sake of simplicity, the example above shows a search index that is created using the Azure portal. -> Indices can also be created programmatically. - -## QnA Maker - -Some knowledge bots may simply aim to answer frequently asked questions (FAQs). -QnA Maker -is a powerful tool that's designed specifically for this use case. -QnA Maker has the built-in ability to scrape questions and answers from an existing FAQ site, plus it also allows you to manually configure your own custom list of questions and answers. -QnA Maker has natural language processing abilities, enabling it to even provide answers to questions that are worded slightly differently than expected. -However, it does not have semantic language understanding abilities. -It cannot determine that a puppy is a type of dog, for example. - -Using the QnA Maker web interface, you can configure a knowledge base with three question and answer pairs: - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/KnowledgeBaseConfig.png) - -Then, you can test it by asking a series of questions: - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/exampleQnAConvo.png) - -The bot correctly answers the questions that directly map to the ones that were configured in the knowledge base. However, it incorrectly responds to the question "can I bring my tea?", because this question is most similar in structure to the question "can I bring my vodka?." The reason QnA Maker gives an incorrect answer is that it does not inherently understand the meaning of words. It does not know that "tea" is a type of nonalcoholic drink. Therefore, it answers "Alcohol is not allowed." - -> [!TIP] -> Create your QnA pairs and then test and re-train your bot by using -> the "Inspect" button under the conversation to select an alternative answer for each -> incorrect answer that is given. - -## LUIS - -Some knowledge bots require natural language processing (NLP) capabilities so that they can -analyze a user's messages to determine the user's intent. -[Language Understanding (LUIS)](https://www.luis.ai) provides a fast and effective means of adding NLP capabilities to bots. -LUIS enables you to use existing, pre-built models from Bing and Cortana whenever they meet your needs, as well as allowing you to create specialized models of your own. - -When working with huge datasets, it's not necessarily feasible to train an NLP model with every variation of an entity. -In a music playing bot, for example, a user might message "Play Reggae", "Play Bob Marley", or "Play One Love". -Although a bot could map each of these messages to the intent "playMusic", -without being trained with every artist, genre and song name, -an NLP model would not be able to identify whether the entity is a genre, artist or song. -By using an NLP model to identify the generic entity of type "music", the bot could search -its data store for that entity, and proceed from there. - -## Combining Search, QnA Maker, and/or LUIS - -Search, QnA Maker and LUIS are each powerful tools in their own right, but they can -also be combined to build knowledge bots that possess more than one of those capabilities. - -### LUIS and Search - -In the music festival bot example [covered earlier](#search), -the bot guides the conversation by showing buttons that represent the lineup. -However, this bot could also incorporate natural language understanding by using LUIS -to determine intent and entities within questions such as "what kind of music does Romit Girdhar play?". The bot could then search against an Azure Search index using musician name. - -It wouldn't be feasible to train the model with every possible musician name since there are so many potential values, but you could provide enough representative examples for LUIS to properly identify the entity at hand. For example, consider that you train your model by providing examples of musicians: - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/answerGenre.png) -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/answerGenreOneWord.png) - -When you test this model with new utterances like, "what kind of music do the beatles play?", -LUIS successfully determines the intent "answerGenre" and the identifies entity "the beatles." -However, if you submit a longer question such as "what kind of music does the devil makes three play?", -LUIS identifies "the devil" as the entity. - -![Dialog Structure](~/media/bot-service-design-pattern-knowledge-base/devilMakesThreeScore.png) - -By training the model with example entities that are representative of the underlying dataset, you -can increase the accuracy of your bot's language understanding. - -> [!TIP] -> In general, it is better for the model to err by identifying excess words in its entity recognition, e.g., identify "John Smith please" from the utterance "Call John Smith please", -> rather than identify too few words, e.g., identify "John" from the utterance "Call John Smith please". -> The search index will ignore irrelevant words such as "please" in the phrase "John Smith please". - -### LUIS and QnA Maker - -Some knowledge bots might use QnA Maker to answer basic questions in combination with LUIS to determine intents, extract entities and invoke more elaborate dialogs. For example, consider a simple IT Help Desk bot. This bot may use QnA Maker to answer basic questions about Windows or Outlook, but it might also need to facilitate scenarios like password reset, which require intent recognition and back-and-forth communication between user and bot. There are a few ways that a bot may implement a hybrid of LUIS and QnA Maker: - -1. Call both QnA Maker and LUIS at the same time, and respond to the user by using information from the first one that returns a score of a specific threshold. -2. Call LUIS first, and if no intent meets a specific threshold score, i.e., "None" intent is triggered, then call QnA Maker. Alternatively, create a LUIS intent for QnA Maker, feeding your LUIS model with example QnA questions that map to "QnAIntent." -3. Call QnA Maker first, and if no answer meets a specific threshold score, then call LUIS. - -The Bot Framework SDK provide built-in support for LUIS and QnA Maker. This enables you to trigger dialogs or automatically answer questions using LUIS and/or QnA Maker without having to implement custom calls to either tool. See the [Dispatch Tool Tutorial](https://docs.microsoft.com/azure/bot-service/bot-builder-tutorial-dispatch?view=azure-bot-service-4.0) for more information. - -> [!TIP] -> When implementing a combination of LUIS, QnA Maker, and/or Azure Search, -> test inputs with each of the tools to determine the threshold score for each of your models. -> LUIS, QnA Maker, and Azure Search each generate scores by using a different scoring criteria, so -> the scores generated across these tools are not directly comparable. -> Additionally, LUIS and QnA Maker normalize scores. A certain score may be considered 'good' -> in one LUIS model but not so in another model. - -## Sample code - -- For a sample that shows how to create a basic knowledge bot using the Bot Framework SDK for .NET, see the Knowledge Bot sample in GitHub. - - -[qnamakerTemplate]: https://docs.botframework.com/azure-bot-service/templates/qnamaker/#navtitle diff --git a/articles/bot-service-design-pattern-task-automation.md b/articles/bot-service-design-pattern-task-automation.md deleted file mode 100644 index 654780d5e..000000000 --- a/articles/bot-service-design-pattern-task-automation.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -title: Create task automation bots - Bot Service -description: Learn how to design bots that perform tasks without further human intervention. -author: matvelloso -ms.author: mateusv -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 2/13/2018 -monikerRange: 'azure-bot-service-3.0' ---- - -# Create task automation bots - -[!INCLUDE [pre-release-label](./includes/pre-release-label-v3.md)] - -A task automation bot enables the user to complete a specific task or set of tasks without any assistance from a human. -This type of bot often closely resembles a typical app or website, communicating with the user primarily via rich user controls and text. -It may have natural language understanding capabilities to enrich conversations with users. - -## Example use case: password-reset - -To better understand the nature of a task bot, consider an example use case: password-reset. - -The Contoso company receives several help desk calls each day from employees who need to reset their passwords. Contoso wants to automate the simple, repeatable task of resetting a employee's password so that help desk agents can devote their time to addressing more complex issues. - -John, an experienced developer from Contoso, decides to create a bot to automate the password-reset task. -He begins by writing a design specification for the bot, just as he would do if he were creating a new app or website. - -### Navigation model - -The specification defines the navigation model: - -![Dialog Structure](~/media/bot-service-design-pattern-task-automation/simple-task1.png) - -The user begins at the `RootDialog`. When they request a password reset, they -will be directed to the `ResetPasswordDialog`. -With the `ResetPasswordDialog`, the bot will prompt the user for two pieces of information: phone number and birth date. - -> [!IMPORTANT] -> The bot design described in this article is intended for example purposes only. -> In real-world scenarios, a password-reset bot would likely implement a more robust identity verification process. - -### Dialogs - -Next, the specification describes the appearance and functionality of each dialog. - -#### Root dialog - -The root dialog provides the user with two options: - -1. **Change Password** is for scenarios where the user knows their current password and simply wants to change it. -2. **Reset Password** is for scenarios where the user has forgotten or misplaced their password and needs to generate a new one. - -> [!NOTE] -> For simplicity, this article describes only the **reset password** flow. - -The specification describes the root dialog as shown in the following screenshot. - -![Dialog Structure](~/media/bot-service-design-pattern-task-automation/simple-task2.png) - -#### ResetPassword dialog - -When the user chooses **Reset Password** from the root dialog, the `ResetPassword` dialog is invoked. -The `ResetPassword` dialog then invokes two other dialogs. -First, it invokes the `PromptStringRegex` dialog to collect the user's phone number. -Then it invokes the `PromptDate` dialog to collect the user's date of birth. - -> [!NOTE] -> In this example, John chose to implement the logic for collecting the user's phone number -> and date of birth by using two separate dialogs. -> The approach not only simplifies the code required for each dialog, but also increases the odds of these -> dialogs being usable by other scenarios in the future. - -The specification describes the `ResetPassword` dialog. - -![Dialog Structure](~/media/bot-service-design-pattern-task-automation/simple-task3.png) - -#### PromptStringRegex dialog - -The `PromptStringRegex` dialog prompts the user to enter their phone number, and verifies that the phone number -that the user provides matches the expected format. -It also accounts for the scenario where the user repeatedly provides invalid input. -The spec describes the `PromptStringRegex` dialog. - -![Dialog Structure](~/media/bot-service-design-pattern-task-automation/simple-task4.png) - -### Prototype - -Finally, the spec provides an example of a user communicating with the bot to successfully complete the password-reset task. - -![Dialog Structure](~/media/bot-service-design-pattern-task-automation/simple-task5.png) - -## Bot, app, or website? - -You may be wondering, if a task automation bot closely resembles an app or website, why not just build an app or website instead? -Depending on your particular scenario, building an app or website instead of a bot may be an entirely reasonable choice. -You may even choose to embed your bot into an app, by using the [Bot Framework Direct Line API][directLineAPI] -or Web Chat control. -Implementing your bot within the context of an app provides the best of both worlds: a rich app experience and a conversational experience, all in one place. - -In many cases, however, building an app or website can be significantly more complex and more expensive than building a bot. -An app or website often needs to support multiple clients and platforms, packaging and deploying -can be tedious and time-consuming processes, and the user experience of having to download and install an app is not necessarily ideal. -For these reasons, a bot may often provide a much simpler way of solving the problem at hand. - -Additionally, bots provide the freedom to easily expand and extend. -For example, a developer may choose to add natural language and speech capabilities to the password-reset bot so that it can be accessed via audio call, -or she may add support for text messages. -The company may setup kiosks throughout the building and embed the password-reset bot into that experience. - - -## Additional resources - -- [Dialogs](~/dotnet/bot-builder-dotnet-dialogs.md) -- [Manage conversation flow with dialogs (.NET)](~/dotnet/bot-builder-dotnet-manage-conversation-flow.md) -- [Manage conversation flow with dialogs (Node.js)](~/nodejs/bot-builder-nodejs-manage-conversation-flow.md) - - -[directLineAPI]: https://docs.botframework.com/restapi/directline3/#navtitle diff --git a/articles/bot-service-design-principles.md b/articles/bot-service-design-principles.md deleted file mode 100644 index e3c748926..000000000 --- a/articles/bot-service-design-principles.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -title: Principles of bot design - Bot Service -description: Learn what makes a good conversational bot and how to plan and design bots to fit your needs and delight your users. -keywords: best practices, bot design -author: matvelloso -ms.author: mateusv -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 - ---- - -# Principles of bot design - -The Bot Framework enables developers to create compelling bot experiences that solve a variety of business problems. By learning the concepts described in this section, you'll become equipped to design a bot that aligns with best practices and capitalizes on lessons learned thus far in this relatively new arena. - -## Designing a bot - -If you are building a bot, it's safe to assume that you are expecting users to use it. -It is also safe to assume that you are hoping that users will prefer the bot experience over alternative experiences like apps, websites, phone calls, and other means of addressing their particular needs. -In other words, your bot is competing for users' time against things like apps and websites. -So, how can you maximize the odds that your bot will achieve its ultimate goal of attracting and keeping users? -It's simply a matter of prioritizing the right factors when designing your bot. - -## Factors that do not guarantee a bot's success - -When designing your bot, be aware that none of the following factors necessarily guarantee a bot's success: - -- **How “smart” the bot is**: -In most cases, it is unlikely that making your bot smarter will guarantee happy users or adoption of your platform. In reality, many bots have little advanced machine learning or natural language capabilities. A bot may include those capabilities if they're necessary to solve the problems that it's designed to address, however you should not assume any correlation between a bot's intelligence and user adoption of the bot. - -- **How much natural language the bot supports**: -Your bot can be great at conversations. -It can have a vast vocabulary and can even make great jokes. -But unless it addresses the problems that your users need to solve, these capabilities may contribute very little to making your bot successful. -In fact, some bots have no conversational capability at all. And in many cases, that's perfectly fine. - -- **Voice**: -It isn’t always the case that enabling bots for speech will lead to great user experiences. -Often, forcing users to use voice can result in a frustrating user experience. -As you design your bot, always consider whether voice is the appropriate channel for the given problem. -Is there going to be a noisy environment? -Will voice convey the information that needs to be shared with the user? - -## Factors that do influence a bot's success - -Most successful apps or websites have at least one thing in common: a great user experience. -Bots are no different in that regard. -Therefore, ensuring a great user experience should be your number one priority when designing a bot. -Some key considerations include: - -- Does the bot easily solve the user’s problem with the minimum number of steps? - -- Does the bot solve the user’s problem better/easier/faster than any of the alternative experiences? - -- Does the bot run on the devices and platforms the user cares about? - -- Is the bot discoverable? Do the users naturally know what to do when using it? - -None of these questions directly relates to factors such as how smart the bot is, how much natural language capability it has, whether it uses machine learning, or which programming language was used to create it. Users are unlikely to care about any of these things if the bot solves the problem that they need to address and delivers a great user experience. A great bot user experience does not require users to type too much, talk too much, repeat themselves several times, or explain things that the bot should automatically know. - -> [!TIP] -> Regardless of the type of application you're creating (bot, website, or app), make user experience a top priority. - -The process of designing a bot is like the process of designing an app or website, so -the lessons learned from decades of building UI and delivering UX for apps and websites still apply when it comes to designing bots. - -Whenever you are unsure about the right design approach for your bot, step back and ask yourself the following question: how would you solve that problem in an app or a website? Chances are, the same answer can be applied to bot design. - -## Next steps - -Now that you're familiar with some basic principles of bot design, learn more about the basic principles for [designing the first interaction](~/bot-service-design-first-interaction.md) between a user and bot. diff --git a/articles/bot-service-design-user-experience.md b/articles/bot-service-design-user-experience.md deleted file mode 100644 index d1beb624e..000000000 --- a/articles/bot-service-design-user-experience.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: Design the user experience - Bot Service -description: Learn how to design your bot to deliver an engaging user experience, by using rich user controls, natural language understanding, and speech. -keywords: overview, design, user experience, UX, rich user control -author: matvelloso -ms.author: mateusv -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 09/20/2018 - ---- - -# Design the user experience - -You can create bots with a variety of features such as text, buttons, images, rich cards displayed in carousel or list format, and more. However, each channel such as Facebook, Slack, Skype, etc. ultimately controls how its messaging clients render features. Even when multiple channels support a feature, each channel may render the feature in a slightly different way. In cases where a message contains feature(s) that a channel does not natively support, the channel may attempt to down-render message contents as text or as a static image, which can significantly impact the message's appearance on the client. In some cases, a channel may not support a particular feature at all. For example, GroupMe clients cannot display a typing indicator. - -## Rich user controls - -**Rich user controls** are common UI controls such as buttons, images, carousels, and menus that the bot presents to the user and the user engages with to communicate choice and intent. A bot can use a collection of UI controls to mimic an app, or can even run embedded within an app. When a bot is embedded within an app or website, it can represent virtually any UI control by leveraging the capabilities of the app that is hosting it. - -For decades, application and website developers have relied on UI controls to enable users to interact with their applications and these same UI controls can also be very effective in bots. For instance, buttons are a great way to present the user with a simple choice. Allowing the user to communicate "Hotels" by clicking a button labeled **Hotels** is easier and quicker than forcing the user to type "Hotels." This especially holds true on mobile devices, where clicking is greatly preferred over typing. - -## Cards - -Cards allow you to present your users with a variety of visual, audio, and/or selectable messages and help to assist conversation flow. If a user needs to select from within a fixed set of items you can display a carousel of cards, each containing an image, a text description, and a single selection button. If a user has a set of choices for a single item, you can present a smaller single image and a collection of buttons with various options to choose between. Did they ask for more information on a subject? Cards can provide in depth information using audio or video output, or a receipt that details their shopping experience. There is an incredibly wide range uses for cards to help guide the conversation between your user and your bot. The type of card you use will be determined by the needs of your application. Let’s take a closer look at cards, their actions, and some recommended uses. - -Microsoft Bot Service cards are programmable objects containing standardized collections of rich user controls that are recognized across a wide range of channels. The following table describes the list of available cards and best practice suggestions of usage for each type of card. - -| Card type | Example | Description | -| ---- | ---- | ---- | -| AdaptiveCard | ![Adaptive card Image](./media/adaptive-card.png) | An open card exchange format rendered as a JSON object. Typically used for cross-channel deployment of cards. Cards adapt to the look and feel of each host channel. | -| AnimationCard | ![Animation card Image](./media/animation-card1.png) | A card that can play animated GIFs or short videos. | -| AudioCard | ![Audio card Image](./media/audio-card.png) | A card that can play an audio file. | -| HeroCard | ![Hero card Image](./media/hero-card1.png) | A card that contains a single large image, one or more buttons, and text. Typically used to visually highlight a potential user selection. | -| ThumbnailCard | ![Thumbnail card Image](./media/thumbnail-card.png) | A card that contains a single thumbnail image, one or more buttons, and text. Typically used to visually highlight the buttons for a potential user selection. | -| ReceiptCard | ![Receipt card Image](./media/receipt-card1.png) | A card that enables a bot to provide a receipt to the user. It typically contains the list of items to include on the receipt, tax and total information, and other text. | -| SignInCard | ![Sign-in card Image](./media/sign-in-card.png) | A card that enables a bot to request that a user sign-in. It typically contains text and one or more buttons that the user can click to initiate the sign-in process. | -| SuggestedAction | ![Suggested actions card Image](./media/suggested-actions.png) | Presents your user with a set of CardActions representing a user choice. This card disappears once any of the suggested actions is selected. | -| VideoCard | ![Video card Image](./media/video-card.png) | A card that can play videos. Typically used to open a URL and stream an available video. | -| CardCarousel | ![Card carousel Image](./media/card-carousel.png) | A horizontally scrollable collection of cards that allows your user to easily view a series of possible user choices.| - -Cards allow you to design your bot once, and have it work across a variety of channels. However, not all card types are fully supported across all available channels. - -Detailed instructions for adding cards to your bot can be found within these sections [Add rich card media attachments](v4sdk/bot-builder-howto-add-media-attachments.md) and [Add suggested actions to messages](v4sdk/bot-builder-howto-add-suggested-actions.md). Sample code can also be found here for cards: [C#](https://aka.ms/bot-cards-sample-code-cs)/[JS](https://aka.ms/bot-cards-sample-code-js) adaptive cards: [C#](https://aka.ms/bot-adaptive-cards-sample-code)/[JS](https://aka.ms/bot-adaptive-cards-js-sample-code), attachments: [C#](https://aka.ms/bot-attachments-sample-code)/[JS](https://aka.ms/bot-attachments-js-sample-code), and suggested actions: [C#](https://aka.ms/bot-suggested-actions-code)/[JS](https://aka.ms/bot-suggested-actions-js-code). - - - -When designing your bot, do not automatically dismiss common UI elements as not being "smart enough." As discussed [previously](~/bot-service-design-principles.md#designing-a-bot), your bot should be designed to solve the user's problem in the best, quickest, and easiest manner possible. Avoid the temptation to start by incorporating natural language understanding, as it is often unnecessary and introduces unjustified complexity. - -> [!TIP] -> Start by using the minimum UI controls that enable the bot to solve the user's problem, -> and add other elements later if those controls are no longer sufficient. - - -## Text and natural language understanding - -A bot can accept **text** input from users and attempt to parse that input using regular expression matching or **natural language understanding** APIs, such as LUIS. Depending on the type of input that the user provides, natural language understanding may or may not be a good solution. - -In some cases, a user may be **answering a very specific question**. For example, if the bot asks, "What is your name?", the user may answer with text that specifies only the name, "John", or with a sentence, "My name is John". - -Asking specific questions reduces the scope of potential responses that the bot might reasonably receive, which decreases the complexity of the logic necessary to parse and understand the response. For example, consider the following broad, open-ended question: "How are you feeling?". Understanding the many possible permutations of potential answers to such a question is a very complex task. - -In contrast, specific questions such as "Are you feeling pain? yes/no" and "Where are you feeling pain? chest/head/arm/leg" would likely prompt more specific answers that a bot can parse and understand without needing to implement natural language understanding. - -> [!TIP] -> Whenever possible, ask specific questions that will not require natural language understanding capabilities to parse the response. This will simplify your bot and increase the success your bot will understand the user. - - -In other cases, a user may be **typing a specific command**. For example, a DevOps bot that enables developers to manage virtual machines could be designed to accept specific commands such as "/STOP VM XYZ" or "/START VM XYZ". Designing a bot to accept specific commands like this makes for a good user experience, as the syntax is easy to learn and the expected outcome of each command is clear. Additionally, the bot will not require natural language understanding capabilities, since the user's input can be easily parsed using regular expressions. - -> [!TIP] -> Designing a bot to require specific commands from the user can often provide a good user experience while -> also eliminating the need for natural language understanding capability. - - -In the case of a *knowledge base* bot or *questions and answers* bot, a user may be **asking general questions**. For example, imagine a bot that can answer questions based on the contents of thousands of documents. QnA Maker and Azure Search are both technologies which are designed specifically for this type of scenario. For more information, see [Design knowledge bots](bot-service-design-pattern-knowledge-base.md). - -> [!TIP] -> If you are designing a bot that will answer questions based on structured or unstructured data from -> databases, web pages, or documents, consider using technologies that are designed specifically to address this -> scenario rather than attempting to solve the problem with natural language understanding. - - -In other scenarios, a user may be **typing simple requests based on natural language**. For example, a user may type "I want a pepperoni pizza" or "Are there any vegetarian restaurants within 3 miles from my house open now?". Natural language understanding APIs such as [LUIS.ai](https://www.luis.ai) are a great fit for scenarios like this. - -Using the APIs, your bot can extract the key components of the user's text to identify the user's intent. When implementing natural language understanding capabilities in your bot, set realistic expectations for the level of detail that users are likely to provide in their input. - -![how users talk](./media/bot-service-design-user-experience/buy-house.png) - -> [!TIP] -> When building natural language models, do not assume that users will provide all the required information in their initial query. -> Design your bot to specifically request the information it requires, guiding the user to provide that information -> by asking a series of questions, if necessary. - - -## Speech - -A bot can use **speech** input and/or output to communicate with users. In cases where a bot is designed to support devices that have no keyboard or monitor, speech is the only means of communicating with the user. - -## Choosing between rich user controls, text and natural language, and speech - -Just like people communicate with each other using a combination of gestures, voice, and symbols, bots can communicate with users using a combination of rich user controls, text (sometimes including natural language), and speech. These communication methods can be used together; you do not need to choose one over another. - -For example, imagine a "cooking bot" that helps users with recipes, where the bot may provide instructions by playing a video or displaying a series of pictures to explain what needs to be done. Some users may prefer to flip pages of the recipe or ask the bot questions using speech while they are assembling a recipe. Others may prefer to touch the screen of a device instead of interacting with the bot via speech. When designing your bot, incorporate the UX elements that support the ways in which users will likely prefer to interact with your bot, given the specific use cases that it is intended support. - diff --git a/articles/bot-service-manage-analytics.md b/articles/bot-service-manage-analytics.md deleted file mode 100644 index 7ac02008e..000000000 --- a/articles/bot-service-manage-analytics.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: Bot analytics - Bot Service -description: Learn how to use data collection and analysis to improve your bot with analytics in the Bot Framework. -keywords: bot analytics, application insights, traffic, latency, integrations, AppInsights -author: JonathanFingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/04/2018 ---- - -# Bot analytics - -Analytics is an extension of [Application Insights](/azure/application-insights/app-insights-analytics). Application Insights provides **service-level** and instrumentation data like traffic, latency, and integrations. Analytics provides **conversation-level** reporting on user, message, and channel data. - -## View analytics for a bot - -To access Analytics, open the bot in the Azure portal and click **Analytics**. - -Too much data? You can [enable and configure sampling](/azure/application-insights/app-insights-sampling) for the Application Insights linked to your bot. This reduces telemetry traffic and storage while maintaining statistically correct analysis. - -### Specify channel - -Choose which channels appear in the graphs below. Note that if a bot is not enabled on a channel, there will be no data from that channel. - -![Select channel](~/media/analytics-channels.png) - -* Check the check box to include a channel in the chart. -* Clear the check box to remove a channel from the chart. - -### Specify time period - -Analysis is available for the past 90 days only. Data collection began when Application Insights was enabled. - -![Select time period](~/media/analytics-timepick.png) - -Click the drop-down menu and then click the amount of time the graphs should display. -Note that changing the overall time frame will cause the time increment (X-axis) on the graphs to change accordingly. - -### Grand totals - -The total number of active users and activities sent and received during the specified time frame. -Dashes `--` indicate no activity. - -### Retention - -Retention tracks how many users who sent one message came back later and sent another one. -The chart is a rolling 10-day window; the results are not affected by changing the time frame. - -![Retention chart](~/media/analytics-retention.png) - -Note that the most recent possible date is two days ago; a user sent messages the day before yesterday and then *returned* yesterday. - -### User - -The Users graph tracks how many users accessed the bot using each channel during the specified time frame. - -![Users graph](~/media/analytics-users.png) - -* The percentage chart shows what percentage of users used each channel. -* The line graph indicates how many users were accessing the bot at a certain time. -* The legend for the line graph indicates which color represents which channel and the includes the total number of users during the specified time period. - -### Activities - -The Activities graph tracks how many activities were sent and received using which channel during the specified time frame. - -![activities graph](~/media/analytics-activities.png) - -* The percentage chart shows what percentage of activities were communicated over each channel. -* The line graph indicates how many activities were sent and received over the specified time frame. -* The legend for the line graph indicates which line color represents each channel and the total number of activities sent and received on that channel during the specified time period. - -## Enable analytics - -Analytics are not available until Application Insights has been enabled and configured. Application Insights will begin collecting data as soon as it is enabled. For example, if Application Insights was enabled a week ago for a six-month-old bot, it will have collected one week of data. - -> [!NOTE] -> Analytics requires both an Azure subscription and Application Insights [resource](/azure/application-insights/app-insights-create-new-resource). -To access Application Insights, open the bot in the [Azure Portal](https://portal.azure.com/) and click **Settings**. - -You can add Application Insights when you create your bot resource. - -You can also create an Application Insights resource later and connect it to your bot. - -1. Create an Application Insights [resource](/azure/application-insights/app-insights-create-new-resource). -2. Open the bot in the dashboard. Click **Settings** and scroll down to the **Analytics** section. -3. Enter the information to connect the bot to Application Insights. All fields are required. - -![Connect Insights](~/media/analytics-enable.png) - - - -For more information on how to locate these values, see [Application Insights keys](~/bot-service-resources-app-insights-keys.md). - -## Additional resources -* [Application Insights keys](~/bot-service-resources-app-insights-keys.md) \ No newline at end of file diff --git a/articles/bot-service-manage-channels.md b/articles/bot-service-manage-channels.md deleted file mode 100644 index a4a5a9f8d..000000000 --- a/articles/bot-service-manage-channels.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Configure a bot to run on one or more channels - Bot Service -description: Learn how to configure a bot to run on one or more channels using the Bot Framework Portal. -keywords: bot channels, configure, cortana, facebook messenger, kik, slack, skype, azure portal -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 09/22/2018 ---- - -# Connect a bot to channels - -A channel is a connection between the bot and communication apps. You configure a bot to connect to the channels you want it to be available on. The Bot Framework Service, configured through the Azure portal, connects your bot to these channels and facilitates communication between your bot and the user. You can connect to many popular services, such as [Cortana](bot-service-channel-connect-cortana.md), [Facebook Messenger](bot-service-channel-connect-facebook.md), [Kik](bot-service-channel-connect-kik.md), and [Slack](bot-service-channel-connect-slack.md), as well as several others. The [Web Chat](bot-service-channel-connect-webchat.md) channel is pre-configured for you. In addition to standard channels provided with the Bot Connector Service, you can also connect your bot to your own client application using [Direct Line](bot-service-channel-connect-directline.md) as your channel. - -The Bot Framework Service allows you to develop your bot in a channel-agnostic way by normalizing messages that the bot sends to a channel. This involves converting it from the bot framework schema into the channel’s schema. However, if the channel does not support all aspects of the bot framework schema, the service will try to convert the message to a format that the channel does support. For example, if the bot sends a message that contains a card with action buttons to the email channel, the connector may send the card as an image and include the actions as links in the message’s text. - -For most channels, you must provide channel configuration information to run your bot on the channel. Most channels require that your bot have an account on the channel, and others, like Facebook Messenger, require your bot to have an application registered with the channel also. - -To configure your bot to connect to a channel, complete the following steps: - -1. Sign in to the Azure Portal. -2. Select the bot that you want to configure. -3. In the Bot Service blade, click **Channels** under **Bot Management**. -4. Click the icon of the channel you want to add to your bot. - -![Connect to channels](./media/channels/connect-to-channels.png) - -After you've configured the channel, users on that channel can start using your bot. - -## Publish a bot - -The publishing process is different for each channel. - -[!INCLUDE [publishing](./includes/snippet-publish-to-channel.md)] - -## Additional resources - -The SDK includes samples that you can use to build bots. Visit the [Samples repo on GitHub](https://github.com/Microsoft/BotBuilder-samples) to see a list of samples. diff --git a/articles/bot-service-manage-overview.md b/articles/bot-service-manage-overview.md deleted file mode 100644 index eeacd1783..000000000 --- a/articles/bot-service-manage-overview.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Manage a bot - Bot Service -description: Learn how to manage a bot through the bot service portal. -keywords: azure portal, bot management, test in web chat, MicrosoftAppID, MicrosoftAppPassword, application settings -author: v-ducvo -ms.author: rstand -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 8/13/2019 ---- -# Manage a bot - -[!INCLUDE [applies-to-both](includes/applies-to-both.md)] - -This topic explains how to manage a bot using the Azure portal. - -## Bot settings overview - -![Bot settings overview](~/media/azure-manage-a-bot/overview.png) - -In the **Overview** blade, you can find high level information about your bot. For example, you can see your bot's **Subscription ID**, **pricing tier**, and **Messaging endpoint**. - -## Bot management - - You can find most of your bot's management options under the **BOT MANAGEMENT** section. Below is a list of options to help you manage your bot. - -![Bot management](~/media/azure-manage-a-bot/bot-management.png) - -| Option | Description | -| ---- | ---- | -| **Build** | The Build tab provides options for making changes to your bot. This option is not available for **Registration Only Bot**. | -| **Test in Web Chat** | Use the integrated Web Chat control to help you quickly test your bot. | -| **Analytics** | If analytics is turned on for your bot, you can view the analytics data that Application Insights has collected for your bot. | -| **Channels** | Configure the channels your bot uses to communicate with users. | -| **Settings** | Manage various bot profile settings such as display name, analytics, and messaging endpoint. | -| **Speech priming** | Manage the connections between your LUIS app and the Bing Speech service.. | -| **Bot Service pricing** | Manage the pricing tier for the bot service. | - -## App service settings - -![App Service Settings](~/media/azure-manage-a-bot/app-service-settings.png) - -The **Application Settings** blade contains detailed information about your bot, such as the bot's environment, debug settings, and application settings keys. - -### MicrosoftAppID and MicrosoftAppPassword - -The **MicrosoftAppID** and **MicrosoftAppPassword** are kept within the bot's settings file(`appsettings.json` or `.env`), or Azure Key Vault. To retrieve them, either download your bot's setting or config file (for older bots, if it exists), or access Azure Key Vault. It may be necessary for you to test locally with the ID and password. - -> [!NOTE] -> The **Bot Channels Registration** bot service comes with a *MicrosoftAppID* but because there is no app service associated with this type of service, there is no **Application Settings** blade for you to look up the *MicrosoftAppPassword*. To get the password, you must go generate one. To generate the password for a **Bot Channels Registration**, see [Bot Channels Registration password](bot-service-quickstart-registration.md#get-registration-password) - -## Next steps -Now that you have explored the Bot Service blade in the Azure portal, learn how to use the Online Code Editor to customize your bot. -> [!div class="nextstepaction"] -> [Use the Online Code Editor](bot-service-build-online-code-editor.md) diff --git a/articles/bot-service-manage-settings.md b/articles/bot-service-manage-settings.md deleted file mode 100644 index 62e25ee44..000000000 --- a/articles/bot-service-manage-settings.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Configure bot settings - Bot Service -description: Learn how to configure the various options for your bot using the Azure portal. -keywords: configure bot settings, Display Name, Icon, Application Insights, Settings blade -author: v-royhar -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- -# Configure bot settings - -The bot settings, such as Display name, Icon, and Application Insights, can be viewed and modified on its **Settings** blade. - -![The bot settings blade](~/media/bot-service-portal-configure-settings/bot-settings-blade.png) - -Below is the list of fields on the **Settings** blade: - -| Field | Description | -| :--- | :--- | -| Icon | A custom icon to visually identify your bot in channels and as the icon for Skype, Cortana, and other services. This icon must be in PNG format, and no larger than 30K in size. This value can be changed at any time. | -| Display name | The name of your bot in channels and directories. This value can be changed at any time. 35 character limit. | -| Bot handle | Unique identifier for your bot. This value cannot be changed after creating your bot with the Bot Service. | -| Messaging endpoint | The endpoint to communicate with your bot. | -| Microsoft App ID | Unique identifier for your bot. This value cannot be changed. You can generate a new password by clicking on the **Manage** link. | -| Application Insights Instrumentation key | Unique key for bot telemetry. Copy your Azure Application Insights Key to this field if you want to receive bot telemetry for this bot. This value is optional. Bots created in the Azure Portal will have this key generated for them. For more details on this field, see [Application Insights keys](~/bot-service-resources-app-insights-keys.md). | -| Application Insights API key | Unique key for bot analytics. Copy your Azure Application Insights API Key to this field if you want to view analytics about your bot in the Dashboard. This value is optional. For more details on this field, see [Application Insights keys](~/bot-service-resources-app-insights-keys.md). | -| Application Insights Application ID | Unique key for bot analytics. Copy your Azure Insights Application ID Key to this field if you want to view analytics about your bot in the Dashboard. This value is optional. Bots created in the Azure Portal will have this key generated for them. For more details on this field, see [Application Insights keys](~/bot-service-resources-app-insights-keys.md). | - -> [!NOTE] -> After you have changed settings for your bot, click the **Save** button at the top of the blade to save your new bot settings. - -## Next steps -Now that you have learned how to configure settings for your bot service, learn about how to configure speech priming. -> [!div class="nextstepaction"] -> [Speech priming](bot-service-manage-speech-priming.md) \ No newline at end of file diff --git a/articles/bot-service-manage-speech-priming.md b/articles/bot-service-manage-speech-priming.md deleted file mode 100644 index 375929f7f..000000000 --- a/articles/bot-service-manage-speech-priming.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: Configure speech priming - Bot Service -description: Learn how to configure speech priming for your bot service using the Azure Portal. -keywords: speech priming, speech recognition, LUIS -author: v-royhar -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Configure speech priming - -Speech priming improves the recognition of spoken words and phrases that are commonly used in your bot. For speech-enabled bots that use the Web Chat and Cortana channels, speech priming uses examples specified in Language Understanding (LUIS) apps to improve speech recognition accuracy for important words. - -Your bot may already be integrated with a LUIS app, or you can choose to create a LUIS app to associate with your bot for speech priming. The LUIS app contains examples of what you expect users to say to your bot. Important words that you want the bot to recognize should be labeled as entities. For example, in a chess bot you want to make sure that when the user says "Move knight", it isn’t interpreted as "Move night". The LUIS app should include examples in which "knight" is labeled as an entity. - -> [!NOTE] -> To use speech priming with the Web Chat channel, you must use the Bing Speech service. See [Enable speech in the Web Chat channel](~/bot-service-channel-connect-webchat-speech.md) for an explanation of how to use the Bing Speech service. - -> [!IMPORTANT] -> Speech priming only applies to bots configured for the Cortana channel or the Web Chat channel. - -> [!IMPORTANT] -> Priming is not supported from non U.S. regional LUIS apps including: eu.luis.ai and au.luis.ai - -## Change the list of LUIS apps your bot uses - -To change the list of LUIS apps used by Bing Speech with your bot, do the following: - -1. Click **Speech priming** on the bot service blade. The list of LUIS apps available to you will appear. -2. Select the LUIS apps you want Bing Speech to use. - - a. To select a LUIS app in the list, hover over the LUIS model until a checkbox appears, then check the checkbox. - - b. To select a LUIS app that is not on the list, scroll to the bottom and enter the LUIS Application ID GUID into the text box. - -3. Click **Save** to save the list of LUIS apps associated with Bing Speech for your bot. - -![The speech priming panel](~/media/bot-service-manage-speech-priming/speech-priming.png) - -## Additional Resources - -- To learn more about enabling speech in Web Chat see [Enable speech in the Web Chat channel](~/bot-service-channel-connect-webchat-speech.md). -- To learn more about speech priming, see [Speech Support in Bot Framework – Web Chat to Directline, to Cortana](https://blog.botframework.com/2017/06/26/Speech-To-Text/). -- To learn more about LUIS apps, see [Language Understanding Intelligent Service](https://www.luis.ai). diff --git a/articles/bot-service-migrate-bot.md b/articles/bot-service-migrate-bot.md deleted file mode 100644 index dec2842a4..000000000 --- a/articles/bot-service-migrate-bot.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: Migrate your bot to Azure - Bot Service -description: Learn how to migrate your bot from the legacy Bot Framework Portal to a bot service in the Azure portal. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 3/22/2019 -monikerRange: 'azure-bot-service-3.0' ---- - -# Migrate your bot to Azure - -All **Azure Bot Service (Preview)** bots created in the [Bot Framework Portal](http://dev.botframework.com) must migrate to the new Bot Service in Azure. The service was made generally available (GA) in December 2017. - -Note that, registration bots connected only to the following channels are *not* required to migrate: **Teams**, **Skype**, or **Cortana**. For example, a registration bot connected to **Facebook** and **Skype** *is required* to migrate but a registration bot connected to **Skype** and **Cortana** *is not required* to migrate. - -> [!IMPORTANT] -> Before migrating a Functions bot created with Node.js, it is required that you use **Azure Functions Pack** to package the **node_modules** modules together. Doing so will improve performance during migration and execution of the Functions bot after it is migrated. -> To package your modules, see [Package a Functions bot with Funcpack](#package-a-functions-bot-with-funcpack). - -To migrate your bot, do the following: - -1. Sign into the [Bot Framework Portal](http://dev.botframework.com) and click **My bots**. -2. Click **Migrate** button for the bot you want to migrate. -3. Accept the **Terms** and click **Migrate** to start the migration process or click **Cancel** to cancel this action. - -> [!IMPORTANT] -> While the migration task is in progress, do not navigate away from the page or refresh the page. Doing so will cause the migration task to stop pre-maturely and you will have to perform the action again. -> To ensure the migration completes successfully, wait for the confirmation message. - -After the migration process completes successfully, the **Migration status** will indicate that the bot is migrated and a **Roll back migration** button will be available for a week after the migration date in case of issues. - -Clicking the name of a migrated bot will open the bot in the [Azure portal](https://portal.azure.com). - -## Package a Functions bot with Funcpack - -Functions bots created with Node.js must be packed using [Funcpack](https://github.com/Azure/azure-functions-pack) before migrating. To Funcpack your project, follow these steps: - -1. [Download](bot-service-build-download-source-code.md) your code locally if you haven’t already. -2. Update all the npm packages in **packages.json** to the latest versions and then run `npm install`. -3. Open **messages/index.js** and change `module.exports = { default: connector.listen() }` -to `module.exports = connector.listen();` -4. Install Funcpack via npm: `npm install -g azure-functions-pack` -5. To package the **node_modules** directory, run the following command: `funcpack pack ./` -6. Test your bot locally by running the Functions bot using the Bot Framework Emulator. More info on how to run the *funcpack* bot [here](https://github.com/Azure/azure-functions-pack#how-to-run). -7. Upload your code back to Azure. Make sure the `.funcpack` directory is uploaded. You do not need to upload the **node_modules** directory. -8. Test your remote bot to make sure it responds as expected. -9. Migrate your bot using the steps above. - -## Migration under the hood - -Depending on the type of bot you are migrating, the list below can help you better understand what is happening under the hood. - -* **Web App Bot** or **Functions Bot**: For these types of bots, the source code project is copied from the old bot to the new bot. Other resources such as your bot's storage, Application Insights, LUIS, etc. are left as is. In those cases, the new bot contains a copy of the IDs/keys/passwords to those existing resources. -* **Bot Channels Registration**: For this type of bots, the migration process simply create a new **Bot Channels Registration** and copy the endpoint from the old bot over. -* Regardless of the types of bots you are migrating, the migration process does not modify the existing bot's state in anyway. This allows you to safely roll back if you need to do so. -* If you have [continuous deployment](bot-service-build-continuous-deployment.md) set up, you will need to set it up again so that your source control connects to the new bot instead. - -## Understanding Azure Resources after migration -Once migration is done, your **Resource Group** will contain a number of Azure resources that are needed for your bot to work. The type and number of resources depend on the type of bot have you migrated. Refer to following sections to lean more. - -### Registration Bot - -This is the simplest type. The Resource Group in Azure will only contain one resource of type “Bot Channel Registration”. This is the equivalent of the previous bot record in the Bot Framework Developer Portal. - -![Bot Channel Registration bot listings in Azure](~/media/bot-service-migrate-bot/channel-registration-bot.png) - -### Web App Bot -The Web App bot migration will provision a Bot Service resource of type “Web App Bot” and a new App Service Web App (in green in the screenshot below). The previous Azure Bot Service (Preview) bot will still be there and can be deleted (in red in the screenshot below). - -![Web App bot listings in Azure](~/media/bot-service-migrate-bot/web-app-bot.png) - -### Functions Bot -The Functions bot migration will provision a Bot Service resource of type “Functions Bot” and a new App Service Functions App (in green in the screenshot below). The previous Azure Bot Service (Preview) bot will still be there and can be deleted (in red in the screenshot below). - -![Functions bot listings in Azure](~/media/bot-service-migrate-bot/functions-bot.png) - - -## Roll back migration - -In the event something went wrong with the bot during migration or after it is migrated, you can **Roll back migration**. To roll back a migration, do the following: - -1. Sign into the [Bot Framework Portal](http://dev.botframework.com) and click **My bots**. -2. Click **Roll back migration** button for the bot you want to roll back. A prompt will appear. -3. Click **Yes, roll back** to proceed or **Cancel** to cancel the roll back action. - -> [!NOTE] -> Roll back functionality will be available for a week after migration, and should be used only if you run into issues in the migrated bot. - -## Migration troubleshooting/Known issues -My node.js/functions bot migrated successfully, but it fails to respond: - -* **Check endpoint** - * Go to the **Settings** blade in your bot resource and verify that the bot endpoint has a “code” querystring parameter with a value in it. If not, you need to add it. -* **Check secrets folder in kudu for backups** - * In some rare cases there might be a few backup secret files that are creating a conflict. Go to the **home\data\Functions\secrets** folder in Kudu and delete any **host.snapshot** (or **host.backup**) file you find in there. There should be only one **host.json** and one **messages.json**. Finally restart the App Service and retry chatting with your bot. - -For any other issue please submit a CRI to Azure Support or file an issue in [GitHub](https://github.com/MicrosoftDocs/bot-framework-docs/issues). - - -## Next steps - -Now that your bot is migrated, learn how to manage your bot from the Azure portal. - -> [!div class="nextstepaction"] -> [Manage a bot](bot-service-manage-overview.md) diff --git a/articles/bot-service-overview-introduction.md b/articles/bot-service-overview-introduction.md deleted file mode 100644 index 83a7be227..000000000 --- a/articles/bot-service-overview-introduction.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Azure Bot Service Introduction - Bot Service -description: Learn about Bot Service, a service for building, connecting, testing, deploying, monitoring, and managing bots. -keywords: overview, introduction, SDK, outline -author: Kaiqb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/15/2019 ---- - -# About Azure Bot Service - -[!INCLUDE [applies-to-both](includes/applies-to-both.md)] - -Azure Bot Service and Bot Framework provide tools to build, test, deploy, and manage intelligent bots, all in one place. Through the use of modular and extensible framework provided by the SDK, tools, templates, and AI services developers can create bots that use speech, understand natural language, handle questions and answers, and more. - -## What is a bot? -Bots provide an experience that feels less like using a computer and more like dealing with a person - or at least an intelligent robot. They can be used to shift simple, repetitive tasks, such as taking a dinner reservation or gathering profile information, on to automated systems that may no longer require direct human intervention. Users converse with a bot using text, interactive cards, and speech. A bot interaction can be a quick question and answer, or it can be a sophisticated conversation that intelligently provides access to services. - -Bots are a lot like modern web applications, living on the internet and use APIs to send and receive messages. What's in a bot varies widely depending on what kind of bot it is. Modern bot software relies on a stack of technology and tools to deliver increasingly complex experiences on a wide variety of platforms. However, a simple bot could just receive a message and echo it back to the user with very little code involved. - -Bots can do the same things other types of software can do - read and write files, use databases and APIs, and do the regular computational tasks. What makes bots unique is their use of mechanisms generally reserved for human-to-human communication. - -Azure Bot Service and Bot Framework offer: -- Bot Framework SDK for developing bots -- Bot Framework Tools to cover end-to-end bot development workflow -- Bot Framework Service (BFS) to send and receive messages and events between bots and channels -- Bot deployment and channel configuration in Azure - -Additionally, bots may use other Azure services, such as: -- Azure Cognitive Services to build intelligent applications -- Azure Storage for cloud storage solution - -## Building a bot - -Azure Bot Service and Bot Framework offer an integrated set of tools and services to facilitate this process. Choose your favorite development environment or command line tools to create your bot. SDKs exist for C#, JavaScript, and Typescript. (SDKs for Java and Python are under development.) We provide tools for various stages of bot development to help you design and build bots. - -![Bot Overview](media/bot-service-overview.png) - -### Plan -As with any type of software, having a thorough understanding of the goals, processes and user needs is important to the process of creating a successful bot. Before writing code, review the bot [design guidelines](bot-service-design-principles.md) for best practices and identify the needs for your bot. You can create a simple bot or include more sophisticated capabilities such as speech, natural language understanding, and question answering. - -### Build -Your bot is a web service that implements a conversational interface and communicates with the Bot Framework Service to send and receive messages and events. Bot Framework Service is one of the components of the Azure Bot Service and Bot Framework. You can create bots in any number of environments and languages. You can start your bot development in the [Azure portal](bot-service-quickstart.md), or use [[C#](dotnet/bot-builder-dotnet-sdk-quickstart.md) | [JavaScript](javascript/bot-builder-javascript-quickstart.md) | [Python](python/bot-builder-python-quickstart.md)] templates for local development. - -As part of the Azure Bot Service and Bot Framework, we offer additional components you can use to extend your bot's functionality: - -| Feature | Description | Link | -| --- | --- | --- | -| Add natural language processing | Enable your bot to understand natural language, understand spelling errors, use speech, and recognize the user's intent | How to use [LUIS](~/v4sdk/bot-builder-howto-v4-luis.md) -| Answer questions | Add a knowledge base to answer questions users ask in a more natural, conversational way | How to use [QnA Maker](~/v4sdk/bot-builder-howto-qna.md) -| Manage multiple models | If using more than one model, such as for LUIS and QnA Maker, intelligently determine when to use which one during your bot's conversation | [Dispatch](~/v4sdk/bot-builder-tutorial-dispatch.md) tool| -| Add cards and buttons | Enhance the user experience with media other than text, such as graphics, menus, and cards | How to [add cards](v4sdk/bot-builder-howto-add-media-attachments.md) | - -> [!NOTE] -> The table above is not a comprehensive list. Explore the articles on the left, starting with [sending messages](~/v4sdk/bot-builder-howto-send-messages.md), for more bot functionality. - -Additionally, we provide command line tools to help you to create, manage, and test bot assets. These tools can configure LUIS apps, build a QnA knowledge base, build models to dispatch between components, mock a conversation, and more. You can find more details in the command line tools [readme](https://aka.ms/botbuilder-tools-readme). - -You also have access to a variety of [samples](https://github.com/microsoft/botbuilder-samples) that showcase many of the capabilities available through the SDK. These are great for developers looking for a more feature rich starting point. - -### Test -Bots are complex apps, with a lot of different parts working together. Like any other complex app, this can lead to some interesting bugs or cause your bot to behave differently than expected. Before publishing, test your bot. We provide several ways to test bots before they are released for use: - -- Test your bot locally with the [emulator](bot-service-debug-emulator.md). The Bot Framework Emulator is a stand-alone app that not only provides a chat interface but also debugging and interrogation tools to help understand how and why your bot does what it does. The emulator can be run locally alongside your in-development bot application. - -- Test your bot on the [web](bot-service-manage-test-webchat.md). Once configured through the Azure portal your bot can also be reached through a web chat interface. The web chat interface is a great way to grant access to your bot to testers and other people who do not have direct access to the bot's running code. - -- [Unit Test](https://docs.microsoft.com/azure/bot-service/unit-test-bots) your bot with the July update of Bot Framework SDK. - - - -### Publish -When you are ready for your bot to be available on the web, publish your bot to [Azure](bot-builder-howto-deploy-azure.md) or to your own web service or data center. Having an address on the public internet is the first step to your bot coming to life on your site, or inside chat channels. - -### Connect          -Connect your bot to channels such as Facebook, Messenger, Kik, Skype, Slack, Microsoft Teams, Telegram, text/SMS, Twilio, Cortana, and Skype. Bot Framework does most of the work necessary to send and receive messages from all of these different platforms - your bot application receives a unified, normalized stream of messages regardless of the number and type of channels it is connected to. For information on adding channels, see [channels](bot-service-manage-channels.md) topic. - -### Evaluate -Use the data collected in Azure portal to identify opportunities to improve the capabilities and performance of your bot. You can get service-level and instrumentation data like traffic, latency, and integrations. Analytics also provides conversation-level reporting on user, message, and channel data. For more information, see [how to gather analytics](bot-service-manage-analytics.md). - - -## Next steps -Check out these [case studies](https://azure.microsoft.com/services/bot-service/) of bots or click on the link below to create a bot. -> [!div class="nextstepaction"] -> [Create a bot](bot-service-quickstart.md) diff --git a/articles/bot-service-overview-readme.md b/articles/bot-service-overview-readme.md deleted file mode 100644 index f1d45c306..000000000 --- a/articles/bot-service-overview-readme.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: How Bot Service works - Bot Service -description: Learn about the features and capabilities of Bot Service. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# How Bot Service works - -Bot Service provides the core components for creating bots, including the Bot Framework SDK for developing bots and the Bot Framework for connecting bots to channels. Bot Service provides five templates you can choose from when creating your bots with support for .NET and Node.js. - -> [!IMPORTANT] -> You must have a Microsoft Azure subscription before you can use Bot Service. If you do not already have a subscription, you can register for a free account. - -## Hosting plans -Bot Service provides two hosting plans for your bots. You can choose a hosting plan that suits your needs. - -### App Service plan - -A bot that uses an App Service plan is a standard Azure web app you can set to allocate a predefined capacity with predictable costs and scaling. With a bot that uses this hosting plan, you can: - -* Edit bot source code online using an advanced in-browser code editor. -* Download, debug, and re-publish your C# bot using Visual Studio. -* Set up continuous deployment easily for Visual Studio Online and Github. -* Use sample code prepared for the Bot Framework SDK. - -### Consumption plan -A bot that uses a Consumption plan is a serverless bot that runs on Azure Functions, and uses the pay-per-run Azure Functions pricing. A bot that uses this hosting plan can scale to handle huge traffic spikes. You can edit bot source code online using a basic in-browser code editor. For more information about the runtime environment of a Consumption plan bot, see Azure Functions Consumption and App Service plans. - -## Templates - -Bot Service enables you to quickly and easily create a bot in either C# or Node.js by using one of five templates. - -[!INCLUDE [Bot Service templates](~/includes/snippet-abs-templates.md)] - -[Learn more](bot-service-concept-templates.md) about the different templates and how they can help you build bots. - -## Develop and deploy - -By default, Bot Service enables you to develop your bot directly in the browser using the Online Code Editor, without any need for a tool chain. - -You can develop and debug your bot locally with the Bot Framework SDK and an IDE, such as Visual Studio 2017. You can publish your bot directly to Azure using Visual Studio 2017 or the Azure CLI. You can also [set up continuous deployment](bot-service-continuous-deployment.md) with the source control system of your choice, such as VSTS or GitHub. With continuous deployment configured, you can develop and debug in an IDE on your local computer, and any code changes that you commit to source control automatically deploy to Azure. - -> [!TIP] -> After enabling continuous deployment, be sure to modify your code through continuous deployment only and not through other mechanisms to avoid conflict. - -## Manage your bot - -During the process of creating a bot using Bot Service, you specify a name for your bot, set up its hosting plan, choose a pricing tier, and configure some other settings. After your bot has been created, you can change its settings, configure it to run on one or more channels, and test it with in Web Chat. - -## Next steps - -> [!div class="nextstepaction"] -> [Create a bot with Bot Service](bot-service-quickstart.md) \ No newline at end of file diff --git a/articles/bot-service-quickstart-registration.md b/articles/bot-service-quickstart-registration.md deleted file mode 100644 index 6bc4a49f2..000000000 --- a/articles/bot-service-quickstart-registration.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: Create a Bot Channels Registration with Bot Service - Bot Service -description: Learn how to register an existing bot with Bot Service. -ms.author: kamrani -manager: kamrani -ms.topic: conceptual -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Register a bot with Azure Bot Service - -This topic shows you how to create an **Azure Bot Service** resource to register your bot. You need this if the bot is hosted elsewhere and you want to make it available in Azure and connect it to Azure Bot Service channels. - -This allows you to build, connect, and manage your bot to interact with users, wherever they are, via Cortana, Skype, Messenger and many other services. - -> [!IMPORTANT] -> You only need to register your bot if it is not hosted in Azure. If you [created a bot](v4sdk/abs-quickstart.md) through the Azure portal then it is already registered with the service. - -## Create a registration resource - -1. In your browser, navigate to the [Azure portal](https://ms.portal.azure.com). - - > [!TIP] - > If you do not have a subscription, you can register for a free account. - -1. In the left pane, click **Create a resource**. -1. In the right pane selection box enter *bot*. And in the drop-down list, select **Bot Channels Registration** or **Web App Bot** depending on your application. -For the **Web Bot App**, follow the steps described in the article: [Create a bot with Azure Bot Service](v4sdk/abs-quickstart.md). You will create a bot in Azure that is automatically registered with the Azure Bot Service. -1. Click the **Create** button to start the process. -1. In the **Bot Service** blade, provide the requested information about your bot as specified in the table below the image. - - ![Create registration bot blade](media/azure-bot-quickstarts/registration-create-bot-service-blade.png) - - |Setting |Suggested value|Description| - |---|---|--| - |**Bot name** |Your bot's display name|The display name for the bot that appears in channels and directories. This name can be changed at anytime.| - |**Subscription**|Your subscription|Select the Azure subscription you want to use.| - |**Resource Group**|myResourceGroup|You can create a new [resource group](/azure/azure-resource-manager/resource-group-overview#resource-groups) or choose from an existing one.| - |**Location**|West US|Choose a location near where your bot is deployed or near other services your bot will access.| - |**Pricing tier**|F0|Select a pricing tier. You may update the pricing tier at any time. For more information, see [Bot Service pricing](https://azure.microsoft.com/pricing/details/bot-service/).| - |**Messaging endpoint**|URL|Enter the URL for your bot's messaging endpoint.| - |**Application Insights**|On| Decide if you want to turn [Application Insights](bot-service-manage-analytics.md) **On** or **Off**. If you select **On**, you must also specify a regional location. | - |**Microsoft App ID and password**| Auto create App ID and password |Use this option if you need to manually enter a Microsoft App ID and password. See the next section [Manual app registration](#manual-app-registration). Otherwise, a new Microsoft App ID and password will be created in registration process. | - - > [!IMPORTANT] - > Do not forget to enter the URL for your bot's messaging endpoint. - -1. Click the **Create** button. Wait for the resource to be created. It will show in your resources list. - -### Get registration password - -After the registration is completed, Azure Active Directory assigns a unique application ID to your registration, and you're taken to your application's *Overview* page. - -To obtain the password follow the steps described next. - -1. In resource list, click on the Azure App Service resource just created. -1. Im the right pane, in the resource blade, click **Settings**. The resource *Settings* page is displayed. -1. In the Settings page copy the generated **Microsoft App ID** and save it to a file. -1. Click the **Manage** link by *Microsoft App ID*. - - ![Create registration bot blade](media/azure-bot-quickstarts/bot-channels-registration-app-settings.png) - -1. In the *Certificates & secrets* displayed page, click the **New client secret** button. - - ![Create registration bot blade](media/azure-bot-quickstarts/bot-channels-registration-app-secrets.png) - -1. Add the description, select the expiration time, and click the **Add** button. - - ![Create registration bot blade](media/azure-bot-quickstarts/bot-channels-registration-app-secrets-create.png) - - This will generate a new password for your bot. Copy this password and save it to a file. This is the only time you will see this password. If you do not have the full password saved, you will need to repeat the process to create a new password should you need it later. - -## Manual app registration - -A manual registration is necessary for situations like: - -- You are unable to make the registrations in your organization and need another party to create the App ID for the bot you're building. -- You need to manually create your own app ID (and password). - -See [FAQ - App Registration](bot-service-resources-bot-framework-faq.md#app-registration). - -> [!IMPORTANT] -> In the section *Supports account types*, you must choose one of the 2 multi-tenant types that is: *Accounts in any organizational directory (Any Azure AD - Multitenant)* or *Accounts in any organizational directory (Any Azure AD - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox, Outlook.com)*, when creating the app, otherwise the bot will not work. For more information, see [Register a new application using the Azure portal](https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app#register-a-new-application-using-the-azure-portal). - -## Update the bot - -If you're using the Bot Framework SDK for .NET, set the following key values in the web.config file: - -- `MicrosoftAppId = ` -- `MicrosoftAppPassword = ` - -If you're using the Bot Framework SDK for Node.js, set the following environment variables: - -- `MICROSOFT_APP_ID = ` -- `MICROSOFT_APP_PASSWORD = ` - -## Test the bot - -Now that your bot service is created, [test it in Web Chat](bot-service-manage-test-webchat.md). Enter a message and your bot should respond. - -## Next steps - -In this topic, you learned how to register your hosted bot with the Bot Service. The next step is to learn how to manage your Bot Service. - -> [!div class="nextstepaction"] -> [Manage a bot](bot-service-manage-overview.md) diff --git a/articles/bot-service-resources-app-insights-keys.md b/articles/bot-service-resources-app-insights-keys.md deleted file mode 100644 index 745649cbc..000000000 --- a/articles/bot-service-resources-app-insights-keys.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Application Insights keys - Bot Service -description: Learn how to get Application Insights keys to add telemetry to a bot. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/19/2019 - ---- - -# Application Insights keys - -Azure **Application Insights** displays data about your application in a Microsoft Azure resource. To add telemetry to your bot you need an Azure subscription and an Application Insights resource created for your bot. From this resource, you can obtain the three keys to configure your bot: - -1. Instrumentation key -2. Application ID -3. API key - -This topic will show you how to create these Application Insights keys. - -> [!NOTE] -> During the bot creation or registration process, you were given the option to turn **Application Insights** *On* or *Off*. If you had turned it *On* then your bot already has all the necessary Application Insights keys it needs. However, if you had turned it *Off* then you can follow the instructions in this topic to help you manually create these keys. - -## Instrumentation key - -To get the Instrumentation key, do the following: -1. From the [Azure portal](https://portal.azure.com), under the Monitor section, create a new **Application Insights** resource (or use an existing one). -![Portal screen capture of Application Insights listing](~/media/portal-app-insights-add-new.png) - -2. From the list of Application Insights resources, click the Application Insight resource you just created. - -3. Click **Overview**. - -4. Expand the **Essentials** block and find the **Instrumentation Key**. -![Portal screen capture of Overview](~/media/portal-app-insights-instrumentation-key-dropdown.png) -![Portal screen capture of the Instrumentation key](~/media/portal-app-insights-instrumentation-key.png) - -5. Copy the **Instrumentation Key** and paste it to the **Application Insights Instrumentation Key** field of your bot's settings. - -## Application ID - -To get the Application ID, do the following: -1. From your Application Insights resource, click **API Access**. - -2. Copy the **Application ID** and paste it to the **Application Insights Application ID** field of your bot's settings. -![Portal screen capture of the Application ID](~/media/portal-app-insights-appid.png) - -## API key - -To get the API key, do the following: -1. From the Application Insights resource, click **API Access**. - -2. Click **Create API Key**. - -3. Enter a short description, check the **Read telementry** option, and click the **Generate key** button. -![Portal screen capture of the Application ID and API Key](~/media/portal-app-insights-appid-apikey.png) - - > [!WARNING] - > Copy this **API key** and save it because this key will never be shown to you again. If you lose this key, you have to create a new one. - -4. Copy the API key to the **Application Insights API key** field of your bot's settings. - -## Additional resources -For more information on how to connect these fields into your bot's settings, see [Enable analytics](~/bot-service-manage-analytics.md#enable-analytics). diff --git a/articles/bot-service-resources-bot-framework-faq.md b/articles/bot-service-resources-bot-framework-faq.md deleted file mode 100644 index 06a2130a5..000000000 --- a/articles/bot-service-resources-bot-framework-faq.md +++ /dev/null @@ -1,281 +0,0 @@ ---- -title: Bot Service Frequently Asked Questions - Bot Service -description: A list of Frequently Asked Questions about elements of the Bot Framework and when new features will become available. -author: scheyal -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 02/19/2020 ---- - -# Bot Framework Frequently Asked Questions - -This article contains answers to some frequently asked questions about the Bot Framework. - -## Background and availability - -### Why did Microsoft develop the Bot Framework? - -While the Conversation User Interface (CUI) is upon us, at this point few developers have the expertise and tools needed to create new conversational experiences or enable existing applications and services with a conversational interface their users can enjoy. We have created the Bot Framework to make it easier for developers to build and connect great bots to users, wherever they converse, including on Microsoft's premier channels. - -### What is the v4 SDK? -Bot Framework v4 SDK builds on the feedback and learnings from the prior Bot Framework SDKs. It introduces the right levels of abstraction while enabling rich componentization of the bot building blocks. You can start with a simple bot and grow your bot in sophistication using a modular and extensible framework. You can find [FAQ](https://github.com/Microsoft/botbuilder-dotnet/wiki/FAQ) for the SDK on GitHub. - -### Running a bot offline - - -Before talking about the use of a bot offline, meaning a bot not deployed on Azure or on some other host services but on premises, let's clarify a few points. - -- A bot is a web service that does not have a UI, so the user must interact with it via other means, in the form of channels, which use the [Azure Connector Service](rest-api/bot-framework-rest-connector-concepts.md#bot-connector-service). The connector functions as a *proxy* to relay messages between a client and the bot. -- The **connector** is a global application hosted on Azure nodes and spread geographically for availability and scalability. -- You use the [Bot Channel Registration](bot-service-quickstart-registration.md) to register the bot with the connector. - >[!NOTE] - > The bot must have its endpoint publicly reachable by the connector. - -You can run a bot offline with limited capabilities. For example, if you want to use a bot offline that has LUIS capability, you must build a container for the bot, and required tools, and a container for LUIS. Both connected via Docker Compose bridged network. - -This is a "partial" offline solution because a Cognitive Services container needs periodic online connection. - -> [!NOTE] -> The QnA service is not supported in a bot running offline. - -For more information, see: - -- [Deploy the Language Understanding (LUIS) container to Azure Container Instances](https://docs.microsoft.com/azure/cognitive-services/luis/deploy-luis-on-container-instances) -- [Container support in Azure Cognitive Services](https://docs.microsoft.com/azure/cognitive-services/cognitive-services-container-support) - -## Bot Framework SDK Version 3 Lifetime Support and Deprecation Notice -Microsoft Bot Framework SDK V4 was released in September 2018, and since then we have shipped a few dot-release improvements. As announced previously, the V3 SDK is being retired. Accordingly, there will be no more development in V3 repositories. **Existing V3 bot workloads will continue to run without interruption. We have no plans to disrupt any running workloads**. - -As mentioned, Bot Builder SDK V3 bots continue to run and be supported by Azure Bot Service. Bot Builder SDK V3 will only be supported for critical security bug fixes, connector, and protocol layer compatibility updates. - -All new features and capabilities are developed exclusively on [Bot Framework SDK V4](https://github.com/microsoft/botframework-sdk). Customers are encouraged to migrate their bots to V4 as soon as possible. - -We highly recommend that you start migrating your V3 bots to V4. In order to support this migration we have produced migration documentation and will provide extended support for migration initiatives (via standard channels such as Stack Overflow and Microsoft Customer Support). - - -For more information please refer to the following references: -* [Essential Migration Guidance](https://aka.ms/bf-migration-overview) -* Primary V4 Repositories to develop Bot Framework bots - * [Botbuilder for dotnet](https://github.com/microsoft/botbuilder-dotnet) - * [Botbuilder for JS](https://github.com/microsoft/botbuilder-js) -* QnA Maker Libraries were replaced with the following V4 libraries: - * [Libraries for dotnet](https://github.com/Microsoft/botbuilder-dotnet/tree/master/libraries/Microsoft.Bot.Builder.AI.QnA) - * [Libraries for JS](https://github.com/Microsoft/botbuilder-js/blob/master/libraries/botbuilder-ai/src/qnaMaker.ts) -* Azure Libraries were replaced with the following V4 libraries: - * [Botbuilder for JS Azure](https://github.com/Microsoft/botbuilder-js/tree/master/libraries/botbuilder-azure) - * [Botbuilder for dotnet Azure](https://github.com/Microsoft/botbuilder-dotnet/tree/master/libraries/Microsoft.Bot.Builder.Azure) - -### V3 Status Summary - -#### ABS Service -1. The ABS service side will continue to support running V3 bots with no planned end of life and any running bots will not be disrupted. -2. Channels will remain compatible with V3 with no disruption or end of life plan. -3. Creation of new V3 bots is disabled on the portal; however, expert users who wish to deploy their V3 bots independently, not on ABS (e.g. as webapp service) can do so. - -#### SDK and Tools -1. We are not investing in V3 from SDK side, and will only apply critical security fixes to the SDK branches for the foreseeable future (Exception: We plan to add a Skills connector to allow V4 bots to call legacy V3 bots). -2. SDKs and tools development is exclusively on V4 with no V3 work done or planned (hence we’re already “there”). -3. We do not prevent anyone from running old tools to manage their V3 bots. - - -## How can I migrate Azure Bot Service from one region to another? - -Azure Bot Service does not support region move. It’s a global service that is not tied to any specific region. - -## Channels -### When will you add more conversation experiences to the Bot Framework? - -We plan on making continuous improvements to the Bot Framework, including additional channels, but cannot provide a schedule at this time. -If you would like a specific channel added to the framework, [let us know][Support]. - -### I have a communication channel I’d like to be configurable with Bot Framework. Can I work with Microsoft to do that? - -We have not provided a general mechanism for developers to add new channels to Bot Framework, but you can connect your bot to your app via the [Direct Line API][DirectLineAPI]. If you are a developer of a communication channel and would like to work with us to enable your channel in the Bot Framework [we’d love to hear from you][Support]. - -### If I want to create a bot for Microsoft Teams, what tools and services should I use? - -The Bot Framework is designed to build, connect, and deploy high quality, responsive, performant and scalable bots for Teams and many other channels. The SDK can be used to create text/sms, image, button and card-capable bots (which constitute the majority of bot interactions today across conversation experiences) as well as bot interactions which are Teams-specific such as rich audio and video experiences. - -If you already have a great bot and would like to reach the Teams audience, your bot can easily be connected to Teams (or any supported channel) via the Bot Framework for REST API (provided it has an internet-accessible REST endpoint). - -### How do I create a bot that uses the US Government data center? - -There are 2 major steps required to create a bot that uses a US Government data center. -1. Add a “channel provider” setting in your appsettings.json (or the App Service Settings). This needs to be specifically set to this name/value constant: ChannelService = "https://botframework.azure.us". An example using appsetting.json is shown below. - -```json -{ - "MicrosoftAppId": "", - "MicrosoftAppPassword": "", - "ChannelService": "https://botframework.azure.us" -} -``` -2. If you are using .NET core, you will need to add a ConfigurationChannelProvider in your startup.cs file. How you do this varies based on which version of the SDK you are using. - -- For versions 4.3 and above, in your ConfigureServices method, you need to create a ConfigurationChannelProvider instance. When using the BotFrameworkHttpAdapter class, you inject this as singleton into the service collection like this: - -```csharp -services.AddSingleton(); -``` -- For versions prior to 4.3, in your ConfigureServices method, find the AddBot method. When setting the options, make sure you add: - -```csharp -options.ChannelProvider = new ConfigurationChannelProvider(); -``` -You can find more information concerning Govenment Services [here](https://docs.microsoft.com/azure/azure-government/documentation-government-services-aiandcognitiveservices#azure-bot-service) - -## Security and Privacy -### Do the bots registered with the Bot Framework collect personal information? If yes, how can I be sure the data is safe and secure? What about privacy? - -Each bot is its own service, and developers of these services are required to provide Terms of Service and Privacy Statements per their Developer Code of Conduct. You can access this information from the bot’s card in the Bot Directory. - -to provide the I/O service, the Bot Framework transmits your message and message content (including your ID), from the chat service you used to the bot. - -### Can I host my bot on my own servers? -Yes. Your bot can be hosted anywhere on the Internet. On your own servers, in Azure, or in any other datacenter. The only requirement is that the bot must expose a publicly-accessible HTTPS endpoint. - -### How do you ban or remove bots from the service? - -Users have a way to report a misbehaving bot via the bot’s contact card in the directory. Developers must abide by Microsoft terms of service to participate in the service. - -### Which specific URLs do I need to whitelist in my corporate firewall to access Bot Framework services? -If you have an outbound firewall blocking traffic from your bot to the Internet, you'll need to whitelist the following URLs in that firewall: -- login.botframework.com (Bot authentication) -- login.microsoftonline.com (Bot authentication) -- westus.api.cognitive.microsoft.com (for Luis.ai NLP integration) -- state.botframework.com (Bot state storage for prototyping) -- cortanabfchanneleastus.azurewebsites.net (Cortana channel) -- cortanabfchannelwestus.azurewebsites.net (Cortana Channel) -- *.botframework.com (channels) - -> [!NOTE] -> You may use `.botframework.com` if you’d prefer not to whitelist a URL with an asterisk. `` is equal to every channel your bot uses such as `directline.botframework.com`, `webchat.botframework.com`, and `slack.botframework.com`. It is also worthwhile to watch traffic over your firewall while testing the bot to make sure nothing else is getting blocked. - -### Can I block all traffic to my bot except traffic from the Bot Connector Service? -No. This sort of IP Address or DNS whitelisting is impractical. The Bot Framework Connector Service is hosted in Azure datacenters world-wide and the list of Azure IPs is constantly changing. Whitelisting certain IP addresses may work one day and break the next as the Azure IP Addresses change. - -### What keeps my bot secure from clients impersonating the Bot Framework Connector Service? -1. The security token accompanying every request to your bot has the ServiceUrl encoded within it, which means that even if an attacker gains access to the token, they cannot redirect the conversation to a new ServiceUrl. This is enforced by all implementations of the SDK and documented in our authentication [reference](https://docs.microsoft.com/azure/bot-service/rest-api/bot-framework-rest-connector-authentication?view=azure-bot-service-3.0#bot-to-connector) materials. - -2. If the incoming token is missing or malformed, the Bot Framework SDK will not generate a token in response. This limits how much damage can be done if the bot is incorrectly configured. -3. Inside the bot, you can manually check the ServiceUrl provided in the token. This makes the bot more fragile in the event of service topology changes so this is possible but not recommended. - - -Note that these are outbound connections from the bot to the Internet. There is not a list of IP Addresses or DNS names that the Bot Framework Connector Service will use to talk to the bot. Inbound IP Address whitelisting is not supported. - -## Rate limiting -### What is rate limiting? -The Bot Framework service must protect itself and its customers against abusive call patterns (e.g., denial of service attack), so that no single bot can adversely affect the performance of other bots. To achieve this kind of protection, we’ve added rate limits (also known as throttling) to all endpoints. By enforcing a rate limit, we can restrict the frequency with which a bot can make a specific call. For example: with rate limiting enabled, if a bot wanted to post a large number of activities, it would have to space them out over a time period. Please note that the purpose of rate-limiting is not to cap the total volume for a bot. It is designed to prevent abuse of the conversational infrastructure that does not follow human conversation patterns. - -### How will I know if I’m impacted? -It is unlikely you’ll experience rate limiting, even at high volume. Most rate limiting would only occur due to bulk sending of activities (from a bot or from a client), extreme load testing, or a bug. When a request is throttled, an HTTP 429 (Too Many Requests) response is returned along with a Retry-After header indicating the amount of time (in seconds) to wait before retrying the request would succeed. You can collect this information by enabling analytics for your bot via Azure Application Insights. Or, you can add code in your bot to log messages. - -### How does rate limiting occur? -It can happen if: -- a bot sends messages too frequently -- a client of a bot sends messages too frequently -- Direct Line clients request a new Web Socket too frequently - -### What are the rate limits? -We’re continuously tuning the rate limits to make them as lenient as possible while at the same time protecting our service and our users. Because thresholds will occasionally change, we aren’t publishing the numbers at this time. If you are impacted by rate limiting, feel free to reach out to us at [bf-reports@microsoft.com](mailto://bf-reports@microsoft.com). - -## Related Services -### How does the Bot Framework relate to Cognitive Services? - -Both the Bot Framework and [Cognitive Services](https://www.microsoft.com/cognitive) are new capabilities introduced at [Microsoft Build 2016](https://build.microsoft.com) that will also be integrated into Cortana Intelligence Suite at GA. Both these services are built from years of research and use in popular Microsoft products. These capabilities combined with ‘Cortana Intelligence’ enable every organization to take advantage of the power of data, the cloud and intelligence to build their own intelligent systems that unlock new opportunities, increase their speed of business and lead the industries in which they serve their customers. - -### What is Cortana Intelligence? - -Cortana Intelligence is a fully managed Big Data, Advanced Analytics and Intelligence suite that transforms your data into intelligent action. -It is a comprehensive suite that brings together technologies founded upon years of research and innovation throughout Microsoft (spanning advanced analytics, machine learning, big data storage and processing in the cloud) and: - -* Allows you to collect, manage and store all your data that can seamlessly and cost effectively grow over time in a scalable and secure way. -* Provides easy and actionable analytics powered by the cloud that allow you to predict, prescribe and automate decision making for the most demanding problems. -* Enables intelligent systems through cognitive services and agents that allow you to see, hear, interpret and understand the world around you in more contextual and natural ways. - -With Cortana Intelligence, we hope to help our enterprise customers unlock new opportunities, increase their speed of business and be leaders in their industries. - -### What is the Direct Line channel? - -Direct Line is a REST API that allows you to add your bot into your service, mobile app, or webpage. - -You can write a client for the Direct Line API in any language. Simply code to the [Direct Line protocol][DirectLineAPI], generate a secret in the Direct Line configuration page, and talk to your bot from wherever your code lives. - -Direct Line is suitable for: - -* Mobile apps on iOS, Android, and Windows Phone, and others -* Desktop applications on Windows, OSX, and more -* Webpages where you need more customization than the [embeddable Web Chat channel][WebChat] offers -* Service-to-service applications - - -## App Registration - -### I need to manually create my App Registration. How do I create my own App Registration? - -Creating your own App Registration will be necessary for situations like the following: - -- You created your bot in the Bot Framework portal (such as https://dev.botframework.com/bots/new) -- You are unable to make app registrations in your organization and need another party to create the App ID for the bot you're building -- You otherwise need to manually create your own App ID (and password) - -To create your own App ID, follow the steps below. - -1. Sign into your [Azure account](https://portal.azure.com). If you don't have an Azure account, you can [sign up for a free account](https://azure.microsoft.com/free/). -2. Go to [the app registrations blade](https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade) and click **New registration** in the action bar at the top. - - ![new registration](media/app-registration/new-registration.png) - -3. Enter a display name for the application registration in the *Name* field and select the supported account types. The name does not have to match the bot ID. - - > [!IMPORTANT] - > In the *Supported account types*, select the *Accounts in any organizational directory and personal Microsoft accounts (e.g. Skype, Xbox, Outlook.com)* radio button. If any of the other options are selected, **the bot will be unusable**. - - ![registration details](media/app-registration/registration-details.png) - -4. Click **Register** - - After a few moments, the newly created app registration should open a blade. Copy the *Application (client) ID* in the Overview blade and paste it in to the App ID field. - - ![application id](media/app-registration/app-id.png) - -If you’re creating your bot through the Bot Framework portal, then you’re done setting up your app registration; the secret will be generated automatically. - -If you’re making your bot in the Azure portal, you need to generate a secret for your app registration. - -1. Click on **Certificates & secrets** in the left navigation column of your app registration’s blade. -2. In that blade, click the **New client secret** button. In the dialog that pops up, enter an optional description for the secret and select **Never** from the Expires radio button group. - - ![new secret](media/app-registration/new-secret.png) - -3. Copy your secret’s value from the table under *Client secrets* and paste it into the *Password* field for your application, and click **OK** at the bottom of that blade. Then, proceed with the bot creation. - - > [!NOTE] - > The secret will only be visible while on this blade, and you won't be able to retreive it after you leave that page. Be sure to copy it somewhere safe. - - ![new app id](media/app-registration/create-app-id.png) - - -[DirectLineAPI]: https://docs.microsoft.com/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-concepts -[Support]: bot-service-resources-links-help.md -[WebChat]: bot-service-channel-connect-webchat.md - -## Resources -### Which RBAC role is required to create and deploy a bot? - -Creating a bot in the Azure portal requires Contributor access either in the subscription or in a specific resource group. A user with the *Contributor* role in a resource group can create a new bot in that specific resource group. A user in the *Contributor* role for a subscription can create a bot in a new or existing resource group. - -Using the Azure CLI, a role-based access control approach can support custom roles. If you want to make a custom role with more constrained permissions, the following set will allow the user to create and deploy a bot that also supports LUIS, QnA Maker, and Application Insights. - - "Microsoft.Web/*", - "Microsoft.BotService/*", - "Microsoft.Storage/*", - "Microsoft.Resources/deployments/*", - "Microsoft.CognitiveServices/*", - "Microsoft.Search/searchServices/*", - "Microsoft.Insights/*", - "Microsoft.Insights/components/*" - -LUIS and QnA Maker require Cognitive Services permissions. QnA Maker also requires Search permissions. When creating a custom role, remember that any inherited *deny* permissions will supercede these *allow* permissions. diff --git a/articles/bot-service-resources-identifiers-guide.md b/articles/bot-service-resources-identifiers-guide.md deleted file mode 100644 index e95052a53..000000000 --- a/articles/bot-service-resources-identifiers-guide.md +++ /dev/null @@ -1,164 +0,0 @@ ---- -title: Guide to IDs in the Bot Framework - Bot Service -description: This guide describes the characteristics of ID fields present in the Bot Framework v3 protocol. -keywords: id, bots, protocol -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 04/30/2019 - ---- - -# ID fields in the Bot Framework - -This guide describes the characteristics of ID fields in the Bot Framework. - -## Channel ID - -Every Bot Framework channel is identified by a unique ID. - -Example: `"channelId": "skype"` - -Channel IDs serve as namespaces for other IDs. Runtime calls in the Bot Framework protocol must take place -within the context of a channel; the channel gives meaning to the conversation and account IDs used when -communicating. - -By convention all channel IDs are lowercase. Channels guarantee that the channel IDs they emit have consistent -casing, and thus bots may use ordinal comparisons to establish equivalence. - -### Rules for channel IDs - -- Channel IDs are case-sensitive. - -## Bot Handle - -Every bot that has been registered with the Azure Bot Service has a bot handle. - -Example: `FooBot` - -A bot handle represents a bot's registration with the online Azure Bot Service. This registration is associated -with an HTTP webhook endpoint and registrations with channels. - -The Azure Bot Service ensures uniqueness of bot handles. The Azure portal performs a case-insensitive -uniqueness check (meaning that case variations of bot handle are treated as a single handle) although this is -a characteristic of the Azure portal, and not necessarily the bot handle itself. - -### Rules for bot handles - -* Bot handles are unique (case-insensitive) within the Bot Framework. - -## App ID - -Every bot that has been registered with the Azure Bot Service has an App ID. - -> [!NOTE] -> Previously, apps were commonly referred to as "MSA Apps" or "MSA/AAD Apps." Apps are now more commonly referred to simply as "apps", but some protocol elements may refer to apps as "MSA Apps" in perpetuity. - -Example: `"msaAppId": "353826a6-4557-45f8-8d88-6aa0526b8f77"` - -An app represents a registration with the Identity team's App portal, and serves as the service-to-service -identity mechanism within the Bot Framework runtime protocol. Apps may have other non-bot associations, such -as websites and mobile/desktop applications. - -Every registered bot has exactly one app. Although it's not possible for a bot owner to independently change which -app is associated with their bot, the Bot Framework team can do so in a small number of exceptional cases. - -Bots and channels may use app IDs to uniquely identify a registered bot. - -App IDs are guaranteed to be GUIDs. App IDs should be compared without case sensitivity. - -### Rules for app IDs - -* App IDs are unique (GUID comparison) within the Microsoft App platform. -* Every bot has exactly one corresponding app. -* Changing which app a bot is associated with requires the assistance of the Bot Framework team. - -## Channel Account - -Every bot and user has an account within each channel. The account contains an identifier (`id`) and other -informative bot non-structural data, like an optional name. - -Example: `"from": { "id": "john.doe@contoso.com", "name": "John Doe" }` - -This account describes the address within the channel where messages may be sent and received. In some -cases, these registrations exist within a single service (e.g., Skype, Facebook). In others, they are registered -across many systems (email addresses, phone numbers). In more anonymous channels (e.g., Web Chat), the registration -may be ephemeral. - -Channel accounts are nested within channels. A Facebook account, for example, is simply a number. This -number may have a different meaning in other channels, and it doesn't have meaning outside all channels. - -The relationship between channel accounts and users (actual people) depends on conventions associated with -each channel. For example, an SMS number typically refers to one person for a period of time, after which -the number may be transferred to someone else. Conversely, a Facebook account typically refers to one person -in perpetuity, although it is not uncommon for two people to share a Facebook account. - -In most channels, it's appropriate to think of a channel account as a kind of mailbox where messages can be -delivered. It's typical for most channels to allow multiple address to map to a single mailbox; for example, -"jdoe@contoso.com" and "john.doe@service.contoso.com" may resolve to the same inbox. Some channels go -a step further and alter the account's address based on which bot is accessing it; for example, both Skype -and Facebook alter user IDs so every bot has a different address for sending and receiving messages. - -While it's possible in some cases to establish equivalency between addresses, establishing equivalency -between mailboxes and equivalency between people requires knowledge of the conventions within the channel, -and is in many cases not possible. - -A bot is informed of its channel account address via the `recipient` field on activities sent to the bot. - -### Rules for channel accounts - -* Channel accounts have meaning only within their associated channel. -* More than one ID may resolve to the same account. -* Ordinal comparison may be used to establish that two IDs are the same. -* There is generally no comparison that can be used to identify whether two different IDs resolve - to the same account, bot or person. -* The stability of associations between IDs, accounts, mailboxes, and people depends on the channel. - -## Conversation ID - -Messages are sent and received in the context of a conversation, which is identifiable by ID. - -Example: `"conversation": { "id": "1234" }` - -A conversation contains an exchange of messages and other activities. Every conversation has zero or more -activities, and every activity appears in exactly one conversation. Conversations may be perpetual, or may -have distinct starts and ends. The process of creating, modifying, or ending a conversation occurs within -the channel (i.e., a conversation exists when the channel is aware of it) and the characteristics of these -processes are established by the channel. - -The activities within a conversation are sent by users and bots. The definition for which users "participate" -in a conversation varies by channel, and can theoretically include present users, users who have ever -received a message, users who sent a message. - -Several channels (e.g., SMS, Skype, and possibly others) have the quirk that the conversation ID assigned to a 1:1 -conversation is the remote channel account ID. This quirk has two side-effects: -1. The conversation ID is subjective based on who is viewing it. If Participants A and B are talking, - participant A sees the conversation ID to be "B" and participant B sees the conversation ID to be "A." -2. If the bot has multiple channel accounts within this channel (for example, if the bot has two SMS numbers), - the conversation ID is not sufficient to uniquely identify the conversation within the bot's field of view. - -Thus, a conversation ID does not necessarily uniquely identify a single conversation within a channel even -for a single bot. - -### Rules for conversation IDs - -* Conversations have meaning only within their associated channel. -* More than one ID may resolve to the same conversation. -* Ordinal equality does not necessarily establish that two conversation IDs are the same conversation, although - in most cases, it does. - -## Activity ID - -Activities are sent and received within the Bot Framework protocol, and these are sometimes identifiable. - -Example: `"id": "5678"` - -Activity IDs are optional and employed by channels to give the bot a way to reference the ID in subsequent -API calls, if they are available: -* Replying to a particular activity -* Querying for the list of participants at the activity level - -Because no further use cases have been established, there are no additional rules for the treatment of activity -IDs. diff --git a/articles/bot-service-resources-links-help.md b/articles/bot-service-resources-links-help.md deleted file mode 100644 index d777828cc..000000000 --- a/articles/bot-service-resources-links-help.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: Additional support resources for the Bot Framework - Bot Service -description: Learn about additional support resources for the Bot Framework. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Bot Framework additional resources - -These resources provide additional information and support for developing bots with the Bot Framework. - -> [!IMPORTANT] -> Please use one of these resources for support rather than posting comments on this article. This article is not monitored -> for support requests. - -| Support type | Contact | -|-----------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Community support | Questions can be posted at [Stack Overflow](https://stackoverflow.com/questions/tagged/botframework) using the `botframework` tag. Please note that Stack Overflow has guidelines such as requiring a descriptive title, a complete and concise problem statement, and sufficient details to reproduce your issue. Feature requests or overly broad questions are off-topic; new users should visit the [Stack Overflow Help Center](https://stackoverflow.com/help/how-to-ask) for more details. | -| Community chat group | [Gitter.IM](https://gitter.im/Microsoft/BotBuilder) | -| Using a bot | Contact the bot's developer through their publisher e-mail | -| Bot Framework SDK issues/suggestions | Use the issues tab on the GitHub repo | -| Azure help and support | Azure Help + Support | -| Documentation issues | Submit an issue to the Bot Framework documentation GitHub repo. | -| Documentation updates | Click the Edit link on an article and submit a pull request to the Bot Framework documentation GitHub repo. | -| Reporting abuse | Contact us at [bf-reports@microsoft.com](mailto://bf-reports@microsoft.com) | - diff --git a/articles/bot-service-resources-upgrade-to-v3.md b/articles/bot-service-resources-upgrade-to-v3.md deleted file mode 100644 index c45d7fb69..000000000 --- a/articles/bot-service-resources-upgrade-to-v3.md +++ /dev/null @@ -1,179 +0,0 @@ ---- -title: Upgrade your bot to Bot Framework API v3 - Bot Service -description: Learn how to upgrade your bot to Bot Framework API v3. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Upgrade your bot to Bot Framework API v3 - -At Build 2016 Microsoft announced the Microsoft Bot Framework and its initial iteration of the Bot Connector API, along with Bot Builder and Bot Connector SDKs. Since then, we've been collecting your feedback and actively working to improve the REST API and SDKs. - -In July 2016, Bot Framework API v3 was released and Bot Framework API v1 was deprecated. Bots that use API v1 ceased to function on Skype in December 2016 and on all remaining channels on February 23, 2017. If you created a bot using API v1 and want to make it functional again, you must upgrade it to API v3 by following the instructions in this article. To ensure that you understand the upgrade process from end-to-end, read through this article completely before you begin. - -## Step 1: Get your App ID and password from the Bot Framework Portal - -Sign in to the [Bot Framework Portal](https://dev.botframework.com/), click **My bots**, then select your bot to open its dashboard. Next, click the **SETTINGS** link that is located left side of the page under **Bot Management**. - -Within the **Configuration** section of the settings page, examine the contents of the **Microsoft App ID** field and proceed with next steps. - - - -1. Click **Manage Microsoft App ID and password**. -![Configuration](./media/upgrade/manage-app-id.png) - -2. Click **Generate New Password**. -![Generate new password](./media/upgrade/generate-new-password.png) - -3. Copy and save the new password along with the MSA App ID; you will need these values in the future. -![New password](./media/upgrade/new-password-generated.png) - -Another method of retrieving your **Microsoft App ID and Password** can be done following these [instructions](https://blog.botframework.com/2018/07/03/find-your-azure-bots-appid-and-appsecret/). - - - -## Step 2: Update your bot code to version 4.0 - -V1 bots are no longer compatible. To update your bot you will need to create a new bot under V3 instead. If you want to preserve any of your old code you will have to migrate your code manually. - -The easiest solution is to recreate your bot with the new [SDK](https://docs.microsoft.com/azure/bot-service/?view=azure-bot-service-4.0) and deploy it. - -If you wish to preserve your old code, follow the steps below: - -1. Create a new Bot application. -2. Copy over your old code to your new Bot application. -3. Upgrade the SDK to the latest version via the Nuget package manager. -4. Fix any errors that appear, reference the new [SDK](https://docs.microsoft.com/azure/bot-service/?view=azure-bot-service-4.0). -5. Deploy your bot to Azure by following these [instructions](https://docs.microsoft.com/azure/bot-service/bot-builder-howto-deploy-azure?view=azure-bot-service-4.0) - - - -### BotBuilder and Connector are now one SDK - -Instead of having to install separate SDKs for the Builder and Connector by using multiple NuGet packages (or NPM modules), you can now get both libraries in a single Bot Framework SDK: - -- Bot Framework SDK for .NET: `Microsoft.Bot.Builder` NuGet package -- Bot Framework SDK for Node.js: `botbuilder` NPM module - -The standalone `Microsoft.Bot.Connector` SDK is now obsolete and is no longer being maintained. - -### Message is now Activity - -The `Message` object has been replaced with the `Activity` object in API v3. The most common type of activity is **message**, but there are other activity types that can be used to communicate various types of information to a bot or channel. For more information about messages, see [Create messages](~/dotnet/bot-builder-dotnet-create-messages.md) and [Send and receive activities](~/dotnet/bot-builder-dotnet-connector.md). - -### Activity types & events - -Some events have been renamed and/or refactored in API v3. In addition, a new `ActivityTypes` enumeration has been added to the Connector to eliminate the need to remember specific activity types. - -- The `conversationUpdate` Activity type replaces Bot/User Added/Removed To/From Conversation with a single method. -- The new `typing` Activity type enables your bot to indicate that it is compiling a response and to know when the user is typing a response. -- The new `contactRelationUpdate` Activity type enables your bot to know if it has been added to or removed from user's contact list. - -When your bot receives a `conversationUpdate` activity, the `MembersRemoved` property and `MembersAdded` property will indicate who was added to or removed from the conversation. When your bot receives a `contactRelationUpdate` activity, the `Action` property will indicate whether the user added the bot to or removed the bot from their contact list. For more information about activity types, see [Activities overview](~/dotnet/bot-builder-dotnet-activities.md). - -### Addressing messages - -Where the sender, recipient, and channel information is specified within a message has changed slightly in API v3: - -|API v1 field | API v3 field| -|--------|--------| -| `From` object | `From` object | -| `To` object | `Recipient` object | -| `ChannelConversationID` property | `Conversation` object| -| `ChannelId` property | `ChannelId` property | - -For more information about addressing messages, see [Send and receive activities](~/dotnet/bot-builder-dotnet-connector.md). - -### Sending replies - -In Bot Framework API v3, all replies to the user will be sent asynchronously over a separately initiated HTTP request rather than inline with the HTTP POST for the incoming message to the bot. Since no message will be returned inline to the user through the Connector, the return type of your bot's post method will be `HttpResponseMessage`. This means that your bot does not synchronously "return" the string that you wish to send to the user, but instead sends a reply message at any point in your code instead of having to reply back as a response to the incoming POST. These two methods will both send a message to a conversation: - -- `SendToConversation` -- `ReplyToConversation` - -The `SendToConversation` method will append the specified message to the end of the conversation, while the `ReplyToConversation` method will (for conversations that support it) add the specified message as a direct reply to a prior message in the conversation. For more information about these methods, see [Send and receive activities](~/dotnet/bot-builder-dotnet-connector.md). - -### Starting conversations - -In Bot Framework API v3, you can start a conversation by either using the new method `CreateDirectConversation` to start a private conversation with a single user or by using the new method `CreateConversation` to start a group conversation with multiple users. For more information about starting conversations, see [Send and receive activities](~/dotnet/bot-builder-dotnet-connector.md#start-a-conversation). - -### Attachments and options - -Bot Framework API v3 introduces a more robust implementation of attachments and cards. The `Options` type is no longer supported in API v3 and has instead been replaced by cards. For more information about adding attachments to messages using .NET, see [Add media attachments to messages](~/dotnet/bot-builder-dotnet-add-media-attachments.md) and [Add rich card attachments to messages](~/dotnet/bot-builder-dotnet-add-rich-card-attachments.md). - -### Bot data storage (bot state) - -In Bot Framework API v1, the API for managing bot state data was folded into the messaging API. In Bot Framework API v3, these APIs are separate. Now, you must use the Bot State service to get state data (instead of assuming that it will be included within the `Message` object) and to store state data (instead of passing it as part of the `Message` object). For information about managing bot state data using the Bot State service, [Manage state data](~/dotnet/bot-builder-dotnet-state.md). - -> [!IMPORTANT] -> The Bot Framework State Service API is not recommended for production environments, and may be deprecated in a future release. It is recommended that you update your bot code to use the in-memory storage for testing purposes or use one of the **Azure Extensions** for production bots. For more information, see the **Manage state data** topic for [.NET](~/dotnet/bot-builder-dotnet-state.md) or [Node](~/nodejs/bot-builder-nodejs-state.md) implementation. - -### Web.config changes - -Bot Framework API v1 stored the authentication properties with these keys in **Web.Config**: - -- `AppID` -- `AppSecret` - -Bot Framework API v3 stores the authentication properties with these keys in **Web.Config**: - -- `MicrosoftAppID` -- `MicrosoftAppPassword` - -## Step 3: Deploy your Update Bot to Azure. - -After you have upgraded your bot code to API v3 simply deploy the bot to Azure following these [instructions](https://docs.microsoft.com/azure/bot-service/bot-builder-howto-deploy-azure?view=azure-bot-service-4.0). Since V1 is no longer supported, all bots will automatically use the V3 API when deployed to the Azure services. - - \ No newline at end of file diff --git a/articles/bot-service-resources-user-agent.md b/articles/bot-service-resources-user-agent.md deleted file mode 100644 index 61deb675f..000000000 --- a/articles/bot-service-resources-user-agent.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: Bot Framework User-Agent requests - Bot Service -description: Understanding requests from bot framework to your web server. -author: JohnD-ms -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- -# Bot Framework User-Agent requests - -If you’re reading this message, you’ve probably received a request from a Microsoft Bot Framework service. This guide will help you understand the nature of these requests and provide steps to stop them, if so desired. - -If you received a request from our service, it likely had a User-Agent header formatted similar to the string below: - -```User-Agent: BF-DirectLine/3.0 (Microsoft-BotFramework/3.0 +https://botframework.com/ua)``` - -The most important part of this string is the **Microsoft-BotFramework** identifier, which is used by the Microsoft Bot Framework, a collection of tools and services that allows independent software developers to create and operate their own bots. - -If you’re a bot developer, you may already know why these requests are being directed to your service. If not, continue reading to learn more. - -## Why is Microsoft contacting my service? - -The Bot Framework connects users on chat services like Skype and Facebook Messenger to bots, which are web servers with REST APIs running on internet-accessible endpoints. The HTTP calls to bots (also called webhook calls) are sent only to URLs specified by a bot developer who registered with the Bot Framework developer portal. - -If you’re receiving unsolicited requests from Bot Framework services to your web service, it is likely because a developer has either accidentally or knowingly entered your URL as the webhook callback for their bot. - -## To stop these requests - -For assistance in stopping undesired requests from reaching your web service, please contact [bf-reports@microsoft.com](mailto://bf-reports@microsoft.com). diff --git a/articles/bot-service-review-guidelines.md b/articles/bot-service-review-guidelines.md deleted file mode 100644 index f0806f993..000000000 --- a/articles/bot-service-review-guidelines.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -ms.topic: conceptual -ms.author: kamrani -ms.service: bot-service -title: Bot review guidelines ---- - -# Bot review guidelines - -We welcome you and thank you for investing your talents and time in building bot, botlets, web apps, add-ins, or skills (“app integrations”) for Microsoft channels. The following are the minimum requirements your app integration must meet before it may be published to a Microsoft channel such as Skype or Microsoft Teams. Each channel may have specific requirements in addition to the requirements detailed below. If applicable, you’ll find channel- specific terms on each channel’s configuration page, and you may be required to sign-up for a channel’s service before you can publish a bot to that channel. - -## App Integration Policies -### 1. Value, Representation, Security and Usability. - -Your app integration and its associated metadata must: - -- have distinct and informative metadata and must provide a valuable and quality user experience; -- accurately and clearly reflect the source, functionality, and features of your app integration and describe any important limitations; -- not use a name or icon similar to that of other apps, and may not claim to be from a company, government body, or other entity if you do not have permission to make that representation; -- not jeopardize or compromise user security, or the security or functionality of the Microsoft channel; -- not attempt to change or extend the described functionality in violation of these policies or the applicable Microsoft channel terms; -- not include or enable malware; -- be testable; -- continue to run and remain responsive to user input; -- include a working link to your Terms of Service; -- operate as described in its description, profile, terms of use and privacy policy; -- operate in accordance with the terms applicable to the Microsoft Bot Framework (or other terms applicable to its development) and the Microsoft Channel Terms (or other applicable terms for the channel upon which your app integration is published); -- inform users if your app integration includes human interaction (e.g. customer service or support with a live person); -- be localized for all languages that it supports. The text of your app integration’s description must be localized in each language that you declare. - -### 2. Privacy - -- If your app integration handles users' personal information (personal information includes all information or data that identifies or could be used to identify a person, or that is associated with such information or data. Examples of personal information include: name and address, phone number, biometric identifiers, location, contacts, photos, audio & video recordings, documents, SMS, email, or other text communication, screenshots, and in some cases, combined browsing history), you must provide a prominent link from your app integration to an applicable privacy policy, and such privacy policy must comply with all applicable laws, regulations and policy requirements. This policy should cover what data you are collecting or transmitting, what you will be doing with that data, and (if applicable) who you'll be sharing it with. If you don’t have a privacy statement, here are some third-party resources* that might be of some assistance: - -Future of Privacy Forum – [Application Privacy Policy Generator](http://www.applicationprivacy.org/do-tools/privacy-policy-generator/) - -Iubenda – [Privacy Policy Generator](http://www.iubenda.com/en) - -*_You agree to assume all risk and liability arising from your use of these third-party resources and that Microsoft is not responsible for any issues arising out of your use of them._ -- Your app integration must not collect, store or transmit personal information unrelated to its primary purpose, without first obtaining express user consent. You must obtain all consents from users to process personal information where required by law. -- You may not publish an app integration that is directed at children under the age of 13 (as defined in the Children’s Online Privacy Protection Act), without express permission from Microsoft. - -### 3. Financial Transactions -- For payment enabled app integrations: - - Your app integration may not transmit financial instrument details through the user interface; - - Subject to any channel or third-party platform restrictions, your app integration may: (a) support payments through the [Microsoft Seller Center](https://seller.microsoft.com/) subject to the terms of the Microsoft Seller Center Agreement; or (b) transmit links to other secure payment services; - - If your app integration enables the foregoing payment mechanisms, you must disclose this in your app integrations terms of use and privacy policy (and any profile page or website for the app integration) before the end user agrees to use your app integration; - - You must clearly indicate that an app integration is payment-enabled in the its profile and provide end users with the merchant’s customer service details; and - - You may not publish app integrations on any Microsoft channel that include links or otherwise direct users to payment services for the purchase of digital goods without express permission from Microsoft. - -### 4. Content -- All content in your app integration and associated metadata must be either originally created by the publisher, appropriately licensed from the third-party rights holder, used as permitted by the rights holder, or used as otherwise permitted by law. -- You will not publish an app integration or content in your app integration that: - - is illegal; - - exploits, harms, or threatens to harm children; - - includes advertising, spam, unwanted or unsolicited or bulk communications, posts or messages; - - could be considered inappropriate or offensive material (involving, for example, nudity, bestiality, profanity, pornography or sexually explicit, graphic or gratuitous violence, tobacco products, criminal, dangerous or irresponsible activity, drugs, human rights violations, the creation or illegal use of weapons against a person or animal in the real world, irresponsible use of alcohol products); - - is false or misleading (e.g., asking for money under false pretenses, impersonating someone else); - - is harmful to you, the Microsoft Channel or others or creates a safety risk (e.g., transmitting viruses, stalking, posting terrorist content, communicating hate speech, or advocating discrimination, hatred, or violence based on considerations of race, ethnicity, national origin, language, gender, age, disability, religion, sexual orientation, status as a veteran, or membership in any other social group); - - infringes upon the rights of others (e.g., unauthorized sharing of copyrighted music or other copyrighted material; - - is defamatory, libelous, slanderous, or threatening; - - violates the privacy of others; - - processes information that (a) relates to a patient’s condition, treatment or payment for treatment; (b) identifies individuals as or communicates with patients, health plan members or beneficiaries; or (c) is otherwise ‘protected health information’ under the Health Insurance Portability and Accountability Act, as amended ("HIPAA") or perform any activity governed by HIPAA if you are a ‘covered entity’ or ‘business associate’ as defined under HIPAA; - - is offensive in any country/region to which your app is targeted. Content may be considered offensive in certain countries/regions because of local laws or cultural norms; - - helps others to break these rules. -- You must notify Microsoft in advance by sending an email to the specific channel you have published to if you make any material changes to your app integration. Changes made to your bot’s registration may require your bot to be re-reviewed to ensure that it continues to meet the requirements stated here. Microsoft has the right, in its sole discretion, to intermittently review app integrations on any channel and remove without notice. diff --git a/articles/bot-service-scenario-commerce.md b/articles/bot-service-scenario-commerce.md deleted file mode 100755 index 6e4db0502..000000000 --- a/articles/bot-service-scenario-commerce.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Commerce bot scenario - Bot Service -description: Explore the Commerce bot scenario with the Bot Framework. -author: BrianRandell -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- -# Commerce bot scenario - -[!INCLUDE [pre-release-label](includes/pre-release-label-v3.md)] - -The [Commerce bot](bot-service-scenario-commerce.md) scenario describes a bot that replaces the traditional e-mail and phone call interactions that people typically have with a hotel's concierge service. The bot takes advantage of Cognitive Services to better process customer requests via text and voice with context gathered from integration with backend services. - -![The application bot diagram](~/media/scenarios/bot-service-scenario-commerce-bot.png) - -Here is the logic flow of a Commerce bot that functions as a concierge for a hotel: - -1. The customer uses the hotel mobile app. -2. Using Azure AD B2C, the user authenticates. -3. Using the custom Application Bot, user requests information. -4. Cognitive Services helps process the natural language request. -5. Response is reviewed by customer who can refine the question using natural conversation. -6. After the user is happy with the results, the Application Bot updates the customer’s reservation. -7. Application insights gathers runtime telemetry to help development with bot performance and usage. - -## Sample bot -The sample Commerce bot is designed around a fictitious hotel concierge service. Written in C#, customers access the Bot once they've authenticated Azure AD B2C with a hotel via the chain's member services mobile app. The chain stores reservations in a SQL Database. A customer can use natural phrase questions like "How much to rent a pool cabana for my stay". The Bot in turn has context about what hotel and the duration of the guest's stay. In addition, Language Understanding (LUIS) Service makes it easy for the bot to get context from even a simple phrase like "pool cabana". The Bot provides the answer and then can offer to book a cabana for the guest, providing choices around the number of days and type of cabana. Once the Bot has all the necessary data, it books the request. The guest can also use their voice to make the same request. - -You can download or clone the source code for this sample bot from [Samples for Common Bot Framework Scenarios](https://aka.ms/abs-scenarios). - -## Components you'll use -The Commerce bot uses the following components: -- Azure AD for Authentication -- Cognitive Services: LUIS -- Application Insights - -### Azure Active Directory (Azure AD) -Azure Active Directory (Azure AD) is Microsoft’s multi-tenant cloud based directory and identity management service. As a Bot developer, Azure AD lets you focus on building your Bot by making it fast and simple to integrate with a world class identity management solution used by millions of organizations around the world. Azure AD supports a B2C connector allowing you to identify individuals using external IDs such as Google, Facebook, or a Microsoft Account. Azure AD removes the responsibility from you having to manage the user's credentials and instead focus your Bot's solution knowing you can correlate the user of the Bot with the correct data exposed by your application. - -### Cognitive Services: LUIS -As a member of the Cognitive Services family of technologies, Language Understanding (LUIS) brings the power of machine learning to your apps. Currently, LUIS supports several languages that enables your Bot to understand what a person wants. When integrating with LUIS, you express intent and define the entities your Bot understands. You then teach your Bot to understand those intents and entities by training it with example utterances. You have the ability to tweak your integration using phrase lists and regex features so that your Bot is as fluid as possible for your particular conversation needs. - -### Application Insights -Application Insights helps you get actionable insights through application performance management (APM) and instant analytics. Out of the box you get rich performance monitoring, powerful alerting, and easy-to-consume dashboards to help ensure your Bot is available and performing as you expect. You can quickly see if you have a problem, then perform a root cause analysis to find and fix the issue. - -## Next steps -Next, learn about the Cortana Skill bot scenario. - -> [!div class="nextstepaction"] -> [Cortana Skills bot scenario](bot-service-scenario-cortana-skill.md) diff --git a/articles/bot-service-scenario-cortana-skill.md b/articles/bot-service-scenario-cortana-skill.md deleted file mode 100755 index f6c1d725f..000000000 --- a/articles/bot-service-scenario-cortana-skill.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Cortana Skills bot scenario - Bot Service -description: Explore the Cortana Skills bot scenario with the Bot Framework. -author: BrianRandell -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- -# Cortana Skills Bot Scenario - -[!INCLUDE [pre-release-label](includes/pre-release-label-v3.md)] - -The Cortana Skills Bot extends Cortana to make it easy to book a mobile auto maintenance appointment using voice with context from your calendar. - -Cortana is your personal assistant. Using the natural interface of your voice and a custom Cortana Skill Bot, you can ask Cortana to speak to an organization, such as an auto shop, to help you make an appointment. The service can provide a list of services, times available, and duration. Cortana can look at your calendar to see if you have something at a conflicting time and if not, create the appointment and add it to your calendar. - -![The Cortana Skill bot diagram](~/media/scenarios/bot-service-scenario-cortana-skill.png) - -Here is the logic flow of a Cortana Skills bot for an auto shop: - -1. The user accesses Cortana from their PC or mobile device. -2. Using either text or voice commands, the user asks for an automobile maintenance appointment. -3. Because the bot is integrated with Cortana, it has access to the user's calendar and applies logic to the request. -4. With that information, the bot can query the auto service for valid appointments. -5. Presented with contextual options, the user can book the appointment. -6. Application insights gathers runtime telemetry to help development with bot performance and usage. - -## Sample bot -With a Cortana Skills Bot, it's all about personal context. Using Cortana you could use your voice to ask for "Bob's Mobile Maintenance" to come work on your car based on your location. Using personal information exposed via Cortana your bot can confirm the location based on where the user is at when they're talking to the bot. - -You can download or clone the source code for this sample bot from [Samples for Common Bot Framework Scenarios](https://aka.ms/abs-scenarios). - -## Components you'll use -The Cortana Bot uses the following components: -- Cortana -- Application Insights - -### Cortana -Now you can add support to your Bot by creating a Cortana Skill. You use the Cortana skills kit to build new features (called skills) for Cortana. A skill is a construct that allows Cortana to do more. You build skills to integrate with your Bots allowing Cortana to complete tasks and get things done. As part of the invocation process, Cortana can (with the user's consent) pass information about the user to a skill at runtime, so that the skill can customize its experience accordingly. Cortana's contextual knowledge allows your Bot to be useful and possibly even clever for them. Once invoked, certain types of skills can manipulate Cortana's interface to have a conversation between the skill and the end user. Once published, users can see and use your skill on Cortana for Windows 10 Anniversary Update+ (Desktop and Mobile), iOS, and Android. - -### Application Insights -Application Insights helps you get actionable insights through application performance management (APM) and instant analytics. Out of the box you get rich performance monitoring, powerful alerting, and easy-to-consume dashboards to help ensure your Bot is available and performing as you expect. You can quickly see if you have a problem, then perform a root cause analysis to find and fix the issue. - -## Next steps -Next, learn about the Enterprise Productivity bot scenario. - -> [!div class="nextstepaction"] -> [Enterprise Productivity bot scenario](bot-service-scenario-enterprise-productivity.md) diff --git a/articles/bot-service-scenario-enterprise-productivity.md b/articles/bot-service-scenario-enterprise-productivity.md deleted file mode 100755 index 9b34a81ba..000000000 --- a/articles/bot-service-scenario-enterprise-productivity.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Enterprise Productivity bot scenario - Bot Service -description: Explore the Enterprise Productivity bot scenario with the Bot Framework. -author: BrianRandell -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Enterprise Productivity Bot Scenario - -[!INCLUDE [pre-release-label](includes/pre-release-label-v3.md)] - -The Enterprise Bot shows how you can increase your productivity by integrating a bot with your Office 365 calendar and other services. - -Quickly accessing customer information without having to have a bunch of windows open is what the Enterprise Productivity Bot is all about. Using simple chat commands, a sales rep can look up a customer and check their next appointment via the Graph API and Office 365. From there they can access customer specific information stored in Dynamics CRM such as get a case or create a new one. - -![The Enterprise bot diagram](~/media/scenarios/bot-service-scenario-enterprise-bot.png) - -Here is the logic flow of an Enterprise Productivity bot: - -1. The employee accesses the Enterprise Productivity bot. -2. Azure Active Directory validates the employee's identity. -3. The Enterprise Productivity bot is able to query the employee's Office 365 calendar via the Azure Graph. -4. Using data gathered from the calendar, the bot accesses case information in Dynamics CRM. -5. The information is returned to the employee who can filter down the data without leaving the bot. -6. Application insights gathers runtime telemetry to help development with bot performance and usage. - -You can download or clone the source code for this sample bot from [Samples for Common Bot Framework Scenarios](https://aka.ms/abs-scenarios). - -## Sample bot -Because Bots are accessible from a variety of channels, you could use it at your desk from a corporate portal or from Skype while on the go--you just need to be authenticated. With Azure AD integration your Enterprise Productivity Bot knows that that if you're able to access it, you've been authenticated by Azure AD. From there you can ask the bot to check when your next appointment is with a particular customer. The Bot gets this information by querying Office 365 via the Graph API. Then, if there's an appointment in the next seven days, the Bot queries CRM looking for any recent cases for the customer. The Bot responds with either no cases found or the number of open and closed cases. From there you can ask the Bot to list out the cases by type and drill into individual cases. - -## Components you'll use -The Enterprise Productivity Bot uses the following components: -- Azure AD for Authentication -- Graph API to Office 365 -- Dynamics CRM -- Application Insights - -### Azure Active Directory (Azure AD) -Azure Active Directory (Azure AD) is Microsoft’s multi-tenant cloud based directory and identity management service. As a Bot developer, Azure AD lets you focus on building your Bot by making it fast and simple to integrate with a world class identity management solution used by millions of organizations around the world. By defining an Azure AD app, you can control who has access to your Bot and the data it exposes, without implementing your own complex authentication and authorization system. - -### Graph API to Office 365 -The Microsoft Graph exposes multiple APIs from Office 365 and other Microsoft cloud services through a single endpoint at https://graph.microsoft.com. Microsoft Graph makes it easier for you and Bot to execute queries. The API exposes data from multiple Microsoft cloud services, including Exchange Online as part of Office 365, Azure Active Directory, SharePoint, and more. You can use the API to navigate between entities and relationships. You can use the API from your Bots using the SDK or REST endpoints as well as from your other apps with native support Android, iOS, Ruby, UWP, Xamarin and more. - -### Dynamics CRM -Dynamics CRM is a customer engagement platform. Using Bots and CRM's APIs, you can build rich interactive Bots that can access the rich data stored in CRM. The power of Dynamics CRM is available to your Bot to create cases, check on status, knowledge management searches and more. - -### Application Insights -Application Insights helps you get actionable insights through application performance management (APM) and instant analytics. Out of the box you get rich performance monitoring, powerful alerting, and easy-to-consume dashboards to help ensure your Bot is available and performing as you expect. You can quickly see if you have a problem, then perform a root cause analysis to find and fix the issue. - -## Next steps -Next, learn about the Information bot scenario. - -> [!div class="nextstepaction"] -> [Information bot scenario](bot-service-scenario-informational.md) diff --git a/articles/bot-service-scenario-informational.md b/articles/bot-service-scenario-informational.md deleted file mode 100755 index c4eb93154..000000000 --- a/articles/bot-service-scenario-informational.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Information bot scenario - Bot Service -description: Explore the Information bot scenario with the Bot Framework. -author: BrianRandell -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- -# Information Bot Scenario - -[!INCLUDE [pre-release-label](includes/pre-release-label-v3.md)] - -This Information Bot could answer questions defined in a knowledge set or FAQ using Cognitive Services QnA Maker and answer more open-ended questions by using Azure Search. - -Often information is buried in structured data stores like SQL Server that can be easily surfaced via search. Imagine looking up a customer's order status by simple conversational commands. Using Cognitive Services QnA Maker, the user is presented with a set of valid search options like, lookup a customer, review a customer's most recent order, etc. With the QnA format defined the user can easily ask questions that are backed by Azure Search which can look up data stored in a SQL Database. - -![The Information bot diagram](~/media/scenarios/bot-service-scenario-informational-bot.png) - -Here is the logic flow of an Information bot: - -1. The employee starts the Information bot. -2. Azure Active Directory validates the employee's identity. -3. The employee can ask the bot what type of queries are supported. -4. Cognitive Services returns a FAQ bot built with the QnA Maker. -5. The employee defines a valid query. -6. The bot submits the query to Azure Search which returns information about the application data. -7. Application insights gathers runtime telemetry to help development with bot performance and usage. - -## Sample bot -The sample Bot, written in C#, runs in Microsoft Azure working with data indexed by Azure Search from a SQL Database instance. The Bot exposes a list of questions that can be asked with information on how to phrase the question (the answer) using Cognitive Services: QnA Maker. The user of the Bot can then type a query that looks up data via Azure Search in a broad or specific area of the database that is indexed. The sample provides a simple database with customers and order information. Application Insights tracks Bot usage and helps you monitor the Bot for exceptions. The Bot is published under as an Azure AD app so that you can restrict who has access to the information. - -You can download or clone the source code for this sample bot from [Samples for Common Bot Framework Scenarios](https://aka.ms/abs-scenarios). - -## Components you'll use -The Information Bot uses the following components: -- Azure AD for Authentication -- Cognitive Services: QnA Maker -- Azure Search -- Application Insights - -### Azure Active Directory (Azure AD) -Azure Active Directory (Azure AD) is Microsoft’s multi-tenant cloud based directory and identity management service. As a Bot developer, Azure AD lets you focus on building your Bot by making it fast and simple to integrate with a world class identity management solution used by millions of organizations around the world. By defining an Azure AD app, you can control who has access to your Bot and the data it exposes, without implementing your own complex authentication and authorization system. - -### Cognitive Services: QnA Maker -Cognitive Services QnA Maker helps you provide an FAQ data source which your users can query from your Bot. When approaching vast amounts of information stored in different systems, it can be useful to help users filter down the information source and set. A single SQL database can have enormous amounts of information that when a free form search is applied brings back too much information. By first using QnA Maker, you can define a road map for your Bot users so they know how to ask intelligent questions that can then be retrieved via Azure Search. - -### Azure Search -Azure Search is a cloud search service for apps that let you get your search indices up and running quickly. Running on top of Microsoft Azure, you can easily scale up and down as your usage demands. You can connect search results to business goals with great control over search ranking and surface data hidden in your databases. - -### Application Insights -Application Insights helps you get actionable insights through application performance management (APM) and instant analytics. Out of the box you get rich performance monitoring, powerful alerting, and easy-to-consume dashboards to help ensure your Bot is available and performing as you expect. You can quickly see if you have a problem, then perform a root cause analysis to find and fix the issue. - -## Next steps -Next, learn about the Internet of Things bot scenario. - -> [!div class="nextstepaction"] -> [Internet of Things bot scenario](bot-service-scenario-internet-things.md) diff --git a/articles/bot-service-scenario-internet-things.md b/articles/bot-service-scenario-internet-things.md deleted file mode 100755 index 42bcea00d..000000000 --- a/articles/bot-service-scenario-internet-things.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: Internet of Things bot scenario - Bot Service -description: Explore the Internet of Things bot scenario with the Bot Framework. -author: BrianRandell -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- -# Internet of Things (IoT) Bot Scenario - -[!INCLUDE [pre-release-label](includes/pre-release-label-v3.md)] - -This Internet of Things (IoT) Bot makes it easy for you to control devices around your home, such as a Philips Hue light using voice or interactive chat commands. - -People love to talk to their things. Since the days of the first TV remote, people have loved not having to move to affect their environment. This IoT bot allows a person to manage a Philips Hue by simple chat commands or voice. In addition, when using chat, a person can be given visual choices related to colors to pick. - -![The Internet of Things bot diagram](~/media/scenarios/bot-service-scenario-iot-bot.png) - -Here is the logic flow of an IoT bot: - -1. The user logs into Skype and accesses the IoT bot. -2. Using voice, the user asks the bot to turn on the lights via the IoT device. -3. The request is relayed to a 3rd party service that has access to the IoT device network. -4. The results of the command are returned to the user. -5. Application insights gathers runtime telemetry to help development with bot performance and usage. - -## Sample bot -The IoT bot will allow you to quickly use chat commands from channels like Skype or Slack to control your Hue. To facilitate remote access, you'll call IFTTT applets predefined to work with Hue. - -You can download or clone the source code for this sample bot from [Samples for Common Bot Framework Scenarios](https://aka.ms/abs-scenarios). - -## Components you'll use -The Internet of Things (IoT) Bot uses the following components: -- Philips Hue -- If This Then That (IFTTT) -- Application Insights - -### Philips Hue -Philips Hue connected bulbs and bridge let you to take full control of your lighting. Whatever you want to do with your lighting, Hue can. Hue has an API you can use from your local network. However, you want to be able to access your Hue controlled devices and lights from anywhere using a friendly Bot interface. Thus you'll access Hue via IFTTT. - -### IFTTT -IFTTT is a free web-based service that people use to create chains of simple conditional statements, called applets. You can trigger an applet from your Bot to have it do something on your behalf. There are a number of predefined Hue applets available to turn lights on and off, change the scene, and more. - -### Application Insights -Application Insights helps you get actionable insights through application performance management (APM) and instant analytics. Out of the box you get rich performance monitoring, powerful alerting, and easy-to-consume dashboards to help ensure your Bot is available and performing as you expect. You can quickly see if you have a problem, then perform a root cause analysis to find and fix the issue. diff --git a/articles/bot-service-scenario-overview.md b/articles/bot-service-scenario-overview.md deleted file mode 100755 index 4af32f336..000000000 --- a/articles/bot-service-scenario-overview.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: Bot Service scenarios overview - Bot Service -description: Explore key scenarios for powerful and successful bots built with Bot Service. -author: BrianRandell -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- -# Bot scenarios - -[!INCLUDE [pre-release-label](includes/pre-release-label-v3.md)] - -This topic explores key scenarios for powerful and successful bots built using Bot Service. - -You can download or clone the source code for all the scenarios bot samples from [Samples for Common Bot Framework Scenarios](https://aka.ms/abs-scenarios). - -## Commerce bot scenario -The [Commerce bot](bot-service-scenario-commerce.md) scenario describes a bot that replaces the traditional e-mail and phone call interactions that people typically have with a hotel's concierge service. The bot takes advantage of Cognitive Services to better process customer requests via text and voice with context gathered from integration with backend services. - -In the Commerce bot scenario, a customer can make a request for concierge services with a hotel. She is authenticated via an Azure Active Directory v2 authentication endpoint. The bot can look up the customer's reservations and provide different service options. For example, the customer might book a cabana by the pool. The bot uses Language Understanding Intelligent Services (LUIS) to parse the request and then the bot walks the user through the process of booking a cabana for an existing reservation. - -## Cortana Skill bot scenario -The [Cortana Skill bot](bot-service-scenario-cortana-skill.md) scenario takes advantage of Cortana. Using the natural interface of your voice and a custom Cortana Skill bot, you can ask Cortana to speak to a organization, such as a mobile auto detailing company, to help you make an appointment based on where you’re at when you make the call. The bot can provide a list of services, times available, and duration. - -## Enterprise Productivity bot scenario -The [Enterprise Productivity bot](bot-service-scenario-enterprise-productivity.md) scenario shows you how to integrate a bot with your Office 365 calendar and other services to increase your productivity. - -The bot integrates with Office 365 to make it quicker and easier to create a meeting request with another person. In the process of doing so you could access additional services like Dynamics CRM. This sample provides the code necessary to integrate with Office 365 with authentication via Azure Active Directory. It provides mock entry points for external services as an exercise for the reader. - -## Information bot scenario -This [Information bot](bot-service-scenario-informational.md) can answer questions defined in a knowledge set or FAQ using Cognitive Services QnA Maker and answer more open-ended questions Azure Search. - -Often information is buried in structured data stores like SQL Server that can be easily surfaced via search. Imagine looking up a customer's order status by simple conversational commands. Using Cognitive Services QnA Maker, the user is presented with a set of valid search options like, lookup a customer, review customer's most recent order, etc. With the QnA format defined the user can easily ask questions that are backed by Azure Search which can look up data stored in a SQL Database. - -## IoT bot scenario -This [Internet of Things (IoT) bot](bot-service-scenario-internet-things.md) bot makes it easy for you to control devices around your home, such as a Philips Hue light using interactive chat commands. - -Using this simple bot, you can control your Philips Hue lights in conjunction with the free If This Then That (IFTTT) service. As an IoT device, the Philips Hue can be controlled locally via their exposed API. However, this API is not exposed for general access from outside the local network. However, IFTTT is a "[Friend of Hue](http://www2.meethue.com/friends-of-hue/ifttt/)" and thus has exposed a number of control commands that you can issue such as turning lights on and off, changing the light color, or the light intensity. - -## Next steps -Now that you have an overview of the scenarios, dive deeper into each scenario. - -> [!div class="nextstepaction"] -> [Commerce bot](bot-service-scenario-commerce.md) diff --git a/articles/bot-service-troubleshoot-500-errors.md b/articles/bot-service-troubleshoot-500-errors.md deleted file mode 100644 index 56177395b..000000000 --- a/articles/bot-service-troubleshoot-500-errors.md +++ /dev/null @@ -1,172 +0,0 @@ ---- -title: Troubleshoot bot HTTP 500 errors - Bot Service -description: How to troubleshoot HTTP 500 errors in a deployed bot. -keywords: troubleshoot, HTTP 500, problems. -author: jonathanFingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/19/2019 ---- - -# Troubleshoot HTTP 500 errors - -The first step in troubleshooting 500 errors is enabling Application Insights. - - -See [conversation analytics telemetry](https://aka.ms/botframeworkanalytics) for information about how to add Application Insights to an existing bot. - -## Enable Application Insights on ASP.Net - -For basic Application Insights support, see how to [set up Application Insights for your ASP.NET website](https://docs.microsoft.com/azure/application-insights/app-insights-asp-net). The Bot Framework (starting with v4.2) provides an additional level of Application Insights telemetry, but it is not required for diagnosing HTTP 500 errors. - -## Enable Application Insights on Node.js - -For basic Application Insights support, see how to [monitor your Node.js services and apps with Application Insights](https://docs.microsoft.com/azure/azure-monitor/learn/nodejs-quick-start). The Bot Framework (starting with v4.2) provides an additional level of Application Insights telemetry, but it is not required for diagnosing HTTP 500 errors. - -## Query for exceptions - -The easiest method of analyzing HTTP status code 500 errors is to begin with exceptions. - -The following queries will tell you the most recent exceptions: - -```sql -exceptions -| order by timestamp desc -| project timestamp, operation_Id, appName -``` - -From the first query, select a few of the operation IDs and look for more information: - -```sql -let my_operation_id = "d298f1385197fd438b520e617d58f4fb"; -let union_all = () { - union - (traces | where operation_Id == my_operation_id), - (customEvents | where operation_Id == my_operation_id), - (requests | where operation_Id == my_operation_id), - (dependencies | where operation_Id == my_operation_id), - (exceptions | where operation_Id == my_operation_id) -}; - -union_all - | order by timestamp desc -``` - -If you have only `exceptions`, analyze the details and see if they correspond to lines in your code. If you only see exceptions coming from the Channel Connector (`Microsoft.Bot.ChannelConnector`) then see [No Application Insights events](#no-application-insights-events) to ensure that Application Insights is set up correctly and your code is logging events. - -## No Application Insights events - -If you are receiving 500 errors and there are no further events within Application Insights from your bot, check the following: - -### Ensure bot runs locally - -Make sure your bot runs locally first with the emulator. - -### Ensure configuration files are being copied (.NET only) - -Make sure your `appsettings.json` and any other configuration files are being packaged correctly during the deployment process. - -#### Application assemblies - -Ensure the Application Insights assemblies are being packaged correctly during the deployment process. - -- Microsoft.ApplicationInsights -- Microsoft.ApplicationInsights.TraceListener -- Microsoft.AI.Web -- Microsoft.AI.WebServer -- Microsoft.AI.ServeTelemetryChannel -- Microsoft.AI.PerfCounterCollector -- Microsoft.AI.DependencyCollector -- Microsoft.AI.Agent.Intercept - -Make sure your `appsettings.json` and any other configuration files are being packaged correctly during the deployment process. - -#### appsettings.json - -Within your `appsettings.json` file ensure the Instrumentation Key is set. - -## [ASP.NET Web API](#tab/dotnetwebapi) - -```json -{ - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - }, - "Console": { - "IncludeScopes": "true" - } - } -} -``` - -## [ASP.NET Core](#tab/dotnetcore) - -```json -{ - "ApplicationInsights": { - "InstrumentationKey": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - } -} -``` - ---- - -### Verify config file - -Ensure there's an Application Insights key included in your config file. - -```json -{ - "ApplicationInsights": { - "type": "appInsights", - "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", - "subscriptionId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", - "resourceGroup": "my resource group", - "name": "my appinsights name", - "serviceName": "my service name", - "instrumentationKey": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", - "applicationId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", - "apiKeys": {}, - "id": "" - } -}, -``` - -### Check logs - -Bot ASP.Net and Node will emit logs at the server level that can be inspected. - -#### Set up a browser to watch your logs - -1. Open your bot in the [Azure Portal](https://portal.azure.com/). -1. Open the **App Service Settings / All App service settings** page to see all service settings. -1. Open the **Monitoring / Diagnostics Logs** page for the app service. - - Ensure that **Application Logging (Filesystem)** is enabled. Be sure to click **Save** if you change this setting. -1. Switch to the **Monitoring / Log Stream** page. - - Select **Web server logs** and ensure you see a message that you are connected. It should look something like the following: - - ```bash - Connecting... - 2018-11-14T17:24:51 Welcome, you are now connected to log-streaming service. - ``` - - Keep this window open. - -#### Set up browser to restart your bot service - -1. Using a separate browser, open your bot in the Azure Portal. -1. Open the **App Service Settings / All App service settings** page to see all service settings. -1. Switch to the **Overview** page for the app service and click **Restart**. - - It will prompt if you are sure; select **yes**. -1. Return to the first browser window and watch the logs. -1. Verify that you are receiving new logs. - - If there is no activity, redeploy your bot. - - Then switch to the **Application logs** page and look for any errors. diff --git a/articles/bot-service-troubleshoot-authentication-problems.md b/articles/bot-service-troubleshoot-authentication-problems.md deleted file mode 100644 index 96640d4ad..000000000 --- a/articles/bot-service-troubleshoot-authentication-problems.md +++ /dev/null @@ -1,227 +0,0 @@ ---- -title: Troubleshooting Bot Framework Authentication - Bot Service -description: Learn how to troubleshoot authentication errors with your bot. -author: DeniseMak -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 04/30/2019 ---- - -# Troubleshooting Bot Framework authentication - -This guide can help you to troubleshoot authentication issues with your bot by evaluating a series of scenarios to determine where the problem exists. - -> [!NOTE] -> To complete all steps in this guide, you will need to download and use the [Bot Framework Emulator][Emulator] and must have access to the bot's registration settings in the Azure Portal. - -## App ID and password - -Bot security is configured by the **Microsoft App ID** and **Microsoft App Password** that you obtain when you register your bot with the Bot Framework. These values are typically specified within the bot's configuration file and used to retrieve access tokens from the Microsoft Account service. - -If you have not yet done so, [deploy your bot to azure](~/bot-builder-howto-deploy-azure.md) to obtain a **Microsoft App ID** and **Microsoft App Password** that it can use for authentication. - -> [!NOTE] -> To find your bot's **AppID** and **AppPassword** for an already deployed bot, see [MicrosoftAppID and MicrosoftAppPassword](bot-service-manage-overview.md#microsoftappid-and-microsoftapppassword). - -## Step 1: Disable security and test on localhost - -In this step, you will verify that your bot is accessible and functional on localhost when security is disabled. - -> [!WARNING] -> Disabling security for your bot may allow unknown attackers to impersonate users. Only implement the following procedure if you are operating in a protected debugging environment. - -### Disable security - -To disable security for your bot, edit its configuration settings to remove the values for app ID and password. - -::: moniker range="azure-bot-service-3.0" - -If you're using the Bot Framework SDK for .NET, edit these settings in your Web.config file: - -```xml - - - - -``` - -If you're using the Bot Framework SDK for Node.js, edit these values (or update the corresponding environment variables): - -```javascript -var connector = new builder.ChatConnector({ - appId: null, - appPassword: null -}); -``` - -::: moniker-end - -::: moniker range="azure-bot-service-4.0" - -If you're using the Bot Framework SDK for .NET, edit the settings in your `appsettings.json` file: - -```json - "MicrosoftAppId": "", - "MicrosoftAppPassword": "" -``` - -If you're using the Bot Framework SDK for Node.js, edit these values (or update the corresponding environment variables): - -```javascript -const adapter = new BotFrameworkAdapter({ - appId: null, - appPassword: null -}); -``` - -::: moniker-end - -### Test your bot on localhost - -Next, test your bot on localhost by using the Bot Framework Emulator. - -1. Start your bot on localhost. -2. Start the Bot Framework Emulator. -3. Connect to your bot using the emulator. - - Type `http://localhost:port-number/api/messages` into the emulator's address bar, where **port-number** matches the port number shown in the browser where your application is running. - - Ensure that the **Microsoft App ID** and **Microsoft App Password** fields are both empty. - - Click **Connect**. -4. To test connectivity to your bot, type some text into the emulator and press Enter. - -If the bot responds to the input and there are no errors in the chat window, you have verified that your bot is accessible and functional on localhost when security is disabled. Proceed to [Step 2](#step-2). - -If one or more error(s) are indicated in the chat window, click the error(s) for details. Common issues include: - -* The emulator settings specify an incorrect endpoint for the bot. Make sure you have included the proper port number in the URL and the proper path at the end of the URL (e.g., `/api/messages`). -* The emulator settings specify a bot endpoint that begins with `https`. On localhost, the endpoint should begin with `http`. -* The emulator settings specify a value for the **Microsoft App ID** field and/or the **Microsoft App Password** field. Both fields should be empty. -* Security has not been disabled of for the bot. [Verify](#disable-security-localhost) that the bot does not specify a value for either app ID or password. - -## Step 2: Verify your bot's app ID and password - -In this step, you will verify that the app ID and password that your bot will use for authentication are valid. (If you do not know these values, [obtain them](#PW) now.) - -> [!WARNING] -> The following instructions disable SSL verification for `login.microsoftonline.com`. Only perform this procedure on a secure network and consider changing your application's password afterward. - -### Issue an HTTP request to the Microsoft login service - -These instructions describe how to use [cURL](https://curl.haxx.se/download.html) to issue an HTTP request to the Microsoft login service. You may use an alternative tool such as Postman, just ensure that the request conforms to the Bot Framework [authentication protocol](~/rest-api/bot-framework-rest-connector-authentication.md). - -To verify that your bot's app ID and password are valid, issue the following request using **cURL**, replacing `APP_ID` and `APP_PASSWORD` with your bot's app ID and password. - -> [!TIP] -> Your password may contain special characters that make the following call invalid. If so, try converting your password to URL encoding. - -```cmd -curl -k -X POST https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token -d "grant_type=client_credentials&client_id=APP_ID&client_secret=APP_PASSWORD&scope=https%3A%2F%2Fapi.botframework.com%2F.default" -``` - -This request attempts to exchange your bot's app ID and password for an access token. If the request is successful, you will receive a JSON payload that contains an `access_token` property, amongst others. - -```json -{"token_type":"Bearer","expires_in":3599,"ext_expires_in":0,"access_token":"eyJ0eXAJKV1Q..."} -``` - -If the request is successful, you have verified that the app ID and password that you specified in the request are valid. Proceed to [Step 3](#step-3). - -If you receive an error in response to the request, examine the response to identify the cause of the error. If the response indicates that the app ID or the password is invalid, [obtain the correct values](#PW) from the Bot Framework Portal and re-issue the request with the new values to confirm that they are valid. - -## Step 3: Enable security and test on localhost - -At this point, you have verified that your bot is accessible and functional on localhost when security is disabled and confirmed that the app ID and password that the bot will use for authentication are valid. In this step, you will verify that your bot is accessible and functional on localhost when security is enabled. - -### Enable security - -Your bot's security relies on Microsoft services, even when your bot is running only on localhost. To enable security for your bot, edit its configuration settings to populate app ID and password with the values that you verified in [Step 2](#step-2). Additionally, make sure your packages are up to date, specifically `System.IdentityModel.Tokens.Jwt` and `Microsoft.IdentityModel.Tokens`. - -If you're using the Bot Framework SDK for .NET, populate these settings in your `appsettings.config` or the corresponding values in your `appsettings.json` file: - -```xml - - - - -``` - -If you're using the Bot Framework SDK for Node.js, populate these settings (or update the corresponding environment variables): - -```javascript -var connector = new builder.ChatConnector({ - appId: 'APP_ID', - appPassword: 'PASSWORD' -}); -``` - -> [!NOTE] -> To find your bot's **AppID** and **AppPassword**, see [MicrosoftAppID and MicrosoftAppPassword](bot-service-manage-overview.md#microsoftappid-and-microsoftapppassword). - -### Test your bot on localhost - -Next, test your bot on localhost by using the Bot Framework Emulator. - -1. Start your bot on localhost. -2. Start the Bot Framework Emulator. -3. Connect to your bot using the emulator. - - Type `http://localhost:port-number/api/messages` into the emulator's address bar, where **port-number** matches the port number shown in the browser where your application is running. - - Enter your bot's app ID into the **Microsoft App ID** field. - - Enter your bot's password into the **Microsoft App Password** field. - - Click **Connect**. -4. To test connectivity to your bot, type some text into the emulator and press Enter. - -If the bot responds to the input and there are no errors in the chat window, you have verified that your bot is accessible and functional on localhost when security is enabled. Proceed to [Step 4](#step-4). - -If one or more error(s) are indicated in the chat window, click the error(s) for details. Common issues include: - -* The emulator settings specify an incorrect endpoint for the bot. Make sure you have included the proper port number in the URL and the proper path at the end of the URL (e.g., `/api/messages`). -* The emulator settings specify a bot endpoint that begins with `https`. On localhost, the endpoint should begin with `http`. -* In the emulator settings, the **Microsoft App ID** field and/or the **Microsoft App Password** do not contain valid values. Both fields should be populated and each field should contain the corresponding value that you verified in [Step 2](#step-2). -* Security has not been enabled for the bot. [Verify](#enable-security-localhost) that the bot configuration settings specify values for both app ID and password. - -## Step 4: Test your bot in the cloud - -At this point, you have verified that your bot is accessible and functional on localhost when security is disabled, confirmed that your bot's app ID and password are valid, and verified that your bot is accessible and functional on localhost when security is enabled. In this step, you will deploy your bot to the cloud and verify that it is accessible and functional there with security enabled. - -### Deploy your bot to the cloud - -The Bot Framework requires that bots be accessible from the internet, so you must deploy your bot to a cloud hosting platform such as Azure. Be sure to enable security for your bot prior to deployment, as described in [Step 3](#step-3). - -> [!NOTE] -> If you do not already have a cloud hosting provider, you can register for a free account.. - -If you deploy your bot to Azure, SSL will automatically be configured for your application, thereby enabling the **HTTPS** endpoint that the Bot Framework requires. If you deploy to another cloud hosting provider, be sure to verify that your application is configured for SSL so that the bot will have an **HTTPS** endpoint. - -### Test your bot - -To test your bot in the cloud with security enabled, complete the following steps. - -1. Ensure that your bot has been successfully deployed and is running. -2. Sign in to the Azure Portal. -3. Click **My Bots**. -4. Select the bot that you want to test. -5. Click **Test** to open the bot in an embedded web chat control. -6. To test connectivity to your bot, type some text into the web chat control and press Enter. - -If an error is indicated in the chat window, use the error message to determine the cause of the error. Common issues include: - -* The **Messaging endpoint** specified on the **Settings** page for your bot in the Bot Framework Portal is incorrect. Make sure you have included the proper path at the end of the URL (e.g., `/api/messages`). -* The **Messaging endpoint** specified on the **Settings** page for your bot in the Bot Framework Portal does not begin with `https` or is not trusted by the Bot Framework. Your bot must have a valid, chain-trusted certificate. -* The bot is configured with missing or incorrect values for app ID or password. [Verify](#enable-security-localhost) that the bot configuration settings specify valid values for app ID and password. - -If the bot responds appropriately to the input, you have verified that your bot is accessible and functional in the cloud with security enabled. At this point, your bot is ready to securely [connect to a channel](~/bot-service-manage-channels.md) such as Skype, Facebook Messenger, Direct Line, and others. - -## Additional resources - -If you are still experiencing issues after completing the steps above, you can: - -* Review how-to [debug a bot](bot-service-debug-bot.md) and the other debugging articles in that section. -* [Debug your bot in the cloud](~/bot-service-debug-emulator.md) using the Bot Framework Emulator and ngrok tunnelling software. *ngrok is not a Microsoft product.* -* Use a proxying tool like [Fiddler](https://www.telerik.com/fiddler) to inspect HTTPS traffic to and from your bot. *Fiddler is not a Microsoft product.* -* Review the [Bot Connector authentication guide][BotConnectorAuthGuide] to learn about the authentication technologies that the Bot Framework uses. -* Solicit help from others by using the Bot Framework [support][Support] resources. - -[BotConnectorAuthGuide]: ~/rest-api/bot-framework-rest-connector-authentication.md -[Support]: bot-service-resources-links-help.md -[Emulator]: bot-service-debug-emulator.md diff --git a/articles/bot-service-troubleshoot-bot-configuration.md b/articles/bot-service-troubleshoot-bot-configuration.md deleted file mode 100644 index 5f6357aad..000000000 --- a/articles/bot-service-troubleshoot-bot-configuration.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: Troubleshoot bot configuration issues - Bot Service -description: How to troubleshoot configuration issues in a deployed bot. -keywords: troubleshoot, configuration, web chat, problems. -author: jonathanFingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 4/30/2019 ---- - -# Troubleshoot bot configuration issues - -The first step in troubleshooting a bot is to test it in Web Chat. This will allow you to determine if the problem is specific to your bot (bot doesn't work in any channel) or to a particular channel (bot works in some channels but not others). - -## Test in Web Chat - -1. Open your bot resource in the [Azure Portal](https://portal.azure.com/). -1. Open the **Test in Web Chat** pane. -1. Send your bot a message. - -![Test In Web Chat](./media/test-in-webchat.png) - -If the bot does not respond with the expected output, go to [Bot does not work in Web Chat](#bot-does-not-work-in-web-chat). Otherwise, go to [Bot works in Web Chat but not in other channels](#bot-works-in-web-chat-but-not-in-other-channels). - -## Bot does not work in Web Chat - -There could be a number of reasons why a bot doesn't work. Most likely, the bot application is down and cannot receive messages, or the bot receives the messages but fails to respond. - -To see if the bot is running: - -1. Open the **Overview** pane. -1. Copy the **Messaging endpoint** and paste it into your browser. - -If the endpoint returns HTTP Error 405, that means the bot is reachable and the bot is able to respond to messages. You should investigate whether your bot [times out](https://github.com/daveta/analytics/blob/master/troubleshooting_timeout.md) or [fails with an HTTP 5xx error](bot-service-troubleshoot-500-errors.md). - -If the endpoint returns an error "This site can't be reached" or "can't reach this page", that means that your bot is down and you need to redeploy it. - -## Bot works in Web Chat but not in other channels - -If the bot works as expected in Web Chat but fails in some other channel, possible reasons are: - -- [Troubleshoot bot configuration issues](#troubleshoot-bot-configuration-issues) - - [Test in Web Chat](#test-in-web-chat) - - [Bot does not work in Web Chat](#bot-does-not-work-in-web-chat) - - [Bot works in Web Chat but not in other channels](#bot-works-in-web-chat-but-not-in-other-channels) - - [Channel configuration issues](#channel-configuration-issues) - - [Channel-specific behavior](#channel-specific-behavior) - - [Channel outage](#channel-outage) - - [Additional resources](#additional-resources) - -### Channel configuration issues - -It's possible that channel configuration parameters have been set incorrectly or have changed externally. For example, a bot has configured the Facebook channel for a particular page and the page was later deleted. The simplest solution is remove the channel and redo the channel configuration anew. - -The links below provide instructions for configuring channels supported by the Bot Framework: - -- [Cortana](bot-service-channel-connect-cortana.md) -- [DirectLine](bot-service-channel-connect-directline.md) -- [Email](bot-service-channel-connect-email.md) -- [Facebook](bot-service-channel-connect-facebook.md) -- [GroupMe](bot-service-channel-connect-groupme.md) -- [Kik](bot-service-channel-connect-kik.md) -- [Microsoft Teams](https://docs.microsoft.com/microsoftteams/platform/concepts/bots/bots-overview) -- [Skype](bot-service-channel-connect-skype.md) -- [Skype for Business](bot-service-channel-connect-skypeforbusiness.md) -- [Slack](bot-service-channel-connect-slack.md) -- [Telegram](bot-service-channel-connect-telegram.md) -- [Twilio](bot-service-channel-connect-twilio.md) - -### Channel-specific behavior - -Implementation of some features can differ by channel. For example, not all channels support Adaptive Cards. Most channels support Buttons, but they are rendered in a channel-specific way. If you see differences in how some message types work in different channels, consult the [channels reference](bot-service-channels-reference.md) article. - -Below are some additional links that can help with individual channels: - -- [Add bots to Microsoft Teams apps](https://docs.microsoft.com/microsoftteams/platform/concepts/bots/bots-overview) -- [Facebook: Introduction to the Messenger Platform](https://developers.facebook.com/docs/messenger-platform/introduction) -- [Principles of Cortana Skills design](https://docs.microsoft.com/cortana/skills/design-principles) -- [Skype for Developers](https://dev.skype.com/bots) -- [Slack: Enabling interactions with bots](https://api.slack.com/bot-users) - -### Channel outage - -Occasionally, some channels might have an interruption of service. Usually, such outages don't last long. However, if you suspect an outage, consult a channel web site or social media. - -Another way to determine if a channel has an outage is to create a test bot (such as a simple Echo Bot) and add a channel. If the test bot works with some channels but not others, that would indicate that the problem is not in your production bot. - -## Additional resources - -See how-to [debug a bot](bot-service-debug-bot.md) and the other debugging articles in that section. diff --git a/articles/bot-service-troubleshoot-general-problems.md b/articles/bot-service-troubleshoot-general-problems.md deleted file mode 100644 index a8ceb1916..000000000 --- a/articles/bot-service-troubleshoot-general-problems.md +++ /dev/null @@ -1,311 +0,0 @@ ---- -title: Troubleshooting bots - Bot Service -description: Troubleshoot general problems in bot development using technical frequently asked questions. -author: DeniseMak -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 09/17/2019 ---- - -# Troubleshooting general problems -These frequently asked questions can help you to troubleshoot common bot development or operational issues. - -## How can I troubleshoot issues with my bot? - -1. Debug your bot's source code with [Visual Studio Code](debug-bots-locally-vscode.md) or [Visual Studio](https://docs.microsoft.com/visualstudio/debugger/navigating-through-code-with-the-debugger?view=vs-2017). -1. Test your bot using the [emulator](bot-service-debug-emulator.md) before you deploy it to the cloud. -1. Deploy your bot to a cloud hosting platform such as Azure and then test connectivity to your bot by using the built-in web chat control on your bot's dashboard in the Azure Portal. If you encounter issues with your bot after you deploy it to Azure, you might consider using this blog article: [Understanding Azure troubleshooting and support](https://azure.microsoft.com/blog/understanding-azure-troubleshooting-and-support/). -1. Rule out [authentication][TroubleshootingAuth] as a possible issue. -1. Test your bot on Skype. This will help you to validate the end-to-end user experience. -1. Consider testing your bot on channels that have additional authentication requirements such as Direct Line or Web Chat. -1. Review the how-to [debug a bot](bot-service-debug-bot.md) and the other debugging articles in that section. - -## How can I troubleshoot authentication issues? - -For details about troubleshooting authentication issues with your bot, see [troubleshooting][TroubleshootingAuth] Bot Framework authentication. - -## I'm using the Bot Framework SDK for .NET. How can I troubleshoot issues with my bot? - -**Look for exceptions.** -In Visual Studio 2017, go to **Debug** > **Windows** > **Exception Settings**. In the **Exceptions Settings** window, select the **Break When Thrown** checkbox next to **Common Language Runtime Exceptions**. You may also see diagnostics output in your Output window when there are thrown or unhandled exceptions. - -**Look at the call stack.** -In Visual Studio, you can choose whether or you are debugging [Just My Code](https://msdn.microsoft.com/library/dn457346.aspx) or not. Examining the full call stack may provide additional insight into any issues. - -**Ensure all dialog methods end with a plan to handle the next message.** -All dialog steps need to feed into the next step of the waterfall, or end the current dialog to pop it off the stack. If a step is not correctly handled, the conversation will not continue like you expect. Take a look at the concept article for [dialogs](v4sdk/bot-builder-concept-dialog.md) for more on dialogs. - -## Why doesn't the Typing activity do anything? -Some channels do not support transient typing updates in their client. - -## What is the difference between the Connector library and Builder library in the SDK? - -The Connector library is the exposition of the REST API. The Builder library adds the conversational dialog programming model and other features such as prompts, waterfalls, chains, and guided form completion. The Builder library also provides access to cognitive services such as LUIS. - -## What causes an error with HTTP status code 429 "Too Many Requests"? - -An error response with HTTP status code 429 indicates that too many requests have been issued in a given amount of time. The body of the response should include an explanation of the problem and may also specify the minimum required interval between requests. One possible source for this error is [ngrok](https://ngrok.com/). If you are on a free plan and running into ngrok's limits, go to the pricing and limits page on their website for more [options](https://ngrok.com/product#pricing). - -## Why aren't my bot messages getting received by the user? - -The message activity generated in response must be correctly addressed, otherwise it won’t arrive at its intended destination. In the vast majority of cases you will not need to handle this explicitly; the SDK takes care of addressing the message activity for you. - -Correctly addressing an activity means including the appropriate *conversation reference* details along with details about the sender and the recipient. In most cases, the message activity is sent in response to one that had arrived. Therefore, the addressing details can be taken from the inbound activity. - -If you examine traces or audit logs, you can check to make sure your messages are correctly addressed. If they aren't, set a breakpoint in your bot and see where the IDs are being set for your message. - -## How can I run background tasks in ASP.NET? - -In some cases, you may want to initiate an asynchronous task that waits for a few seconds and then executes some code to clear the user profile or reset conversation/dialog state. For details about how to achieve this, see [How to run Background Tasks in ASP.NET](https://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx). In particular, consider using [HostingEnvironment.QueueBackgroundWorkItem](https://msdn.microsoft.com/library/dn636893(v=vs.110).aspx). - - -## How do user messages relate to HTTPS method calls? - -When the user sends a message over a channel, the Bot Framework web service will issue an HTTPS POST to the bot's web service endpoint. The bot may send zero, one, or many messages back to the user on that channel, by issuing a separate HTTPS POST to the Bot Framework for each message that it sends. - -## My bot is slow to respond to the first message it receives. How can I make it faster? - -Bots are web services and some hosting platforms, including Azure, automatically put the service to sleep if it does not receive traffic for a certain period of time. If this happens to your bot, it must restart from scratch the next time it receives a message, which makes its response much slower than if it was already running. - -Some hosting platforms enable you to configure your service so that it will not be put to sleep. To do this in Azure, navigate to your bot's service in the [Azure Portal](https://portal.azure.com), select **Application settings**, and then select **Always on**. This option is available in most, but not all, service plans. - -## How can I guarantee message delivery order? - -The Bot Framework will preserve message ordering as much as possible. For example, if you send message A and wait for the completion of that HTTP operation before you initiate another HTTP operation to send message B, the Bot Framework will automatically understand that message A should precede message B. However, in general, message delivery order cannot be guaranteed since the channel is ultimately responsible for message delivery and may reorder messages. - -## How can I intercept all messages between the user and my bot? - -Using the Bot Framework SDK for .NET, you can provide implementations of the `IPostToBot` and `IBotToUser` interfaces to the `Autofac` dependency injection container. Using the Bot Framework SDK for any language, you can use middleware for much the same purpose. The [BotBuilder-Azure](https://github.com/Microsoft/BotBuilder-Azure) repository contains C# and Node.js libraries that will log this data to an Azure table. - -## Why are parts of my message text being dropped? - -The Bot Framework and many channels interpret text as if it were formatted with [Markdown](https://en.wikipedia.org/wiki/Markdown). Check to see if your text contains characters that may be interpreted as Markdown syntax. - -## How can I support multiple bots at the same bot service endpoint? - -This [sample](https://github.com/Microsoft/BotBuilder/issues/2258#issuecomment-280506334) shows how to configure the `Conversation.Container` with the right `MicrosoftAppCredentials` and use a simple `MultiCredentialProvider` to authenticate multiple App IDs and passwords. - -## Identifiers - -## How do identifiers work in the Bot Framework? - -For details about identifiers in the Bot Framework, see the Bot Framework [guide to identifiers][BotFrameworkIDGuide]. - -## How can I get access to the user ID? - -SMS and email messages will provide the raw user ID in the `from.Id` property. In Skype messages, the `from.Id` property will contain a unique ID for the user which differs from the user's Skype ID. If you need to connect to an existing account, you can use a sign-in card and implement your own OAuth flow to connect the user ID to your own service's user ID. - -## Why are my Facebook user names not showing anymore? - -Did you change your Facebook password? Doing so will invalidate the access token, and you will need to update your bot's configuration settings for the Facebook Messenger channel in the Azure Portal. - -## Why is my Kik bot replying "I'm sorry, I can't talk right now"? - -Bots in development on Kik are allowed 50 subscribers. After 50 unique users have interacted with your bot, any new user that attempts to chat with your bot will receive the message "I'm sorry, I can't talk right now." For more information, see [Kik documentation](https://botsupport.kik.com/hc/articles/225764648-How-can-I-share-my-bot-with-Kik-users-while-in-development-). - -## How can I use authenticated services from my bot? - -For Azure Active Directory authentication, see the adding authentication [V3](https://docs.microsoft.com/azure/bot-service/bot-builder-tutorial-authentication?view=azure-bot-service-3.0&tabs=csharp) | [V4](https://docs.microsoft.com/azure/bot-service/bot-builder-tutorial-authentication?view=azure-bot-service-4.0&tabs=csharp). - -> [!NOTE] -> If you add authentication and security functionality to your bot, you should ensure that the patterns you implement in your code comply with the security standards that are appropriate for your application. - -## How can I limit access to my bot to a pre-determined list of users? - -Some channels, such as SMS and email, provide unscoped addresses. In these cases, messages from the user will contain the raw user ID in the `from.Id` property. - -Other channels, such as Skype, Facebook, and Slack, provide either scoped or tenanted addresses in a way that prevents a bot from being able to predict a user’s ID ahead of time. In these cases, you will need to authenticate the user via a login link or shared secret in order to determine whether or not they are authorized to use the bot. - -## Why does my Direct Line 1.1 conversation start over after every message? - -If your Direct Line conversation appears to start over after every message, the `from` property is likely missing or `null` in messages that your Direct Line client sent to the bot. When a Direct Line client sends a message with the `from` property either missing or `null`, the Direct Line service automatically allocates an ID, so every message that the client sends will appear to originate from a new, different user. - -To fix this, set the `from` property in each message that the Direct Line client sends to a stable value that uniquely represents the user who is sending the message. For example, if a user is already signed-in to a webpage or app, you might use that existing user ID as the value of the `from` property in messages that the user sends. Alternatively, you might choose to generate a random user ID on page-load or on application-load, store that ID in a cookie or device state, and use that ID as the value of the `from` property in messages that the user sends. - -## What causes the Direct Line 3.0 service to respond with HTTP status code 502 "Bad Gateway"? -Direct Line 3.0 returns HTTP status code 502 when it tries to contact your bot but the request does not complete successfully. This error indicates that either the bot returned an error or the request timed out. For more information about errors that your bot generates, go to the bot's dashboard within the Azure Portal and click the "Issues" link for the affected channel. If you have Application Insights configured for your bot, you can also find detailed error information there. - -::: moniker range="azure-bot-service-3.0" - -## What is the IDialogStack.Forward method in the Bot Framework SDK for .NET? - -The primary purpose of `IDialogStack.Forward` is to reuse an existing child dialog that is often "reactive", where the child dialog (in `IDialog.StartAsync`) waits for an object `T` with some `ResumeAfter` handler. In particular, if you have a child dialog that waits for an `IMessageActivity` `T`, you can forward the incoming `IMessageActivity` (already received by some parent dialog) by using the `IDialogStack.Forward` method. For example, to forward an incoming `IMessageActivity` to a `LuisDialog`, call `IDialogStack.Forward` to push the `LuisDialog` onto the dialog stack, run the code in `LuisDialog.StartAsync` until it schedules a wait for the next message, and then immediately satisfy that wait with the forwarded `IMessageActivity`. - -`T` is usually an `IMessageActivity`, since `IDialog.StartAsync` is typically constructed to wait for that type of activity. You might use `IDialogStack.Forward` to a `LuisDialog` as a mechanism to intercept messages from the user for -some processing before forwarding the message to an existing `LuisDialog`. Alternatively, you can also use `DispatchDialog` with `ContinueToNextGroup` for that purpose. - -You would expect to find the forwarded item in the first `ResumeAfter` handler (e.g. `LuisDialog.MessageReceived`) that is scheduled by `StartAsync`. - -::: moniker-end - -## What is the difference between "proactive" and "reactive"? - -From the perspective of your bot, "reactive" means that the user initiates the conversation by sending a message to the bot, and the bot reacts by responding to that message. In contrast, "proactive" means that the bot initiates the conversation by sending the first message to the user. For example, a bot may send a proactive message to notify a user when a timer expires or an event occurs. - -## How can I send proactive messages to the user? - -For examples that show how to send proactive messages, see the [C# V4 samples](https://github.com/Microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/16.proactive-messages) and [Node.js V4 samples](https://github.com/Microsoft/BotBuilder-Samples/tree/master/samples/javascript_nodejs/16.proactive-messages) within the BotBuilder-Samples repository on GitHub. - -## How can I reference non-serializable services from my C# dialogs? - -There are multiple options: - -* Resolve the dependency through `Autofac` and `FiberModule.Key_DoNotSerialize`. This is the cleanest solution. -* Use [NonSerialized](https://msdn.microsoft.com/library/system.nonserializedattribute(v=vs.110).aspx) and [OnDeserialized](https://msdn.microsoft.com/library/system.runtime.serialization.ondeserializedattribute(v=vs.110).aspx) attributes to restore the dependency on deserialization. This is the simplest solution. -* Do not store that dependency, so that it won't be serialized. This solution, while technically feasible, is not recommended. -* Use the reflection serialization surrogate. This solution may not be feasible in some cases and risks serializing too much. - -::: moniker range="azure-bot-service-3.0" - -## Where is conversation state stored? - -Data in the user, conversation, and private conversation property bags is stored using the Connector's `IBotState` interface. Each property bag is scoped by the bot's ID. The user property bag is keyed by user ID, the conversation property bag is keyed by conversation ID, and the private conversation property bag is keyed by both user ID and conversation ID. - -If you use the Bot Framework SDK for .NET or the Bot Framework SDK for Node.js to build your bot, the dialog stack and dialog data will both automatically be stored as entries in the private conversation property bag. The C# implementation uses binary serialization, and the Node.js implementation uses JSON serialization. - -The `IBotState` REST interface is implemented by two services. - -* The Bot Framework Connector provides a cloud service that implements this interface and stores data in Azure. This data is encrypted at rest and does not intentionally expire. -* The Bot Framework Emulator provides an in-memory implementation of this interface for debugging your bot. This data expires when the emulator process exits. - -If you want to store this data within your data centers, you can provide a custom implementation of the state service. This can be done at least two ways: - -* Use the REST layer to provide a custom `IBotState` service. -* Use the Builder interfaces in the language (Node.js or C#) layer. - -> [!IMPORTANT] -> The Bot Framework State Service API is not recommended for production environments, and may be deprecated in a future release. It is recommended that you update your bot code to use the in-memory storage for testing purposes or use one of the **Azure Extensions** for production bots. For more information, see the **Manage state data** topic for [.NET](~/dotnet/bot-builder-dotnet-state.md) or [Node](~/nodejs/bot-builder-nodejs-state.md) implementation. - -::: moniker-end - -## What is an ETag? How does it relate to bot data bag storage? - -An [ETag](https://en.wikipedia.org/wiki/HTTP_ETag) is a mechanism for [optimistic concurrency control](https://en.wikipedia.org/wiki/Optimistic_concurrency_control). The bot data bag storage uses ETags to prevent conflicting updates to the data. An ETag error with HTTP status code 412 "Precondition Failed" indicates that there were multiple "read-modify-write" sequences executing concurrently for that bot data bag. - -The dialog stack and state are stored in bot data bags. For example, you might see the "Precondition Failed" ETag error if your bot is still processing a previous message when it receives a new message for that conversation. - -## What causes an error with HTTP status code 412 "Precondition Failed" or HTTP status code 409 "Conflict"? - -The Connector's `IBotState` service is used to store the bot data bags (i.e., the user, conversation, and private bot data bags, where the private bot data bag includes the dialog stack "control flow" state). Concurrency control in the `IBotState` service is managed by optimistic concurrency via ETags. If there is an update conflict (due to a concurrent update to a single bot data bag) during a "read-modify-write" sequence, then: - -* If ETags are preserved, an error with HTTP status code 412 "Precondition Failed" is thrown from the `IBotState` service. This is the default behavior in the Bot Framework SDK for .NET. -* If ETags are not preserved (i.e., ETag is set to `\*`), then the "last write wins" policy will be in effect, which prevents the "Precondition Failed" error but risks data loss. This is the default behavior in the Bot Framework SDK for Node.js. - -## How can I fix "Precondition Failed" (412) or "Conflict" (409) errors? - -These errors indicate that your bot processed multiple messages for the same conversation at once. If your bot is connected to services that require precisely ordered messages, -you should consider locking the conversation state to make sure messages are not processed in parallel. - -::: moniker range="azure-bot-service-3.0" - -The Bot Framework SDK for .NET provides a mechanism (class `LocalMutualExclusion` which implements `IScope`) to -pessimistically serialize the handling of a single conversations with an in-memory semaphore. You could extend this implementation to use a Redis lease, scoped by the conversation address. - -If your bot is not connected to external services or if processing messages in parallel from the same conversation is acceptable, you can add this code to ignore any collisions that occur in the Bot State API. This will allow the last reply to set the conversation state. - -```cs -var builder = new ContainerBuilder(); -builder - .Register(c => new CachingBotDataStore(c.Resolve(), CachingBotDataStoreConsistencyPolicy.LastWriteWins)) - .As>() - .AsSelf() - .InstancePerLifetimeScope(); -builder.Update(Conversation.Container); -``` - -## How do I version the bot data stored through the State API? - -> [!IMPORTANT] -> The Bot Framework State Service API is not recommended for production environments or v4 bots, and may be fully deprecated in a future release. It is recommended that you update your bot code to use the in-memory storage for testing purposes or use one of the **Azure Extensions** for production bots. For more information, see the [Manage state data](v4sdk/bot-builder-howto-v4-state.md) topic. - -The State service enables you to persist progress through the dialogs in a conversation so that a user can return to a conversation with a bot later without losing their position. To preserve this, the bot data property bags that are stored via the State API are not automatically cleared when you modify the bot's code. You should decide whether or not the bot data should be cleared, based upon whether your modified code is compatible with older versions of your data. - -* If you want to manually reset the conversation's dialog stack and state during development of your bot, you can use the `/deleteprofile` command to delete state data. Make sure to include the leading space in this command, to prevent the channel from interpreting it. -* After your bot has been deployed to production, you can version your bot data so that if you bump the version, the associated state data is cleared. With the Bot Framework SDK for Node.js, this can be accomplished using middleware and with the Bot Framework SDK for .NET, this can be accomplished using an `IPostToBot` implementation. - -> [!NOTE] -> If the dialog stack cannot be deserialized correctly, due to serialization format changes or because the code has changed too much, the conversation state will be reset. - -::: moniker-end - -## What are the possible machine-readable resolutions of the LUIS built-in date, time, duration, and set entities? - -For a list of examples, see the [Pre-built entities section][LUISPreBuiltEntities] of the LUIS documentation. - -## How can I use more than the maximum number of LUIS intents? - -You might consider splitting up your model and calling the LUIS service in series or parallel. - -## How can I use more than one LUIS model? - -Both the Bot Framework SDK for Node.js and the Bot Framework SDK for .NET support calling multiple LUIS models from a single LUIS intent dialog. Keep in mind the following caveats: - -* Using multiple LUIS models assumes the LUIS models have non-overlapping sets of intents. -* Using multiple LUIS models assumes the scores from different models are comparable, to select the "best matched intent" across multiple models. -* Using multiple LUIS models means that if an intent matches one model, it will also strongly match the "none" intent of the other models. You can avoid selecting the "none" intent in this situation; the Bot Framework SDK for Node.js will automatically scale down the score for "none" intents to avoid this issue. - -## Where can I get more help on LUIS? - -* [Introduction to Language Understanding (LUIS) - Microsoft Cognitive Services](https://www.youtube.com/watch?v=jWeLajon9M8) (video) -* [Advanced Learning Session for Language Understanding (LUIS)](https://www.youtube.com/watch?v=39L0Gv2EcSk) (video) -* [LUIS documentation](/azure/cognitive-services/LUIS/Home) -* [Language Understanding Forum](https://social.msdn.microsoft.com/forums/azure/home?forum=LUIS) - - -## What are some community-authored dialogs? - -* [BotAuth](https://www.nuget.org/packages/BotAuth) - Azure Active Directory authentication -* [BestMatchDialog](http://www.garypretty.co.uk/2016/08/01/bestmatchdialog-for-microsoft-bot-framework-now-available-via-nuget/) - Regular expression-based dispatch of user text to dialog methods - -## What are some community-authored templates? - -* [ES6 BotBuilder](https://github.com/brene/botbuilder-es6-template) - ES6 Bot Builder template - -## Why do I get an Authorization_RequestDenied exception when creating a bot? - -Permission to create Azure Bot Service bots are managed through the Azure Active Directory (AAD) portal. If permissions are not properly configured in the [AAD portal](https://aad.portal.azure.com), users will get the **Authorization_RequestDenied** exception when trying to create a bot service. - -First check whether you are a "Guest" of the directory: - -1. Sign-in to [Azure portal](https://portal.azure.com). -2. Click **All services** and search for *active*. -3. Select **Azure Active Directory**. -4. Click **Users**. -5. Find the user from the list and ensure that the **User Type** is not a **Guest**. - -![Azure Active Directory User-type](~/media/azure-active-directory/user_type.png) - -Once you verified that you are not a **Guest**, then to ensure that users within an active directory can create bot service, the directory administrator needs to configure the following settings: - -1. Sign-in to [AAD portal](https://aad.portal.azure.com). Go to **Users and groups** and select **User settings**. -2. Under **App registration** section, set **Users can register applications** to **Yes**. This allows users in your directory to create bot service. -3. Under the **External users** section, set **Guest users permissions are limited** to **No**. This allows guest users in your directory to create bot service. - -![Azure Active Directory Admin Center](~/media/azure-active-directory/admin_center.png) - -## Why can't I migrate my bot? - -If you are having issues migrating your bot, it might be because the bot belongs to a directory other than your default directory. Try these steps: - -1. From the target directory, add a new user (via email address) that is not a member of the default directory, grant the user contributor role on the subscriptions that are the target of the migration. - -2. From [Dev Portal](https://dev.botframework.com), add the user’s email address as co-owners of the bot that should be migrated. Then sign out. - -3. Sign in to [Dev Portal](https://dev.botframework.com) as the new user and proceed to migrate the bot. - -## Where can I get more help? - -* Leverage the information in previously answered questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/botframework), or post your own questions using the `botframework` tag. Please note that Stack Overflow has guidelines such as requiring a descriptive title, a complete and concise problem statement, and sufficient details to reproduce your issue. Feature requests or overly broad questions are off-topic; new users should visit the [Stack Overflow Help Center](https://stackoverflow.com/help/how-to-ask) for more details. -* Consult [BotBuilder issues](https://github.com/Microsoft/BotBuilder/issues) in GitHub for information about known issues with the Bot Framework SDK, or to report a new issue. -* Leverage the information in the BotBuilder community discussion on [Gitter](https://gitter.im/Microsoft/BotBuilder). - - - - -[LUISPreBuiltEntities]: /azure/cognitive-services/luis/pre-builtentities -[BotFrameworkIDGuide]: bot-service-resources-identifiers-guide.md -[StateAPI]: ~/rest-api/bot-framework-rest-state.md -[TroubleshootingAuth]: bot-service-troubleshoot-authentication-problems.md - diff --git a/articles/breadcrumb/TOC.yml b/articles/breadcrumb/TOC.yml deleted file mode 100644 index db616db0c..000000000 --- a/articles/breadcrumb/TOC.yml +++ /dev/null @@ -1,17 +0,0 @@ -- name: Docs - href: / - homepage: / - items: - - name: Bot Service - tocHref: /Bot-Framework/ - topicHref: /Bot-Framework/index - items: - - name: Bot Builder SDK for .NET - tocHref: /Bot-Framework/dotnet - topicHref: /Bot-Framework/dotnet/ - - name: Bot Builder SDK for Node.js - tocHref: /Bot-Framework/nodejs - topicHref: /Bot-Framework/nodejs/ - - name: Bot Framework REST API - tocHref: /Bot-Framework/rest-api - topicHref: /Bot-Framework/rest-api/ \ No newline at end of file diff --git a/articles/channel-connect-teams.md b/articles/channel-connect-teams.md deleted file mode 100644 index 6317867d1..000000000 --- a/articles/channel-connect-teams.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: Connect a bot to Teams - Bot Service -description: Learn how to configure a bot for access through the Team. -keywords: Teams, bot channel, configure Teams -author: kamrani -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 08/26/2019 ---- -# Connect a bot to Teams - -To add the Microsoft Teams channel, open the bot in the [Azure portal](https://portal.azure.com), click the **Channels** blade, and then -click **Teams**. - -![Add Teams channel](media/teams/connect-teams-channel.png) - -Next, click **Save**. - -![Save Teams channel](media/teams/save-teams-channel.png) - -After adding the Teams channel, go to the **Channels** page and click on **Get bot embed code**. - -![Get embed code](media/teams/get-embed-code.png) - -- Copy the _https_ part of the code that is showin in the **Get bot embed code** dialog. For example, `https://teams.microsoft.com/l/chat/0/0?users=28:b8a22302e-9303-4e54-b348-343232`. - -- In the browser, paste this address and then choose the Microsoft Teams app (client or web) that you use to add the bot to Teams. You should be able to see the bot listed as a contact that you can send messages to and recieves messages from in Microsoft Teams. - -> [!IMPORTANT] -> Adding a bot by GUID, for anything other than testing purposes, is not recommended. Doing so severely limits the functionality of a bot. Bots in production should be added to Teams as part of an app. See [Create a bot](https://docs.microsoft.com/microsoftteams/platform/concepts/bots/bots-create) and [Test and debug your Microsoft Teams bot](https://docs.microsoft.com/microsoftteams/platform/concepts/bots/bots-test). - - -## Additional information -For Microsoft Teams specific information, see Teams [documentation](https://docs.microsoft.com/microsoftteams/platform/overview). diff --git a/articles/channels/TOC.md b/articles/channels/TOC.md deleted file mode 100644 index 714773bbc..000000000 --- a/articles/channels/TOC.md +++ /dev/null @@ -1,9 +0,0 @@ -# [Implement channel-specific functionality](../dotnet/bot-builder-dotnet-channeldata.md) -# [Build a Cortana skill](../dotnet/bot-builder-dotnet-cortana-skill.md) -# [Conduct audio calls with Skype](../dotnet/bot-builder-dotnet-audio-calls.md) -# Conduct real-time media calls with Skype -## [Real-time media calling concepts](../dotnet/bot-builder-dotnet-real-time-media-concepts.md) -## [Requirements for real-time media bots](../dotnet/bot-builder-dotnet-real-time-media-requirements.md) -## [Build a real-time media bot](../dotnet/bot-builder-dotnet-real-time-audio-video-call-overview.md) -## [Deploy a real-time media bot](../dotnet/bot-builder-dotnet-real-time-deploy-visual-studio.md) - \ No newline at end of file diff --git a/articles/conversation-designer/conversation-designer-adaptive-cards.md b/articles/conversation-designer/conversation-designer-adaptive-cards.md deleted file mode 100644 index a450ddce0..000000000 --- a/articles/conversation-designer/conversation-designer-adaptive-cards.md +++ /dev/null @@ -1,142 +0,0 @@ ---- -title: Configure adaptive cards - Bot Service -description: Learn how to configure adaptive cards. -author: vkannan -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -ROBOTS: NoIndex, NoFollow ---- - -# Configure adaptive cards -> [!IMPORTANT] -> Conversation Designer is not available to all customers yet. More details on -> availability of Conversation Designer will come later this year. - -Adaptive Cards is a new schema that defines rich UI cards for use in several -different endpoints including Microsoft Bot Framework channels. - -Conversation Designer provides a deeply integrated authoring environment to author, preview, and use adaptive cards in your bots. - -Adaptive cards can be defined in several different key places. - -- A simple response to action for a task. -- In feedback state in a dialogue. -- In prompt states in a dialogue. Note that prompts can have separate cards: one for the response and another for re-prompting. - -To define an adaptive card, navigate to the relevant editor. Browse and choose from one of the existing Adaptive Card -Templates or build your own in the JSON code editor. - -As you are building a card, a rich preview of the card is rendered in the authoring portal. - -> [!NOTE] -> Features of adaptive cards remain under ongoing development. All channels do not support all adaptive card features at this time. To see which features each channel supports, see the Channel status section. - -## Input form - -Adaptive cards can contain input forms. In Conversation Designer, forms are integrated with task entities. For example, if a field has an `id` of **myName** and the form `Submit` action is performed, a `taskEntity` with the name **myName** will be created and will contain the value of the field. - -The code snippet below shows how the **myName** entity is defined in code: - -```javascript -{ - "type": "Input.Text", - "id": "myName", - "placeholder": "Last, First" -} -``` - -Additionally, if a field has an id of `@task` then the value of the field will be used as a task name. When this field is triggered (e.g.: a button click), then the named task will be executed. - -Take this snippet code for example: - -```javascript -{ - 'type': 'Action.Submit', - 'title': 'Search', - 'speak': 'Search', - 'data': { - '@task': 'Hotel Search' - } -} -``` - -When this button is clicked, a submit action is triggered and the `context.sticky` will be set to `Hotel Search`. This will result in the **Hotel Search** task to execute. To use this feature, make sure the `@task` matches a task name that you have defined in Conversation Designer. - -## Use entities and language generation templates -Adaptive cards support full language generation resolution. - -* `entityName` uses entities inside the card. -* `responseTemplateName` uses simple or conditional response templates inside the card. - -You can learn more about adaptive cards here TODO: Insert link to adaptive cards schema documentation --> - -## Sample adaptive card payload - -The following JSON shows the payload of an adaptive card. - -```json -{ - "$schema": "https://microsoft.github.io/AdaptiveCards/schemas/adaptive-card.json", - "type": "AdaptiveCard", - "version": "1.0", - "body": [ - { - "speak": "Serious Pie is a Pizza restaurant which is rated 9.3 by customers.", - "type": "ColumnSet", - "columns": [ - { - "type": "Column", - "size": "2", - "items": [ - { - "type": "TextBlock", - "text": "[Greeting], [TimeOfDayTemplate], You can eat in {location}", - "weight": "bolder", - "size": "extraLarge" - }, - { - "type": "TextBlock", - "text": "9.3 · $$ · Pizza", - "isSubtle": true - }, - { - "type": "TextBlock", - "text": "[builtin.feedback.display]", - "wrap": true - } - ] - }, - { - "type": "Column", - "size": "1", - "items": [ - { - "type": "Image", - "url": "http://res.cloudinary.com/sagacity/image/upload/c_crop,h_670,w_635,x_0,y_0/c_scale,w_640/v1397425743/Untitled-4_lviznp.jpg", - "size":"auto" - } - ] - } - ] - } - ], - "actions": [ - { - "type": "Action.Http", - "method": "POST", - "title": "More Info", - "url": "http://foo.com" - }, - { - "type": "Action.Http", - "method": "POST", - "title": "View on Foursquare", - "url": "http://foo.com" - } - ] -} -``` - diff --git a/articles/debug/TOC.md b/articles/debug/TOC.md deleted file mode 100644 index 0998e9a6a..000000000 --- a/articles/debug/TOC.md +++ /dev/null @@ -1,6 +0,0 @@ - -# [Debug a bot using IDE](../bot-service-debug-bot.md) -# [Debug with the Bot Framework Emulator](../bot-service-debug-emulator.md) -# [Debug a bot with inspection middleware](../bot-service-debug-inspection-middleware.md) -# [Debug your bot using transcript files](../v4sdk/bot-builder-debug-transcript.md) -# [Test a Cortana skill](../bot-service-debug-cortana-skill.md) diff --git a/articles/design/TOC.md b/articles/design/TOC.md deleted file mode 100644 index 585e84c67..000000000 --- a/articles/design/TOC.md +++ /dev/null @@ -1,11 +0,0 @@ -# [Principles of bot design](../bot-service-design-principles.md) -# [First interaction](../bot-service-design-first-interaction.md) -# [Design and control conversation flow](../bot-service-design-conversation-flow.md) -# [Design bot navigation](../bot-service-design-navigation.md) -# [Design the user experience](../bot-service-design-user-experience.md) -# Patterns -## [Task automation](../bot-service-design-pattern-task-automation.md) -## [Knowledge base](../bot-service-design-pattern-knowledge-base.md) -## [Handoff to human](../bot-service-design-pattern-handoff-human.md) -## [Bots in apps](../bot-service-design-pattern-embed-app.md) -## [Bots in websites](../bot-service-design-pattern-embed-web-site.md) diff --git a/articles/directline-speech-bot.md b/articles/directline-speech-bot.md deleted file mode 100644 index a5cc0efc5..000000000 --- a/articles/directline-speech-bot.md +++ /dev/null @@ -1,166 +0,0 @@ ---- -title: Develop DirectLine Speech Bot - Bot Service -description: Develop DirectLine Speech Bot -keywords: develop Direct Line speech bot, speech bot -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/01/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Use Direct Line Speech in your bot - -[!INCLUDE [applies-to-v4](includes/applies-to.md)] - -Direct Line Speech uses a new WebSocket based streaming capability of Bot Framework to exchange messages between the Direct Line Speech channel and your bot. After enabling the Direct Line Speech channel in the Azure Portal, you will need to update your bot to listen for and accept these WebSocket connections. These instructions explain how to do this. - -## Step 1: Upgrade to the 4.6 SDK - -For Direct Line Speech ensure you are using version 4.6 or above the Bot Builder SDK. - -## Step 2: Update your .NET Core bot code if your bot uses AddBot and UseBotFramework instead of a BotController - -If you have created a bot using v4 of the Bot Builder SDK prior to version 4.3.2, your bot likely does not include a BotController but instead uses the AddBot() and UseBotFramework() methods in the Startup.cs file to expose the POST endpoint where the bot receives messages. To expose the new streaming endpoint, you will need to add a BotController and remove the AddBot() and UseBotFramework() methods. These instructions walk through the changes that need to be made. If you already have these changes, continue to the next step. - -Add a new MVC controller to your bot project by adding a file called BotController.cs. Add the controller code to this file: - -```cs - -[Route("api/messages")] - -[ApiController] - -public class BotController : ControllerBase -{ - private readonly IBotFrameworkHttpAdapter _adapter; - private readonly IBot _bot; - public BotController(IBotFrameworkHttpAdapter adapter, IBot bot) - { - _adapter = adapter; - - _bot = bot; - } - - [HttpPost, HttpGet] - public async Task ProcessMessageAsync() - { - await _adapter.ProcessAsync(Request, Response, _bot); - } -} -``` - -In the **Startup.cs** file, locate the Configure method. Remove the `UseBotFramework()` line and make sure you have these lines to `UseWebSockets`: - -```cs - -public void Configure(IApplicationBuilder app, IHostingEnvironment env) -{ - ... - app.UseDefaultFiles(); - app.UseStaticFiles(); - app.UseWebSockets(); - app.UseMvc(); - ... -} -``` - -Also in the Startup.cs file, locate the ConfigureServices method. Remove the `AddBot()` line and make sure you have lines for adding your `IBot` and a `BotFrameworkHttpAdapter`: - -```cs - -public void ConfigureServices(IServiceCollection services) -{ - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); - services.AddSingleton(); - services.AddSingleton(); - - // Create the Bot Framework Adapter. - services.AddSingleton(); - - // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. - services.AddTransient(); -} -``` - -The remainder of your bot code stays the same! - -## Step3: Ensure WebSockets are enabled - -When you create a new bot from the Azure Portal using one of the templates such as EchoBot, you will get a bot that includes an ASP.NET MVC controller that exposes a GET and POST endpoint and will also use WebSockets. These instructions explain how to add these elements to your bot if you are upgrading or did not make your bot from a template. - -Open **BotController.cs** under the Controllers folder in your solution - -Find the `PostAsync` method in the class and update its decoration from [HttpPost] to [HttpPost, HttpGet]: - -```cs - -[HttpPost, HttpGet] -public async Task PostAsync() -{ - await _adapter.ProcessAsync(Request, Response, _bot); -} -``` - -Save and close BotController.cs - -Open **Startup.cs** in the root of your solution. - -In Startup.cs, navigate to the bottom of the Configure method. Before the call to `app.UseMvc()`, add a call to `app.UseWebSockets()`. This is important as the order of these use calls matters. The end of the method should look something like this: - -```cs -public void Configure(IApplicationBuilder app, IHostingEnvironment env) -{ - ... - app.UseDefaultFiles(); - app.UseStaticFiles(); - app.UseWebSockets(); - app.UseMvc(); - ... -} - -``` -The remainder of your bot code stays the same! - - - -Step 4: Optionally set the Speak field on Activities to customize what is spoken to the user - -By default, all messages sent through Direct Line Speech to the user will be spoken. - -You can optionally customize how the message is spoken by setting the Speak field of any Activity sent from the bot: - -```cs - -public IActivity Speak(string message) -{ - var activity = MessageFactory.Text(message); - string body = @" - - " + - $"{message}" + ""; - - activity.Speak = body; - return activity; -} -``` - -The following snippet shows how to use the previous Speak function: - -```cs - -protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) -{ - await turnContext.SendActivityAsync(Speak($"Echo: {turnContext.Activity.Text}"), cancellationToken); -} -``` - -## Additional information - -- For a complete example of creating and using a voice enabled bot, see [Tutorial: Voice-enable your bot using the Speech SDK](https://docs.microsoft.com/azure/cognitive-services/speech-service/tutorial-voice-enable-your-bot-speech-sdk). - -- For more information on working with activities, see [how bots work](https://docs.microsoft.com/azure/bot-service/bot-builder-basics) ans [how to send and receive text messageshttps://docs.microsoft.com/azure/bot-service/bot-builder-howto-send-messages?view=azure-bot-service-4.0](). - - diff --git a/articles/docfx.json b/articles/docfx.json deleted file mode 100644 index 82972f91a..000000000 --- a/articles/docfx.json +++ /dev/null @@ -1,130 +0,0 @@ -{ - "build": { - "content": [ - { - "group": "bot-service", - "src": ".", - "dest": ".", - "files": [ - "**/*.md", - "**/*.yml" - ], - "exclude": [ - "**/obj/**", - "**/includes/**", - "**/_themes/**", - "**/_themes.pdf/**", - "bot-framework/**", - "README.md", - "LICENSE", - "LICENSE-CODE", - "ThirdPartyNotices", - "v4sdk/**" - ] - }, - { - "group": "bot-service", - "files": [ - "**/*.md", - "**/*.yml" - ], - "src": "v4sdk", - "exclude": [ - "**/obj/**", - "**/includes/**", - "README.md", - "LICENSE", - "LICENSE-CODE", - "ThirdPartyNotices" - ] - } - - - ], - "resource": [ - { - "files": [ - "**/*.png", - "**/*.jpg", - "**/*.svg" - ], - "exclude": [ - "**/obj/**", - "bot-framework/**", - "~/includes/**" - ] - }, - { - "group": "bot-service", - "src": ".", - "dest": ".", - "files": [ - "**/*.png", - "**/*.jpg", - "**/*.gif", - "**/*.svg" - ], - "exclude": [ - "**/obj/**", - "**/includes/**", - "v4sdk" - ] - }, - { - "group": "bot-service", - "src": "v4sdk", - "files": [ - "**/*.png", - "**/*.jpg", - "**/*.gif", - "**/*.svg" - ], - "exclude": [ - "**/obj/**", - "**/includes/**" - ] - } - - ], - "overwrite": [], - "externalReference": [], - "globalMetadata": { - "uhfHeaderId": "MSDocsHeader-BotFramework", - "breadcrumb_path": "/bot-framework/breadcrumb/TOC.json", - "author": "kaiqb", - "brand": "azure", - "searchScope": [ - "Azure", - "BotService" - ], - "ms.date": "12/13/2018", - "titleSuffix": "Bot Service", - "feedback_system": "GitHub", - "feedback_github_repo": "MicrosoftDocs/bot-docs" - }, - "fileMetadata": { - "ms.author": { - "**/**.md": "kaiqb" - }, - "manager": { - "**/**.md": "kaiqb" - }, - "ms.date": { - "**/**.md": "12/13/2018" - }, - "monikerRange": { - "v4sdk/**.md": "azure-bot-service-4.0" - } - }, - "template": [], - "dest": "bot-framework", - "markdownEngineName": "markdig", - "groups": { - "bot-service": { - "dest": "bot-service", - "moniker_range": ">= azure-bot-service-3.0" - } - } - - } -} diff --git a/articles/dotnet/TOC.md b/articles/dotnet/TOC.md deleted file mode 100644 index ad88a0b43..000000000 --- a/articles/dotnet/TOC.md +++ /dev/null @@ -1,45 +0,0 @@ -# [Bot Framework SDK for .NET](bot-builder-dotnet-overview.md) -# [Key concepts](bot-builder-dotnet-concepts.md) -# Messages and activities -## [Activities overview](bot-builder-dotnet-activities.md) -## [Create messages](bot-builder-dotnet-create-messages.md) -## [Add media attachments to messages](bot-builder-dotnet-add-media-attachments.md) -## [Add rich cards to messages](bot-builder-dotnet-add-rich-card-attachments.md) - -## [Add speech to messages](bot-builder-dotnet-text-to-speech.md) -## [Add input hints to messages](bot-builder-dotnet-add-input-hints.md) -## [Add suggested actions to messages](bot-builder-dotnet-add-suggested-actions.md) -## [Send and receive activities](bot-builder-dotnet-connector.md) -## [Implement global message handlers](bot-builder-dotnet-global-handlers.md) -## [Intercept messages](bot-builder-dotnet-middleware.md) -## [Send proactive messages](bot-builder-dotnet-proactive-messages.md) -# Dialogs -## [Dialogs overview](bot-builder-dotnet-dialogs.md) -## [Manage conversation flow](bot-builder-dotnet-manage-conversation-flow.md) -## [Scorable dialogs](bot-builder-dotnet-scorable-dialogs.md) -# FormFlow -## [Basic features of FormFlow](bot-builder-dotnet-formflow.md) -## [Advanced features of FormFlow](bot-builder-dotnet-formflow-advanced.md) -## [FormBuilder](bot-builder-dotnet-formflow-formbuilder.md) -## [Pattern language](bot-builder-dotnet-formflow-pattern-language.md) -## [Localization](bot-builder-dotnet-formflow-localize.md) -## [JSON schema](bot-builder-dotnet-formflow-json-schema.md) -# Channels -## [Implement channel-specific functionality](bot-builder-dotnet-channeldata.md) -## [Build a Cortana skill](bot-builder-dotnet-cortana-skill.md) -## [Conduct audio calls with Skype](bot-builder-dotnet-audio-calls.md) - -# State data -## [Manage state data](bot-builder-dotnet-state.md) -## [Manage state data using Cosmos DB](bot-builder-dotnet-state-azure-cosmosdb.md) -## [Manage state data using Table storage](bot-builder-dotnet-state-azure-table-storage.md) -# [Recognize intent with LUIS](bot-builder-dotnet-luis-dialogs.md) -# [Request payment](bot-builder-dotnet-request-payment.md) -# [Add Azure Search](bot-builder-dotnet-search-azure.md) -# [Secure your bot](bot-builder-dotnet-security.md) diff --git a/articles/dotnet/bot-builder-dotnet-activities.md b/articles/dotnet/bot-builder-dotnet-activities.md deleted file mode 100644 index 2fff5f817..000000000 --- a/articles/dotnet/bot-builder-dotnet-activities.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: Activities overview - Bot Service -description: Learn about the different activity types available within the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Activities overview - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -[!INCLUDE [Activity concept overview](../includes/snippet-dotnet-concept-activity.md)] - -## Activity types in the Bot Framework SDK for .NET - -The following activity types are supported by the Bot Framework SDK for .NET. - -| Activity.Type | Interface | Description | -|------|------|------| -| [message](#message) | IMessageActivity | Represents a communication between bot and user. | -| [conversationUpdate](#conversationupdate) | IConversationUpdateActivity | Indicates that the bot was added to a conversation, other members were added to or removed from the conversation, or conversation metadata has changed. | -| [contactRelationUpdate](#contactrelationupdate) | IContactRelationUpdateActivity | Indicates that the bot was added or removed from a user's contact list. | -| [typing](#typing) | ITypingActivity | Indicates that the user or bot on the other end of the conversation is compiling a response. | -| [deleteUserData](#deleteuserdata) | n/a | Indicates to a bot that a user has requested that the bot delete any user data it may have stored. | -| [endOfConversation](#endofconversation) | IEndOfConversationActivity | Indicates the end of a conversation. | -| [event](#event) | IEventActivity | Represents a communication sent to a bot that is not visible to the user. | -| [invoke](#invoke) | IInvokeActivity | Represents a communication sent to a bot to request that it perform a specific operation. This activity type is reserved for internal use by the Microsoft Bot Framework. | -| [messageReaction](#messagereaction) | IMessageReactionActivity | Indicates that a user has reacted to an existing activity. For example, a user clicks the "Like" button on a message. | - -## message - -Your bot will send **message** activities to communicate information to and receive **message** activities from users. -Some messages may simply consist of plain text, while others may contain richer content such as [text to be spoken](bot-builder-dotnet-text-to-speech.md), [suggested actions](bot-builder-dotnet-add-suggested-actions.md), [media attachments](bot-builder-dotnet-add-media-attachments.md), [rich cards](bot-builder-dotnet-add-rich-card-attachments.md), and [channel-specific data](bot-builder-dotnet-channeldata.md). -For information about commonly-used message properties, see [Create messages](bot-builder-dotnet-create-messages.md). - -## conversationUpdate - -A bot receives a **conversationUpdate** activity whenever it has been added to a conversation, -other members have been added to or removed from a conversation, -or conversation metadata has changed. - -If members have been added to the conversation, the activity's `MembersAdded` property will contain an array of -`ChannelAccount` objects to identify the new members. - -To determine whether your bot has been added to the conversation (i.e., is one of the new members), evaluate whether the `Recipient.Id` value for the activity (i.e., your bot's id) -matches the `Id` property for any of the accounts in the `MembersAdded` array. - -If members have been removed from the conversation, the `MembersRemoved` property will contain an array of `ChannelAccount` objects to identify the removed members. - -> [!TIP] -> If your bot receives a **conversationUpdate** activity indicating that a user has joined the conversation, -> you may choose to have it respond by sending a welcome message to that user. - -## contactRelationUpdate - -A bot receives a **contactRelationUpdate** activity whenever it is added to or removed from a user's contact list. The value of the activity's `Action` property (add | remove) indicates whether the bot has been added or removed from the user's contact list. - -## typing - -A bot receives a **typing** activity to indicate that the user is typing a response. -A bot may send a **typing** activity to indicate to the user that it is working to fulfill a request or compile a response. - -## deleteUserData - -A bot receives a **deleteUserData** activity when a user requests deletion of any data that the bot has previously persisted for him or her. If your bot receives this type of activity, it should delete any personally identifiable information (PII) that it has previously stored for the user that made the request. - -## endOfConversation - -A bot receives an **endOfConversation** activity to indicate that the user has ended the conversation. A bot may send an **endOfConversation** activity to indicate to the user that the conversation is ending. - -## event - -Your bot may receive an **event** activity from an external process or service that wants to -communicate information to your bot without that information being visible to users. The -sender of an **event** activity typically does not expect the bot to acknowledge receipt in any way. - -## invoke - -Your bot may receive an **invoke** activity that represents a request for it to perform a specific operation. -The sender of an **invoke** activity typically expects the bot to acknowledge receipt via HTTP response. -This activity type is reserved for internal use by the Microsoft Bot Framework. - -## messageReaction - -Some channels will send **messageReaction** activities to your bot when a user reacted to an existing activity. For example, a user clicks the "Like" button on a message. The **ReplyToId** property will indicate which activity the user reacted to. - -The **messageReaction** activity may correspond to any number of **messageReactionTypes** that the channel defined. For example, "Like" or "PlusOne" as reaction types that a channel may send. - -## Additional resources - -- [Send and receive activities](bot-builder-dotnet-connector.md) -- [Create messages](bot-builder-dotnet-create-messages.md) -- [Activity class](https://aka.ms/ActivityClass-dotnet-API) diff --git a/articles/dotnet/bot-builder-dotnet-add-input-hints.md b/articles/dotnet/bot-builder-dotnet-add-input-hints.md deleted file mode 100644 index 8bed49b97..000000000 --- a/articles/dotnet/bot-builder-dotnet-add-input-hints.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: Add input hints to messages (v3 C#) - Bot Service -description: Learn how to add input hints to messages using the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Add input hints to messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-add-input-hints.md) -> - [Node.js](../nodejs/bot-builder-nodejs-send-input-hints.md) -> - [REST](../rest-api/bot-framework-rest-connector-add-input-hints.md) - -By specifying an input hint for a message, you can indicate whether your bot is accepting, expecting, or ignoring user input after the message is delivered to the client. For many channels, this enables clients to set the state of user input controls accordingly. For example, if a message's input hint indicates that the bot is ignoring user input, the client may close the microphone and disable the input box to prevent the user from providing input. - -## Accepting input - -To indicate that your bot is passively ready for input but is not awaiting a response from the user, set the message's input hint to `InputHints.AcceptingInput`. On many channels, this will cause the client's input box to be enabled and microphone to be closed, but still accessible to the user. For example, Cortana will open the microphone to accept input from the user if the user holds down the microphone button. The following code example creates a message that indicates the bot is accepting user input. - -```cs -Activity reply = activity.CreateReply("This is the text that will be displayed."); -reply.Speak = "This is the text that will be spoken."; -reply.InputHint = InputHints.AcceptingInput; -await connector.Conversations.ReplyToActivityAsync(reply); -``` - -## Expecting input - -To indicate that your bot is awaiting a response from the user, set the message's input hint to `InputHints.ExpectingInput`. On many channels, this will cause the client's input box to be enabled and microphone to be open. The following code example creates a message that indicates the bot is expecting user input. - -```cs -Activity reply = activity.CreateReply("This is the text that will be displayed."); -reply.Speak = "This is the text that will be spoken."; -reply.InputHint = InputHints.ExpectingInput; -await connector.Conversations.ReplyToActivityAsync(reply); -``` - -## Ignoring input - -To indicate that your bot is not ready to receive input from the user, set the message's input hint to `InputHints.IgnorningInput`. On many channels, this will cause the client's input box to be disabled and microphone to be closed. The following code example creates a message that indicates the bot is ignoring user input. - -```cs -Activity reply = activity.CreateReply("This is the text that will be displayed."); -reply.Speak = "This is the text that will be spoken."; -reply.InputHint = InputHints.IgnoringInput; -await connector.Conversations.ReplyToActivityAsync(reply); -``` - -## Default values for input hint - -If you do not set the input hint for a message, the Bot Framework SDK will automatically set it for you by using this logic: - -- If your bot sends a prompt, the input hint for the message will specify that your bot is **expecting input**. -- If your bot sends single message, the input hint for the message will specify that your bot is **accepting input**. -- If your bot sends a series of consecutive messages, the input hint for all but the final message in the series will specify that your bot is **ignoring input**, and the input hint for the final message in the series will specify that your bot is **accepting input**. - -## Additional resources - -- [Create messages](bot-builder-dotnet-create-messages.md) -- [Add speech to messages](bot-builder-dotnet-text-to-speech.md) -- Activity class -- InputHints class diff --git a/articles/dotnet/bot-builder-dotnet-add-media-attachments.md b/articles/dotnet/bot-builder-dotnet-add-media-attachments.md deleted file mode 100644 index 43b0898e4..000000000 --- a/articles/dotnet/bot-builder-dotnet-add-media-attachments.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: Add media attachments to messages (v3 C#) - Bot Service -description: Learn how to add media attachments to messages using the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Add media attachments to messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-add-media-attachments.md) -> - [Node.js](../nodejs/bot-builder-nodejs-send-receive-attachments.md) -> - [REST](../rest-api/bot-framework-rest-connector-add-media-attachments.md) - -A message exchange between user and bot can contain media attachments (e.g., image, video, audio, file). - -The `Attachments` property of the Activity object contains an array of Attachment objects that represent the media attachments and rich cards within to the message. - -> [!NOTE] -> [Add rich cards to messages](bot-builder-dotnet-add-rich-card-attachments.md). - -## Add a media attachment - -To add a media attachment to a message, create an `Attachment` object for the `message` activity and set -the `ContentType`, `ContentUrl`, and `Name` properties. - -[!code-csharp[Add media attachment](../includes/code/dotnet-add-attachments.cs#addMediaAttachment)] - -If an attachment is an image, audio, or video, the Connector service will communicate attachment data to the channel in a way that enables the [channel](bot-builder-dotnet-channeldata.md) to render that attachment within the conversation. If the attachment is a file, the file URL will be rendered as a hyperlink within the conversation. - -## Additional resources - -- [Channels reference][inspector] -- [Activities overview](bot-builder-dotnet-activities.md) -- [Create messages](bot-builder-dotnet-create-messages.md) -- [Add rich cards to messages](bot-builder-dotnet-add-rich-card-attachments.md) -- Activity class -- Attachment class - -[inspector]: ../bot-service-channels-reference.md - diff --git a/articles/dotnet/bot-builder-dotnet-add-rich-card-attachments.md b/articles/dotnet/bot-builder-dotnet-add-rich-card-attachments.md deleted file mode 100644 index fdc25d631..000000000 --- a/articles/dotnet/bot-builder-dotnet-add-rich-card-attachments.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -title: Add rich card attachments to messages (v3 C#) - Bot Service -description: Learn how to add rich cards to messages using the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Add rich card attachments to messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-add-rich-card-attachments.md) -> - [Node.js](../nodejs/bot-builder-nodejs-send-rich-cards.md) -> - [REST](../rest-api/bot-framework-rest-connector-add-rich-cards.md) - -A message exchange between user and bot can contain one or more rich cards rendered as a list or carousel. - -The `Attachments` property of the [Activity](https://docs.botframework.com/csharp/builder/sdkreference/dc/d2f/class_microsoft_1_1_bot_1_1_connector_1_1_activity.html) object contains an array of [Attachment](https://docs.microsoft.com/dotnet/api/microsoft.bot.connector.attachments?view=botconnector-3.12.2.4) objects that represent the rich cards and media attachments within the message. - -> [!NOTE] -> For information about how to add media attachments to messages, see -> [Add media attachments to messages](bot-builder-dotnet-add-media-attachments.md). - -## Types of rich cards - -The Bot Framework currently supports eight types of rich cards: - -| Card type | Description | -|----|----| -| [Adaptive Card](/adaptive-cards/get-started/bots) | A customizable card that can contain any combination of text, speech, images, buttons, and input fields. See [per-channel support](/adaptive-cards/get-started/bots#channel-status). | -| [Animation Card][animationCard] | A card that can play animated GIFs or short videos. | -| [Audio Card][audioCard] | A card that can play an audio file. | -| [Hero Card][heroCard] | A card that typically contains a single large image, one or more buttons, and text. | -| [Thumbnail Card][thumbnailCard] | A card that typically contains a single thumbnail image, one or more buttons, and text. | -| [Receipt Card][receiptCard] | A card that enables a bot to provide a receipt to the user. It typically contains the list of items to include on the receipt, tax and total information, and other text. | -| [SignIn Card][signinCard] | A card that enables a bot to request that a user sign-in. It typically contains text and one or more buttons that the user can click to initiate the sign-in process. | -| [Video Card][videoCard] | A card that can play videos. | - -> [!TIP] -> To display multiple rich cards in list format, set the activity's `AttachmentLayout` property to "list". -> To display multiple rich cards in carousel format, set the activity's `AttachmentLayout` property to "carousel". -> If the channel does not support carousel format, it will display the rich cards in list format, even if the `AttachmentLayout` property specifies "carousel". - -## Process events within rich cards - -To process events within rich cards, define `CardAction` objects to specify what should happen when the user clicks a button or taps a section of the card. Each `CardAction` object contains these properties: - -| Property | Type | Description | -|----|----|----| -| Type | string | type of action (one of the values specified in the table below) | -| Title | string | title of the button | -| Image | string | image URL for the button | -| Value | string | value needed to perform the specified type of action | - -> [!NOTE] -> Buttons within Adaptive Cards are not created using `CardAction` objects, -> but instead using the schema that is defined by [Adaptive Cards](http://adaptivecards.io). -> See [Add an Adaptive Card to a message](#adaptive-card) for an example that shows how to -> add buttons to an Adaptive Card. - -This table lists the valid values for `CardAction.Type` and describes -the expected contents of `CardAction.Value` for each type: - -| CardAction.Type | CardAction.Value | -|----|----| -| openUrl | URL to be opened in the built-in browser | -| imBack | Text of the message to send to the bot (from the user who clicked the button or tapped the card). This message (from user to bot) will be visible to all conversation participants via the client application that is hosting the conversation. | -| postBack | Text of the message to send to the bot (from the user who clicked the button or tapped the card). Some client applications may display this text in the message feed, where it will be visible to all conversation participants. | -| call | Destination for a phone call in this format: **tel:123123123123** | -| playAudio | URL of audio to be played | -| playVideo | URL of video to be played | -| showImage | URL of image to be displayed | -| downloadFile | URL of file to be downloaded | -| signin | URL of OAuth flow to be initiated | - -## Add a Hero card to a message - -The Hero card typically contains a single large image, one or more buttons, and text. - -This code example shows how to create a reply message that contains three Hero cards rendered in carousel format: - -[!code-csharp[Add HeroCard attachment](../includes/code/dotnet-add-attachments.cs#addHeroCardAttachment)] - -## Add a Thumbnail card to a message - -The Thumbnail card typically contains a single thumbnail image, one or more buttons, and text. - -This code example shows how to create a reply message that contains two Thumbnail cards rendered in list format: - -[!code-csharp[Add ThumbnailCard attachment](../includes/code/dotnet-add-attachments.cs#addThumbnailCardAttachment)] - -## Add a Receipt card to a message - -The Receipt card enables a bot to provide a receipt to the user. -It typically contains the list of items to include on the receipt, tax and total information, and other text. - -This code example shows how to create a reply message that contains a Receipt card: - -[!code-csharp[Add ReceiptCard attachment](../includes/code/dotnet-add-attachments.cs#addReceiptCardAttachment)] - -## Add a Sign-in card to a message - -The Sign-in card enables a bot to request that a user sign-in. -It typically contains text and one or more buttons that the user can click to initiate the sign-in process. - -This code example shows how to create a reply message that contains a Sign-in card: - -[!code-csharp[Add SignInCard attachment](../includes/code/dotnet-add-attachments.cs#addSignInCardAttachment)] - -## Add an Adaptive card to a message - -The Adaptive Card can contain any combination of text, speech, images, buttons, and input fields. -Adaptive Cards are created using the JSON format specified in Adaptive Cards, which gives you full control over card content and format. - -To create an Adaptive Card using .NET, install the `AdaptiveCards` NuGet package. Then, leverage the information within the Adaptive Cards site to understand Adaptive Card schema, explore Adaptive Card elements, and see JSON samples that can be used to create cards of varying composition and complexity. Additionally, you can use the Interactive Visualizer to design Adaptive Card payloads and preview card output. - -This code example shows how to create a message that contains an Adaptive Card for a calendar reminder: - -[!code-csharp[Add Adaptive Card attachment](../includes/code/dotnet-add-attachments.cs#addAdaptiveCardAttachment)] - -The resulting card contains three blocks of text, an input field (choice list), and three buttons: - -![Adaptive Card calendar reminder](../media/adaptive-card-reminder.png) - -## Additional resources - -- [Channels reference](../bot-service-channels-reference.md) -- Adaptive Cards -- [Activities overview](bot-builder-dotnet-activities.md) -- [Create messages](bot-builder-dotnet-create-messages.md) -- [Add media attachments to messages](bot-builder-dotnet-add-media-attachments.md) -- Activity class -- Attachment class - -[animationCard]: /dotnet/api/microsoft.bot.connector.animationcard -[audioCard]: /dotnet/api/microsoft.bot.connector.audiocard -[heroCard]: /dotnet/api/microsoft.bot.connector.herocard -[thumbnailCard]: /dotnet/api/microsoft.bot.connector.thumbnailcard -[receiptCard]: /dotnet/api/microsoft.bot.connector.receiptcard -[signinCard]: /dotnet/api/microsoft.bot.connector.signincard -[videoCard]: /dotnet/api/microsoft.bot.connector.videocard - -[inspector]: ../bot-service-channels-reference.md diff --git a/articles/dotnet/bot-builder-dotnet-add-suggested-actions.md b/articles/dotnet/bot-builder-dotnet-add-suggested-actions.md deleted file mode 100644 index 871958668..000000000 --- a/articles/dotnet/bot-builder-dotnet-add-suggested-actions.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Add suggested actions to messages (v3 C#) - Bot Service -description: Learn how to add suggested actions to messages using the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 03/13/2018 -monikerRange: 'azure-bot-service-3.0' ---- -# Add suggested actions to messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-add-suggested-actions.md) -> - [Node.js](../nodejs/bot-builder-nodejs-send-suggested-actions.md) -> - [REST](../rest-api/bot-framework-rest-connector-add-suggested-actions.md) - -[!INCLUDE [Introduction to suggested actions](../includes/snippet-suggested-actions-intro.md)] - -## Send suggested actions - -To add suggested actions to a message, set the `SuggestedActions` property of the activity to a list of [CardAction][cardAction] objects that represent the buttons to be presented to the user. - -This code example shows how to create a message that presents three suggested actions to the user: - -[!code-csharp[Add suggested actions](../includes/code/dotnet-add-suggested-actions.cs#addSuggestedActions)] - -When the user taps one of the suggested actions, the bot will receive a message from the user that contains the `Value` of the corresponding action. - -## Additional resources - -- [Activities overview](bot-builder-dotnet-activities.md) -- [Create messages](bot-builder-dotnet-create-messages.md) -- [Activity class](https://aka.ms/ActivityClass-dotnet-API) -- IMessageActivity interface -- CardAction class -- SuggestedActions class - -[cardAction]: /dotnet/api/microsoft.bot.connector.cardaction - -[inspector]: ../bot-service-channel-inspector.md - - diff --git a/articles/dotnet/bot-builder-dotnet-audio-calls.md b/articles/dotnet/bot-builder-dotnet-audio-calls.md deleted file mode 100644 index fd9e9b02b..000000000 --- a/articles/dotnet/bot-builder-dotnet-audio-calls.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -title: Conduct audio calls with Skype - Bot Service -description: Learn how to conduct audio calls with Skype using the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Conduct audio calls with Skype - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -[!INCLUDE [Introduction to conducting audio calls](../includes/snippet-audio-call-intro.md)] - -The architecture for a bot that supports audio calls is very similar to that of a typical bot. -The following code samples show how to enable support for audio calls via Skype with the Bot Framework SDK for .NET. - -## Enable support for audio calls - -To enable a bot to support audio calls, define the `CallingController`. - -```cs -[BotAuthentication] -[RoutePrefix("api/calling")] -public class CallingController : ApiController -{ - public CallingController() : base() - { - CallingConversation.RegisterCallingBot(callingBotService => new IVRBot(callingBotService)); - } - - [Route("callback")] - public async Task ProcessCallingEventAsync() - { - return await CallingConversation.SendAsync(this.Request, CallRequestType.CallingEvent); - } - - [Route("call")] - public async Task ProcessIncomingCallAsync() - { - return await CallingConversation.SendAsync(this.Request, CallRequestType.IncomingCall); - } -} -``` - -> [!NOTE] -> In addition to the `CallingController`, which supports audio calls, a bot may also contain a -> `MessagesController` to support messages. Providing both options allows users to interact with -> the bot in the way that they prefer. - -## Answer the call - -The `ProcessIncomingCallAsync` task will execute whenever a user initiates a call to this bot from Skype. -The constructor registers the `IVRBot` class, which has a predefined handler for the `incomingCallEvent`. - -The first action within the workflow should determine if the bot answers or rejects the incoming call. This workflow instructs the bot to answer the incoming call and then play a welcome message. - -```cs -private Task OnIncomingCallReceived(IncomingCallEvent incomingCallEvent) -{ - this.callStateMap[incomingCallEvent.IncomingCall.Id] = new CallState(incomingCallEvent.IncomingCall.Participants); - - incomingCallEvent.ResultingWorkflow.Actions = new List - { - new Answer { OperationId = Guid.NewGuid().ToString() }, - GetPromptForText(WelcomeMessage) - }; - - return Task.FromResult(true); -} -``` - -## After the bot answers - -If the bot answers the call, subsequent actions specified within the workflow will instruct the -**Skype Bot Platform for Calling** to play prompt, record audio, recognize speech, or collect digits from a dial pad. -The final action of the workflow might be to end the call. - -This code sample defines a handler that will set up a menu after the welcome message completes. - -```cs -private Task OnPlayPromptCompleted(PlayPromptOutcomeEvent playPromptOutcomeEvent) -{ - var callState = this.callStateMap[playPromptOutcomeEvent.ConversationResult.Id]; - SetupInitialMenu(playPromptOutcomeEvent.ResultingWorkflow); - return Task.FromResult(true); -} -``` - -The `CreateIvrOptions` method defines that menu that will be presented to the user. - -```cs -private static Recognize CreateIvrOptions(string textToBeRead, int numberOfOptions, bool includeBack) -{ - if (numberOfOptions > 9) - { - throw new Exception("too many options specified"); - } - - var choices = new List(); - - for (int i = 1; i <= numberOfOptions; i++) - { - choices.Add(new RecognitionOption { Name = Convert.ToString(i), DtmfVariation = (char)('0' + i) }); - } - - if (includeBack) - { - choices.Add(new RecognitionOption { Name = "#", DtmfVariation = '#' }); - } - - var recognize = new Recognize - { - OperationId = Guid.NewGuid().ToString(), - PlayPrompt = GetPromptForText(textToBeRead), - BargeInAllowed = true, - Choices = choices - }; - - return recognize; -} -``` - -The `RecognitionOption` class defines both the spoken answer as well as the corresponding Dual-Tone Multi-Frequency (DTMF) variation. DTMF enables the user to answer by typing the corresponding digits on the keypad instead of speaking. - -The `OnRecognizeCompleted` method processes the user's selection, and the input parameter `recognizeOutcomeEvent` contains the value of the user's selection. - -```cs -private Task OnRecognizeCompleted(RecognizeOutcomeEvent recognizeOutcomeEvent) -{ - var callState = this.callStateMap[recognizeOutcomeEvent.ConversationResult.Id]; - ProcessMainMenuSelection(recognizeOutcomeEvent, callState); - return Task.FromResult(true); -} -``` - -## Support natural language -The bot can also be designed to support natural language responses. The **Bing Speech API** enables the bot to recognize words in the user's spoken reply. - -```cs -private async Task OnRecordCompleted(RecordOutcomeEvent recordOutcomeEvent) -{ - recordOutcomeEvent.ResultingWorkflow.Actions = new List - { - GetPromptForText(EndingMessage), - new Hangup { OperationId = Guid.NewGuid().ToString() } - }; - - // Convert the audio to text - if (recordOutcomeEvent.RecordOutcome.Outcome == Outcome.Success) - { - var record = await recordOutcomeEvent.RecordedContent; - string text = await this.GetTextFromAudioAsync(record); - - var callState = this.callStateMap[recordOutcomeEvent.ConversationResult.Id]; - - await this.SendSTTResultToUser("We detected the following audio: " + text, callState.Participants); - } - - recordOutcomeEvent.ResultingWorkflow.Links = null; - this.callStateMap.Remove(recordOutcomeEvent.ConversationResult.Id); -} -``` - -## Sample code - -For a complete sample that shows how to support audio calls with Skype using the Bot Framework SDK for .NET, see the Skype Calling Bot sample in GitHub. - -## Additional resources - -- Bot Framework SDK for .NET Reference -- Skype Calling Bot sample (GitHub) diff --git a/articles/dotnet/bot-builder-dotnet-channeldata.md b/articles/dotnet/bot-builder-dotnet-channeldata.md deleted file mode 100644 index cab732f8f..000000000 --- a/articles/dotnet/bot-builder-dotnet-channeldata.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Implement channel-specific functionality (v3 C#) - Bot Service -description: Learn how to implement channel-specific functionality using the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Implement channel-specific functionality - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -[!INCLUDE [Channel Data Content](../includes/snippet-channeldata.md)] diff --git a/articles/dotnet/bot-builder-dotnet-concepts.md b/articles/dotnet/bot-builder-dotnet-concepts.md deleted file mode 100644 index 29d8f0d90..000000000 --- a/articles/dotnet/bot-builder-dotnet-concepts.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: Key concepts in the Bot Framework SDK for .NET - Bot Service -description: Understand the key concepts and tools for building and deploying conversational bots available in the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Key concepts in the Bot Framework SDK for .NET - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-concepts.md) -> - [Node.js](../nodejs/bot-builder-nodejs-concepts.md) - -This article introduces key concepts in the Bot Framework SDK for .NET. - -## Connector - -The [Bot Framework Connector](bot-builder-dotnet-connector.md) provides a single REST API that enables a bot to communicate across multiple channels such as Skype, Email, Slack, and more. It facilitates communication between bot and user by relaying messages from bot to channel and from channel to bot. - -In the Bot Framework SDK for .NET, the [Connector][connectorLibrary] library enables access to the Connector. - -## Activity - -[!INCLUDE [Activity concept overview](../includes/snippet-dotnet-concept-activity.md)] - -For details about Activities in the Bot Framework SDK for .NET, -see [Activities overview](bot-builder-dotnet-activities.md). - -## Dialog - -When you create a bot using the Bot Framework SDK for .NET, you can use [dialogs](bot-builder-dotnet-dialogs.md) to model -a conversation and manage [conversation flow](../bot-service-design-conversation-flow.md#dialog-stack). -A dialog can be composed of other dialogs to maximize reuse, and a dialog context maintains the [stack of dialogs](../bot-service-design-conversation-flow.md) that are active in the conversation at any point in time. -A conversation that comprises dialogs is portable across computers, which makes it possible for your bot implementation to scale. - -In the Bot Framework SDK for .NET, the [Builder][builderLibrary] library enables you to manage dialogs. - -## FormFlow - -You can use [FormFlow](bot-builder-dotnet-formflow.md) within the Bot Framework SDK for .NET to streamline of building a bot that collects information from the user. -For example, a bot that takes sandwich orders must collect several pieces of information from the user such as type of bread, choice of toppings, size, and so on. Given basic guidelines, FormFlow can automatically generate the dialogs necessary to manage a guided conversation like this. - -## State - -[!INCLUDE [State concept overview](../includes/snippet-dotnet-concept-state.md)] - -For details about managing state using the Bot Framework SDK for .NET, -see [Manage state data](bot-builder-dotnet-state.md). - -## Naming conventions - -The Bot Framework SDK for .NET library uses strongly-typed, Pascal-cased naming conventions. -However, the JSON messages that are transported back and forth over the wire use camel-case naming conventions. -For example, the C# property **ReplyToId** is serialized as **replyToId** in the JSON message that's -transported over the wire. - -## Security - -You should ensure that your bot's endpoint can only be called by the Bot Framework Connector service. -For more information on this topic, see [Secure your bot](bot-builder-dotnet-security.md). - -## Next steps - -Now you know the concepts behind every bot. You can quickly [build a bot using Visual Studio](bot-builder-dotnet-quickstart.md) using a template. Next, study each key concept in more detail, starting with dialogs. - -> [!div class="nextstepaction"] -> [Dialogs in the Bot Framework SDK for .NET](bot-builder-dotnet-dialogs.md) - -[connectorLibrary]: /dotnet/api/microsoft.bot.connector - -[builderLibrary]: /dotnet/api/microsoft.bot.builder.dialogs diff --git a/articles/dotnet/bot-builder-dotnet-connector.md b/articles/dotnet/bot-builder-dotnet-connector.md deleted file mode 100644 index 99a900694..000000000 --- a/articles/dotnet/bot-builder-dotnet-connector.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: Send and receive activities - Bot Service -description: Learn how to exchange information with a user across various channels by using the Connector service via the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Send and receive activities - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -The Bot Framework Connector provides a single REST API that enables a bot to communicate across multiple -channels such as Skype, Email, Slack, and more. -It facilitates communication between bot and user, by relaying messages from bot to channel -and from channel to bot. - -This article describes how to use the Connector via the Bot Framework SDK for .NET to -exchange information between bot and user on a channel. - -> [!NOTE] -> While it is possible to construct a bot by exclusively using the techniques that are described -> in this article, the Bot Framework SDK provides additional features like -> [dialogs](bot-builder-dotnet-dialogs.md) and [FormFlow](bot-builder-dotnet-formflow.md) that -> can streamline the process of managing conversation flow and state and -> make it simpler to incorporate cognitive services such as language understanding. - -## Create a connector client - -The [ConnectorClient][ConnectorClient] class contains the methods that a bot uses to communicate with a user on a channel. -When your bot receives an Activity object from the Connector, -it should use the `ServiceUrl` specified for that activity to create the connector client that it'll -subsequently use to generate a response. - -[!code-csharp[Create connector client](../includes/code/dotnet-send-and-receive.cs#createConnectorClient)] - -> [!TIP] -> Because a channel's endpoint may not be stable, your bot should direct communications to the endpoint -> that the Connector specifies in the `Activity` object, whenever possible (rather than relying upon a cached endpoint). -> -> If your bot needs to initiate the conversation, it can use a cached endpoint for the specified channel -> (since there will be no incoming `Activity` object in that scenario), but it should refresh cached endpoints often. - -## Create a reply - -The Connector uses an [Activity](bot-builder-dotnet-activities.md) object to pass information back and forth between bot and channel (user). -Every activity contains information used for routing the message to the appropriate destination -along with information about who created the message (`From` property), -the context of the message, and the recipient of the message (`Recipient` property). - -When your bot receives an activity from the Connector, the incoming activity's `Recipient` property specifies -the bot's identity in that conversation. -Because some channels (e.g., Slack) assign the bot a new identity when it's added to a conversation, -the bot should always use the value of the incoming activity's `Recipient` property as the value of -the `From` property in its response. - -Although you can create and initialize the outgoing `Activity` object yourself from scratch, -the Bot Framework SDK provides an easier way of creating a reply. -By using the incoming activity's `CreateReply` method, -you simply specify the message text for the response, and the outgoing activity is created -with the `Recipient`, `From`, and `Conversation` properties automatically populated. - -[!code-csharp[Create reply](../includes/code/dotnet-send-and-receive.cs#createReply)] - -## Send a reply - -Once you've created a reply, you can send it by calling the connector client's `ReplyToActivity` method. -The Connector will deliver the reply using the appropriate channel semantics. - -[!code-csharp[Send reply](../includes/code/dotnet-send-and-receive.cs#sendReply)] - -> [!TIP] -> If your bot is replying to a user's message, always use the `ReplyToActivity` method. - -## Send a (non-reply) message - -If your bot is part of a conversation, it can send a message that is not a direct reply to -any message from the user by calling the `SendToConversation` method. - -[!code-csharp[Send non-reply message](../includes/code/dotnet-send-and-receive.cs#sendNonReplyMessage)] - -You may use the `CreateReply` method to initialize the new message (which would automatically set -the `Recipient`, `From`, and `Conversation` properties for the message). -Alternatively, you could use the `CreateMessageActivity` method to create the new message -and set all property values yourself. - -> [!NOTE] -> The Bot Framework does not impose any restrictions on the number of messages that a bot may send. -> However, most channels enforce throttling limits to restrict bots from sending a large number of messages in a short period of time. -> Additionally, if the bot sends multiple messages in quick succession, -> the channel may not always render the messages in the proper sequence. - -## Start a conversation - -There may be times when your bot needs to initiate a conversation with one or more users. -You can start a conversation by calling either the `CreateDirectConversation` method (for a private conversation with a single user) -or the `CreateConversation` method (for a group conversation with multiple users) -to retrieve a `ConversationAccount` object. -Then, create the message and send it by calling the `SendToConversation` method. -To use either the `CreateDirectConversation` method or the `CreateConversation` method, -you must first [create the connector client](#create-a-connector-client) by using the target channel's service URL -(which you may retrieve from cache, if you've persisted it from previous messages). - -> [!NOTE] -> Not all channels support group conversations. -> To determine whether a channel supports group conversations, consult the channel's documentation. - -This code example uses the `CreateDirectConversation` method to create a private conversation with a single user. - -[!code-csharp[Start private conversation](../includes/code/dotnet-send-and-receive.cs#startPrivateConversation)] - -This code example uses the `CreateConversation` method to create a group conversation with multiple users. - -[!code-csharp[Start group conversation](../includes/code/dotnet-send-and-receive.cs#startGroupConversation)] - -## Additional resources - -- [Activities overview](bot-builder-dotnet-activities.md) -- [Create messages](bot-builder-dotnet-create-messages.md) -- Bot Framework SDK for .NET Reference -- Activity class -- ConnectorClient class - -[ConnectorClient]: /dotnet/api/microsoft.bot.connector.connectorclient diff --git a/articles/dotnet/bot-builder-dotnet-cortana-skill.md b/articles/dotnet/bot-builder-dotnet-cortana-skill.md deleted file mode 100644 index 4d584aba4..000000000 --- a/articles/dotnet/bot-builder-dotnet-cortana-skill.md +++ /dev/null @@ -1,364 +0,0 @@ ---- -title: Build a Cortana skill using .NET - Bot Service -description: Learn core concepts for building a Cortana skill in the Bot Framework SDK for .NET. -keywords: Bot Framework, Cortana skill, speech, .NET, SDK, key concepts, core concepts -author: DeniseMak -manager: kamrani -ms.author: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' - -#ROBOTS: Index ---- - -# Build a speech-enabled bot with Cortana skills - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-cortana-skill.md) -> - [Node.js](../nodejs/bot-builder-nodejs-cortana-skill.md) - - -The Bot Framework SDK for .NET enables you to a build speech-enabled bot by connecting it to the Cortana channel as a Cortana skill. - - -> [!TIP] -> For more information on what a skill is, and what they can do, see [The Cortana Skills Kit][CortanaGetStarted]. - -Creating a Cortana skill using Bot Framework requires very little Cortana-specific knowledge and primarily consists of building a bot. One of the likely key differences from other bots that you may have created in the past is that Cortana has both a visual and an audio component. For the visual component, Cortana provides an area of the canvas for rendering content such as cards. For the audio component, you provide text or SSML in your bot's messages, which Cortana reads to the user, giving your bot a voice. - -> [!NOTE] -> Cortana is available on many different devices. Some have a screen while others, like a standalone speaker, might not. You should make sure that your bot is capable of handling both scenarios. See [Cortana-specific entities][CortanaSpecificEntities] to learn how to check device information. - -## Adding speech to your bot - -Spoken messages from your bot are represented as Speech Synthesis Markup Language (SSML). The Bot Framework SDK lets you include SSML in your bot's responses to control what the bot says, in addition to what it shows. You can also control the state of Cortana's microphone, by specifying whether your bot is accepting, expecting, or ignoring user input. - -Set the `Speak` property of the `IMessageActivity` object to specify a message for Cortana to say. If you specify plain text, Cortana determines how the words are pronounced. - -```cs -Activity reply = activity.CreateReply("This is the text that Cortana displays."); -reply.Speak = "This is the text that Cortana will say."; -``` - -If you want more control over pitch, tone, and emphasis, format the `Speak` property as [Speech Synthesis Markup Language (SSML)](http://www.w3.org/TR/speech-synthesis/). - -The following code example specifies that the word "text" should be spoken with a moderate amount of emphasis: -```cs -Activity reply = activity.CreateReply("This is the text that will be displayed."); -reply.Speak = "This is the text that will be spoken."; -``` - - -The **InputHint** property helps indicate to Cortana whether your bot is expecting input. The default value is **ExpectingInput** for a prompt, and **AcceptingInput** for other types of responses. - - -| Value | Description | -|------|------| -| **AcceptingInput** | Your bot is passively ready for input but is not waiting on a response. Cortana accepts input from the user if the user holds down the microphone button.| -| **ExpectingInput** | Indicates that the bot is actively expecting a response from the user. Cortana listens for the user to speak into the microphone. | -| **IgnoringInput** | Cortana is ignoring input. Your bot may send this hint if it is actively processing a request and will ignore input from users until the request is complete. | - - - -This example shows how to let Cortana know that user input is expected. The microphone will be left open. -```cs -// Add an InputHint to let Cortana know to expect user input -Activity reply = activity.CreateReply("This is the text that will be displayed."); -reply.Speak = "This is the text that will be spoken."; -reply.InputHint = InputHints.ExpectingInput; -``` - - - -## Display cards in Cortana - -In addition to spoken responses, Cortana can also display card attachments. Cortana supports the following rich cards: - -| Card type | Description | -|----|----| -| [HeroCard][heroCard] | A card that typically contains a single large image, one or more buttons, and text. | -| [ThumbnailCard][thumbnailCard] | A card that typically contains a single thumbnail image, one or more buttons, and text. | -| [ReceiptCard][receiptCard] | A card that enables a bot to provide a receipt to the user. It typically contains the list of items to include on the receipt, tax and total information, and other text. | -| [SignInCard][signinCard] | A card that enables a bot to request that a user sign-in. It typically contains text and one or more buttons that the user can click to initiate the sign-in process. | - - -See [Card design best practices][CardDesign] to see what these cards look like inside Cortana. For an example of how to use a rich card in a bot, see [Add rich card attachments to messages](bot-builder-dotnet-add-rich-card-attachments.md). - - - - -## Sample: RollerSkill -The code in the following sections comes from a sample Cortana skill for rolling dice. Download the full code for the bot from the [BotBuilder-Samples repository](https://github.com/Microsoft/BotBuilder-Samples/). - -You invoke the skill by saying its [invocation name][InvocationNameGuidelines] to Cortana. For the roller skill, after you [add the bot to the Cortana channel][CortanaChannel] and register it as a Cortana skill, you can invoke it by telling Cortana "Ask Roller" or "Ask Roller to roll dice". - -### Explore the code - - - -To invoke the appropriate dialogs, the activity handlers defined in `RootDispatchDialog.cs` use regular expressions to match the user's input. For example, the handler in the following example is triggered if the user says something like "I'd like to roll some dice". Synonyms are included in the regular expression so that similar utterances will trigger the dialog. -```cs - [RegexPattern("(roll|role|throw|shoot).*(dice|die|dye|bones)")] - [RegexPattern("new game")] - [ScorableGroup(1)] - public async Task NewGame(IDialogContext context, IActivity activity) - { - context.Call(new CreateGameDialog(), AfterGameCreated); - } -``` - -The `CreateGameDialog` dialog sets up a custom game for the bot to play. It uses a `PromptDialog` to ask the user how many sides they want the dice to have and then how many should be rolled. Note that the `PromptOptions` object that is used to initialize the prompt contains a `speak` property for the spoken version of the prompt. - -```cs - [Serializable] - public class CreateGameDialog : IDialog - { - public async Task StartAsync(IDialogContext context) - { - context.UserData.SetValue(Utils.GameDataKey, new GameData()); - - var descriptions = new List() { "4 Sides", "6 Sides", "8 Sides", "10 Sides", "12 Sides", "20 Sides" }; - var choices = new Dictionary>() - { - { "4", new List { "four", "for", "4 sided", "4 sides" } }, - { "6", new List { "six", "sex", "6 sided", "6 sides" } }, - { "8", new List { "eight", "8 sided", "8 sides" } }, - { "10", new List { "ten", "10 sided", "10 sides" } }, - { "12", new List { "twelve", "12 sided", "12 sides" } }, - { "20", new List { "twenty", "20 sided", "20 sides" } } - }; - - var promptOptions = new PromptOptions( - Resources.ChooseSides, - choices: choices, - descriptions: descriptions, - speak: SSMLHelper.Speak(Utils.RandomPick(Resources.ChooseSidesSSML))); // spoken prompt - - PromptDialog.Choice(context, this.DiceChoiceReceivedAsync, promptOptions); - } - - private async Task DiceChoiceReceivedAsync(IDialogContext context, IAwaitable result) - { - GameData game; - if (context.UserData.TryGetValue(Utils.GameDataKey, out game)) - { - int sides; - if (int.TryParse(await result, out sides)) - { - game.Sides = sides; - context.UserData.SetValue(Utils.GameDataKey, game); - } - - var promptText = string.Format(Resources.ChooseCount, sides); - - var promptOption = new PromptOptions(promptText, choices: null, speak: SSMLHelper.Speak(Utils.RandomPick(Resources.ChooseCountSSML))); - - var prompt = new PromptDialog.PromptInt64(promptOption); - context.Call(prompt, this.DiceNumberReceivedAsync); - } - } - - private async Task DiceNumberReceivedAsync(IDialogContext context, IAwaitable result) - { - GameData game; - if (context.UserData.TryGetValue(Utils.GameDataKey, out game)) - { - game.Count = await result; - context.UserData.SetValue(Utils.GameDataKey, game); - } - - context.Done(game); - } - } -``` - -The `PlayGameDialog` renders the results both by displaying them in a `HeroCard` and building a spoken message to say using the `Speak` method. - -```cs - [Serializable] - public class PlayGameDialog : IDialog - { - private const string RollAgainOptionValue = "roll again"; - - private const string NewGameOptionValue = "new game"; - - private GameData gameData; - - public PlayGameDialog(GameData gameData) - { - this.gameData = gameData; - } - - public async Task StartAsync(IDialogContext context) - { - if (this.gameData == null) - { - if (!context.UserData.TryGetValue(Utils.GameDataKey, out this.gameData)) - { - // User started session with "roll again" so let's just send them to - // the 'CreateGameDialog' - context.Done(null); - } - } - - int total = 0; - var randomGenerator = new Random(); - var rolls = new List(); - - // Generate Rolls - for (int i = 0; i < this.gameData.Count; i++) - { - var roll = randomGenerator.Next(1, this.gameData.Sides); - total += roll; - rolls.Add(roll); - } - - // Format rolls results - var result = string.Join(" . ", rolls.ToArray()); - bool multiLine = rolls.Count > 5; - - var card = new HeroCard() - { - Subtitle = string.Format( - this.gameData.Count > 1 ? Resources.CardSubtitlePlural : Resources.CardSubtitleSingular, - this.gameData.Count, - this.gameData.Sides), - Buttons = new List() - { - new CardAction(ActionTypes.ImBack, "Roll Again", value: RollAgainOptionValue), - new CardAction(ActionTypes.ImBack, "New Game", value: NewGameOptionValue) - } - }; - - if (multiLine) - { - card.Text = result; - } - else - { - card.Title = result; - } - - var message = context.MakeMessage(); - message.Attachments = new List() - { - card.ToAttachment() - }; - - // Determine bots reaction for speech purposes - string reaction = "normal"; - - var min = this.gameData.Count; - var max = this.gameData.Count * this.gameData.Sides; - var score = total / max; - if (score == 1) - { - reaction = "Best"; - } - else if (score == 0) - { - reaction = "Worst"; - } - else if (score <= 0.3) - { - reaction = "Bad"; - } - else if (score >= 0.8) - { - reaction = "Good"; - } - - // Check for special craps rolls - if (this.gameData.Type == "Craps") - { - switch (total) - { - case 2: - case 3: - case 12: - reaction = "CrapsLose"; - break; - case 7: - reaction = "CrapsSeven"; - break; - case 11: - reaction = "CrapsEleven"; - break; - default: - reaction = "CrapsRetry"; - break; - } - } - - // Build up spoken response - var spoken = string.Empty; - if (this.gameData.Turns == 0) - { - spoken += Utils.RandomPick(Resources.ResourceManager.GetString($"Start{this.gameData.Type}GameSSML")); - } - - spoken += Utils.RandomPick(Resources.ResourceManager.GetString($"{reaction}RollReactionSSML")); - - message.Speak = SSMLHelper.Speak(spoken); - - // Increment number of turns and store game to roll again - this.gameData.Turns++; - context.UserData.SetValue(Utils.GameDataKey, this.gameData); - - // Send card and bots reaction to user. - message.InputHint = InputHints.AcceptingInput; - await context.PostAsync(message); - - context.Done(null); - } - } -``` -## Next steps - -If your bot is running locally or deployed in the cloud, you can invoke it from Cortana. See [Test a Cortana skill](../bot-service-debug-cortana-skill.md) for the steps required to try out your Cortana skill. - - -## Additional resources -* [The Cortana Skills Kit][CortanaGetStarted] -* [Add speech to messages](bot-builder-dotnet-text-to-speech.md) -* [SSML Reference][SSMLRef] -* [Voice design best practices for Cortana][VoiceDesign] -* [Card design best practices for Cortana][CardDesign] -* [Cortana Dev Center][CortanaDevCenter] -* [Testing and debugging best practices for Cortana][Cortana-TestBestPractice] -* Bot Framework SDK for .NET Reference - -[CortanaGetStarted]: /cortana/getstarted -[BFPortal]: https://dev.botframework.com/ - -[SSMLRef]: https://aka.ms/cortana-ssml -[CortanaDevCenter]: https://developer.microsoft.com/cortana - -[CortanaSpecificEntities]: https://aka.ms/cortana-channel-data -[CortanaAuth]: https://aka.ms/add-auth-cortana-skill - -[InvocationNameGuidelines]: https://aka.ms/cortana-invocation-guidelines -[VoiceDesign]: https://aka.ms/cortana-design-voice -[CardDesign]: https://aka.ms/cortana-design-card -[Cortana-Debug]: https://aka.ms/cortana-enable-debug -[Cortana-Publish]: https://aka.ms/cortana-publish - - -[CortanaChannel]: https://aka.ms/bot-cortana-channel -[Cortana-TestBestPractice]: https://aka.ms/cortana-test-best-practice - -[heroCard]: /dotnet/api/microsoft.bot.connector.herocard - -[thumbnailCard]: /dotnet/api/microsoft.bot.connector.thumbnailcard - -[receiptCard]: /dotnet/api/microsoft.bot.connector.receiptcard - -[signinCard]: /dotnet/api/microsoft.bot.connector.signincard - - diff --git a/articles/dotnet/bot-builder-dotnet-create-messages.md b/articles/dotnet/bot-builder-dotnet-create-messages.md deleted file mode 100644 index 1984bb816..000000000 --- a/articles/dotnet/bot-builder-dotnet-create-messages.md +++ /dev/null @@ -1,139 +0,0 @@ ---- -title: Create messages with the Bot Framework SDK for .NET - Bot Service -description: Learn about commonly-used message properties within the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Create messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -Your bot will send **message** [activities](bot-builder-dotnet-activities.md) to communicate information to users, and likewise, will also receive **message** activities from users. -Some messages may simply consist of plain text, while others may contain richer content such as [text to be spoken](bot-builder-dotnet-text-to-speech.md), [suggested actions](bot-builder-dotnet-add-suggested-actions.md), -[media attachments](bot-builder-dotnet-add-media-attachments.md), [rich cards](bot-builder-dotnet-add-rich-card-attachments.md), and [channel-specific data](bot-builder-dotnet-channeldata.md). - -This article describes some of the commonly-used message properties. - -## Customizing a message - -To have more control over the text formatting of your messages, you can create a custom message using the [Activity](https://docs.botframework.com/csharp/builder/sdkreference/dc/d2f/class_microsoft_1_1_bot_1_1_connector_1_1_activity.html) object and set the properties necessary before sending it to the user. - -This sample shows how to create a custom `message` object and set the `Text`, `TextFormat`, and `Local` properties. - -[!code-csharp[Set message properties](../includes/code/dotnet-create-messages.cs#setBasicProperties)] - -The `TextFormat` property of a message can be used to specify the format of the text. The `TextFormat` property can be set to **plain**, **markdown**, or **xml**. The default value for `TextFormat` is **markdown**. - -## Attachments - -The `Attachments` property of a message activity can be used to send and receive simple media attachments -(image, audio, video, file) and rich cards. -For details, see [Add media attachments to messages](bot-builder-dotnet-add-media-attachments.md) and -[Add rich cards to messages](bot-builder-dotnet-add-rich-card-attachments.md). - -## Entities - -The `Entities` property of a message is an array of open-ended schema.org -objects which allows the exchange of common contextual metadata between the channel and bot. - -### Mention entities - -Many channels support the ability for a bot or user to "mention" someone within the context of a conversation. -To mention a user in a message, populate the message's `Entities` property with a `Mention` object. -The `Mention` object contains these properties: - -| Property | Description | -|----|----| -| Type | type of the entity ("mention") | -| Mentioned | `ChannelAccount` object that indicates which user was mentioned | -| Text | text within the `Activity.Text` property that represents the mention itself (may be empty or null) | - -This code example shows how to add a `Mention` entity to the `Entities` collection. - -[!code-csharp[set Mention](../includes/code/dotnet-create-messages.cs#setMention)] - -> [!TIP] -> When attempting to determine user intent, the bot may want to ignore that portion -> of the message where it is mentioned. Call the `GetMentions` method and evaluate -> the `Mention` objects returned in the response. - -### Place objects - -Location-related information can be conveyed -within a message by populating the message's `Entities` property with either -a `Place` object or a `GeoCoordinates` object. - -The `Place` object contains these properties: - -| Property | Description | -|----|----| -| Type | type of the entity ("Place") | -| Address | description or `PostalAddress` object (future) | -| Geo | GeoCoordinates | -| HasMap | URL to a map or `Map` object (future) | -| Name | name of the place | - -The `GeoCoordinates` object contains these properties: - -| Property | Description | -|----|----| -| Type | type of the entity ("GeoCoordinates") | -| Name | name of the place | -| Longitude | longitude of the location (WGS 84) | -| Latitude | latitude of the location (WGS 84) | -| Elevation | elevation of the location (WGS 84) | - -This code example shows how to add a `Place` entity to the `Entities` collection: - -[!code-csharp[set GeoCoordinates](../includes/code/dotnet-create-messages.cs#setGeoCoord)] - -### Consume entities - -To consume entities, use either the `dynamic` keyword or strongly-typed classes. - -This code example shows how to use the `dynamic` keyword to process an entity within the `Entities` property of a message: - -[!code-csharp[examine entity using dynamic keyword](../includes/code/dotnet-create-messages.cs#examineEntity1)] - -This code example shows how to use a strongly-typed class to process an entity within the `Entities` property of a message: - -[!code-csharp[examine entity using typed class](../includes/code/dotnet-create-messages.cs#examineEntity2)] - -## Channel data - -The `ChannelData` property of a message activity can be used to implement channel-specific functionality. -For details, see [Implement channel-specific functionality](bot-builder-dotnet-channeldata.md). - -## Text to speech - -The `Speak` property of a message activity can be used to specify the text to be spoken by your bot on a speech-enabled channel. The `InputHint` property of a message activity can be used to control the state of the client's microphone and input box (if any). For details, see [Add speech to messages](bot-builder-dotnet-text-to-speech.md). - -## Suggested actions - -The `SuggestedActions` property of a message activity can be used to present buttons that the user can tap to provide input. Unlike buttons that appear within rich cards (which remain visible and accessible to the user even after being tapped), buttons that appear within the suggested actions pane will disappear after the user makes a selection. For details, see [Add suggested actions to messages](bot-builder-dotnet-add-suggested-actions.md). - -## Next steps - -A bot and a user can send messages to each other. When the message is more complex, your bot can send a rich card in a message to the user. Rich cards cover many presentation and interaction scenarios commonly needed in most bots. - -> [!div class="nextstepaction"] -> [Send a rich card in a message](bot-builder-dotnet-add-rich-card-attachments.md) - -## Additional resources - -- [Activities overview](bot-builder-dotnet-activities.md) -- [Send and receive activities](bot-builder-dotnet-connector.md) -- [Add media attachments to messages](bot-builder-dotnet-add-media-attachments.md) -- [Add rich cards to messages](bot-builder-dotnet-add-rich-card-attachments.md) -- [Add speech to messages](bot-builder-dotnet-text-to-speech.md) -- [Add suggested actions to messages](bot-builder-dotnet-add-suggested-actions.md) -- [Implement channel-specific functionality](bot-builder-dotnet-channeldata.md) -- Activity class -- IMessageActivity interface - diff --git a/articles/dotnet/bot-builder-dotnet-dialogs.md b/articles/dotnet/bot-builder-dotnet-dialogs.md deleted file mode 100644 index cd721098d..000000000 --- a/articles/dotnet/bot-builder-dotnet-dialogs.md +++ /dev/null @@ -1,226 +0,0 @@ ---- -title: Dialogs overview (v3 C#) - Bot Service -description: Learn how to use dialogs within the Bot Framework SDK for .NET to model conversations and manage conversation flow. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Dialogs in the Bot Framework SDK for .NET - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-dialogs.md) -> - [Node.js](../nodejs/bot-builder-nodejs-dialog-overview.md) - -When you create a bot using the Bot Framework SDK for .NET, you can use dialogs to model -a conversation and manage [conversation flow](../bot-service-design-conversation-flow.md). -Each dialog is an abstraction that encapsulates its own state in a C# class that implements `IDialog`. -A dialog can be composed with other dialogs to maximize reuse, and a dialog context maintains the [stack of dialogs](../bot-service-design-conversation-flow.md#dialog-stack) that are active in the conversation at any point in time. - -A conversation that comprises dialogs is portable across computers, which makes it possible for your bot implementation to scale. -When you use dialogs in the Bot Framework SDK for .NET, conversation state (the dialog stack and the state of each dialog in the stack) is automatically stored to your choice of [state data](bot-builder-dotnet-state.md) storage. This enables your bot's service code to be stateless, much like a web application that does not need to store session state in web server memory. - -## Echo bot example - -Consider this echo bot example, which describes how to change the bot that's created in the -[Quickstart](bot-builder-dotnet-quickstart.md) tutorial so that it uses dialogs to -exchange messages with the user. - -> [!TIP] -> To follow along with this example, use the instructions in the -> [Quickstart](bot-builder-dotnet-quickstart.md) tutorial to create a bot, and then -> update its **MessagesController.cs** file as described below. - -### MessagesController.cs - -In the Bot Framework SDK for .NET, the [Builder][builderLibrary] library enables you to implement dialogs. -To access the relevant classes, import the `Dialogs` namespace. - -[!code-csharp[Using statement](../includes/code/dotnet-dialogs.cs#usingStatement)] - -Next, add this `EchoDialog` class to **MessagesController.cs** to represent the conversation. - -[!code-csharp[EchoDialog class](../includes/code/dotnet-dialogs.cs#echobot1)] - -Then, wire the `EchoDialog` class to the `Post` method by calling the `Conversation.SendAsync` method. - -[!code-csharp[Post method](../includes/code/dotnet-dialogs.cs#echobot2)] - -### Implementation details - -The `Post` method is marked `async` because Bot Builder uses the C# facilities for handling -asynchronous communication. -It returns a `Task` object, which represents the task that is responsible for sending replies to the -passed-in message. -If there is an exception, the `Task` that is returned by the method will contain the exception information. - -The `Conversation.SendAsync` method is key to implementing dialogs with the Bot Framework SDK -for .NET. It follows the dependency inversion principle and performs these steps: - -1. Instantiates the required components -2. Deserializes the conversation state (the dialog stack and the state of each dialog in the stack) from `IBotDataStore` -3. Resumes the conversation process where the bot suspended and waits for a message -4. Sends the replies -5. Serializes the updated conversation state and saves it back to `IBotDataStore` - -When the conversation first starts, the dialog does not contain state, -so `Conversation.SendAsync` constructs `EchoDialog` and calls its `StartAsync` method. -The `StartAsync` method calls `IDialogContext.Wait` with the continuation delegate -to specify the method that should be called when a new message is received (`MessageReceivedAsync`). - -The `MessageReceivedAsync` method waits for a message, posts a response, and waits for the next message. -Every time `IDialogContext.Wait` is called, the bot enters a suspended state and can be restarted on any -computer that receives the message. - -A bot that's created by using the code samples above will reply to each message that the user sends by simply -echoing back the user's message prefixed with the text 'You said: '. -Because the bot is created using dialogs, it can evolve to support more complex conversations without having -to explicitly manage state. - -## Echo bot with state example - -This next example builds upon the one above by adding the ability to track dialog state. -When the `EchoDialog` class is updated as shown in the code sample below, -the bot will reply to each message that the user sends by echoing back the user's -message prefixed with a number (`count`) followed by the text 'You said: '. -The bot will continue to increment `count` with each reply, until the user elects to reset the count. - -### MessagesController.cs - -[!code-csharp[EchoDialog class](../includes/code/dotnet-dialogs.cs#echobot3)] - -### Implementation details - -As in the first example, the `MessageReceivedAsync` method is called when a new message is received. -This time though, the `MessageReceivedAsync` method evaluates the user's message before responding. -If the user's message is "reset", the built-in `PromptDialog.Confirm` prompt spawns a sub-dialog that -asks the user to confirm the count reset. -The sub-dialog has its own private state that does not interfere with the parent dialog's state. -When the user responds to the prompt, the result of the sub-dialog is passed to the `AfterResetAsync` method, -which sends a message to the user to indicate whether or not the count was reset and then -calls `IDialogContext.Wait` with a continuation back to `MessageReceivedAsync` on the next message. - -## Dialog context - -The `IDialogContext` interface that is passed into each dialog method -provides access to the services that a dialog requires to save state and communicate with the channel. -The `IDialogContext` interface comprises three interfaces: [Internals.IBotData][iBotData], -[Internals.IBotToUser][iBotToUser], and [Internals.IDialogStack][iDialogStack]. - -### Internals.IBotData - -The `Internals.IBotData` interface provides access to the -per-user, per-conversation, and private conversation state data that's maintained by Connector. -Per-user state data is useful for storing user data that is not related to a specific conversation, -while per-conversation data is useful for storing general data about a conversation, and -private conversation data is useful for storing user data that is related to a specific conversation. - -### Internals.IBotToUser - -`Internals.IBotToUser` provides methods to send a message from bot to user. -Messages may be sent inline with the response to the web API method call or -directly by using the [Connector client](bot-builder-dotnet-connector.md#create-a-connector-client). -Sending and receiving messages through the dialog context ensures that the `Internals.IBotData` state is passed through the Connector. - -### Internals.IDialogStack - -`Internals.IDialogStack` provides methods to manage the [dialog stack](../bot-service-design-conversation-flow.md#dialog-stack). Most of the time, the dialog stack will -automatically be managed for you. However, there may be cases where you want to explictly manage the stack. -For example, you might want to call a child dialog and add it to the -top of the dialog stack, mark the current dialog as complete (thereby removing it from the dialog stack and returning the result to the prior dialog in the stack), -suspend the current dialog until a message from the user arrives, or even reset the dialog stack altogether. - -## Serialization - -The dialog stack and the state of all active dialogs are serialized to the per-user, per-conversation -[IBotDataBag][iBotDataBag]. -The serialized blob is persisted in the messages that the bot sends to and receives from -the [Connector](bot-builder-dotnet-concepts.md#connector). -To be serialized, a `Dialog` class must include the `[Serializable]` attribute. -All `IDialog` implementations in the [Builder][builderLibrary] library are marked as serializable. - -The [Chain methods](#dialog-chains) provide a fluent interface to dialogs that is usable in LINQ query syntax. -The compiled form of LINQ query syntax often uses anonymous methods. -If these anonymous methods do not reference the environment of local variables, then these anonymous methods have no state and are trivially serializable. -However, if the anonymous method captures any local variable in the environment, -the resulting closure object (generated by the compiler) is not marked as serializable. -In this situation, Bot Builder will throw a `ClosureCaptureException` to identify the issue. - -To use reflection to serialize classes that are not marked as serializable, the -Builder library includes a reflection-based serialization surrogate that you can use to register with [Autofac][autofac]. - -[!code-csharp[Serialization](../includes/code/dotnet-dialogs.cs#serialization)] - -## Dialog chains - -While you can explicitly manage the stack of active dialogs by using `IDialogStack.Call` and `IDialogStack.Done`, you can also implicitly manage the stack of -active dialogs by using these fluent [Chain][chain] methods. - - -| Method | Type | Notes | -|-----------------------------|---------|------------------------------------------------------------------------| -| Chain.Select | LINQ | Supports "select" and "let" in LINQ query syntax. | -| Chain.SelectMany | LINQ | Supports successive "from" in LINQ query syntax. | -| Chain.Where | LINQ | Supports "where" in LINQ query syntax. | -| Chain.From | Chains | Instantiates a new instance of a dialog. | -| Chain.Return | Chains | Returns a constant value into the chain. | -| Chain.Do | Chains | Allows for side-effects within the chain. | -| Chain.ContinueWith | Chains | Simple chaining of dialogs. | -| Chain.Unwrap | Chains | Unwrap a dialog nested in a dialog. | -| Chain.DefaultIfException | Chains | Swallows an exception from the previous result and returns default(T). | -| Chain.Loop | Branch | Loops the entire chain of dialogs. | -| Chain.Fold | Branch | Folds results from an enumeration of dialogs into a single result. | -| Chain.Switch | Branch | Supports branching into different dialog chains. | -| Chain.PostToUser | Message | Posts a message to the user. | -| Chain.WaitToBot | Message | Waits for a message to the bot. | -| Chain.PostToChain | Message | Starts a chain with a message from the user. | - -### Examples - -The LINQ query syntax uses the `Chain.Select` method. - -[!code-csharp[Chain.Select](../includes/code/dotnet-dialogs.cs#chain1)] - -Or the `Chain.SelectMany` method. - -[!code-csharp[Chain.SelectMany](../includes/code/dotnet-dialogs.cs#chain2)] - -The `Chain.PostToUser` and `Chain.WaitToBot` methods post messages from the bot to the user and vice versa. - -[!code-csharp[Chain.PostToUser](../includes/code/dotnet-dialogs.cs#chain3)] - -The `Chain.Switch` method branches the conversation dialog flow. - -[!code-csharp[Chain.Switch](../includes/code/dotnet-dialogs.cs#chain4)] - -If `Chain.Switch` returns a nested `IDialog>`, then the inner `IDialog` can be unwrapped with `Chain.Unwrap`. This allows branching conversations to different paths of chained dialogs, possibly of unequal length. This example shows a more complete example of branching dialogs written in the fluent chain style with implicit stack management. - -[!code-csharp[Chain.Switch](../includes/code/dotnet-dialogs.cs#chain5)] - -## Next steps - -Dialogs manage conversation flow between a bot and a user. A dialog defines how to interact with a user. A bot can use many dialogs organized in stacks to guide the conversation with the user. In the next section, see how the dialog stack grows and shrinks as you create and dismiss dialogs in the stack. - -> [!div class="nextstepaction"] -> [Manage conversation flow with dialogs](bot-builder-dotnet-manage-conversation-flow.md) - - -[builderLibrary]: /dotnet/api/microsoft.bot.builder.dialogs - -[iBotData]: /dotnet/api/microsoft.bot.builder.dialogs.internals.ibotdata - -[iBotToUser]: /dotnet/api/microsoft.bot.builder.dialogs.internals.ibottouser - -[iDialogStack]: /dotnet/api/microsoft.bot.builder.dialogs.internals.idialogstack - -[iBotDataBag]: /dotnet/api/microsoft.bot.builder.dialogs.ibotdatabag - -[autofac]: /dotnet/api/microsoft.bot.builder.autofac.base - -[chain]: /dotnet/api/microsoft.bot.builder.dialogs.chain diff --git a/articles/dotnet/bot-builder-dotnet-formflow-advanced.md b/articles/dotnet/bot-builder-dotnet-formflow-advanced.md deleted file mode 100644 index c9c47ee5b..000000000 --- a/articles/dotnet/bot-builder-dotnet-formflow-advanced.md +++ /dev/null @@ -1,359 +0,0 @@ ---- -title: Advanced features of FormFlow - Bot Service -description: Learn how to customize user experience using FormFlow and the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Advanced features of FormFlow - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -[Basic features of FormFlow](bot-builder-dotnet-formflow.md) describes a basic FormFlow -implementation that delivers a fairly generic user experience. -To deliver a more customized user experience using FormFlow, you can specify initial form state, -add business logic to manage interdependencies between fields and process user input, -and use attributes to customize prompts, override templates, -designate optional fields, match user input, and validate user input. - -## Specify initial form state and entities - -When you launch a [FormDialog][formDialog], you may optionally pass in an instance of your state. -If you do pass in an instance of your state, then by default, -FormFlow will skip steps for any fields that already contain values; -the user will not be prompted for those fields. -To force the form to prompt the user for all fields (including those fields that already contain values in the -initial state), pass in [FormOptions.PromptFieldsWithValues][promptFieldsWithValues] when you launch -the `FormDialog`. If a field contains an initial value, the prompt will use that value as the default value. - -You can also pass in [LUIS](https://luis.ai/) entities to bind to the state. -If the `EntityRecommendation.Type` is a path to a field in your C# class, -the `EntityRecommendation.Entity` will be passed through the recognizer to bind to your field. -FormFlow will skip steps for any fields that are bound to an entity; -the user will not be prompted for those fields. - -## Add business logic - -To handle interdependencies between form fields or apply specific logic during the process of getting or setting -a field value, you can specify business logic within a validation function. -A validation function lets you manipulate the state and return a [ValidateResult][validateResult] object that can contain: - -- a feedback string that describes the reason that a value is invalid -- a transformed value -- a set of choices for clarifying a value - -This code example shows a validation function for the `Toppings` field. -If input for the field contains the `ToppingOptions.Everything` enumeration value, the function -ensures that the `Toppings` field value contains the full list of toppings. - -[!code-csharp[Validation function](../includes/code/dotnet-formflow-advanced.cs#validationFunction)] - -In addition to the validation function, you can add the [Term](#match-user-input-using-the-terms-attribute) attribute -to match user expressions such as "everything" or "not". - -[!code-csharp[Terms for Toppings](../includes/code/dotnet-formflow-advanced.cs#toppingsTerms)] - -Using the validation function shown above, this snippet shows the -interaction between bot and user when the user requests "everything but Jalapenos." - -```console -Please select one or more toppings (current choice: No Preference) - 1. Everything - 2. Avocado - 3. Banana Peppers - 4. Cucumbers - 5. Green Bell Peppers - 6. Jalapenos - 7. Lettuce - 8. Olives - 9. Pickles - 10. Red Onion - 11. Spinach - 12. Tomatoes -> everything but jalapenos -For sandwich toppings you have selected Avocado, Banana Peppers, Cucumbers, Green Bell Peppers, Lettuce, Olives, Pickles, Red Onion, Spinach, and Tomatoes. -``` - -## FormFlow attributes - -You can add these C# attributes to your class to customize behavior of a FormFlow dialog. - -| Attribute | Purpose | -|----|----| -| [Describe][describeAttribute] | Alter how a field or a value is shown in a template or card | -| [Numeric][numericAttribute] | Restrict the accepted values of a numeric field | -| [Optional][optionalAttribute] | Mark a field as optional | -| [Pattern][patternAttribute] | Define a regular expression to validate a string field | -| [Prompt][promptAttribute] | Define the prompt for a field | -| [Template][templateAttribute] | Define the template to use to generate prompts or values in prompts | -| [Terms][termsAttribute] | Define the input terms that match a field or value | - -## Customize prompts using the Prompt attribute - -Default prompts are automatically generated for each field in your form, -but you can specify a custom prompt for any field by using the `Prompt` attribute. -For example, if the default prompt for the `SandwichOrder.Sandwich` field is "Please select a sandwich", -you can add the `Prompt` attribute to specify a custom prompt for that field. - -[!code-csharp[Prompt attribute](../includes/code/dotnet-formflow-advanced.cs#promptAttribute)] - -This example uses [pattern language](bot-builder-dotnet-formflow-pattern-language.md) -to dynamically populate the prompt with form data at runtime: `{&}` is replaced with the description -of the field and `{||}` is replaced with the list of choices in the enumeration. - -> [!NOTE] -> By default, the description of a field is generated from the field's name. -> To specify a custom description for a field, add the `Describe` attribute. - -This snippet shows the customized prompt that is specified by the example above. - -```console -What kind of sandwich would you like? -1. BLT -2. Black Forest Ham -3. Buffalo Chicken -4. Chicken And Bacon Ranch Melt -5. Cold Cut Combo -6. Meatball Marinara -7. Oven Roasted Chicken -8. Roast Beef -9. Rotisserie Style Chicken -10. Spicy Italian -11. Steak And Cheese -12. Sweet Onion Teriyaki -13. Tuna -14. Turkey Breast -15. Veggie -> -``` - -A `Prompt` attribute may also specify parameters that affect how the form displays the prompt. -For example, the `ChoiceFormat` parameter determines how the form renders the list of choices. - -[!code-csharp[Prompt attribute ChoiceFormat parameter](../includes/code/dotnet-formflow-advanced.cs#promptChoice)] - -In this example, the value of the `ChoiceFormat` parameter indicates that the choices should be -displayed as a bulleted list (instead of a numbered list). - -```console -What kind of sandwich would you like? -- BLT -- Black Forest Ham -- Buffalo Chicken -- Chicken And Bacon Ranch Melt -- Cold Cut Combo -- Meatball Marinara -- Oven Roasted Chicken -- Roast Beef -- Rotisserie Style Chicken -- Spicy Italian -- Steak And Cheese -- Sweet Onion Teriyaki -- Tuna -- Turkey Breast -- Veggie -> -``` - -## Customize prompts using the Template attribute - -While the `Prompt` attribute enables you to customize the prompt for a single field, -the `Template` attribute enables you to replace the default templates that FormFlow uses to automatically -generate prompts. -This code example uses the `Template` attribute to redefine how the form handles -all enumeration fields. The attribute indicates that the user may select only one item, -sets the prompt text by using [pattern language](bot-builder-dotnet-formflow-pattern-language.md), -and specifies that the form should display only one item per line. - -[!code-csharp[Template attribute](../includes/code/dotnet-formflow-advanced.cs#templateAttribute)] - -This snippet shows the resulting prompts for the `Bread` field and `Cheese` field. - -```console -What kind of bread would you like on your sandwich? - 1. Nine Grain Wheat - 2. Nine Grain Honey Oat - 3. Italian - 4. Italian Herbs And Cheese - 5. Flatbread -> - -What kind of cheese would you like on your sandwich? - 1. American - 2. Monterey Cheddar - 3. Pepperjack -> -``` - -If you use the `Template` attribute to replace the default templates that FormFlow uses to -generate prompts, you may want to interject some variation into the prompts and messages -that the form generates. -To do so, you can define multiple text strings using -[pattern language](bot-builder-dotnet-formflow-pattern-language.md), and the form will randomly choose -from the available options each time it needs to display a prompt or message. - -This code example redefines the [TemplateUsage.NotUnderstood][notUnderstood] -template to specify two different variations of -message. When the bot needs to communicate that it does not understand a user's input, it will -determine message contents by randomly selecting one of the two text strings. - -[!code-csharp[Template variations of message](../includes/code/dotnet-formflow-advanced.cs#templateMessages)] - -This snippet shows an example of the resulting the interaction between bot and user. - -```console -What size of sandwich do you want? (1. Six Inch, 2. Foot Long) -> two feet -I do not understand "two feet". -> two feet -Try again, I don't get "two feet" -> -``` - -## Designate a field as optional using the Optional attribute - -To designate a field as optional, use the `Optional` attribute. -This code example specifies that the `Cheese` field is optional. - -[!code-csharp[Optional attribute](../includes/code/dotnet-formflow-advanced.cs#optionalAttribute)] - -If a field is optional and no value has been specified, -the current choice will be displayed as "No Preference". - -```console -What kind of cheese would you like on your sandwich? (current choice: No Preference) - 1. American - 2. Monterey Cheddar - 3. Pepperjack - > -``` - -If a field is optional and the user has specified a value, -"No Preference" will be displayed as the last choice in the list. - -```console -What kind of cheese would you like on your sandwich? (current choice: American) - 1. American - 2. Monterey Cheddar - 3. Pepperjack - 4. No Preference -> -``` - -## Match user input using the Terms attribute - -When a user sends a message to a bot that is built using FormFlow, -the bot attempts to identify the meaning of the user's input by matching the input to a list of terms. -By default, the list of terms is generated by applying these steps to the field or value: - -1. Break on case changes and underscore (_). -2. Generate each n-gram up to a maximum length. -3. Add "s?" to the end of each word (to support plurals). - -For example, the value "AngusBeefAndGarlicPizza" would generate these terms: - -- 'angus?' -- 'beefs?' -- 'garlics?' -- 'pizzas?' -- 'angus? beefs?' -- 'garlics? pizzas?' -- 'angus beef and garlic pizza' - -To override this default behavior and define the list of terms that are used to match -user input to a field or a value in a field, use the `Terms` attribute. -For example, you may use the `Terms` attribute (with a regular expression) to account for the fact that users are -likely to misspell the word "rotisserie." - -[!code-csharp[Terms attribute](../includes/code/dotnet-formflow-advanced.cs#termsAttribute)] - -By using the `Terms` attribute, you increase the likelihood of -being able to match user input with one of the valid choices. -The `Terms.MaxPhrase` parameter in this example causes the `Language.GenerateTerms` to generate additional variations of terms. - -This snippet shows the resulting interaction between bot and user when the user misspells "Rotisserie." - -```console -What kind of sandwich would you like? - 1. BLT - 2. Black Forest Ham - 3. Buffalo Chicken - 4. Chicken And Bacon Ranch Melt - 5. Cold Cut Combo - 6. Meatball Marinara - 7. Oven Roasted Chicken - 8. Roast Beef - 9. Rotisserie Style Chicken - 10. Spicy Italian - 11. Steak And Cheese - 12. Sweet Onion Teriyaki - 13. Tuna - 14. Turkey Breast - 15. Veggie -> rotissary checkin -For sandwich I understood Rotisserie Style Chicken. "checkin" is not an option. -``` - -## Validate user input using the Numeric attribute or Pattern attribute - -To restrict the range of allowed values for a numeric field, use the `Numeric` attribute. -This code example uses the `Numeric` attribute to specify that input for the `Rating` field -must be a number between 1 and 5. - -[!code-csharp[Numeric attribute](../includes/code/dotnet-formflow-advanced.cs#numericAttribute)] - -To specify the required format for the value of a particular field, use the `Pattern` attribute. -This code example uses the `Pattern` attribute to specify the required format for the value of the -`PhoneNumber` field. - -[!code-csharp[Pattern attribute](../includes/code/dotnet-formflow-advanced.cs#patternAttribute)] - -## Summary - -This article has described how to deliver a customized user experience with FormFlow -by specifying initial form state, -adding business logic to manage interdependencies between fields and process user input, -and using attributes to customize prompts, override templates, -designate optional fields, match user input, and validate user input. -For information about additional ways to customize the user experience with FormFlow, -see [Customize a form using FormBuilder](bot-builder-dotnet-formflow-formbuilder.md). - -## Sample code - -[!INCLUDE [Sample code](../includes/snippet-dotnet-formflow-samples.md)] - -## Additional resources - -- [Basic features of FormFlow](bot-builder-dotnet-formflow.md) -- [Customize a form using FormBuilder](bot-builder-dotnet-formflow-formbuilder.md) -- [Localize form content](bot-builder-dotnet-formflow-localize.md) -- [Define a form using JSON schema](bot-builder-dotnet-formflow-json-schema.md) -- [Customize user experience with pattern language](bot-builder-dotnet-formflow-pattern-language.md) -- Bot Framework SDK for .NET Reference - -[formDialog]: /dotnet/api/microsoft.bot.builder.formflow.formdialog - -[promptFieldsWithValues]: /dotnet/api/microsoft.bot.builder.formflow.formoptions.promptfieldswithvalues - -[validateResult]: /dotnet/api/microsoft.bot.builder.formflow.validateresult - -[describeAttribute]: /dotnet/api/microsoft.bot.builder.formflow.describeattribute - -[numericAttribute]: /dotnet/api/microsoft.bot.builder.formflow.numericattribute - -[optionalAttribute]: /dotnet/api/microsoft.bot.builder.formflow.optionalattribute - -[patternAttribute]: /dotnet/api/microsoft.bot.builder.formflow.patternattribute - -[promptAttribute]: /dotnet/api/microsoft.bot.builder.formflow.promptattribute - -[templateAttribute]: /dotnet/api/microsoft.bot.builder.formflow.templateattribute - -[termsAttribute]: /dotnet/api/microsoft.bot.builder.formflow.termsattribute - -[notUnderstood]: /dotnet/api/microsoft.bot.builder.formflow.templateusage.notunderstood diff --git a/articles/dotnet/bot-builder-dotnet-formflow-formbuilder.md b/articles/dotnet/bot-builder-dotnet-formflow-formbuilder.md deleted file mode 100644 index 3d83e5065..000000000 --- a/articles/dotnet/bot-builder-dotnet-formflow-formbuilder.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: Customize a form using FormBuilder - Bot Service -description: Learn how to dynamically change and customize the conversation flow and contents using FormBuilder for the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Customize a form using FormBuilder - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -[Basic features of FormFlow](bot-builder-dotnet-formflow.md) describes a basic FormFlow implementation that -delivers a fairly generic user experience, and [Advanced features of FormFlow](bot-builder-dotnet-formflow-advanced.md) describes how you can -customize user experience by using business logic and attributes. -This article describes how you can use -[FormBuilder][formBuilder] to customize user experience even further, by -specifying the sequence in which the form executes steps -and dynamically defining field values, confirmations, and messages. - -## Dynamically define field values, confirmations, and messages - -Using FormBuilder, you can dynamically define field values, confirmations, and messages. - -### Dynamically define field values - -A sandwich bot that is designed to add a free drink or cookie to any order that specifies a foot-long sandwich -uses the `Sandwich.Specials` field to store data about free items. -In this case, the value of the `Sandwich.Specials` field must be dynamically set -for each order according to whether or not the order contains a foot-long sandwich. - -The `Specials` field is specified as optional and "None" is designated as text for the choice that indicates no preference. - -[!code-csharp[Field definition](../includes/code/dotnet-formflow-formbuilder.cs#fieldDefinition)] - -This code example shows how to dynamically set the value of the `Specials` field. - -[!code-csharp[Define value](../includes/code/dotnet-formflow-formbuilder.cs#defineValue)] - -In this example, the [Advanced.Field.SetType][setType] method specifies -the field type (`null` represents an enumeration field). -The [Advanced.Field.SetActive][setActive] method specifies that the field -should only be enabled if the length of the sandwich is `Length.FootLong`. -Finally, the [Advanced.Field.SetDefine][setDefine] method specifies an async -delegate that defines the field. -The delegate is passed the current state object and the [Advanced.Field][field] that is being dynamically defined. -The delegate uses the field's fluent methods to dynamically define values. -In this example, the values are strings and the `AddDescription` and `AddTerms` methods specify the descriptions and terms for each value. - -> [!NOTE] -> To dynamically define a field value, you can implement -> [Advanced.IField][iField] yourself, -> or streamline the process by using the [Advanced.FieldReflector][FieldReflector] class as shown in the example above. - -### Dynamically define messages and confirmations - -Using FormBuilder, you can also dynamically define messages and confirmations. -Each message and confirmation runs only when prior steps in the form are inactive or completed. - -This code example shows a dynamically generated confirmation that computes the cost of the sandwich. - -[!code-csharp[Define confirmation](../includes/code/dotnet-formflow-formbuilder.cs#defineConfirmation)] - -## Customize a form using FormBuilder - -This code example uses FormBuilder to define the steps of the form, -[validate selections](bot-builder-dotnet-formflow-advanced.md#add-business-logic), -and [dynamically define a field value and confirmation](#dynamically-define-field-values-confirmations-and-messages). -By default, steps in the form will be executed in the sequence in which they are listed. -However, steps might be skipped for fields that already contain values or if explicit navigation is specified. - -[!code-csharp[FormBuilder form](../includes/code/dotnet-formflow-formbuilder.cs#formBuilderForm)] - -In this example, the form executes these steps: - -- Shows a welcome message. -- Fills in `SandwichOrder.Sandwich`. -- Fills in `SandwichOrder.Length`. -- Fills in `SandwichOrder.Bread`. -- Fills in `SandwichOrder.Cheese`. -- Fills in `SandwichOrder.Toppings` and adds missing values if the user selected `ToppingOptions.Everything`. --. Shows a message that confirms the selected toppings. -- Fills in `SandwichOrder.Sauces`. -- [Dynamically defines](#dynamically-define-field-values) the field value for `SandwichOrder.Specials`. -- [Dynamically defines](#dynamically-define-messages-and-confirmations) the confirmation for cost of the sandwich. -- Fills in `SandwichOrder.DeliveryAddress` and [verifies](bot-builder-dotnet-formflow-advanced.md#add-business-logic) the resulting string. If the address does not start with a number, the form returns a message. -- Fills in `SandwichOrder.DeliveryTime` with a custom prompt. -- Confirms the order. -- Adds any remaining fields that were defined in the class but not explicitly referenced by `Field`. (If the example did not call the `AddRemainingFields` method, the form would not include any fields that were not explicity referenced.) -- Shows a thank you message. -- Defines an `OnCompletionAsync` handler to process the order. - -## Sample code - -[!INCLUDE [Sample code](../includes/snippet-dotnet-formflow-samples.md)] - -## Additional resources - -- [Basic features of FormFlow](bot-builder-dotnet-formflow.md) -- [Advanced features of FormFlow](bot-builder-dotnet-formflow-advanced.md) -- [Localize form content](bot-builder-dotnet-formflow-localize.md) -- [Define a form using JSON schema](bot-builder-dotnet-formflow-json-schema.md) -- [Customize user experience with pattern language](bot-builder-dotnet-formflow-pattern-language.md) -- Bot Framework SDK for .NET Reference - -[formBuilder]: /dotnet/api/microsoft.bot.builder.formflow.formbuilder-1 - -[setType]: /dotnet/api/microsoft.bot.builder.formflow.advanced.field-1.settype - -[setActive]: /dotnet/api/microsoft.bot.builder.formflow.advanced.field-1.setactive - -[setDefine]: /dotnet/api/microsoft.bot.builder.formflow.advanced.field-1.setdefine - -[field]: /dotnet/api/microsoft.bot.builder.formflow.advanced.field-1 - -[iField]: /dotnet/api/microsoft.bot.builder.formflow.advanced.ifield-1 - -[FieldReflector]: /dotnet/api/microsoft.bot.builder.formflow.advanced.fieldreflector-1 diff --git a/articles/dotnet/bot-builder-dotnet-formflow-json-schema.md b/articles/dotnet/bot-builder-dotnet-formflow-json-schema.md deleted file mode 100644 index c7baa5a10..000000000 --- a/articles/dotnet/bot-builder-dotnet-formflow-json-schema.md +++ /dev/null @@ -1,351 +0,0 @@ ---- -title: Define a form using JSON schema and FormFlow - Bot Service -description: Learn how to define a form using JSON schema and FormFlow with the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Define a form using JSON schema - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -If you use a [C# class](bot-builder-dotnet-formflow.md#create-class) to define the form -when you create a bot with FormFlow, -the form derives from the static definition of your type in C#. -As an alternative, you may instead define the form by using -JSON schema. -A form that is defined using JSON schema is purely data-driven; -you can change the form (and therefore, the behavior of the bot) simply by updating the schema. - -The JSON schema describes the fields within your -JObject -and -includes annotations that control prompts, templates, and terms. -To use JSON schema with FormFlow, you must add the `Microsoft.Bot.Builder.FormFlow.Json` NuGet package to your -project and import the `Microsoft.Bot.Builder.FormFlow.Json` namespace. - -## Standard keywords - -FormFlow supports these standard JSON Schema -keywords: - -| Keyword | Description | -|----|----| -| type | Defines the type of data that the field contains. | -| enum | Defines the valid values for the field. | -| minimum | Defines the minimum numeric value allowed for the field (as described in [NumericAttribute][numericAttribute]). | -| maximum | Defines the maximum numeric value allowed for the field (as described in [NumericAttribute][numericAttribute]). | -| required | Defines which fields are required. | -| pattern | Validates string values (as described in [PatternAttribute][patternAttribute]). | - -## Extensions to JSON Schema - -FormFlow extends the standard JSON Schema -to support several additional properties. - -### Additional properties at the root of the schema - -| Property | Value | -|----|----| -| OnCompletion | C# script with arguments `(IDialogContext context, JObject state)` for completing the form. | -| References | References to include in scripts. For example, `[assemblyReference, ...]`. Paths should be absolute or relative to the current directory. By default, the script includes `Microsoft.Bot.Builder.dll`. | -| Imports | Imports to include in scripts. For example, `[import, ...]`. By default, the script includes the `Microsoft.Bot.Builder`, `Microsoft.Bot.Builder.Dialogs`, `Microsoft.Bot.Builder.FormFlow`, `Microsoft.Bot.Builder.FormFlow.Advanced`, `System.Collections.Generic`, and `System.Linq` namespaces. | - -### Additional properties at the root of the schema or as peers of the type property - -| Property | Value | -|----|----| -| Templates | `{ TemplateUsage: { Patterns: [string, ...], }, ...}` | -| Prompt | `{ Patterns:[string, ...] }` | - -To specify templates and prompts in JSON schema, use the same vocabulary as defined by -[TemplateAttribute][templateAttribute] and [PromptAttribute][promptAttribute]. -Property names and values in the schema should match the property names and values in the underlying C# enumeration. -For example, this schema snippet defines a template that overrides the `TemplateUsage.NotUnderstood` template and specifies a `TemplateBaseAttribute.ChoiceStyle`: - -```json -"Templates":{ "NotUnderstood": { "Patterns": ["I don't get it"], "ChoiceStyle":"Auto"}} -``` - -### Additional properties as peers of the type property - -| Property | Contents | Description | -|--------------|-----------------------------|------------------------------------------------------------------------------------------------------------------| -| DateTime | bool | Indicates whether field is a `DateTime` field. | -| Describe | string or object | Description of a field as described in [DescribeAttribute][describeAttribute]. | -| Terms | `[string,...]` | Regular expressions for matching a field value as described in TermsAttribute. | -| MaxPhrase | int | Runs your terms through `Language.GenerateTerms(string, int)` to expand them. | -| Values | `{ string: {Describe:string | object, Terms:[string, ...], MaxPhrase}, ...}` | -| Active | script | C# script with arguments `(JObject state)->bool` to test whether the field, message, or confirmation is active. | -| Validate | script | C# script with arguments `(JObject state, object value)->ValidateResult` for validating a field value. | -| Define | script | C# script with arguments `(JObject state, Field field)` for dynamically defining a field. | -| Next | script | C# script with arguments `(object value, JObject state)` for determining the next step after filling in a field. | -| Before | `[confirm | message, ...]` | -| After | `[confirm | message, ...]` | -| Dependencies | [string, ...] | Fields that this field, message, or confirmation depends on. | - -Use `{Confirm:script|[string, ...], ...templateArgs}` within the value of the **Before** property or -the **After** property to define a confirmation by using either a C# script with argument `(JObject state)` -or a set of patterns that will be randomly selected with optional template arguments. - -Use `{Message:script|[string, ...] ...templateArgs}` within the value of the **Before** property or -the **After** property to define a message by using either a C# script with argument `(JObject state)` -or a set of patterns that will be randomly selected with optional template arguments. - -## Scripts - -Several of the properties that are described above contain a script as the property value. -A script can be any snippet of C# code that you might normally find in the body of a method. -You can add references by using the **References** property and/or the **Imports** property. -Special global variables include: - -| Variable | Description | -|----|----| -| choice | Internal dispatch for the script to execute. | -| state | `JObject` form state bound for all scripts. | -| ifield | `IField` to allow reasoning over the current field for all scripts except Message/Confirm prompt builders. | -| value | Object value to be validated for **Validate**. | -| field | `Field` to allow dynamically updating a field in **Define**. | -| context | `IDialogContext` context to allow posting results in **OnCompletion**. | - -Fields that are defined via JSON schema have the same ability to extend or override the definitions programatically as any other field. They can also be localized in the same way. - -## JSON schema example - -The simplest way to define a form is to define everything, including any C# code, directly in the -JSON schema. -This example shows the JSON schema for the annotated sandwich bot that is described in -[Customize a form using FormBuilder](bot-builder-dotnet-formflow-formbuilder.md). - -```json -{ - "References": [ "Microsoft.Bot.Sample.AnnotatedSandwichBot.dll" ], - "Imports": [ "Microsoft.Bot.Sample.AnnotatedSandwichBot.Resource" ], - "type": "object", - "required": [ - "Sandwich", - "Length", - "Ingredients", - "DeliveryAddress" - ], - "Templates": { - "NotUnderstood": { - "Patterns": [ "I do not understand \"{0}\".", "Try again, I don't get \"{0}\"." ] - }, - "EnumSelectOne": { - "Patterns": [ "What kind of {&} would you like on your sandwich? {||}" ], - "ChoiceStyle": "Auto" - } - }, - "properties": { - "Sandwich": { - "Prompt": { "Patterns": [ "What kind of {&} would you like? {||}" ] }, - "Before": [ { "Message": [ "Welcome to the sandwich order bot!" ] } ], - "Describe": { "Image": "https://placeholdit.imgix.net/~text?txtsize=16&txt=Sandwich&w=125&h=40&txttrack=0&txtclr=000&txtfont=bold" }, - "type": [ - "string", - "null" - ], - "enum": [ - "BLT", - "BlackForestHam", - "BuffaloChicken", - "ChickenAndBaconRanchMelt", - "ColdCutCombo", - "MeatballMarinara", - "OvenRoastedChicken", - "RoastBeef", - "RotisserieStyleChicken", - "SpicyItalian", - "SteakAndCheese", - "SweetOnionTeriyaki", - "Tuna", - "TurkeyBreast", - "Veggie" - ], - "Values": { - "RotisserieStyleChicken": { - "Terms": [ "rotis\\w* style chicken" ], - "MaxPhrase": 3 - } - } - }, - "Length": { - "Prompt": { - "Patterns": [ "What size of sandwich do you want? {||}" ] - }, - "type": [ - "string", - "null" - ], - "enum": [ - "SixInch", - "FootLong" - ] - }, - "Ingredients": { - "type": "object", - "required": [ "Bread" ], - "properties": { - "Bread": { - "type": [ - "string", - "null" - ], - "Describe": { - "Title": "Sandwich Bot", - "SubTitle": "Bread Picker" - }, - "enum": [ - "NineGrainWheat", - "NineGrainHoneyOat", - "Italian", - "ItalianHerbsAndCheese", - "Flatbread" - ] - }, - "Cheese": { - "type": [ - "string", - "null" - ], - "enum": [ - "American", - "MontereyCheddar", - "Pepperjack" - ] - }, - "Toppings": { - "type": "array", - "items": { - "type": "integer", - "enum": [ - "Everything", - "Avocado", - "BananaPeppers", - "Cucumbers", - "GreenBellPeppers", - "Jalapenos", - "Lettuce", - "Olives", - "Pickles", - "RedOnion", - "Spinach", - "Tomatoes" - ], - "Values": { - "Everything": { "Terms": [ "except", "but", "not", "no", "all", "everything" ] } - } - }, - "Validate": "var values = ((List) value).OfType(); var result = new ValidateResult {IsValid = true, Value = values} ; if (values != null && values.Contains(\"Everything\")) { result.Value = (from topping in new string[] { \"Avocado\", \"BananaPeppers\", \"Cucumbers\", \"GreenBellPeppers\", \"Jalapenos\", \"Lettuce\", \"Olives\", \"Pickles\", \"RedOnion\", \"Spinach\", \"Tomatoes\"} where !values.Contains(topping) select topping).ToList();} return result;", - "After": [ { "Message": [ "For sandwich toppings you have selected {Ingredients.Toppings}." ] } ] - }, - "Sauces": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string", - "enum": [ - "ChipotleSouthwest", - "HoneyMustard", - "LightMayonnaise", - "RegularMayonnaise", - "Mustard", - "Oil", - "Pepper", - "Ranch", - "SweetOnion", - "Vinegar" - ] - } - } - } - }, - "Specials": { - "Templates": { - "NoPreference": { "Patterns": [ "None" ] } - }, - "type": [ - "string", - "null" - ], - "Active": "return (string) state[\"Length\"] == \"FootLong\";", - "Define": "field.SetType(null).AddDescription(\"cookie\", DynamicSandwich.FreeCookie).AddTerms(\"cookie\", Language.GenerateTerms(DynamicSandwich.FreeCookie, 2)).AddDescription(\"drink\", DynamicSandwich.FreeDrink).AddTerms(\"drink\", Language.GenerateTerms(DynamicSandwich.FreeDrink, 2)); return true;", - "After": [ { "Confirm": "var cost = 0.0; switch ((string) state[\"Length\"]) { case \"SixInch\": cost = 5.0; break; case \"FootLong\": cost=6.50; break;} return new PromptAttribute($\"Total for your sandwich is {cost:C2} is that ok?\");" } ] - }, - "DeliveryAddress": { - "type": [ - "string", - "null" - ], - "Validate": "var result = new ValidateResult{ IsValid = true, Value = value}; var address = (value as string).Trim(); if (address.Length > 0 && (address[0] < '0' || address[0] > '9')) {result.Feedback = DynamicSandwich.BadAddress; result.IsValid = false; } return result;" - }, - "PhoneNumber": { - "type": [ "string", "null" ], - "pattern": "(\\(\\d{3}\\))?\\s*\\d{3}(-|\\s*)\\d{4}" - }, - "DeliveryTime": { - "Templates": { - "StatusFormat": { - "Patterns": [ "{&}: {:t}" ], - "FieldCase": "None" - } - }, - "DateTime": true, - "type": [ - "string", - "null" - ], - "After": [ { "Confirm": [ "Do you want to order your {Length} {Sandwich} on {Ingredients.Bread} {&Ingredients.Bread} with {[{Ingredients.Cheese} {Ingredients.Toppings} {Ingredients.Sauces} to be sent to {DeliveryAddress} {?at {DeliveryTime}}?" ] } ] - }, - "Rating": { - "Describe": "your experience today", - "type": [ - "number", - "null" - ], - "minimum": 1, - "maximum": 5, - "After": [ { "Message": [ "Thanks for ordering your sandwich!" ] } ] - } - }, - "OnCompletion": "await context.PostAsync(\"We are currently processing your sandwich. We will message you the status.\");" -} -``` - -## Implement FormFlow with JSON schema - -To implement FormFlow with a JSON schema, use `FormBuilderJson`, which supports the same fluent interface as `FormBuilder`. This code example shows how to implement the JSON schema for the annotated sandwich bot -that is described in [Customize a form using FormBuilder](bot-builder-dotnet-formflow-formbuilder.md). - -[!code-csharp[Use JSON schema](../includes/code/dotnet-formflow-json-schema.cs#useSchema)] - -## Sample code - -[!INCLUDE [Sample code](../includes/snippet-dotnet-formflow-samples.md)] - -## Additional resources - -- [Basic features of FormFlow](bot-builder-dotnet-formflow.md) -- [Advanced features of FormFlow](bot-builder-dotnet-formflow-advanced.md) -- [Customize a form using FormBuilder](bot-builder-dotnet-formflow-formbuilder.md) -- [Localize form content](bot-builder-dotnet-formflow-localize.md) -- [Customize user experience with pattern language](bot-builder-dotnet-formflow-pattern-language.md) -- Bot Framework SDK for .NET Reference - -[numericAttribute]: /dotnet/api/microsoft.bot.builder.formflow.numericattribute - -[patternAttribute]: /dotnet/api/microsoft.bot.builder.formflow.patternattribute - -[templateAttribute]: /dotnet/api/microsoft.bot.builder.formflow.templateattribute - -[promptAttribute]: /dotnet/api/microsoft.bot.builder.formflow.promptattribute - -[describeAttribute]: /dotnet/api/microsoft.bot.builder.formflow.describeattribute diff --git a/articles/dotnet/bot-builder-dotnet-formflow-localize.md b/articles/dotnet/bot-builder-dotnet-formflow-localize.md deleted file mode 100644 index ce4d15c2a..000000000 --- a/articles/dotnet/bot-builder-dotnet-formflow-localize.md +++ /dev/null @@ -1,184 +0,0 @@ ---- -title: Localize form content - Bot Service -description: Learn how to localize form content with FormFlow and the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/02/2018 -monikerRange: 'azure-bot-service-3.0' ---- - -# Localize form content - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -A form's localization language is determined by the current thread's [CurrentUICulture](https://msdn.microsoft.com/library/system.threading.thread.currentuiculture(v=vs.110).aspx) and [CurrentCulture](https://msdn.microsoft.com/library/system.threading.thread.currentculture(v=vs.110).aspx). -By default, the culture derives from the **Locale** field of the current message, but you can -override that default behavior. -Depending on how your bot is constructed, localized information may come from up to three different sources: - -- the built-in localization for **PromptDialog** and **FormFlow** -- a resource file that you generate for the static strings in your form -- a resource file that you create with strings for dynamically-computed fields, messages or confirmations - -## Generate a resource file for the static strings in your form - -Static strings in a form include the strings that the form generates from the information in your C# class -and the strings that you specify as prompts, templates, messages or confirmations. -Strings that are generated from built-in templates are not considered static strings, since those strings are already localized. -Since many of the strings in a form are automatically generated, it is not feasible to use normal C# resource strings directly. -Instead, you can generate a resource file for the static strings in your form either by calling -`IFormBuilder.SaveResources` or by using the **RView** tool that is included with the BotBuilder SDK for .NET. - -### Use IFormBuilder.SaveResources - -You can generate a resource file by -calling [IFormBuilder.SaveResources][saveResources] on your form to save the strings to a .resx file. - -### Use RView - -Alternatively, you can generate a resource file that is based upon your .dll or .exe by using -the RView -tool that is included in the BotBuilder SDK for .NET. -To generate the .resx file, execute **rview** and specify the assembly that contains your static form-building method and the path to that method. -This snippet shows how to generate the `Microsoft.Bot.Sample.AnnotatedSandwichBot.SandwichOrder.resx` resource file using **RView**. - -```csharp -rview -g Microsoft.Bot.Sample.AnnotatedSandwichBot.dll Microsoft.Bot.Sample.AnnotatedSandwichBot.SandwichOrder.BuildForm -``` - -This excerpt shows part of the .resx file that is generated by executing this **rview** command. - -```xml - -Specials - - -Delivery Address - - -Delivery Time - - -Phone Number - - -your experience today - - -Welcome to the sandwich order bot! - - -sandwichs? - -``` - -## Configure your project - -After you have generated a resource file, add it to your project and then set the neutral language by -completing these steps: - -1. Right-click on your project and select **Application**. -2. Click **Assembly Information**. -3. Select the **Neutral Language** value that corresponds to the language in which you developed your bot. - -When your form is created, the [IFormBuilder.Build][build] method will automatically look for resources that contain your form type name and use them to localize the static strings in your form. - -> [!NOTE] -> Dynamically-computed fields that are defined using [Advanced.Field.SetDefine][setDefine] -> (as described in [Using Dynamic Fields](bot-builder-dotnet-formflow-formbuilder.md#dynamically-define-field-values-confirmations-and-messages)) -> cannot be localized in the same manner as static fields, -> since strings for dynamically-computed fields are constructed at the time the form is populated. -> However, you can localize dynamically-computed fields by using normal C# localization mechanisms. - -### Localize resource files - -After you have added resource files to your project, you can localize them by using the -Multilingual App Toolkit (MAT). -Install **MAT**, then enable it for your project by completing these steps: - -1. Select your project in the Visual Studio Solution Explorer. -2. Click **Tools**, **Multilingual App Toolkit**, and **Enable**. -3. Right-click the project and select **Multilingual App Toolkit**, **Add Translations** to select the translations. This will create industry-standard XLF files that you can automatically or manually translate. - -> [!NOTE] -> Although this article describes how to use the Multilingual App Toolkit to localize content, -> you may implement localization via a variety of other means. - -## See it in action - -This code example builds upon the one in [Customize a form using FormBuilder](bot-builder-dotnet-formflow-formbuilder.md) to implement localization as described above. -In this example, the `DynamicSandwich` class (not shown here) contains localization information for -dynamically-computed fields, messages and confirmations. - -[!code-csharp[Build localized form](../includes/code/dotnet-formflow-localize.cs#buildLocalizedForm)] - -This snippet shows the resulting interaction between bot and user when `CurrentUICulture` is **French**. - -```console -Bienvenue sur le bot d'ordre "sandwich" ! -Quel genre de "sandwich" vous souhaitez sur votre "sandwich"? - 1. BLT - 2. Jambon Forêt Noire - 3. Poulet Buffalo - 4. Faire fondre le poulet et Bacon Ranch - 5. Combo de coupe à froid - 6. Boulette de viande Marinara - 7. Poulet rôti au four - 8. Rôti de boeuf - 9. Rotisserie poulet - 10. Italienne piquante - 11. Bifteck et fromage - 12. Oignon doux Teriyaki - 13. Thon - 14. Poitrine de dinde - 15. Veggie -> 2 - -Quel genre de longueur vous souhaitez sur votre "sandwich"? - 1. Six pouces - 2. Pied Long -> ? -* Vous renseignez le champ longueur.Réponses possibles: -* Vous pouvez saisir un numéro 1-2 ou des mots de la description. (Six pouces, ou Pied Long) -* Retourner à la question précédente. -* Assistance: Montrez les réponses possibles. -* Abandonner: Abandonner sans finir -* Recommencer remplir le formulaire. (Vos réponses précédentes sont enregistrées.) -* Statut: Montrer le progrès en remplissant le formulaire jusqu'à présent. -* Vous pouvez passer à un autre champ en entrant son nom. ("Sandwich", Longueur, Pain, Fromage, Nappages, Sauces, Adresse de remise, Délai de livraison, ou votre expérience aujourd'hui). -Quel genre de longueur vous souhaitez sur votre "sandwich"? - 1. Six pouces - 2. Pied Long -> 1 - -Quel genre de pain vous souhaitez sur votre "sandwich"? - 1. Neuf grains de blé - 2. Neuf grains miel avoine - 3. Italien - 4. Fromage et herbes italiennes - 5. Pain plat -> neuf -Par pain "neuf" vouliez-vous dire (1. Neuf grains miel avoine, ou 2. Neuf grains de blé) -``` - -## Sample code - -[!INCLUDE [Sample code](../includes/snippet-dotnet-formflow-samples.md)] - -## Additional resources - -- [Basic features of FormFlow](bot-builder-dotnet-formflow.md) -- [Advanced features of FormFlow](bot-builder-dotnet-formflow-advanced.md) -- [Customize a form using FormBuilder](bot-builder-dotnet-formflow-formbuilder.md) -- [Define a form using JSON schema](bot-builder-dotnet-formflow-json-schema.md) -- [Customize user experience with pattern language](bot-builder-dotnet-formflow-pattern-language.md) -- Bot Framework SDK for .NET Reference - -[build]: /dotnet/api/microsoft.bot.builder.formflow.formbuilder-1.build - -[setDefine]: /dotnet/api/microsoft.bot.builder.formflow.advanced.field-1.setdefine - -[saveResources]: /dotnet/api/microsoft.bot.builder.formflow.iform-1.saveresources diff --git a/articles/dotnet/bot-builder-dotnet-formflow-pattern-language.md b/articles/dotnet/bot-builder-dotnet-formflow-pattern-language.md deleted file mode 100644 index ff3d90b96..000000000 --- a/articles/dotnet/bot-builder-dotnet-formflow-pattern-language.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -title: Customize user experience with pattern language - Bot Service -description: Learn how to customize FormFlow prompts and override FormFlow templates by using pattern language with the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Customize user experience with pattern language - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -When you customize a prompt or override a default template, you can -use pattern language to specify the contents and/or format of the prompt. - -## Prompts and templates - -A [prompt][promptAttribute] defines the message that is sent to the user to request a piece of information or ask for confirmation. You can customize a prompt by using the [Prompt attribute](bot-builder-dotnet-formflow-advanced.md#customize-prompts-using-the-prompt-attribute) or implicitly through [IFormBuilder.Field][field]. - -Forms use templates to automatically construct prompts and other things such as help. -You can override the default template of a class or field by using the [Template attribute](bot-builder-dotnet-formflow-advanced.md#customize-prompts-using-the-template-attribute). - -> [!TIP] -> The [FormConfiguration.Templates][formConfiguration] -> class defines a set of built-in templates that provide good examples of how to use pattern language. - -## Elements of pattern language - -Pattern language uses curly braces (`{}`) to identify elements that will be replaced at runtime with actual -values. This table lists the elements of pattern language. - -| Element | Description | -|----|----| -| `{}` | Shows the value of the current field (the field that the attribute applies to). | -| `{&}` | Shows the description of the current field (unless otherwise specified, this is the name of the field). | -| `{}` | Shows the value of the named field. | -| `{&}` | Shows the description of the named field. | -| {||} | Shows the current choice(s), which could be the current value of a field, "no preference" or the values of an enumeration. | -| `{[{} ...]}` | Shows a list of values from the named fields using [Separator][separator] and [LastSeparator][lastSeparator] to separate the individual values in the list. | -| `{*}` | Shows one line for each active field; each line contains the field description and current value. | -| `{*filled}` | Shows one line for each active field that contains an actual value; each line contains the field description and current value. | -| `{}` | A regular C# format specifier that applies to the nth argument of a template. For the list of available arguments, see [TemplateUsage][templateUsage]. | -| `{?...}` | Conditional substitution. If all referred to pattern elements have values, the values are substituted and the whole expression is used. | - -For the elements listed above: - -- The `` placeholder is the name of a field in your form class. For example, if your class contains a field with the name `Size`, you could specify `{Size}` as the pattern element. - -- An ellipses (`"..."`) within a pattern element indicates that the element may contain multiple values. - -- The `` placeholder is a C# format specifier. For example, if the class contains a field with the name `Rating` and of type `double`, you could specify `{Rating:F2}` as the pattern element to show two digits of precision. - -- The `` placeholder references the nth argument of a template. - -### Pattern language within a Prompt attribute - -This example uses the `{&}` element to show the description of the `Sandwich` field and the -`{||}` element to show the list of choices for that field. - -[!code-csharp[Patterns example](../includes/code/dotnet-formflow-pattern-language.cs#patterns1)] - -This is the resulting prompt: - -```console -What kind of sandwich would you like? -1. BLT -2. Black Forest Ham -3. Buffalo Chicken -4. Chicken And Bacon Ranch Melt -5. Cold Cut Combo -6. Meatball Marinara -7. Oven Roasted Chicken -8. Roast Beef -9. Rotisserie Style Chicken -10. Spicy Italian -11. Steak And Cheese -12. Sweet Onion Teriyaki -13. Tuna -14. Turkey Breast -15. Veggie -> -``` - -## Formatting parameters - -Prompts and templates support these formatting parameters. - -| Usage | Description | -|----|----| -| `AllowDefault` | Applies to {||} pattern elements. Determines whether the form should show the current value of the field as a possible choice. If `true`, the current value is shown as a possible value. The default is `true`. | -| `ChoiceCase` | Applies to {||} pattern elements. Determines whether the text of each choice is normalized (e.g., whether the first letter of each word is capitalized). The default is `CaseNormalization.None`. For possible values, see [CaseNormalization][caseNormalization]. | -| `ChoiceFormat` | Applies to {||} pattern elements. Determines whether to show a list of choices as a numbered list or a bulleted list. For a numbered list, set `ChoiceFormat` to `{0}` (default). For a bulleted list list, set `ChoiceFormat` to `{1}`. | -| `ChoiceLastSeparator` | Applies to {||} pattern elements. Determines whether an inline list of choices includes a separator before the last choice. | -| `ChoiceParens` | Applies to {||} pattern elements. Determines whether an inline list of choices is shown within parentheses. If `true`, the list of choices is shown within parentheses. The default is `true`. | -| `ChoiceSeparator` | Applies to {||} pattern elements. Determines whether an inline list of choices includes a separator before every choice except the last choice. | -| `ChoiceStyle` | Applies to {||} pattern elements. Determines whether the list of choices is shown inline or per line. The default is `ChoiceStyleOptions.Auto` which determines at runtime whether to show the choice inline or in a list. For possible values, see [ChoiceStyleOptions][choiceStyleOptions]. | -| `Feedback` | Applies to prompts only. Determines whether the form echoes the user's choice to indicate that the form understood the selection. The default is `FeedbackOptions.Auto` which echoes the user's input only if part of it is not understood. For possible values, see [FeedbackOptions][feedbackOptions]. | -| `FieldCase` | Determines whether the text of the field's description is normalized (e.g., whether the first letter of each word is capitalized). The default is `CaseNormalization.Lower` which converts the description to lowercase. For possible values, see [CaseNormalization][caseNormalization]. | -| `LastSeparator` | Applies to `{[]}` pattern elements. Determines whether an array of items includes a separator before the last item. | -| `Separator` | Applies to `{[]}` pattern elements. Determines whether an array of items includes a separator before every item in the array except the last item. | -| `ValueCase` | Determines whether the text of the field's value is normalized (e.g., whether the first letter of each word is capitalized)_. The default is `CaseNormalization.InitialUpper` which converts the first letter of each word to uppercase. For possible values, see [CaseNormalization][caseNormalization]. | - -### Prompt attribute with formatting parameter - -This example uses the `ChoiceFormat` parameter to specify that the list of choices should be displayed -as a bulleted list. - -[!code-csharp[Patterns example](../includes/code/dotnet-formflow-pattern-language.cs#patterns2)] - -This is the resulting prompt: - -```console -What kind of sandwich would you like? -* BLT -* Black Forest Ham -* Buffalo Chicken -* Chicken And Bacon Ranch Melt -* Cold Cut Combo -* Meatball Marinara -* Oven Roasted Chicken -* Roast Beef -* Rotisserie Style Chicken -* Spicy Italian -* Steak And Cheese -* Sweet Onion Teriyaki -* Tuna -* Turkey Breast -* Veggie -> -``` - -## Sample code - -[!INCLUDE [Sample code](../includes/snippet-dotnet-formflow-samples.md)] - -## Additional resources - -- [Basic features of FormFlow](bot-builder-dotnet-formflow.md) -- [Advanced features of FormFlow](bot-builder-dotnet-formflow-advanced.md) -- [Customize a form using FormBuilder](bot-builder-dotnet-formflow-formbuilder.md) -- [Localize form content](bot-builder-dotnet-formflow-localize.md) -- [Define a form using JSON schema](bot-builder-dotnet-formflow-json-schema.md) -- Bot Framework SDK for .NET Reference - -[promptAttribute]: /dotnet/api/microsoft.bot.builder.formflow.promptattribute - -[field]: /dotnet/api/microsoft.bot.builder.formflow.iformbuilder-1.field - -[formConfiguration]: /dotnet/api/microsoft.bot.builder.formflow.formconfiguration - -[separator]: /dotnet/api/microsoft.bot.builder.formflow.advanced.templatebaseattribute.separator - -[lastSeparator]: /dotnet/api/microsoft.bot.builder.formflow.advanced.templatebaseattribute.lastseparator - -[templateUsage]: /dotnet/api/microsoft.bot.builder.formflow.templateusage - -[caseNormalization]: /dotnet/api/microsoft.bot.builder.formflow.casenormalization - -[choiceStyleOptions]: /dotnet/api/microsoft.bot.builder.formflow.choicestyleoptions - -[feedbackOptions]: /dotnet/api/microsoft.bot.builder.formflow.feedbackoptions diff --git a/articles/dotnet/bot-builder-dotnet-formflow.md b/articles/dotnet/bot-builder-dotnet-formflow.md deleted file mode 100644 index 8a0f537cc..000000000 --- a/articles/dotnet/bot-builder-dotnet-formflow.md +++ /dev/null @@ -1,378 +0,0 @@ ---- -title: Basic features of FormFlow - Bot Service -description: Learn how to guide conversation flows using FormFlow within the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Basic features of FormFlow - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -[Dialogs](bot-builder-dotnet-dialogs.md) are very powerful and flexible, but handling a guided conversation such as ordering a sandwich can require a lot of effort. At each point in the conversation, there are many possibilities of what will happen next. For example, you may need to clarify an ambiguity, provide help, go back, or show progress. -By using **FormFlow** within the Bot Framework SDK for .NET, you can greatly simplify the process of managing -a guided conversation like this. - -FormFlow automatically generates the dialogs that are necessary to manage a guided conversation, -based upon guidelines that you specify. -Although using FormFlow sacrifices some of the flexibility that you might otherwise get by creating and managing -dialogs on your own, designing a guided conversation using FormFlow can significantly reduce the time it takes -to develop your bot. -Additionally, you may construct your bot using a combination of FormFlow-generated dialogs and other types of -dialogs. For example, a FormFlow dialog may guide the user through the process of completing a form, while a -[LuisDialog][LuisDialog] may evaluate user input to determine intent. - -This article describes how to create a bot that uses the basic features of FormFlow to -collect information from a user. - -## Forms and fields - -To create a bot using FormFlow, you must specify the information that the bot needs to collect from the user. -For example, if the bot's objective is to obtain a user's sandwich order, then you must define a form -that contains fields for the data that the bot needs to fulfill the order. -You can define the form by creating a C# class that contains one or more public properties to -represent the data that the bot will collect from the user. -Each property must be one of these data types: - -- Integral (sbyte, byte, short, ushort, int, uint, long, ulong) -- Floating point (float, double) -- String -- DateTime -- Enumeration -- List of enumerations - -Any of the data types may be nullable, which you can use to model that the field does not have a value. -If a form field is based on an enumeration property that is not nullable, the value **0** in the enumeration represents **null** (i.e., indicates that the field does not have a value), -and you should start your enumeration values at **1**. -FormFlow ignores all other property types and methods. - -For complex objects, you must create a form for the top-level C# class and another form for the complex object. -You can compose the forms together by using typical [dialog](bot-builder-dotnet-dialogs.md) semantics. -It is also possible to define a form directly by implementing [Advanced.IField][iField] -or using [Advanced.Field][field] and populating the dictionaries within it. - -> [!NOTE] -> You can define a form by using either a C# class or JSON schema. -> This article describes how to define a form using a C# class. -> For more information about using JSON schema, see [Define a form using JSON schema](bot-builder-dotnet-formflow-json-schema.md). - -## Simple sandwich bot - -Consider this example of a simple sandwich bot that is designed to obtain a user's sandwich order. - -### Create the form - -The `SandwichOrder` class defines the form and the enumerations define the options for building a sandwich. -The class also includes the static `BuildForm` method that uses [FormBuilder][formBuilder] -to create the form and define a simple welcome message. - -To use FormFlow, you must first import the `Microsoft.Bot.Builder.FormFlow` namespace. - -[!code-csharp[Define form](../includes/code/dotnet-formflow.cs#defineForm)] - -### Connect the form to the framework - -To connect the form to the framework, you must add it to the controller. -In this example, the `Conversation.SendAsync` method calls the static `MakeRootDialog` method, -which in turn, calls the `FormDialog.FromForm` method to create the `SandwichOrder` form. - -[!code-csharp[Connect form to framework](../includes/code/dotnet-formflow.cs#connectToFramework)] - -### See it in action - -By simply defining the form with a C# class and connecting it to the framework, you have enabled FormFlow to -automatically manage the conversation between bot and user. -The example interactions shown below demonstrate the capabilities of a bot that is created by using the -basic features of FormFlow. -In each interaction, a **>** symbol indicates the point at which the user enters a response. - -#### Display the first prompt - -This form populates the `SandwichOrder.Sandwich` property. -The form automatically generates the prompt, "Please select a sandwich", -where the word "sandwich" in the prompt derives from the property name `Sandwich`. -The `SandwichOptions` enumeration defines the choices that are presented to the user, -with each enumeration value being automatically broken into words based upon changes in case and underscores. - -```console -Please select a sandwich -1. BLT -2. Black Forest Ham -3. Buffalo Chicken -4. Chicken And Bacon Ranch Melt -5. Cold Cut Combo -6. Meatball Marinara -7. Oven Roasted Chicken -8. Roast Beef -9. Rotisserie Style Chicken -10. Spicy Italian -11. Steak And Cheese -12. Sweet Onion Teriyaki -13. Tuna -14. Turkey Breast -15. Veggie -> -``` - -#### Provide guidance - -The user can enter "help" at any point in the conversation to get guidance with filling out the form. -For example, if the user enters "help" at the sandwich prompt, the bot will respond with this guidance. - -```console -> help -* You are filling in the sandwich field. Possible responses: -* You can enter a number 1-15 or words from the descriptions. (BLT, Black Forest Ham, Buffalo Chicken, Chicken And Bacon Ranch Melt, Cold Cut Combo, Meatball Marinara, Oven Roasted Chicken, Roast Beef, Rotisserie Style Chicken, Spicy Italian, Steak And Cheese, Sweet Onion Teriyaki, Tuna, Turkey Breast, and Veggie) -* Back: Go back to the previous question. -* Help: Show the kinds of responses you can enter. -* Quit: Quit the form without completing it. -* Reset: Start over filling in the form. (With defaults from your previous entries.) -* Status: Show your progress in filling in the form so far. -* You can switch to another field by entering its name. (Sandwich, Length, Bread, Cheese, Toppings, and Sauce). -``` - -#### Advance to the next prompt - -If the user enters "2" in response to the initial sandwich prompt, -the bot then displays a prompt for the next property that is defined by the form: `SandwichOrder.Length`. - -```console -Please select a sandwich - 1. BLT - 2. Black Forest Ham - 3. Buffalo Chicken - 4. Chicken And Bacon Ranch Melt - 5. Cold Cut Combo - 6. Meatball Marinara - 7. Oven Roasted Chicken - 8. Roast Beef - 9. Rotisserie Style Chicken - 10. Spicy Italian - 11. Steak And Cheese - 12. Sweet Onion Teriyaki - 13. Tuna - 14. Turkey Breast - 15. Veggie -> 2 -Please select a length (1. Six Inch, 2. Foot Long) -> -``` - -#### Return to the previous prompt - -If the user enters "back" at this point in the conversation, the bot will return the previous prompt. -The prompt shows the user's current choice ("Black Forest Ham"); the user may change that selection by -entering a different number or confirm that selection by entering "c". - -```console -> back -Please select a sandwich(current choice: Black Forest Ham) - 1. BLT - 2. Black Forest Ham - 3. Buffalo Chicken - 4. Chicken And Bacon Ranch Melt - 5. Cold Cut Combo - 6. Meatball Marinara - 7. Oven Roasted Chicken - 8. Roast Beef - 9. Rotisserie Style Chicken - 10. Spicy Italian - 11. Steak And Cheese - 12. Sweet Onion Teriyaki - 13. Tuna - 14. Turkey Breast - 15. Veggie -> c -Please select a length (1. Six Inch, 2. Foot Long) -> -``` - -#### Clarify user input - -If the user responds with text (instead of a number) to indicate a choice, -the bot will automatically ask for clarification if user input matches more than one choice. - -```console -Please select a bread - 1. Nine Grain Wheat - 2. Nine Grain Honey Oat - 3. Italian - 4. Italian Herbs And Cheese - 5. Flatbread -> nine grain -By "nine grain" bread did you mean (1. Nine Grain Honey Oat, 2. Nine Grain Wheat) -> 1 -``` - -If user input does not directly match any of the valid choices, the bot will -automatically prompt the user for clarification. - -```console -Please select a cheese (1. American, 2. Monterey Cheddar, 3. Pepperjack) -> amercan -"amercan" is not a cheese option. -> american smoked -For cheese I understood American. "smoked" is not an option. -``` - -If user input specifies multiple choices for a property and the bot does not understand any of the -specified choices, it will automatically prompt the user for clarification. - -```console -Please select one or more toppings - 1. Banana Peppers - 2. Cucumbers - 3. Green Bell Peppers - 4. Jalapenos - 5. Lettuce - 6. Olives - 7. Pickles - 8. Red Onion - 9. Spinach - 10. Tomatoes -> peppers, lettuce and tomato -By "peppers" toppings did you mean (1. Green Bell Peppers, 2. Banana Peppers) -> 1 -``` - -#### Show current status - -If the user enters "status" at any point in the order, the bot's response will indicate -which values have already been specified and which values remain to be specified. - -```console -Please select one or more sauce - 1. Honey Mustard - 2. Light Mayonnaise - 3. Regular Mayonnaise - 4. Mustard - 5. Oil - 6. Pepper - 7. Ranch - 8. Sweet Onion - 9. Vinegar -> status -* Sandwich: Black Forest Ham -* Length: Six Inch -* Bread: Nine Grain Honey Oat -* Cheese: American -* Toppings: Lettuce, Tomatoes, and Green Bell Peppers -* Sauce: Unspecified -``` - -#### Confirm selections - -When the user completes the form, the bot will ask the user to confirm their selections. - -```console -Please select one or more sauce - 1. Honey Mustard - 2. Light Mayonnaise - 3. Regular Mayonnaise - 4. Mustard - 5. Oil - 6. Pepper - 7. Ranch - 8. Sweet Onion - 9. Vinegar -> 1 -Is this your selection? -* Sandwich: Black Forest Ham -* Length: Six Inch -* Bread: Nine Grain Honey Oat -* Cheese: American -* Toppings: Lettuce, Tomatoes, and Green Bell Peppers -* Sauce: Honey Mustard -> -``` - -If the user responds by entering "no", the bot allows the user to update any of the prior selections. -If the user responds by entering "yes", the form has been completed and control is returned to the calling dialog. - -```console -Is this your selection? -* Sandwich: Black Forest Ham -* Length: Six Inch -* Bread: Nine Grain Honey Oat -* Cheese: American -* Toppings: Lettuce, Tomatoes, and Green Bell Peppers -* Sauce: Honey Mustard -> no -What do you want to change? - 1. Sandwich(Black Forest Ham) - 2. Length(Six Inch) - 3. Bread(Nine Grain Honey Oat) - 4. Cheese(American) - 5. Toppings(Lettuce, Tomatoes, and Green Bell Peppers) - 6. Sauce(Honey Mustard) -> 2 -Please select a length (current choice: Six Inch) (1. Six Inch, 2. Foot Long) -> 2 -Is this your selection? -* Sandwich: Black Forest Ham -* Length: Foot Long -* Bread: Nine Grain Honey Oat -* Cheese: American -* Toppings: Lettuce, Tomatoes, and Green Bell Peppers -* Sauce: Honey Mustard -> y -``` - -## Handling quit and exceptions - -If the user enters "quit" in the form or an exception occurs at some point in the conversation, -your bot will need to know the step in which the event occurred, the state of the form when the event occurred, -and which steps of the form were successfully completed prior to the event. -The form returns this information via the `FormCanceledException` class. - -This code example shows how to catch the exception and display a message according to the event that occurred. - -[!code-csharp[Handle exception or quit](../includes/code/dotnet-formflow.cs#handleExceptionOrQuit)] - -## Summary - -This article has described how to use the basic features of FormFlow to create a bot that can: - -- Automatically generate and manage the conversation -- Provide clear guidance and help -- Understand both numbers and textual entries -- Provide feedback to the user regarding what is understood and what is not -- Ask clarifying questions when necessary -- Allow the user to navigate between steps - -Although basic FormFlow functionality is sufficient in some cases, -you should consider the potential benefits of incorporating some of the more advanced -features of FormFlow into your bot. -For more information, see [Advanced features of FormFlow](bot-builder-dotnet-formflow-advanced.md) and [Customize a form using FormBuilder](bot-builder-dotnet-formflow-formbuilder.md). - -## Sample code - -[!INCLUDE [Sample code](../includes/snippet-dotnet-formflow-samples.md)] - -## Next steps - -FormFlow simplifies dialog development. The advanced features of FormFlow let you customize how a FormFlow object behaves. - -> [!div class="nextstepaction"] -> [Advanced features of FormFlow](bot-builder-dotnet-formflow-advanced.md) - -## Additional resources - -- [Customize a form using FormBuilder](bot-builder-dotnet-formflow-formbuilder.md) -- [Localize form content](bot-builder-dotnet-formflow-localize.md) -- [Define a form using JSON schema](bot-builder-dotnet-formflow-json-schema.md) -- [Customize user experience with pattern language](bot-builder-dotnet-formflow-pattern-language.md) -- Bot Framework SDK for .NET Reference - -[LuisDialog]: /dotnet/api/microsoft.bot.builder.dialogs.luisdialog-1 - -[iField]: /dotnet/api/microsoft.bot.builder.formflow.advanced.ifield-1 - -[field]: /dotnet/api/microsoft.bot.builder.formflow.advanced.field-1 - -[formBuilder]: /dotnet/api/microsoft.bot.builder.formflow.formbuilder-1 diff --git a/articles/dotnet/bot-builder-dotnet-global-handlers.md b/articles/dotnet/bot-builder-dotnet-global-handlers.md deleted file mode 100644 index 9a70ac067..000000000 --- a/articles/dotnet/bot-builder-dotnet-global-handlers.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: Implement global message handlers - Bot Service -description: Learn how to enable your bot to listen for and handle user input containing certain keywords using the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Implement global message handlers - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -[!INCLUDE [Introduction to global message handlers](../includes/snippet-global-handlers-intro.md)] - -## Listen for keywords in user input - -The following walk through shows how to implement global message handlers by using the Bot Framework SDK for .NET. - -First, `Global.asax.cs` registers `GlobalMessageHandlersBotModule`, which is implemented as shown here. -In this example, the module registers two scorables: one for managing a request to change settings (`SettingsScorable`) -and another for managing a request to cancel (`CancelScoreable`). - -```cs -public class GlobalMessageHandlersBotModule : Module -{ - protected override void Load(ContainerBuilder builder) - { - base.Load(builder); - - builder - .Register(c => new SettingsScorable(c.Resolve())) - .As>() - .InstancePerLifetimeScope(); - - builder - .Register(c => new CancelScorable(c.Resolve())) - .As>() - .InstancePerLifetimeScope(); - } -} -``` - -The `CancelScorable` contains a `PrepareAsync` method that defines the trigger: -if the message text is "cancel", this scorable will be triggered. - -```cs -protected override async Task PrepareAsync(IActivity activity, CancellationToken token) -{ - var message = activity as IMessageActivity; - if (message != null && !string.IsNullOrWhiteSpace(message.Text)) - { - if (message.Text.Equals("cancel", StringComparison.InvariantCultureIgnoreCase)) - { - return message.Text; - } - } - return null; -} -``` - -When a "cancel" request is received, the `PostAsync` method within `CancelScoreable` -resets the dialog stack. - -```cs -protected override async Task PostAsync(IActivity item, string state, CancellationToken token) -{ - this.task.Reset(); -} -``` - -When a "change settings" request is received, the `PostAsync` method within `SettingsScorable` -invokes the `SettingsDialog` (passing the request to that dialog), thereby adding the `SettingsDialog` -to the top of the dialog stack and putting it in control of the conversation. - -```cs -protected override async Task PostAsync(IActivity item, string state, CancellationToken token) -{ - var message = item as IMessageActivity; - if (message != null) - { - var settingsDialog = new SettingsDialog(); - var interruption = settingsDialog.Void(); - this.task.Call(interruption, null); - await this.task.PollAsync(token); - } -} -``` - -## Sample code - -For a complete sample that shows how to implement global message handlers using the Bot Framework SDK for .NET, see the Global Message Handlers sample in GitHub. - -## Additional resources - -- [Design and control conversation flow](../bot-service-design-conversation-flow.md) -- Bot Framework SDK for .NET Reference -- Global Message Handlers sample (GitHub) diff --git a/articles/dotnet/bot-builder-dotnet-luis-dialogs.md b/articles/dotnet/bot-builder-dotnet-luis-dialogs.md deleted file mode 100644 index 285801752..000000000 --- a/articles/dotnet/bot-builder-dotnet-luis-dialogs.md +++ /dev/null @@ -1,390 +0,0 @@ ---- -title: Recognize intents and entities with LUIS (v3 C#) - Bot Service -description: Learn how to enable your bot to understand natural language by using LUIS dialogs in the Bot Framework SDK for .NET. -author: DeniseMak -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - - -# Recognize intents and entities with LUIS - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -This article uses the example of a bot for taking notes, to demonstrate how Language Understanding ([LUIS][LUIS]) helps your bot respond appropriately to natural language input. A bot detects what a user wants to do by identifying their **intent**. This intent is determined from spoken or textual input, or **utterances**. The intent maps utterances to actions that the bot takes. For example, a note-taking bot recognizes a `Notes.Create` intent to invoke the functionality for creating a note. A bot may also need to extract **entities**, which are important words in utterances. In the example of a note-taking bot, the `Notes.Title` entity identifies the title of each note. - -## Create a Language Understanding bot with Bot Service - -1. In the [Azure portal](https://portal.azure.com), select **Create new resource** in the menu blade and click **See all**. - - ![Create new resource](../media/bot-builder-dotnet-use-luis/bot-service-creation.png) - -2. In the search box, search for **Web App Bot**. - - ![Create new resource](../media/bot-builder-dotnet-use-luis/bot-service-selection.png) - -3. In the **Bot Service** blade, provide the required information, and click **Create**. This creates and deploys the bot service and LUIS app to Azure. - * Set **App name** to your bot’s name. The name is used as the subdomain when your bot is deployed to the cloud (for example, mynotesbot.azurewebsites.net). This name is also used as the name of the LUIS app associated with your bot. Copy it to use later, to find the LUIS app associated with the bot. - * Select the subscription, [resource group](/azure/azure-resource-manager/resource-group-overview), App service plan, and [location](https://azure.microsoft.com/regions/). - * Select the **Language understanding (C#)** template for the **Bot template** field. - - ![Bot Service blade](../media/bot-builder-dotnet-use-luis/bot-service-setting-callout-template.png) - - * Check the box to confirm to the terms of service. - -4. Confirm that the bot service has been deployed. - * Click Notifications (the bell icon that is located along the top edge of the Azure portal). The notification will change from **Deployment started** to **Deployment succeeded**. - * After the notification changes to **Deployment succeeded**, click **Go to resource** on that notification. - -## Try the bot - -Confirm that the bot has been deployed by checking the **Notifications**. The notifications will change from **Deployment in progress...** to **Deployment succeeded**. Click **Go to resource** button to open the bot's resources blade. - -Once the bot is registered, click **Test in Web Chat** to open the Web Chat pane. Type "hello" in Web Chat. - - ![Test the bot in Web Chat](../media/bot-builder-dotnet-use-luis/bot-service-web-chat.png) - -The bot responds by saying "You have reached Greeting. You said: hello". This confirms that the bot has received your message and passed it to a default LUIS app that it created. This default LUIS app detected a Greeting intent. - -## Modify the LUIS app - -Log in to [https://www.luis.ai](https://www.luis.ai) using the same account you use to log in to Azure. Click on **My apps**. In the list of apps, find the app that begins with the name specified in **App name** in the **Bot Service** blade when you created the Bot Service. - -The LUIS app starts with 4 intents: Cancel: Greeting, Help, and None. - -The following steps add the Note.Create, Note.ReadAloud, and Note.Delete intents: - -1. Click on **Prebuit Domains** in the lower left of the page. Find the **Note** domain and click **Add domain**. - -2. This tutorial doesn't use all of the intents included in the **Note** prebuilt domain. In the **Intents** page, click on each of the following intent names and then click the **Delete Intent** button. - * Note.ShowNext - * Note.DeleteNoteItem - * Note.Confirm - * Note.Clear - * Note.CheckOffItem - * Note.AddToNote - - The only intents that should remain in the LUIS app are the following: - * Note.ReadAloud - * Note.Create - * Note.Delete - * None - * Help - * Greeting - * Cancel - - ![intents shown in LUIS app](../media/bot-builder-dotnet-use-luis/luis-intent-list.png) - -3. Click the **Train** button in the upper right to train your app. -4. Click **PUBLISH** in the top navigation bar to open the **Publish** page. Click the **Publish to production slot** button. After successful publish, copy the URL displayed in the **Endpoint** column the **Publish App** page, in the row that starts with the Resource Name Starter_Key. Save this URL to use later in your bot’s code. The URL has a format similar to this example: `https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx?subscription-key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&timezoneOffset=0&verbose=true&q=` - -## Modify the bot code - -Click **Build** and then click **Open online code editor**. - ![Open online code editor](../media/bot-builder-dotnet-use-luis/bot-service-build.png) - -In the code editor, open `BasicLuisDialog.cs`. It contains the following code for handling intents from the LUIS app. -```cs -using System; -using System.Configuration; -using System.Threading.Tasks; - -using Microsoft.Bot.Builder.Dialogs; -using Microsoft.Bot.Builder.Luis; -using Microsoft.Bot.Builder.Luis.Models; - -namespace Microsoft.Bot.Sample.LuisBot -{ - // For more information about this template visit http://aka.ms/basic-luis-dialog - [Serializable] - public class BasicLuisDialog : LuisDialog - { - public BasicLuisDialog() : base(new LuisService(new LuisModelAttribute( - ConfigurationManager.AppSettings["LuisAppId"], - ConfigurationManager.AppSettings["LuisAPIKey"], - domain: ConfigurationManager.AppSettings["LuisAPIHostName"]))) - { - } - - [LuisIntent("None")] - public async Task NoneIntent(IDialogContext context, LuisResult result) - { - await this.ShowLuisResult(context, result); - } - - // Go to https://luis.ai and create a new intent, then train/publish your luis app. - // Finally replace "Greeting" with the name of your newly created intent in the following handler - [LuisIntent("Greeting")] - public async Task GreetingIntent(IDialogContext context, LuisResult result) - { - await this.ShowLuisResult(context, result); - } - - [LuisIntent("Cancel")] - public async Task CancelIntent(IDialogContext context, LuisResult result) - { - await this.ShowLuisResult(context, result); - } - - [LuisIntent("Help")] - public async Task HelpIntent(IDialogContext context, LuisResult result) - { - await this.ShowLuisResult(context, result); - } - - private async Task ShowLuisResult(IDialogContext context, LuisResult result) - { - await context.PostAsync($"You have reached {result.Intents[0].Intent}. You said: {result.Query}"); - context.Wait(MessageReceived); - } - } -} -``` -### Create a class for storing notes - -Add the following `using` statement in BasicLuisDialog.cs. - -```cs -using System.Collections.Generic; -``` - -Add the following code within the `BasicLuisDialog` class, after the constructor definition. - -```cs - // Store notes in a dictionary that uses the title as a key - private readonly Dictionary noteByTitle = new Dictionary(); - - [Serializable] - public sealed class Note : IEquatable - { - - public string Title { get; set; } - public string Text { get; set; } - - public override string ToString() - { - return $"[{this.Title} : {this.Text}]"; - } - - public bool Equals(Note other) - { - return other != null - && this.Text == other.Text - && this.Title == other.Title; - } - - public override bool Equals(object other) - { - return Equals(other as Note); - } - - public override int GetHashCode() - { - return this.Title.GetHashCode(); - } - } - - // CONSTANTS - // Name of note title entity - public const string Entity_Note_Title = "Note.Title"; - // Default note title - public const string DefaultNoteTitle = "default"; -``` - -### Handle the Note.Create intent -To handle the Note.Create intent, add the following code to the `BasicLuisDialog` class. - -```cs - private Note noteToCreate; - private string currentTitle; - [LuisIntent("Note.Create")] - public Task NoteCreateIntent(IDialogContext context, LuisResult result) - { - EntityRecommendation title; - if (!result.TryFindEntity(Entity_Note_Title, out title)) - { - // Prompt the user for a note title - PromptDialog.Text(context, After_TitlePrompt, "What is the title of the note you want to create?"); - } - else - { - var note = new Note() { Title = title.Entity }; - noteToCreate = this.noteByTitle[note.Title] = note; - - // Prompt the user for what they want to say in the note - PromptDialog.Text(context, After_TextPrompt, "What do you want to say in your note?"); - } - - return Task.CompletedTask; - } - - - private async Task After_TitlePrompt(IDialogContext context, IAwaitable result) - { - EntityRecommendation title; - // Set the title (used for creation, deletion, and reading) - currentTitle = await result; - if (currentTitle != null) - { - title = new EntityRecommendation(type: Entity_Note_Title) { Entity = currentTitle }; - } - else - { - // Use the default note title - title = new EntityRecommendation(type: Entity_Note_Title) { Entity = DefaultNoteTitle }; - } - - // Create a new note object - var note = new Note() { Title = title.Entity }; - // Add the new note to the list of notes and also save it in order to add text to it later - noteToCreate = this.noteByTitle[note.Title] = note; - - // Prompt the user for what they want to say in the note - PromptDialog.Text(context, After_TextPrompt, "What do you want to say in your note?"); - - } - - private async Task After_TextPrompt(IDialogContext context, IAwaitable result) - { - // Set the text of the note - noteToCreate.Text = await result; - - await context.PostAsync($"Created note **{this.noteToCreate.Title}** that says \"{this.noteToCreate.Text}\"."); - - context.Wait(MessageReceived); - } -``` - -### Handle the Note.ReadAloud Intent -The bot can use the `Note.ReadAloud` intent to show the contents of a note, or of all the notes if the note title isn't detected. - -Paste the following code into the `BasicLuisDialog` class. -```cs - [LuisIntent("Note.ReadAloud")] - public async Task NoteReadAloudIntent(IDialogContext context, LuisResult result) - { - Note note; - if (TryFindNote(result, out note)) - { - await context.PostAsync($"**{note.Title}**: {note.Text}."); - } - else - { - // Print out all the notes if no specific note name was detected - string NoteList = "Here's the list of all notes: \n\n"; - foreach (KeyValuePair entry in noteByTitle) - { - Note noteInList = entry.Value; - NoteList += $"**{noteInList.Title}**: {noteInList.Text}.\n\n"; - } - await context.PostAsync(NoteList); - } - - context.Wait(MessageReceived); - } - - public bool TryFindNote(string noteTitle, out Note note) - { - bool foundNote = this.noteByTitle.TryGetValue(noteTitle, out note); // TryGetValue returns false if no match is found. - return foundNote; - } - - public bool TryFindNote(LuisResult result, out Note note) - { - note = null; - - string titleToFind; - - EntityRecommendation title; - if (result.TryFindEntity(Entity_Note_Title, out title)) - { - titleToFind = title.Entity; - } - else - { - titleToFind = DefaultNoteTitle; - } - - return this.noteByTitle.TryGetValue(titleToFind, out note); // TryGetValue returns false if no match is found. - } -``` - -### Handle the Note.Delete intent -Paste the following code into the `BasicLuisDialog` class. - -```cs - [LuisIntent("Note.Delete")] - public async Task NoteDeleteIntent(IDialogContext context, LuisResult result) - { - Note note; - if (TryFindNote(result, out note)) - { - this.noteByTitle.Remove(note.Title); - await context.PostAsync($"Note {note.Title} deleted"); - } - else - { - // Prompt the user for a note title - PromptDialog.Text(context, After_DeleteTitlePrompt, "What is the title of the note you want to delete?"); - } - } - - private async Task After_DeleteTitlePrompt(IDialogContext context, IAwaitable result) - { - Note note; - string titleToDelete = await result; - bool foundNote = this.noteByTitle.TryGetValue(titleToDelete, out note); - - if (foundNote) - { - this.noteByTitle.Remove(note.Title); - await context.PostAsync($"Note {note.Title} deleted"); - } - else - { - await context.PostAsync($"Did not find note named {titleToDelete}."); - } - - context.Wait(MessageReceived); - } -``` - -## Build the bot -Right-click on **build.cmd** in the code editor and choose **Run from Console**. - - ![Run build.cmd](../media/bot-builder-dotnet-use-luis/bot-service-run-console.png) - -## Test the bot - -In the Azure Portal, click on **Test in Web Chat** to test the bot. Try type messages like "Create a note", "read my notes", and "delete notes". - ![Test notes bot in Web Chat](../media/bot-builder-dotnet-use-luis/bot-service-test-notebot.png) - -> [!TIP] -> If you find that your bot doesn't always recognize the correct intent or entities, improve your LUIS app's performance by giving it more example utterances to train it. You can retrain your LUIS app without any modification to your bot's code. See [Add example utterances](/azure/cognitive-services/LUIS/add-example-utterances) and [train and test your LUIS app](/azure/cognitive-services/LUIS/train-test). - -> [!TIP] -> If your bot code runs into an issue, check the following: -> * You have [built the bot](./bot-builder-dotnet-luis-dialogs.md#build-the-bot). -> * Your bot code defines a handler for every intent in your LUIS app. - -## Next steps - -From trying the bot, you can see how tasks are invoked by a LUIS intent. However, this simple example doesn't allow for interruption of the currently active dialog. Allowing and handling interruptions like "help" or "cancel" is a flexible design that accounts for what users really do. Learn more about using scorable dialogs so that your dialogs can handle interruptions. - -> [!div class="nextstepaction"] -> [Global message handlers using scorables](bot-builder-dotnet-scorable-dialogs.md) - -## Additional resources - -- [Dialogs](bot-builder-dotnet-dialogs.md) -- [Manage conversation flow with dialogs](bot-builder-dotnet-manage-conversation-flow.md) -- LUIS -- Bot Framework SDK for .NET Reference - -[LUIS]: https://www.luis.ai/ -[NotesSample]: https://github.com/Microsoft/BotFramework-Samples/tree/master/docs-samples/CSharp/Simple-LUIS-Notes-Sample -[NotesSampleJSON]: https://github.com/Microsoft/BotFramework-Samples/blob/master/docs-samples/CSharp/Simple-LUIS-Notes-Sample/Notes.json diff --git a/articles/dotnet/bot-builder-dotnet-manage-conversation-flow.md b/articles/dotnet/bot-builder-dotnet-manage-conversation-flow.md deleted file mode 100644 index 94800ecaf..000000000 --- a/articles/dotnet/bot-builder-dotnet-manage-conversation-flow.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -title: Manage conversation flow with dialogs - Bot Service -description: Learn how to model conversations and manage conversation flow using dialogs and the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' - ---- - -# Manage conversation flow with dialogs - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-manage-conversation-flow.md) -> - [Node.js](../nodejs/bot-builder-nodejs-dialog-manage-conversation-flow.md) - -[!INCLUDE [Dialog flow example](../includes/snippet-dotnet-manage-conversation-flow-intro.md)] - -This article describes how to model this conversation flow by using [dialogs](bot-builder-dotnet-dialogs.md) and the Bot Framework SDK for .NET. - -## Invoke the root dialog - -First, the bot controller invokes the "root dialog". -The following example shows how to wire the basic HTTP POST call to a controller and then invoke the root dialog. - -```cs -public class MessagesController : ApiController -{ - public async Task Post([FromBody]Activity activity) - { - // Redirect to the root dialog. - await Conversation.SendAsync(activity, () => new RootDialog()); - ... - } -} -``` - -## Invoke the 'New Order' dialog - -Next, the root dialog invokes the 'New Order' dialog. - -```cs -[Serializable] -public class RootDialog : IDialog -{ - public async Task StartAsync(IDialogContext context) - { - // Root dialog initiates and waits for the next message from the user. - // When a message arrives, call MessageReceivedAsync. - context.Wait(this.MessageReceivedAsync); - } - - public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable result) - { - var message = await result; // We've got a message! - if (message.Text.ToLower().Contains("order")) - { - // User said 'order', so invoke the New Order Dialog and wait for it to finish. - // Then, call ResumeAfterNewOrderDialog. - await context.Forward(new NewOrderDialog(), this.ResumeAfterNewOrderDialog, message, CancellationToken.None); - } - // User typed something else; for simplicity, ignore this input and wait for the next message. - context.Wait(this.MessageReceivedAsync); - } - - private async Task ResumeAfterNewOrderDialog(IDialogContext context, IAwaitable result) - { - // Store the value that NewOrderDialog returned. - // (At this point, new order dialog has finished and returned some value to use within the root dialog.) - var resultFromNewOrder = await result; - - await context.PostAsync($"New order dialog just told me this: {resultFromNewOrder}"); - - // Again, wait for the next message from the user. - context.Wait(this.MessageReceivedAsync); - } -} -``` - -## Dialog lifecycle - -When a dialog is invoked, it takes control of the conversation flow. -Every new message will be subject to processing by that dialog until it either closes or redirects to another dialog. - -In C#, you can use `context.Wait()` to specify the callback to invoke the next time the user sends a message. -To close a dialog and remove it from the stack (thereby sending the user back to the prior dialog in the stack), use `context.Done()`. -You must end every dialog method with `context.Wait()`, `context.Fail()`, `context.Done()`, -or some redirection directive such as `context.Forward()` or `context.Call()`. -A dialog method that does not end with one of these will result in an error -(because the framework does not know what action to take the next time the user sends a message). - -## Passing state between dialogs - -While you can store state in bot state, you can also pass data between different dialogs by overloading your dialog class constructor. - -```cs -[Serializable] -public class AgeDialog : IDialog -{ - private string name; - - public AgeDialog(string name) - { - this.name = name; - } -} - ``` - -Calling dialog code, passing in name value from the user. - -```cs -private async Task NameDialogResumeAfter(IDialogContext context, IAwaitable result) -{ - try - { - this.name = await result; - context.Call(new AgeDialog(this.name), this.AgeDialogResumeAfter); - } - catch (TooManyAttemptsException) - { - await context.PostAsync("I'm sorry, I'm having issues understanding you. Let's try again."); - await this.SendWelcomeMessageAsync(context); - } -} -``` - -## Sample code - -For a complete sample that shows how to manage a conversation by using dialogs in the Bot Framework SDK for .NET, see the [Basic Multi-Dialog sample](https://aka.ms/v3cs-MultiDialog-Sample) in GitHub. - -## Additional resources - -- [Dialogs](bot-builder-dotnet-dialogs.md) -- [Design and control conversation flow](../bot-service-design-conversation-flow.md) -- [Basic Multi-Dialog sample (GitHub)](https://aka.ms/v3cs-MultiDialog-Sample) -- Bot Framework SDK for .NET Reference diff --git a/articles/dotnet/bot-builder-dotnet-middleware.md b/articles/dotnet/bot-builder-dotnet-middleware.md deleted file mode 100644 index 10632c945..000000000 --- a/articles/dotnet/bot-builder-dotnet-middleware.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: Intercept messages (v3 C#) - Bot Service -description: Learn how to intercept messages between user and bot using the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 03/01/2019 -monikerRange: 'azure-bot-service-3.0' ---- -# Intercept messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-middleware.md) -> - [Node.js](../nodejs/bot-builder-nodejs-intercept-messages.md) - -[!INCLUDE [Introducton to message logging](../includes/snippet-message-logging-intro.md)] - -## Intercept and log messages - -The following code sample shows how to intercept messages that are exchanged between user and bot -using the concept of **middleware** in the Bot Framework SDK for .NET. - -First, create a `DebugActivityLogger` class and define a `LogAsync` method to specify what action is taken for each intercepted message. This example just prints some information about each message. - -```cs -public class DebugActivityLogger : IActivityLogger -{ - public async Task LogAsync(IActivity activity) - { - Debug.WriteLine($"From:{activity.From.Id} - To:{activity.Recipient.Id} - Message:{activity.AsMessageActivity()?.Text}"); - } -} -``` - -Then, add the following code to `Global.asax.cs`. Every message that is exchanged between user and bot (in either direction) will now trigger the `LogAsync` method in the `DebugActivityLogger` class. - -```cs - public class WebApiApplication : System.Web.HttpApplication - { - protected void Application_Start() - { - var builder = new ContainerBuilder(); - builder.RegisterType().AsImplementedInterfaces().InstancePerDependency(); - builder.Update(Conversation.Container); - - GlobalConfiguration.Configure(WebApiConfig.Register); - } - } -``` - -Although this example simply prints some information about each message, you can update the `LogAsync` method to specify the actions that you want to take for each message. - -## Sample code - -For a complete sample that shows how to intercept and log messages using the Bot Framework SDK for .NET, see the Middleware sample in GitHub. - -## Additional resources - -- Bot Framework SDK for .NET Reference -- Middleware sample (GitHub) diff --git a/articles/dotnet/bot-builder-dotnet-overview.md b/articles/dotnet/bot-builder-dotnet-overview.md deleted file mode 100644 index 46a503bf4..000000000 --- a/articles/dotnet/bot-builder-dotnet-overview.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Bot Framework SDK for .NET - Bot Service -description: Get started with Bot Framework SDK for .NET, a powerful, easy-to-use framework for building bots. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Bot Framework SDK for .NET - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-overview.md) -> - [Node.js](../nodejs/bot-builder-nodejs-overview.md) -> - [REST](../rest-api/bot-framework-rest-overview.md) - -The Bot Framework SDK for .NET is a powerful framework for constructing bots that can handle both free-form interactions -and more guided conversations where the user selects from possible values. -It is easy to use and leverages C# to provide a familiar way for .NET developers to write bots. - -Using the SDK, you can build bots that take advantage of the following SDK features: - -- Powerful dialog system with dialogs that are isolated and composable -- Built-in prompts for simple things such as Yes/No, strings, numbers, and enumerations -- Built-in dialogs that utilize powerful AI frameworks such as LUIS -- FormFlow for automatically generating a bot (from a C# class) that guides the user through the -conversation, providing help, navigation, clarification, and confirmation as needed - -> [!IMPORTANT] -> On July 31, 2017 breaking changes have been implemented in the Bot Framework security protocol. -> To prevent these changes from adversely impacting your bot, you must ensure that your application is -> using Bot Framework SDK v3.5 or greater. If you've built a bot using an -> SDK that you obtained prior to January 5, 2017 (the release date for Bot Framework SDK v3.5), -> be sure to upgrade to Bot Framework SDK v3.5 or later. - -## Get the SDK - -The SDK is available as a NuGet package and as open source on GitHub. - -> [!IMPORTANT] -> The Bot Framework SDK for .NET requires .NET Framework 4.6 or newer. If you are adding the SDK to an existing project -> targeting a lower version of the .NET Framework, you will need to update your project to target .NET Framework 4.6 first. - -To install the SDK within a Visual Studio project, complete the following steps: - -1. In **Solution Explorer**, right-click the project name and select **Manage NuGet Packages...**. -2. On the **Browse** tab, type "Microsoft.Bot.Builder" into the search box. -3. Select **Microsoft.Bot.Builder** in the list of results, click **Install**, and accept the changes. - -## Get code samples - -This SDK includes [sample source code](bot-builder-dotnet-samples.md) that uses the features of the Bot Framework SDK for .NET. - -## Next steps - -Learn more about building bots using the Bot Framework SDK for .NET by reviewing articles throughout this section, beginning with: - -- [Quickstart](bot-builder-dotnet-quickstart.md): Quickly build and test a simple bot by following instructions in this step-by-step tutorial. -- [Key concepts](bot-builder-dotnet-concepts.md): Learn about key concepts in the Bot Framework SDK for .NET. - -If you encounter problems or have suggestions regarding the Bot Framework SDK for .NET, see [Support](../bot-service-resources-links-help.md) for a list of available resources. diff --git a/articles/dotnet/bot-builder-dotnet-proactive-messages.md b/articles/dotnet/bot-builder-dotnet-proactive-messages.md deleted file mode 100644 index cf757a4fc..000000000 --- a/articles/dotnet/bot-builder-dotnet-proactive-messages.md +++ /dev/null @@ -1,184 +0,0 @@ ---- -title: Send proactive messages (v3 C#) - Bot Service -description: Learn how to send proactive messages using the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Send proactive messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-proactive-messages.md) -> - [Node.js](../nodejs/bot-builder-nodejs-proactive-messages.md) - -[!INCLUDE [Introduction to proactive messages - part 1](../includes/snippet-proactive-messages-intro-1.md)] - -## Types of proactive messages - -[!INCLUDE [Introduction to proactive messages - part 2](../includes/snippet-proactive-messages-intro-2.md)] - -## Send an ad hoc proactive message - -The following code samples show how to send an ad hoc proactive message with the Bot Framework SDK for .NET. - -To be able to send an ad hoc message to a user, the bot must first collect and store some information about the user from the current conversation. - -```cs -public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable result) -{ - var message = await result; - - // Extract data from the user's message that the bot will need later to send an ad hoc message to the user. - // Store the extracted data in a custom class "ConversationStarter" (not shown here). - - ConversationStarter.toId = message.From.Id; - ConversationStarter.toName = message.From.Name; - ConversationStarter.fromId = message.Recipient.Id; - ConversationStarter.fromName = message.Recipient.Name; - ConversationStarter.serviceUrl = message.ServiceUrl; - ConversationStarter.channelId = message.ChannelId; - ConversationStarter.conversationId = message.Conversation.Id; - - // (Save this information somewhere that it can be accessed later, such as in a database.) - - await context.PostAsync("Hello user, good to meet you! I now know your address and can send you notifications in the future."); - context.Wait(MessageReceivedAsync); -} -``` -> [!NOTE] -> For simplicity, this example does not specify how to store the user data. It does not matter how the data is -> stored as long as the bot can retrieve it later. - -Now that the data has been stored, the bot can simply retrieve the data, construct the ad hoc proactive message, and send it. - -```cs -// Use the data stored previously to create the required objects. -var userAccount = new ChannelAccount(toId,toName); -var botAccount = new ChannelAccount(fromId, fromName); -var connector = new ConnectorClient(new Uri(serviceUrl)); - -// Create a new message. -IMessageActivity message = Activity.CreateMessageActivity(); -if (!string.IsNullOrEmpty(conversationId) && !string.IsNullOrEmpty(channelId)) -{ - // If conversation ID and channel ID was stored previously, use it. - message.ChannelId = channelId; -} -else -{ - // Conversation ID was not stored previously, so create a conversation. - // Note: If the user has an existing conversation in a channel, this will likely create a new conversation window. - conversationId = (await connector.Conversations.CreateDirectConversationAsync( botAccount, userAccount)).Id; -} - -// Set the address-related properties in the message and send the message. -message.From = botAccount; -message.Recipient = userAccount; -message.Conversation = new ConversationAccount(id: conversationId); -message.Text = "Hello, this is a notification"; -message.Locale = "en-us"; -await connector.Conversations.SendToConversationAsync((Activity)message); -``` - -> [!NOTE] -> If the bot specifies a conversation ID that was stored previously, the message will likely be delivered to the user in the existing conversation window on the client. -> If the bot generates a new conversation ID, the message will be delivered to the user in a new conversation window on the client, provided that the client supports multiple conversation windows. - -## Send a dialog-based proactive message - -The following code samples show how to send a dialog-based proactive message by using the Bot Framework SDK for .NET. - -To be able to send a dialog-based proactive message to a user, the bot must first collect and save information from the current conversation. - -```cs -public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable result) -{ - var message = await result; - - // Store information about this specific point the conversation, so that the bot can resume this conversation later. - var conversationReference = message.ToConversationReference(); - ConversationStarter.conversationReference = JsonConvert.SerializeObject(conversationReference); - - await context.PostAsync("Greetings, user! I now know how to start a proactive message to you."); - context.Wait(MessageReceivedAsync); -} -``` - -When it is time to send the message, the bot creates a new dialog and adds it to the top of the dialog stack. The new dialog takes control of the conversation, delivers the proactive message, closes, and then returns control to the previous dialog in the stack. - -```cs -// This will interrupt the conversation and send the user to SurveyDialog, then wait until that's done -public static async Task Resume() -{ - // Recreate the message from the conversation reference that was saved previously. - var message = JsonConvert.DeserializeObject(conversationReference).GetPostToBotMessage(); - var client = new ConnectorClient(new Uri(message.ServiceUrl)); - - // Create a scope that can be used to work with state from bot framework. - using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message)) - { - var botData = scope.Resolve(); - await botData.LoadAsync(CancellationToken.None); - - // This is our dialog stack. - var task = scope.Resolve(); - - // Create the new dialog and add it to the stack. - var dialog = new SurveyDialog(); - // interrupt the stack. This means that we're stopping whatever conversation that is currently happening with the user - // Then adding this stack to run and once it's finished, we will be back to the original conversation - task.Call(dialog.Void(), null); - - await task.PollAsync(CancellationToken.None); - - // Flush the dialog stack back to its state store. - await botData.FlushAsync(CancellationToken.None); - } -} -``` -The `SurveyDialog` controls the conversation until it finishes. When its task is finished, it calls `context.Done` and closes, returning control to the previous dialog. - -```cs -[Serializable] -public class SurveyDialog : IDialog -{ - public async Task StartAsync(IDialogContext context) - { - await context.PostAsync("Hello, I'm the survey dialog. I'm interrupting your conversation to ask you a question. Type \"done\" to resume"); - - context.Wait(this.MessageReceivedAsync); - } - public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable result) - { - if ((await result).Text == "done") - { - await context.PostAsync("Great, back to the original conversation!"); - context.Done(String.Empty); // Finish this dialog. - } - else - { - await context.PostAsync("I'm still on the survey until you type \"done\""); - context.Wait(MessageReceivedAsync); // Not done yet. - } - } -} -``` - -## Sample code - -For a complete sample that shows how to send proactive messages using the Bot Framework SDK for .NET, see the Proactive Messages sample in GitHub. -Within the Proactive Messages sample, simpleSendMessage shows how to send an ad-hoc proactive message and startNewDialog shows how to send a dialog-based proactive message. - -## Additional resources - -- [Design and control conversation flow](../bot-service-design-conversation-flow.md) -- Bot Framework SDK for .NET Reference -- Proactive Messages sample (GitHub) - diff --git a/articles/dotnet/bot-builder-dotnet-request-payment.md b/articles/dotnet/bot-builder-dotnet-request-payment.md deleted file mode 100644 index 14dafcddd..000000000 --- a/articles/dotnet/bot-builder-dotnet-request-payment.md +++ /dev/null @@ -1,168 +0,0 @@ ---- -title: Request payment (v3 C#) - Bot Service -description: Learn how to send a payment request using the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Request payment - -> [!NOTE] -> The Payment service referred to in this article will be deprecated on December 1, 2019. - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-request-payment.md) -> - [Node.js](../nodejs/bot-builder-nodejs-request-payment.md) - -If your bot enables users to purchase items, it can request payment by including -a special type of button within a [rich card](bot-builder-dotnet-add-rich-card-attachments.md). -This article describes how to send a payment request using the Bot Framework SDK for .NET. - -## Prerequisites - -Before you can send a payment request using the Bot Framework SDK for .NET, you must complete these prerequisite tasks. - -### Update Web.config - -Update your bot's **Web.config** file to set `MicrosoftAppId` and `MicrosoftAppPassword` to the app ID and password values that were generated for your bot during the [registration](~/bot-service-quickstart-registration.md) process. - -> [!NOTE] -> To find your bot's **AppID** and **AppPassword**, see [MicrosoftAppID and MicrosoftAppPassword](~/bot-service-manage-overview.md#microsoftappid-and-microsoftapppassword). - -### Create and configure merchant account - -1. Create and activate a Stripe account if you don't have one already. - -2. Sign in to Seller Center with your Microsoft account. - -3. Within Seller Center, connect your account with Stripe. - -4. Within Seller Center, navigate to the Dashboard and copy the value of **MerchantID**. - -5. Update your bot's **Web.config** file to set `MerchantId` to the value that you copied from the Seller Center Dashboard. - -[!INCLUDE [Payment process overview](../includes/snippet-payment-process-overview.md)] - -## Payment Bot sample - -The Payment Bot sample provides an example of a bot that sends a payment request -using .NET. -To see this sample bot in action, you can -try it out in web chat, -add it as a Skype -contact or download the payment bot sample and run it locally using the Bot Framework Emulator. - -> [!NOTE] -> To complete the end-to-end payment process using the **Payment Bot** sample in web chat or Skype, -> you must specify a valid credit card or debit card within your Microsoft account -> (i.e., a valid card from a U.S. card issuer). -> Your card will not be charged and the card's CVV will not be verified, -> because the **Payment Bot** sample runs in test mode (i.e., `LiveMode` is set to `false` in **Web.config**). - -The next few sections of this article describe the three parts of the payment process, -in the context of the **Payment Bot** sample. - -## Requesting payment - -Your bot can request payment from a user by sending a message that contains a -[rich card attachment](bot-builder-dotnet-add-rich-card-attachments.md) with a button that specifies -`CardAction.Type` of "payment". -This code snippet from the **Payment Bot** sample creates a message that contains a Hero card with a **Buy** button that the user can click (or tap) to initiate the payment process. - -[!code-csharp[Request payment](../includes/code/dotnet-request-payment.cs#requestPayment)] - -In this example, the button's type is specified as `PaymentRequest.PaymentActionType`, which -the Bot Builder library defines as "payment". -The button's value is populated by the `BuildPaymentRequest` method, which returns -a `PaymentRequest` object that contains information about supported payment methods, details, -and options. -For more information about implementation details, see **Dialogs/RootDialog.cs** within the -Payment Bot sample. - -This screenshot shows the Hero card (with **Buy** button) that's generated by the code snippet above. - -![Payments sample bot](../media/payments-bot-buy.png) - -> [!IMPORTANT] -> Any user that has access to the **Buy** button may use it to initiate the payment process. -> Within the context of a group conversation, it is not possible to designate a button for use by only -> a specific user. - -## User experience - -When a user clicks the **Buy** button, he or she is directed to a payment web experience to provide all required payment, shipping, and contact information via their Microsoft account. - -![Microsoft payment](../media/microsoft-payment.png) - -### HTTP callbacks - -HTTP callbacks will be sent to your bot to indicate that it should perform certain operations. -Each callback will be an [activity](bot-builder-dotnet-activities.md) -that contains these property values: - -| Property | Value | -|----|----| -| `Activity.Type` | invoke | -| `Activity.Name` | Indicates the type of operation that the bot should perform (e.g., shipping address update, shipping option update, payment complete). | -| `Activity.Value` | The request payload in JSON format. | -| `Activity.RelatesTo` | Describes the channel and user that are associated with the payment request. | - -> [!NOTE] -> `invoke` is a special activity type that is reserved for use by the Microsoft Bot Framework. -> The sender of an `invoke` activity will expect your bot to acknowledge the callback by sending an HTTP response. - -## Processing callbacks - -[!INCLUDE [Process callbacks overview](../includes/snippet-payment-process-callbacks-overview.md)] - -### Shipping Address Update and Shipping Option Update callbacks - -[!INCLUDE [Process shipping address and shipping option callbacks](../includes/snippet-payment-process-callbacks-1.md)] - -### Payment Complete callbacks - -When receiving a Payment Complete callback, your bot will be provided with a copy of the initial, unmodified payment request as -well as the payment response objects in the `Activity.Value` property. The payment response object will contain the final selections -made by the customer along with a payment token. Your bot should take the opportunity to recalculate the final payment request based on -the initial payment request and the customer's final selections. Assuming the customer's selections are determined to be valid, the bot -should verify the amount and currency in the payment token header to ensure that they match the final payment request. If the bot -decides to charge the customer it should only charge the amount in the payment token header as this is the price the customer confirmed. -If there is a mismatch between the values that the bot expects and the values that it received in the Payment Complete callback, it can -fail the payment request by sending HTTP status code `200 OK` along with setting the result field to `failure`. - -In addition to verifying payment details, the bot should also verify that the order can be fulfilled, before it initiates payment -processing. For example, it may want to verify that the item(s) being purchased are still available in stock. -If the values are correct and your payment processor has successfully charged the payment token, then the bot should respond with HTTP -status code `200 OK` along with setting the result field to `success` in order for the payment web experience to display the payment -confirmation. The payment token that the bot receives can only be used once, by the merchant that requested it, and must be submitted to -Stripe (the only payment processor that the Bot Framework currently supports). Sending any HTTP status code in the `400` or `500` range -to will result in a generic error for the customer. - -The `OnInvoke` method in the **Payment Bot** sample processes the callbacks that the bot receives. - -[!code-csharp[Request payment](../includes/code/dotnet-request-payment.cs#processCallback)] - -In this example, the bot examines the `Name` property of the incoming activity to identify the type of -operation it needs to perform, and then calls the appropriate method to process the callback. -For more information about implementation details, see **Controllers/MessagesControllers.cs** -within the Payment Bot sample. - -## Testing a payment bot - -[!INCLUDE [Test a payment bot](../includes/snippet-payment-test-bot.md)] - -In the Payment Bot sample, the `LiveMode` configuration setting in **Web.config** determines whether -Payment Complete callbacks will contain emulated payment tokens or real payment tokens. If `LiveMode` is set to `false`, a header is added to the bot's outbound payment request to indicate that the bot is in test mode, and the Payment Complete callback will contain an emulated payment token that cannot be charged. If `LiveMode` is set to `true`, the header which indicates that the bot is in test mode is omitted from the bot's outbound payment request, and the Payment Complete callback will contain a real payment token that the bot will submit to Stripe for payment processing. This will be a real transaction that results in charges to the specified payment instrument. - -## Additional resources - -- Payment Bot sample -- [Activities overview](bot-builder-dotnet-activities.md) -- [Add rich cards to messages](bot-builder-dotnet-add-rich-card-attachments.md) -- Web Payments at W3C -- Bot Framework SDK for .NET Reference diff --git a/articles/dotnet/bot-builder-dotnet-scorable-dialogs.md b/articles/dotnet/bot-builder-dotnet-scorable-dialogs.md deleted file mode 100644 index d4465b0d1..000000000 --- a/articles/dotnet/bot-builder-dotnet-scorable-dialogs.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -title: Global message handlers using scorables -description: Create more flexible dialogs using scorables within the Bot Framework SDK for .NET. -author: matthewshim-ms -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- -# Global message handlers using scorables - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -Users attempt to access certain functionality within a bot by using words like "help," "cancel," or "start over" in the middle of a conversation when the bot is expecting a different response. You can design your bot to gracefully handle such requests using scorable dialogs. - -Scorable dialogs monitor all incoming messages and determine whether a message is actionable in some way. Messages that are scorable are assigned a score between [0 – 1] by each scorable dialog. The scorable dialog that determines the highest score is added to the top of the dialog stack and then hands the response to the user. After the scorable dialog completes execution, the conversation continues from where it left off. - -Scorables enable you to create more flexible conversations by allowing your users to 'interrupt' the normal conversation flow you find in regular dialogs. - -## Create a scorable dialog - -First, define a new [dialog](bot-builder-dotnet-dialogs.md). The following code uses a dialog that is derived from the `IDialog` interface. - -```cs -public class SampleDialog : IDialog -{ - public async Task StartAsync(IDialogContext context) - { - await context.PostAsync("This is a Sample Dialog which is Scorable. Reply with anything to return to the prior prior dialog."); - - context.Wait(this.MessageReceived); - } - - private async Task MessageReceived(IDialogContext context, IAwaitable result) - { - var message = await result; - - if ((message.Text != null) && (message.Text.Trim().Length > 0)) - { - context.Done(null); - } - else - { - context.Fail(new Exception("Message was not a string or was an empty string.")); - } - } -} -``` -To make a scorable dialog, create a class that inherits from the `ScorableBase` abstract class. The following code shows a `SampleScorable` class. - -```cs -using Microsoft.Bot.Builder.Dialogs; -using Microsoft.Bot.Builder.Dialogs.Internals; -using Microsoft.Bot.Builder.Internals.Fibers; -using Microsoft.Bot.Builder.Scorables.Internals; - -public class SampleScorable : ScorableBase -{ - private readonly IDialogTask task; - - public SampleScorable(IDialogTask task) - { - SetField.NotNull(out this.task, nameof(task), task); - } -} -``` -The `ScorableBase` abstract class inherits from the `IScorable` interface. You will need to implement the following `IScorable` methods in your class: - -- `PrepareAsync` is the first method that is called in the scorable instance. It accepts incoming message activity, analyzes and sets the dialog's state, which is passed to all the other methods of the `IScorable` interface. - -```cs -protected override async Task PrepareAsync(IActivity item, CancellationToken token) -{ - // TODO: insert your code here -} -``` - -- The `HasScore` method checks the state property to determine if the scorable dialog should provide a score for the message. If it returns false, the message will be ignored by the scorable dialog. - -```cs -protected override bool HasScore(IActivity item, string state) -{ - // TODO: insert your code here -} -``` - -- `GetScore` will only trigger if `HasScore` returns true. You’ll provision the logic in this method to determine the score for a message between 0 - 1. - -```cs -protected override double GetScore(IActivity item, string state) -{ - // TODO: insert your code here -} -``` -- In the `PostAsync` method, define core actions to be performed for the scorable class. All scorable dialogs will monitor incoming messages, and assign scores to valid messages based on the scorables' GetScore method. The scorable class which determines the highest score (between 0 - 1.0) will then trigger that scorable's `PostAsync` method. - -```cs -protected override Task PostAsync(IActivity item, string state, CancellationToken token) -{ - //TODO: insert your code here -} -``` - -- `DoneAsync` is called after the scoring process is complete. Use this method to dispose of any scoped resources. - -```cs -protected override Task DoneAsync(IActivity item, string state, CancellationToken token) -{ - //TODO: insert your code here -} -``` - -## Create a module to register the IScorable service - -Next, define a `Module` that will register the `SampleScorable` class as a component. This will provision the `IScorable` service. - -```cs -public class GlobalMessageHandlersBotModule : Module -{ - protected override void Load(ContainerBuilder builder) - { - base.Load(builder); - - builder - .Register(c => new SampleScorable(c.Resolve())) - .As>() - .InstancePerLifetimeScope(); - } -} -``` -## Register the module - -The last step in the process is to apply the `SampleScorable` to the bot's Conversation Container. This will register the scorable service within the Bot Framework's message handling pipeline. The following code shows to update the `Conversation.Container` within the bot app's initialization in **Global.asax.cs**: - -```cs -public class WebApiApplication : System.Web.HttpApplication -{ - protected void Application_Start() - { - this.RegisterBotModules(); - GlobalConfiguration.Configure(WebApiConfig.Register); - } - - private void RegisterBotModules() - { - var builder = new ContainerBuilder(); - builder.RegisterModule(new ReflectionSurrogateModule()); - - //Register the module within the Conversation container - builder.RegisterModule(); - - builder.Update(Conversation.Container); - } -} -``` - -## Additional resources -* [Global Message Handlers sample](https://github.com/Microsoft/BotBuilder-Samples/tree/master/CSharp/core-GlobalMessageHandlers) -* [Simple Scorable Bot sample](https://github.com/Microsoft/BotFramework-Samples/tree/master/blog-samples/CSharp/ScorableBotSample) -* [Dialogs overview](bot-builder-dotnet-dialogs.md) -* [AutoFac](https://autofac.org/) diff --git a/articles/dotnet/bot-builder-dotnet-sdk-quickstart.md b/articles/dotnet/bot-builder-dotnet-sdk-quickstart.md deleted file mode 100644 index e6e795f1b..000000000 --- a/articles/dotnet/bot-builder-dotnet-sdk-quickstart.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Create a bot with the Bot Framework SDK for .NET - Bot Service -description: Create a bot with the Bot Framework SDK for .NET, a powerful bot construction framework. -keywords: Bot Framework SDK, create a bot, quickstart, .NET, getting started, C# bot -author: kamrani -ms.author: kamrani -manager: kamrani -ms.topic: conceptual -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - - -# Create a bot with the Bot Framework SDK for .NET - -[!INCLUDE [applies-to-v4](../includes/applies-to.md)] - -This quickstart walks you through building a bot by using the C# template, and then testing it with the Bot Framework Emulator. - -[!INCLUDE [Azure vs local development](~/includes/snippet-quickstart-paths.md)] - -[!INCLUDE [dotnet quickstart](~/includes/quickstart-dotnet.md)] - -## Additional resources - -See [tunneling (ngrok)](https://github.com/Microsoft/BotFramework-Emulator/wiki/Tunneling-(ngrok)) for how to connect to a bot hosted remotely. - -## Next steps - -> [!div class="nextstepaction"] -> [Deploy your bot to Azure](../bot-builder-deploy-az-cli.md) - diff --git a/articles/dotnet/bot-builder-dotnet-search-azure.md b/articles/dotnet/bot-builder-dotnet-search-azure.md deleted file mode 100644 index a9f92036b..000000000 --- a/articles/dotnet/bot-builder-dotnet-search-azure.md +++ /dev/null @@ -1,185 +0,0 @@ ---- -title: Create data-driven experiences with Azure Search (v3 C#) - Bot Service -description: Learn how to create data-driven experiences with Azure Search and help users navigate large amounts of content in a bot with the Bot Framework SDK for .NET and Azure Search. -author: matthewshim-ms -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 1/28/2019 -monikerRange: 'azure-bot-service-3.0' ---- - -# Create data-driven experiences with Azure Search - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-search-azure.md) -> - [Node.js](../nodejs/bot-builder-nodejs-search-azure.md) - -You can add [Azure Search](https://azure.microsoft.com/services/search/) to a bot to help users navigate large amounts of content and create a data-driven exploration experience. - -Azure Search is an Azure service that offers keyword search, built-in linguistics, custom scoring, faceted navigation, and more. Azure Search can also index content from various sources, including Azure SQL DB, DocumentDB, Blob Storage, and Table Storage. It supports "push" indexing for other sources of data, and it can open PDFs, Office documents, and other formats containing unstructured data. Once collected, the content goes into an Azure Search index, which the bot can then query. - -## Prerequisites - -Install the [Microsoft.Azure.Search](https://www.nuget.org/packages/Microsoft.Azure.Search/4.0.0-preview) Nuget package in your bot project. - -The following three C# projects are required in your bot's solution. These projects provide additional functionality for bots and Azure Search. Fork the projects from [GitHub](https://aka.ms/v3-cs-search-demo) or download the source code directly. - -- The **Search.Azure** project defines the Azure Service call. -- The **Search.Contracts** project defines generic interfaces and data models to handle data. -- The **Search.Dialogs** project includes various generic Bot Builder dialogs used to query Azure Search. - -## Configure Azure Search settings - -Configure the Azure Search settings in the **Web.config** file of the project using your own Azure Search credentials in the value fields. -The constructor in the `AzureSearchClient` class will use these settings to register and bind the bot to the Azure Service. - -```xml - - - - - -``` - -## Create a search dialog - -In your bot's project, create a new `AzureSearchDialog` class to call the Azure Service in your bot. This new class must inherit the `SearchDialog` class from the -**Search.Dialogs** project, which handles most of the heavy lifting. The `GetTopRefiners()` override allows users to narrow/filter their search results without having to start the search over form the beginning, maintaining the search object's state. You can add your own custom refiners in the `TopRefiners` array to let your users filter or narrow down their search results. - -```cs -[Serializable] -public class AzureSearchDialog : SearchDialog -{ - private static readonly string[] TopRefiners = { "refiner1", "refiner2", "refiner3" }; // define your own custom refiners - - public AzureSearchDialog(ISearchClient searchClient) : base(searchClient, multipleSelection: true) - { - } - - protected override string[] GetTopRefiners() - { - return TopRefiners; - } -} -``` - -## Define the response data model - -The **SearchHit.cs** class within the `Search.Contracts` project defines the relevant data to be parsed from the Azure Search response. -For your bot the only mandatory inclusions are the `PropertyBag` IDictionary declaration and creation in the constructor. You can -define all other properties in this class relative to your bot's needs. - -```cs -[Serializable] -public class SearchHit -{ - public SearchHit() - { - this.PropertyBag = new Dictionary(); - } - - public IDictionary PropertyBag { get; set; } - - // customize the fields below as needed - public string Key { get; set; } - - public string Title { get; set; } - - public string PictureUrl { get; set; } - - public string Description { get; set; } -} -``` - -## After Azure Search responds - -Upon a successful query to the Azure Service, the search result will need to be parsed to retrieve the relevant data for the bot to display to -the user. To enable this, you'll need to create a `SearchResultMapper` class. The `GenericSearchResult` object created in the constructor -defines a list and dictionary to store results and facets respectively after each result is parsed respective to your bot's data models. - -Synchronize the properties in the `ToSearchHit` method to match the data model in **SearchHit.cs**. The `ToSearchHit` method will be executed -and generate a new `SearchHit` for every result found in the response. - -```cs -public class SearchResultMapper : IMapper -{ - public GenericSearchResult Map(DocumentSearchResult documentSearchResult) - { - var searchResult = new GenericSearchResult(); - - searchResult.Results = documentSearchResult.Results.Select(r => ToSearchHit(r)).ToList(); - searchResult.Facets = documentSearchResult.Facets?.ToDictionary(kv => kv.Key, kv => kv.Value.Select(f => ToFacet(f))); - - return searchResult; - } - - private static GenericFacet ToFacet(FacetResult facetResult) - { - return new GenericFacet - { - Value = facetResult.Value, - Count = facetResult.Count.Value - }; - } - - private static SearchHit ToSearchHit(SearchResult hit) - { - return new SearchHit - { - // custom properties defined in SearchHit.cs - Key = (string)hit.Document["id"], - Title = (string)hit.Document["title"], - PictureUrl = (string)hit.Document["thumbnail"], - Description = (string)hit.Document["description"] - }; - } -} -``` -After the results are parsed and stored, the information still needs to be displayed to the user. -The `SearchHitStyler` class will need to be managed to accommodate the your data model from the `SearchHit` class. For example, the `Title`, `PictureUrl`, and `Description` properties from the **SearchHit.cs** class are used in the sample code to create a new card attachments. The following code creates a new card attachment for every `SearchHit` object in the `GenericSearchResult` Results list to display to the user. - -```cs -[Serializable] -public class SearchHitStyler : PromptStyler -{ - public override void Apply(ref IMessageActivity message, string prompt, IReadOnlyList options, IReadOnlyList descriptions = null) - { - var hits = options as IList; - if (hits != null) - { - var cards = hits.Select(h => new ThumbnailCard - { - Title = h.Title, - Images = new[] { new CardImage(h.PictureUrl) }, - Buttons = new[] { new CardAction(ActionTypes.ImBack, "Pick this one", value: h.Key) }, - Text = h.Description - }); - - message.AttachmentLayout = AttachmentLayoutTypes.Carousel; - message.Attachments = cards.Select(c => c.ToAttachment()).ToList(); - message.Text = prompt; - } - else - { - base.Apply(ref message, prompt, options, descriptions); - } - } -} -``` -The search results are displayed to the user and you've successfully added Azure Search to your bot. - -## Samples - -For two complete samples that show how to support Azure Search with bots using the Bot Framework SDK for .NET, see the -[Real Estate bot sample](https://github.com/Microsoft/BotBuilder-Samples/tree/v3-sdk-samples/CSharp/demo-Search/RealEstateBot) or [Job Listing bot sample](https://github.com/Microsoft/BotBuilder-Samples/tree/v3-sdk-samples/CSharp/demo-Search/JobListingBot) in GitHub. - -## Additional resources - -- [Azure Search][search] -- [Dialogs overview](bot-builder-dotnet-dialogs.md) - -[search]: /azure/search/search-what-is-azure-search diff --git a/articles/dotnet/bot-builder-dotnet-security.md b/articles/dotnet/bot-builder-dotnet-security.md deleted file mode 100644 index a2cf2efee..000000000 --- a/articles/dotnet/bot-builder-dotnet-security.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Secure your bot - Bot Service -description: Learn how to secure your bot by using HTTPS and Bot Framework Authentication. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Secure your bot - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -Your bot can be connected to many different communication channels (Skype, SMS, email, and others) through the Bot Framework Connector service. This article describes how to secure your bot by using HTTPS and Bot Framework authentication. - -## Use HTTPS and Bot Framework authentication - -To ensure that your bot's endpoint can only be accessed by the Bot Framework [Connector](bot-builder-dotnet-concepts.md#connector), configure your bot's endpoint to use only HTTPS and enable Bot Framework authentication by [registering](~/bot-service-quickstart-registration.md) your bot to acquire its appID and password. - -## Configure authentication for your bot - -Specify the bot's appID and password in your bot's web.config file. - -> [!NOTE] -> To find your bot's **AppID** and **AppPassword**, see [MicrosoftAppID and MicrosoftAppPassword](~/bot-service-manage-overview.md#microsoftappid-and-microsoftapppassword). - -```xml - - - - -``` - -Then, use the `[BotAuthentication]` attribute to specify authentication credentials when using the Bot Framework SDK for .NET to create your bot. - -To use the authentication credentials that are stored in the web.config file, specify the `[BotAuthentication]` with no parameters. - -[!code-csharp[Use botAuthentication attribute](../includes/code/dotnet-security.cs#attribute1)] - -To use other values for authentication credentials, specify the `[BotAuthentication]` attribute and pass in those values. - -[!code-csharp[Use botAuthentication attribute with parameters](../includes/code/dotnet-security.cs#attribute2)] - -## Additional resources - -- [Bot Framework SDK for .NET](bot-builder-dotnet-overview.md) -- [Key concepts in the bot Builder SDK for .NET](bot-builder-dotnet-concepts.md) -- [Register a bot with the Bot Framework](~/bot-service-quickstart-registration.md) diff --git a/articles/dotnet/bot-builder-dotnet-state-azure-cosmosdb.md b/articles/dotnet/bot-builder-dotnet-state-azure-cosmosdb.md deleted file mode 100644 index 83f04ca4f..000000000 --- a/articles/dotnet/bot-builder-dotnet-state-azure-cosmosdb.md +++ /dev/null @@ -1,123 +0,0 @@ ---- -title: Manage custom state data with Azure Cosmos DB (v3 C#) - Bot Service -description: Learn how to save and retrieve state data using Azure Cosmos DB with the Bot Framework SDK for .NET -author: kamrani -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Manage custom state data with Azure Cosmos DB for .NET - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -In this article, you’ll implement Azure Cosmos DB to store and manage your bot’s state data. The default Connector State Service used by bots is not intended for the production environment. You should either use [Azure Extensions](https://github.com/Microsoft/BotBuilder-Azure) available on GitHub or implement a custom state client using data storage platform of your choice. Here are some of the reasons to use custom state storage: - - Higher state API throughput (more control over performance) - - Lower-latency for geo-distribution - - Control over where the data is stored - - Access to the actual state data - - Store more than 32kb of data - -## Prerequisites -You'll need: - - [Microsoft Azure Account](https://azure.microsoft.com/free/) - - [Visual Studio 2015 or later](https://www.visualstudio.com/) - - [Bot Builder Azure NuGet Package](https://www.nuget.org/packages/Microsoft.Bot.Builder.Azure/) - - [Autofac Web Api2 NuGet Package](https://www.nuget.org/packages/Autofac.WebApi2/) - - [Bot Framework Emulator](~/bot-service-debug-emulator.md) - -## Create Azure account -If you don't have an Azure account, click [here](https://azure.microsoft.com/free/) to sign up for a free account. - -## Set up the Azure Cosmos DB database -1. After you’ve logged into the Azure portal, create a new *Azure Cosmos DB* database by clicking **New**. -2. Click **Databases**. -3. Find **Azure Cosmos DB** and click **Create**. -4. Fill in the fields. For the **API** field, select **SQL (DocumentDB)**. When done filling in all the fields, click the **Create** button at the bottom of the screen to deploy the new database. -5. After the new database is deployed, navigate to your new database. Click **Access keys** to find keys and connection strings. Your bot will use this information to call the storage service to save state data. - -## Install NuGet packages -1. Open an existing C# bot project, or create a new one using the Bot template in Visual Studio. -2. Install the following NuGet packages: - - Microsoft.Bot.Builder.Azure - - Autofac.WebApi2 - -## Add connection string -Add the following entries into the Web.config file: -```XML - - -``` -You'll replace the value with your URI and Primary Key found in your Azure Cosmos DB. Save the Web.config file. - -## Modify your bot code -To use **Azure Cosmos DB** storage, add the following lines of code to your bot's **Global.asax.cs** file inside the **Application_Start()** method. - -```cs -using System; -using Autofac; -using System.Web.Http; -using System.Configuration; -using Microsoft.Bot.Connector; -using Microsoft.Bot.Builder.Azure; -using Microsoft.Bot.Builder.Dialogs; -using Microsoft.Bot.Builder.Dialogs.Internals; - -namespace SampleApp -{ - public class WebApiApplication : System.Web.HttpApplication - { - protected void Application_Start() - { - GlobalConfiguration.Configure(WebApiConfig.Register); - var uri = new Uri(ConfigurationManager.AppSettings["DocumentDbUrl"]); - var key = ConfigurationManager.AppSettings["DocumentDbKey"]; - var store = new DocumentDbBotDataStore(uri, key); - - Conversation.UpdateContainer( - builder => - { - builder.Register(c => store) - .Keyed>(AzureModule.Key_DataStore) - .AsSelf() - .SingleInstance(); - - builder.Register(c => new CachingBotDataStore(store, CachingBotDataStoreConsistencyPolicy.ETagBasedConsistency)) - .As>() - .AsSelf() - .InstancePerLifetimeScope(); - - }); - - } - } -} -``` - -Save the global.asax.cs file. Now you are ready to test the bot with the emulator. - -## Run your bot app -Run your bot in Visual Studio, the code you added will create the custom **botdata** table in Azure. - -## Connect your bot to the emulator -At this point, your bot is running locally. Next, start the emulator and then connect to your bot in the emulator: -1. Type http://localhost:port-number/api/messages into the address bar, where port-number matches the port number shown in the browser where your application is running. You can leave Microsoft App ID and Microsoft App Password fields blank for now. You'll get this information later when you [register your bot](~/bot-service-quickstart-registration.md). -2. Click **Connect**. -3. Test your bot by typing a few messages in the emulator. - -## View state data on Azure Portal -To view the state data, sign into your Azure portal and navigate to your database. Click **Data Explorer (preview)** to verify that the state information from your bot is being saved. - -## Next steps -In this article, you used Cosmos DB for saving and managing your bot's data. Next, learn how to model conversation flow by using dialogs. - -> [!div class="nextstepaction"] -> [Manage conversation flow](bot-builder-dotnet-manage-conversation-flow.md) - -## Additional resources -If you are unfamiliar with Inversion of Control containers and Dependency Injection pattern used in the code above, visit [Autofac](http://autofac.readthedocs.io/en/latest/) site for information. - -You can also download a [sample](https://github.com/Microsoft/BotBuilder-Azure/tree/master/CSharp/Samples/DocumentDb) from GitHub to learn more about using Cosmos DB for managing state. diff --git a/articles/dotnet/bot-builder-dotnet-state-azure-table-storage.md b/articles/dotnet/bot-builder-dotnet-state-azure-table-storage.md deleted file mode 100644 index ca9bc61bd..000000000 --- a/articles/dotnet/bot-builder-dotnet-state-azure-table-storage.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: Manage custom state data with Azure Table storage (v3 C#) - Bot Service -description: Learn how to save and retrieve state data using Azure Table Storage with the Bot Framework SDK for .NET -author: kamrani -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Manage custom state data with Azure Table Storage for .NET - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -In this article, you’ll implement Azure Table storage to store and manage your bot’s state data. The default Connector State Service used by bots is not intended for the production environment. You should either use [Azure Extensions](https://github.com/Microsoft/BotBuilder-Azure) available on GitHub or implement a custom state client using data storage platform of your choice. Here are some of the reasons to use custom state storage: - - Higher state API throughput (more control over performance) - - Lower-latency for geo-distribution - - Control over where the data is stored - - Access to the actual state data - - Store more than 32kb of data - -## Prerequisites -You'll need: - - [Microsoft Azure Account](https://azure.microsoft.com/free/) - - [Visual Studio 2015 or later](https://www.visualstudio.com/) - - [Bot Builder Azure NuGet Package](https://www.nuget.org/packages/Microsoft.Bot.Builder.Azure/) - - [Autofac Web Api2 NuGet Package](https://www.nuget.org/packages/Autofac.WebApi2/) - - [Bot Framework Emulator](https://emulator.botframework.com/) - - [Azure Storage Explorer](http://storageexplorer.com/) - -## Create Azure account -If you don't have an Azure account, click [here](https://azure.microsoft.com/free/) to sign up for a free account. - -## Set up the Azure Table storage service -1. After you’ve logged into the Azure portal, create a new Azure Table storage service by clicking on **New**. -2. Search for **Storage account** that implements the Azure Table. -3. Fill in the fields, click the **Create** button at the bottom of the screen to deploy the new storage service. After the new storage service is deployed, it will display features and options available to you. -4. Select the **Access keys** tab on the left, and copy the connection string for later use. Your bot will use this connection string to call the storage service to save state data. - -## Install NuGet packages -1. Open an existing C# bot project, or create a new one using the C# Bot template in Visual Studio. -2. Install the following NuGet packages: - - Microsoft.Bot.Builder.Azure - - Autofac.WebApi2 - -## Add connection string -Add the following entry in your Web.config file: -```XML - - - -``` -Replace "YourConnectionString" with the connection string to the Azure Table storage you saved earlier. Save the Web.config file. - -## Modify your bot code -In the Global.asax.cs file, add the following `using` statements: -```cs -using Autofac; -using System.Configuration; -using Microsoft.Bot.Connector; -using Microsoft.Bot.Builder.Azure; -using Microsoft.Bot.Builder.Dialogs; -using Microsoft.Bot.Builder.Dialogs.Internals; -``` -In the `Application_Start()` method, create an instance of the `TableBotDataStore` class. The `TableBotDataStore` class implements the `IBotDataStore` interface. The `IBotDataStore` interface allows you to override the default Connector State Service connection. - ```cs - var store = new TableBotDataStore(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString); - ``` -Register the service as shown below: - ```cs - Conversation.UpdateContainer( - builder => - { - builder.Register(c => store) - .Keyed>(AzureModule.Key_DataStore) - .AsSelf() - .SingleInstance(); - - builder.Register(c => new CachingBotDataStore(store, - CachingBotDataStoreConsistencyPolicy - .ETagBasedConsistency)) - .As>() - .AsSelf() - .InstancePerLifetimeScope(); - - - }); - ``` -Save the Global.asax.cs file. - -## Run your bot app -Run your bot in Visual Studio, the code you added will create the custom **botdata** table in Azure. - -## Connect your bot to the emulator -At this point, your bot is running locally. Next, start the emulator and then connect to your bot in the emulator: -1. Type http://localhost:port-number/api/messages into the address bar, where port-number matches the port number shown in the browser where your application is running. You can leave Microsoft App ID and Microsoft App Password fields blank for now. You'll get this information later when you [register your bot](~/bot-service-quickstart-registration.md). -2. Click **Connect**. -3. Test your bot by typing a few messages in the emulator. - -## View data in Azure Table storage -To view the state data, open **Storage Explorer** and connect to Azure using your Azure Portal credential or connect directly to the table using the storage name and storage key then navigate to your table name. - -## Next steps -In this article, you implemented Azure Table storage for saving and managing your bot's data. Next, learn how to model conversation flow by using dialogs. - -> [!div class="nextstepaction"] -> [Manage conversation flow](bot-builder-dotnet-manage-conversation-flow.md) - - -## Additional resources - -If you are unfamiliar with Inversion of Control containers and Dependency Injection pattern used in the code above, go to [Autofac](http://autofac.readthedocs.io/en/latest/) site for information. - -You can also download a complete [Azure Table storage](https://github.com/Microsoft/BotBuilder-Azure/tree/master/CSharp/Samples/AzureTable) sample from GitHub. diff --git a/articles/dotnet/bot-builder-dotnet-state.md b/articles/dotnet/bot-builder-dotnet-state.md deleted file mode 100644 index 83bb1b565..000000000 --- a/articles/dotnet/bot-builder-dotnet-state.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: Manage state data (v3 C#) - Bot Service -description: Learn how to save and retrieve state data with the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Manage state data - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-state.md) -> - [Node.js](../nodejs/bot-builder-nodejs-state.md) - -[!INCLUDE [State concept overview](../includes/snippet-dotnet-concept-state.md)] - -## In-memory data storage - -In-memory data storage is intended for testing only. This storage is volatile and temporary. The data is cleared each time the bot is restarted. To use the in-memory storage for testing purposes, you will need to: - -Install the following NuGet packages: -- Microsoft.Bot.Builder.Azure -- Autofac.WebApi2 - -In the **Application_Start** method, create a new instance of the in-memory storage, and register the new data store: - -```cs -// Global.asax file - -var store = new InMemoryDataStore(); - -Conversation.UpdateContainer( - builder => - { - builder.Register(c => store) - .Keyed>(AzureModule.Key_DataStore) - .AsSelf() - .SingleInstance(); - - builder.Register(c => new CachingBotDataStore(store, - CachingBotDataStoreConsistencyPolicy - .ETagBasedConsistency)) - .As>() - .AsSelf() - .InstancePerLifetimeScope(); - - - }); -GlobalConfiguration.Configure(WebApiConfig.Register); - -``` - -You can use this method to set your own custom data storage or use any of the *Azure Extensions*. - -## Manage custom data storage - -For performance and security reasons in the production environment, you may implement your own data storage or consider implementing one of the following data storage options: - -1. [Manage state data with Cosmos DB](bot-builder-dotnet-state-azure-cosmosdb.md) - -2. [Manage state data with Table storage](bot-builder-dotnet-state-azure-table-storage.md) - -With either of these [Azure Extensions](https://www.nuget.org/packages/Microsoft.Bot.Builder.Azure/) options, the mechanism for setting and persisting data via the Bot Framework SDK for .NET remains the same as the in-memory data storage. - -## Bot state methods - -This table lists the methods that you can use to manage state data. - -| Method | Scoped to | Objective | -|----|----|----| -| `GetUserData` | User | Get state data that has previously been saved for the user on the specified channel | -| `GetConversationData` | Conversation | Get state data that has previously been saved for the conversation on the specified channel | -| `GetPrivateConversationData` | User and Conversation | Get state data that has previously been saved for the user within the conversation on the specified channel | -| `SetUserData` | User | Save state data for the user on the specified channel | -| `SetConversationData` | Conversation | Save state data for the conversation on the specified channel.

**Note**: Because the `DeleteStateForUser` method does not delete data that has been stored using the `SetConversationData` method, you must NOT use this method to store a user's personally identifiable information (PII). | -| `SetPrivateConversationData` | User and Conversation | Save state data for the user within the conversation on the specified channel | -| `DeleteStateForUser` | User | Delete state data for the user that has previously been stored by using either the `SetUserData` method or the `SetPrivateConversationData` method.

**Note**: Your bot should call this method when it receives an activity of type [deleteUserData](bot-builder-dotnet-activities.md#deleteuserdata) or an activity of type [contactRelationUpdate](bot-builder-dotnet-activities.md#contactrelationupdate) that indicates the bot has been removed from the user's contact list. | - -If your bot saves state data by using one of the "**Set...Data**" methods, future messages that your bot receives in the same context will contain that data, which your bot can access by using the corresponding "**Get...Data**" method. - -## Useful properties for managing state data - -Each [Activity][Activity] object contains properties that you will use to manage state data. - -| Property | Description | Use case | -|----|----|----| -| `From` | Uniquely identifies a user on a channel | Storing and retrieving state data that is associated with a user | -| `Conversation` | Uniquely identifies a conversation | Storing and retrieving state data that is associated with a conversation | -| `From` and `Conversation` | Uniquely identifies a user and conversation | Storing and retrieving state data that is associated with a specific user within the context of a specific conversation | - -> [!NOTE] -> You may use these property values as keys even if you opt to store state data in your own database, rather than using the Bot Framework state data store. - -## Handle concurrency issues - -Your bot may receive an error response with HTTP status code **412 Precondition Failed** -when it attempts to save state data, if another instance of the bot has changed the data. -You can design your bot to account for this scenario, as shown in the following code example. - -[!code-csharp[Handle exception saving state](../includes/code/dotnet-state.cs#handleException)] - -## Additional resources - -- [Bot Framework troubleshooting guide](../bot-service-troubleshoot-general-problems.md) -- Bot Framework SDK for .NET Reference - -[Activity]: https://docs.botframework.com/csharp/builder/sdkreference/dc/d2f/class_microsoft_1_1_bot_1_1_connector_1_1_activity.html diff --git a/articles/dotnet/bot-builder-dotnet-text-to-speech.md b/articles/dotnet/bot-builder-dotnet-text-to-speech.md deleted file mode 100644 index f173d6175..000000000 --- a/articles/dotnet/bot-builder-dotnet-text-to-speech.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Add speech to messages (v3 C#) - Bot Service -description: Learn how to add speech to messages using the Bot Framework SDK for .NET. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Add speech to messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-text-to-speech.md) -> - [Node.js](../nodejs/bot-builder-nodejs-text-to-speech.md) -> - [REST](../rest-api/bot-framework-rest-connector-text-to-speech.md) - -If you are building a bot for a speech-enabled channel such as Cortana, you can construct messages that specify the text to be spoken by your bot. You can also attempt to influence the state of the client's microphone by specifying an [input hint](bot-builder-dotnet-add-input-hints.md) to indicate whether your bot is accepting, expecting, or ignoring user input. - -## Specify text to be spoken by your bot - -Using the Bot Framework SDK for .NET, there are multiple ways to specify the text to be spoken by your bot on a speech-enabled channel. You can set the `Speak` property of the [message][IMessageActivity], call the `IDialogContext.SayAsync()` method, or specify prompt options `speak` and `retrySpeak` when sending a message using a built-in prompt. - -### IMessageActivity.Speak - -If you are creating a [message][IMessageActivity] and setting its individual properties, you can set the `Speak` property of the message to specify the text to be spoken by your bot. The following code example creates a message that specifies text to be displayed and text to be spoken and indicates that the bot is [accepting user input](bot-builder-dotnet-add-input-hints.md). - -[!code-csharp[Set speak property](../includes/code/dotnet-text-to-speech.cs#Speak1)] - -### IDialogContext.SayAsync() - -If you are using [dialogs](bot-builder-dotnet-dialogs.md), you can call the `SayAsync()` method to create and send a message that specifies the text to be spoken, in addition to the text to be displayed and other options. The following code example creates a message that specifies text to be displayed and text to be spoken. - -[!code-csharp[Call SayAsync()](../includes/code/dotnet-text-to-speech.cs#Speak2)] - -### Prompt options - -Using any of the built-in prompts, you can set the options `speak` and `retrySpeak` to specify the text to be spoken by your bot. The following code example creates a prompt that specifies text to be displayed, text to be spoken initially, and text to be spoken after waiting a while for user input. It uses [SSML](#ssml) formatting to indicate that the word "sure" should be spoken with a moderate amount of emphasis. - -[!code-csharp[Set Prompt options](../includes/code/dotnet-text-to-speech.cs#Speak3)] - -## Speech Synthesis Markup Language (SSML) - -To specify text to be spoken by your bot, you can give it a string that is formatted as Speech Synthesis Markup Language (SSML). SSML is an XML-based markup language (and therefore must be valid XML) that enables you to control various characteristics of your bot's speech such as voice, rate, volume, pronunciation, pitch, and more. For details about SSML, see Speech Synthesis Markup Language Reference. - -When providing the SSML formatted string, the outer SSML wrapper element may be omitted. - -## Input hints - -When you send a message on a speech-enabled channel, you can attempt to influence the state of the client's microphone by also including an input hint to indicate whether your bot is accepting, expecting, or ignoring user input. For more information, see [Add input hints to messages](bot-builder-dotnet-add-input-hints.md). - -## Sample code - -For a complete sample that shows how to create a speech-enabled bot using the Bot Framework SDK for .NET, see the Roller Skill sample in GitHub. - -## Additional resources - -- [Create messages](bot-builder-dotnet-create-messages.md) -- [Add input hints to messages](bot-builder-dotnet-add-input-hints.md) -- Speech Synthesis Markup Language (SSML) -- Roller Skill sample (GitHub) -- Activity class -- IMessageActivity interface -- DialogContext class -- Prompt class - -[IMessageActivity]: /dotnet/api/microsoft.bot.connector.imessageactivity - diff --git a/articles/includes/alert-await-send-activity.md b/articles/includes/alert-await-send-activity.md deleted file mode 100644 index 44e0fee0f..000000000 --- a/articles/includes/alert-await-send-activity.md +++ /dev/null @@ -1,2 +0,0 @@ -> [!IMPORTANT] -> The thread handling the primary bot turn deals with disposing of the context object when it is done. **Be sure to `await` any activity calls** so the primary thread will wait on the generated activity before finishing its processing and disposing of the turn context. Otherwise, if a response (including its handlers) takes any significant amount of time and tries to act on the context object, it may get a _context was disposed_ error. \ No newline at end of file diff --git a/articles/includes/applies-to-both.md b/articles/includes/applies-to-both.md deleted file mode 100644 index 3f296f7b6..000000000 --- a/articles/includes/applies-to-both.md +++ /dev/null @@ -1 +0,0 @@ -**APPLIES TO:** ![yes](../media/yes.png)SDK v4 ![yes](../media/yes.png)SDK v3 diff --git a/articles/includes/applies-to.md b/articles/includes/applies-to.md deleted file mode 100644 index 5f03df722..000000000 --- a/articles/includes/applies-to.md +++ /dev/null @@ -1 +0,0 @@ -**APPLIES TO:** ![yes](../media/yes.png)SDK v4 ![no](../media/no.png) SDK v3 diff --git a/articles/includes/code/azure-bot-debug.js b/articles/includes/code/azure-bot-debug.js deleted file mode 100644 index 83889366b..000000000 --- a/articles/includes/code/azure-bot-debug.js +++ /dev/null @@ -1,5 +0,0 @@ -// -"env": { - "NODE\_ENV": "development" -} -// diff --git a/articles/includes/code/azure-bot-service-serverless-template-basic.cs b/articles/includes/code/azure-bot-service-serverless-template-basic.cs deleted file mode 100644 index 835893796..000000000 --- a/articles/includes/code/azure-bot-service-serverless-template-basic.cs +++ /dev/null @@ -1,139 +0,0 @@ -// -// Authenticates the incoming request. If the request is authentic, it adds the activity.ServiceUrl to -// MicrosoftAppCredentials.TrustedHostNames. Otherwise, it returns Unauthorized. - -if (!await botAuthenticator.Value.TryAuthenticateAsync(req, new [] {activity}, CancellationToken.None)) -{ - return BotAuthentication.GenerateUnauthorizedResponse(req); -} -// - - - -// -switch (activity.GetActivityType()) -{ - case ActivityTypes.Message: - // Processes the user’s message. - break; - case ActivityTypes.ConversationUpdate: - // Welcomes the users to the conversation. - break; - case ActivityTypes.ContactRelationUpdate: - case ActivityTypes.Typing: - case ActivityTypes.DeleteUserData: - default: - log.Error($"Unknown activity type ignored: {activity.GetActivityType()}"); - break; -} -// - - - -// -case ActivityTypes.ConversationUpdate: - IConversationUpdateActivity update = activity; - using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity)) - { - var client = scope.Resolve(); - if (update.MembersAdded.Any()) - { - var reply = activity.CreateReply(); - var newMembers = update.MembersAdded?.Where(t => t.Id != activity.Recipient.Id); - foreach (var newMember in newMembers) - { - reply.Text = "Welcome"; - if (!string.IsNullOrEmpty(newMember.Name)) - { - reply.Text += $" {newMember.Name}"; - } - reply.Text += "!"; - await client.Conversations.ReplyToActivityAsync(reply); - } - } - } - break; -// - - - -// -switch (activity.GetActivityType()) -{ - case ActivityTypes.Message: - await Conversation.SendAsync(activity, () => new EchoDialog()); - break; - ... -} -// - - - -// -[Serializable] -public class EchoDialog : IDialog -{ - protected int count = 1; - - public Task StartAsync(IDialogContext context) - { - try - { - context.Wait(MessageReceivedAsync); - } - catch (OperationCanceledException error) - { - return Task.FromCanceled(error.CancellationToken); - } - catch (Exception error) - { - return Task.FromException(error); - } - - return Task.CompletedTask; - } - ... -} -// - - - -// -public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable argument) -{ - var message = await argument; - if (message.Text == "reset") - { - PromptDialog.Confirm( - context, - AfterResetAsync, - "Are you sure you want to reset the count?", - "Didn't get that!", - promptStyle: PromptStyle.Auto); - } - else - { - await context.PostAsync($"{this.count++}: You said {message.Text}"); - context.Wait(MessageReceivedAsync); - } -} -// - - - -// -public async Task AfterResetAsync(IDialogContext context, IAwaitable argument) -{ - var confirm = await argument; - if (confirm) - { - this.count = 1; - await context.PostAsync("Reset count."); - } - else - { - await context.PostAsync("Did not reset count."); - } - context.Wait(MessageReceivedAsync); -} -// diff --git a/articles/includes/code/azure-bot-service-serverless-template-form.cs b/articles/includes/code/azure-bot-service-serverless-template-form.cs deleted file mode 100644 index 4cc28e59b..000000000 --- a/articles/includes/code/azure-bot-service-serverless-template-form.cs +++ /dev/null @@ -1,91 +0,0 @@ -// -switch (activity.GetActivityType()) -{ - case ActivityTypes.Message: - await Conversation.SendAsync(activity, () => new MainDialog()); - break; - ... -} -// - - - -// -public class MainDialog : IDialog -{ - public MainDialog() - { - } - - public Task StartAsync(IDialogContext context) - { - context.Wait(MessageReceivedAsync); - return Task.CompletedTask; - } - ... -} -// - - - -// -public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable argument) -{ - var message = await argument; - context.Call(BasicForm.BuildFormDialog(FormOptions.PromptInStart), FormComplete); -} - -private async Task FormComplete(IDialogContext context, IAwaitable result) -{ - try - { - var form = await result; - if (form != null) - { - await context.PostAsync("Thanks for completing the form! Just type anything to restart it."); - } - else - { - await context.PostAsync("Form returned empty response! Type anything to restart it."); - } - } - catch (OperationCanceledException) - { - await context.PostAsync("You canceled the form! Type anything to restart it."); - } - - context.Wait(MessageReceivedAsync); -} -// - - - -// -public enum CarOptions { Convertible=1, SUV, EV }; -public enum ColorOptions { Red=1, White, Blue }; - -[Serializable] -public class BasicForm -{ - [Prompt("Hi! What is your {&}?")] - public string Name { get; set; } - - [Prompt("Please select your favorite car type {||}")] - public CarOptions Car { get; set; } - - [Prompt("Please select your favorite {&} {||}")] - public ColorOptions Color { get; set; } - - public static IForm BuildForm() - { - // Builds an IForm based on BasicForm - return new FormBuilder().Build(); - } - - public static IFormDialog BuildFormDialog(FormOptions options = FormOptions.PromptInStart) - { - // Generate a new FormDialog based on IForm - return FormDialog.FromForm(BuildForm, options); - } -} -// diff --git a/articles/includes/code/azure-bot-service-serverless-template-language-understanding.cs b/articles/includes/code/azure-bot-service-serverless-template-language-understanding.cs deleted file mode 100644 index dc0544dae..000000000 --- a/articles/includes/code/azure-bot-service-serverless-template-language-understanding.cs +++ /dev/null @@ -1,34 +0,0 @@ -// -switch (activity.GetActivityType()) -{ - case ActivityTypes.Message: - await Conversation.SendAsync(activity, () => new BasicLuisDialog()); - break; - ... -} -// - - -// -[Serializable] -public class BasicLuisDialog : LuisDialog -{ - public BasicLuisDialog() : base(new LuisService(new LuisModelAttribute(Utils.GetAppSetting("LuisAppId"), Utils.GetAppSetting("LuisAPIKey")))) - { - } - - [LuisIntent("None")] - public async Task NoneIntent(IDialogContext context, LuisResult result) - { - await context.PostAsync($"You have reached the none intent. You said: {result.Query}"); // - context.Wait(MessageReceived); - } - - [LuisIntent("MyIntent")] - public async Task MyIntent(IDialogContext context, LuisResult result) - { - await context.PostAsync($"You have reached the MyIntent intent. You said: {result.Query}"); // - context.Wait(MessageReceived); - } -} -// \ No newline at end of file diff --git a/articles/includes/code/azure-bot-service-serverless-template-proactive.cs b/articles/includes/code/azure-bot-service-serverless-template-proactive.cs deleted file mode 100644 index 0c7f52cc7..000000000 --- a/articles/includes/code/azure-bot-service-serverless-template-proactive.cs +++ /dev/null @@ -1,66 +0,0 @@ -// -public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable argument) -{ - var message = await argument; - - // Create a queue Message - var queueMessage = new Message - { - RelatesTo = context.Activity.ToConversationReference(), - Text = message.Text - }; - - // Write the queue Message to the queue - // AddMessageToQueue() is a utility method you can find in the template - await AddMessageToQueue(JsonConvert.SerializeObject(queueMessage)); - await context.PostAsync($"{this.count++}: You said {queueMessage.Text}. Message added to the queue."); - context.Wait(MessageReceivedAsync); -} -// - - - -// -using System; -using System.Net; -using System.Net.Http; -using Microsoft.Azure.WebJobs.Host; - -public class BotMessage -{ - public string Source { get; set; } - public string Message { get; set; } -} - -public static HttpResponseMessage Run(string myQueueItem, out BotMessage message, TraceWriter log) -{ - message = new BotMessage - { - Source = "Azure Functions (C#)!", - Message = myQueueItem - }; - - return new HttpResponseMessage(HttpStatusCode.OK); -} -// - - - -// -switch (activity.GetActivityType()) -{ - case ActivityTypes.Event: - // handle proactive Message from function - IEventActivity triggerEvent = activity; - var message = JsonConvert.DeserializeObject(((JObject) triggerEvent.Value).GetValue("Message").ToString()); - var messageactivity = (Activity)message.RelatesTo.GetPostToBotMessage(); - - client = new ConnectorClient(new Uri(messageactivity.ServiceUrl)); - var triggerReply = messageactivity.CreateReply(); - triggerReply.Text = $"This is coming back from the trigger! {message.Text}"; - await client.Conversations.ReplyToActivityAsync(triggerReply); - break; - default: - break; -} -// \ No newline at end of file diff --git a/articles/includes/code/azure-bot-service-serverless-template-proactive.js b/articles/includes/code/azure-bot-service-serverless-template-proactive.js deleted file mode 100644 index 6b65d4aef..000000000 --- a/articles/includes/code/azure-bot-service-serverless-template-proactive.js +++ /dev/null @@ -1,49 +0,0 @@ -// -bot.dialog('/', function (session) { - var queuedMessage = { address: session.message.address, text: session.message.text }; - session.sendTyping(); - var queueSvc = azure.createQueueService(process.env.AzureWebJobsStorage); - queueSvc.createQueueIfNotExists('bot-queue', function(err, result, response){ - if(!err){ - var queueMessageBuffer = new Buffer(JSON.stringify(queuedMessage)).toString('base64'); - queueSvc.createMessage('bot-queue', queueMessageBuffer, function(err, result, response){ - if(!err){ - session.send('Your message (\'' + session.message.text + '\') has been added to a queue, and it will be sent back to you via a Function'); - } else { - session.send('There was an error inserting your message into queue'); - } - }); - } else { - session.send('There was an error creating your queue'); - } - }); -}); -// - - - -// -module.exports = function (context, myQueueItem) { - context.log('Sending Bot message', myQueueItem); - - var message = { - 'text': myQueueItem.text, - 'address': myQueueItem.address - }; - - context.done(null, message); -} -// - - - -// -bot.on('trigger', function (message) { - // handle message from trigger function - var queuedMessage = message.value; - var reply = new builder.Message() - .address(queuedMessage.address) - .text('This is coming from the trigger: ' + queuedMessage.text); - bot.send(reply); -}); -// diff --git a/articles/includes/code/azure-bot-service-serverless-template-question-and-answer.cs b/articles/includes/code/azure-bot-service-serverless-template-question-and-answer.cs deleted file mode 100644 index f5253c38c..000000000 --- a/articles/includes/code/azure-bot-service-serverless-template-question-and-answer.cs +++ /dev/null @@ -1,36 +0,0 @@ -// -switch (activity.GetActivityType()) -{ - case ActivityTypes.Message: - await Conversation.SendAsync(activity, () => new BasicQnAMakerDialog()); - break; - ... -} -// - - - -// -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using System.Threading; -using Microsoft.Bot.Connector; -using Microsoft.Bot.Builder.Dialogs; -using Microsoft.Bot.Builder.CognitiveServices.QnAMaker; - -[Serializable] -public class BasicQnAMakerDialog : QnAMakerDialog -{ - //Parameters to QnAMakerService are: - //Required: subscriptionKey, knowledgebaseId, - //Optional: defaultMessage, scoreThreshold[Range 0.0 – 1.0] - public BasicQnAMakerDialog() : base(new QnAMakerService(new QnAMakerAttribute(Utils.GetAppSetting("QnASubscriptionKey"), Utils.GetAppSetting("QnAKnowledgebaseId"), "No good match in FAQ.", 0.5))) - {} -} -// - - - - \ No newline at end of file diff --git a/articles/includes/code/azure-bot-service-serverless-template-question-and-answer.js b/articles/includes/code/azure-bot-service-serverless-template-question-and-answer.js deleted file mode 100644 index 324ade8eb..000000000 --- a/articles/includes/code/azure-bot-service-serverless-template-question-and-answer.js +++ /dev/null @@ -1,17 +0,0 @@ -// -bot.dialog('/', BasicQnAMakerDialog); -// - - - -// -var recognizer = new cognitiveservices.QnAMakerRecognizer({ - knowledgeBaseId: 'set your kbid here', - subscriptionKey: 'set your subscription key here'}); - -var BasicQnAMakerDialog = new cognitiveservices.QnAMakerDialog({ - recognizers: [recognizer], - defaultMessage: 'No good match in FAQ.', - qnaThreshold: 0.5}); -// - diff --git a/articles/includes/code/bot-service-channel-connect-webchat-speech.js b/articles/includes/code/bot-service-channel-connect-webchat-speech.js deleted file mode 100644 index 448296c3e..000000000 --- a/articles/includes/code/bot-service-channel-connect-webchat-speech.js +++ /dev/null @@ -1,66 +0,0 @@ -// Code snippets for channel-connect-webchat-speech.md - -// -const speechOptions = { - speechRecognizer: new BotChat.Speech.BrowserSpeechRecognizer(), - speechSynthesizer: new BotChat.Speech.BrowserSpeechSynthesizer() -}; -// - -// -const speechOptions = { - speechRecognizer: new CognitiveServices.SpeechRecognizer({ subscriptionKey: 'YOUR_COGNITIVE_SPEECH_API_KEY' }), - speechSynthesizer: new CognitiveServices.SpeechSynthesizer({ - gender: CognitiveServices.SynthesisGender.Female, - subscriptionKey: 'YOUR_COGNITIVE_SPEECH_API_KEY', - voiceName: 'Microsoft Server Speech Text to Speech Voice (en-US, JessaRUS)' - }) - }; -// - -// -function getToken() { -// This call would be to your backend, or to retrieve a token that was served as part of the original page. -return fetch( - 'https://api.cognitive.microsoft.com/sts/v1.0/issueToken', - { - headers: { - 'Ocp-Apim-Subscription-Key': 'YOUR_COGNITIVE_SPEECH_API_KEY' - }, - method: 'POST' - } -).then(res => res.text()); -} - -const speechOptions = { - speechRecognizer: new CognitiveServices.SpeechRecognizer({ - fetchCallback: (authFetchEventId) => getToken(), - fetchOnExpiryCallback: (authFetchEventId) => getToken() - }), - speechSynthesizer: new BotChat.Speech.BrowserSpeechSynthesizer() -}; -// - -// -const speechOptions = { - speechRecognizer: new YourOwnSpeechRecognizer(), - speechSynthesizer: new YourOwnSpeechSynthesizer() - }; -// - -// -BotChat.App({ - bot: bot, - locale: params['locale'], - resize: 'detect', - // sendTyping: true, // defaults to false. set to true to send 'typing' activities to bot (and other users) when user is typing - speechOptions: speechOptions, - user: user, - directLine: { - domain: params['domain'], - secret: params['s'], - token: params['t'], - webSocket: params['webSocket'] && params['webSocket'] === 'true' // defaults to true - } - }, document.getElementById('BotChatGoesHere')); -// \ No newline at end of file diff --git a/articles/includes/code/dotnet-add-attachments.cs b/articles/includes/code/dotnet-add-attachments.cs deleted file mode 100644 index b47a1eda1..000000000 --- a/articles/includes/code/dotnet-add-attachments.cs +++ /dev/null @@ -1,254 +0,0 @@ -// -replyMessage.Attachments.Add(new Attachment() -{ - ContentUrl = "https://upload.wikimedia.org/wikipedia/en/a/a6/Bender_Rodriguez.png", - ContentType = "image/png", - Name = "Bender_Rodriguez.png" -}); -// - - - -// -Activity replyToConversation = message.CreateReply("Should go to conversation, in carousel format"); -replyToConversation.AttachmentLayout = AttachmentLayoutTypes.Carousel; -replyToConversation.Attachments = new List(); - -Dictionary cardContentList = new Dictionary(); -cardContentList.Add("PigLatin", "https://"); -cardContentList.Add("Pork Shoulder", "https://"); -cardContentList.Add("Bacon", "https://"); - -foreach(KeyValuePair cardContent in cardContentList) -{ - List cardImages = new List(); - cardImages.Add(new CardImage(url:cardContent.Value )); - - List cardButtons = new List(); - - CardAction plButton = new CardAction() - { - Value = $"https://en.wikipedia.org/wiki/{cardContent.Key}", - Type = "openUrl", - Title = "WikiPedia Page" - }; - - cardButtons.Add(plButton); - - HeroCard plCard = new HeroCard() - { - Title = $"I'm a hero card about {cardContent.Key}", - Subtitle = $"{cardContent.Key} Wikipedia Page", - Images = cardImages, - Buttons = cardButtons - }; - - Attachment plAttachment = plCard.ToAttachment(); - replyToConversation.Attachments.Add(plAttachment); -} - -var reply = await connector.Conversations.SendToConversationAsync(replyToConversation); -// - - - -// -Activity replyToConversation = message.CreateReply("Should go to conversation, in list format"); -replyToConversation.AttachmentLayout = AttachmentLayoutTypes.List; -replyToConversation.Attachments = new List(); - -Dictionary cardContentList = new Dictionary(); -cardContentList.Add("PigLatin", "https://"); -cardContentList.Add("Pork Shoulder", "https://"); - -foreach(KeyValuePair cardContent in cardContentList) -{ - List cardImages = new List(); - cardImages.Add(new CardImage(url:cardContent.Value )); - - List cardButtons = new List(); - - CardAction plButton = new CardAction() - { - Value = $"https://en.wikipedia.org/wiki/{cardContent.Key}", - Type = "openUrl", - Title = "WikiPedia Page" - }; - - cardButtons.Add(plButton); - - ThumbnailCard plCard = new ThumbnailCard() - { - Title = $"I'm a thumbnail card about {cardContent.Key}", - Subtitle = $"{cardContent.Key} Wikipedia Page", - Images = cardImages, - Buttons = cardButtons - }; - - Attachment plAttachment = plCard.ToAttachment(); - replyToConversation.Attachments.Add(plAttachment); -} - -var reply = await connector.Conversations.SendToConversationAsync(replyToConversation); -// - - - -// -Activity replyToConversation = message.CreateReply("Should go to conversation"); -replyToConversation.Attachments = new List(); - -List cardImages = new List(); -cardImages.Add(new CardImage(url: "https://" )); - -List cardButtons = new List(); - -CardAction plButton = new CardAction() -{ - Value = $"https://en.wikipedia.org/wiki/PigLatin", - Type = "openUrl", - Title = "WikiPedia Page" -}; - -cardButtons.Add(plButton); - -ReceiptItem lineItem1 = new ReceiptItem() -{ - Title = "Pork Shoulder", - Subtitle = "8 lbs", - Text = null, - Image = new CardImage(url: "https://"), - Price = "16.25", - Quantity = "1", - Tap = null -}; - -ReceiptItem lineItem2 = new ReceiptItem() -{ -Title = "Bacon", -Subtitle = "5 lbs", -Text = null, -Image = new CardImage(url: "https://"), -Price = "34.50", -Quantity = "2", -Tap = null -}; - -List receiptList = new List(); -receiptList.Add(lineItem1); -receiptList.Add(lineItem2); - -ReceiptCard plCard = new ReceiptCard() -{ - Title = "I'm a receipt card, isn't this bacon expensive?", - Buttons = cardButtons, - Items = receiptList, - Total = "112.77", - Tax = "27.52" -}; - -Attachment plAttachment = plCard.ToAttachment(); -replyToConversation.Attachments.Add(plAttachment); - -var reply = await connector.Conversations.SendToConversationAsync(replyToConversation); -// - - - -// -Activity replyToConversation = message.CreateReply("Should go to conversation"); -replyToConversation.Attachments = new List(); - -List cardButtons = new List(); - -CardAction plButton = new CardAction() -{ - Value = $"https:// - - - -// -Activity replyToConversation = message.CreateReply("Should go to conversation"); -replyToConversation.Attachments = new List(); - -AdaptiveCard card = new AdaptiveCard(); - -// Specify speech for the card. -card.Speak = "Your meeting about \"Adaptive Card design session\" is starting at 12:30pmDo you want to snooze or do you want to send a late notification to the attendees?"; - -// Add text to the card. -card.Body.Add(new TextBlock() -{ - Text = "Adaptive Card design session", - Size = TextSize.Large, - Weight = TextWeight.Bolder -}); - -// Add text to the card. -card.Body.Add(new TextBlock() -{ - Text = "Conf Room 112/3377 (10)" -}); - -// Add text to the card. -card.Body.Add(new TextBlock() -{ - Text = "12:30 PM - 1:30 PM" -}); - -// Add list of choices to the card. -card.Body.Add(new ChoiceSet() -{ - Id = "snooze", - Style = ChoiceInputStyle.Compact, - Choices = new List() - { - new Choice() { Title = "5 minutes", Value = "5", IsSelected = true }, - new Choice() { Title = "15 minutes", Value = "15" }, - new Choice() { Title = "30 minutes", Value = "30" } - } -}); - -// Add buttons to the card. -card.Actions.Add(new OpenUrlAction() -{ - Url = "http://foo.com", - Title = "Snooze" -}); - -card.Actions.Add(new OpenUrlAction() -{ - Url = "http://foo.com", - Title = "I'll be late" -}); - -card.Actions.Add(new OpenUrlAction() -{ - Url = "http://foo.com", - Title = "Dismiss" -}); - -// Create the attachment. -Attachment attachment = new Attachment() -{ - ContentType = AdaptiveCard.ContentType, - Content = card -}; - -replyToConversation.Attachments.Add(attachment); - -var reply = await connector.Conversations.SendToConversationAsync(replyToConversation); -// diff --git a/articles/includes/code/dotnet-add-suggested-actions.cs b/articles/includes/code/dotnet-add-suggested-actions.cs deleted file mode 100644 index ce10a58b8..000000000 --- a/articles/includes/code/dotnet-add-suggested-actions.cs +++ /dev/null @@ -1,15 +0,0 @@ -// -var reply = activity.CreateReply("I have colors in mind, but need your help to choose the best one."); -reply.Type = ActivityTypes.Message; -reply.TextFormat = TextFormatTypes.Plain; - -reply.SuggestedActions = new SuggestedActions() -{ - Actions = new List() - { - new CardAction(){ Title = "Blue", Type=ActionTypes.ImBack, Value="Blue" }, - new CardAction(){ Title = "Red", Type=ActionTypes.ImBack, Value="Red" }, - new CardAction(){ Title = "Green", Type=ActionTypes.ImBack, Value="Green" } - } -}; -// \ No newline at end of file diff --git a/articles/includes/code/dotnet-create-messages.cs b/articles/includes/code/dotnet-create-messages.cs deleted file mode 100644 index e7a4238a4..000000000 --- a/articles/includes/code/dotnet-create-messages.cs +++ /dev/null @@ -1,52 +0,0 @@ -// -IMessageActivity message = Activity.CreateMessageActivity(); -message.Text = "Hello!"; -message.TextFormat = "plain"; -message.Locale = "en-Us"; -// - -// -var entity = new Entity(); -entity.SetAs(new Mention() -{ - Text = "@johndoe", - Mentioned = new ChannelAccount() - { - Name = "John Doe", - Id = "UV341235" - } -}); -entities.Add(entity); -// - -// -var entity = new Entity(); -entity.SetAs(new Place() -{ - Geo = new GeoCoordinates() - { - Latitude = 32.4141, - Longitude = 43.1123123, - } -}); -entities.Add(entity); -// - -// -if (entity.Type == "Place") -{ - dynamic place = entity.Properties; - if (place.geo.latitude > 34) - // do something -} -// - -// -if (entity.Type == "Place") -{ - Place place = entity.GetAs(); - GeoCoordinates geo = place.Geo.ToObject(); - if (geo.Latitude > 34) - // do something -} -// \ No newline at end of file diff --git a/articles/includes/code/dotnet-dialogs.cs b/articles/includes/code/dotnet-dialogs.cs deleted file mode 100644 index 96d9272d2..000000000 --- a/articles/includes/code/dotnet-dialogs.cs +++ /dev/null @@ -1,163 +0,0 @@ -// -using Microsoft.Bot.Builder.Dialogs; -// - - -// -[Serializable] -public class EchoDialog : IDialog -{ - public async Task StartAsync(IDialogContext context) - { - context.Wait(MessageReceivedAsync); - } - - public async Task MessageReceivedAsync(IDialogContext context, IAwaitable argument) - { - var message = await argument; - await context.PostAsync("You said: " + message.Text); - context.Wait(MessageReceivedAsync); - } -} -// - - -// -public virtual async Task Post([FromBody] Activity activity) -{ - // Check if activity is of type message - if (activity != null && activity.GetActivityType() == ActivityTypes.Message) - { - await Conversation.SendAsync(activity, () => new EchoDialog()); - } - else - { - HandleSystemMessage(activity); - } - return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted); -} -// - - -// -[Serializable] -public class EchoDialog : IDialog -{ - protected int count = 1; - - public async Task StartAsync(IDialogContext context) - { - context.Wait(MessageReceivedAsync); - } - - public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable argument) - { - var message = await argument; - if (message.Text == "reset") - { - PromptDialog.Confirm( - context, - AfterResetAsync, - "Are you sure you want to reset the count?", - "Didn't get that!", - promptStyle: PromptStyle.None); - } - else - { - await context.PostAsync($"{this.count++}: You said {message.Text}"); - context.Wait(MessageReceivedAsync); - } - } - - public async Task AfterResetAsync(IDialogContext context, IAwaitable argument) - { - var confirm = await argument; - if (confirm) - { - this.count = 1; - await context.PostAsync("Reset count."); - } - else - { - await context.PostAsync("Did not reset count."); - } - context.Wait(MessageReceivedAsync); - } -} -// - - -// -var builder = new ContainerBuilder(); -builder.RegisterModule(new DialogModule()); -builder.RegisterModule(new ReflectionSurrogateModule()); -// - - -// -var query = from x in new PromptDialog.PromptString(Prompt, Prompt, attempts: 1) - let w = new string(x.Reverse().ToArray()) - select w; -// - - -// -var query = from x in new PromptDialog.PromptString("p1", "p1", 1) - from y in new PromptDialog.PromptString("p2", "p2", 1) - select string.Join(" ", x, y); -// - - -// -query = query.PostToUser(); -// - - -// -var logic = - toBot - .Switch - ( - new RegexCase(new Regex("^hello"), (context, text) => - { - return "world!"; - }), - new Case((txt) => txt == "world", (context, text) => - { - return "!"; - }), - new DefaultCase((context, text) => - { - return text; - } - ) -); -// - - -// -var joke = Chain - .PostToChain() - .Select(m => m.Text) - .Switch - ( - Chain.Case - ( - new Regex("^chicken"), - (context, text) => - Chain - .Return("why did the chicken cross the road?") - .PostToUser() - .WaitToBot() - .Select(ignoreUser => "to get to the other side") - ), - Chain.Default>( - (context, text) => - Chain - .Return("why don't you like chicken jokes?") - ) - ) - .Unwrap() - .PostToUser(). - Loop(); -// \ No newline at end of file diff --git a/articles/includes/code/dotnet-formflow-advanced.cs b/articles/includes/code/dotnet-formflow-advanced.cs deleted file mode 100644 index 2c86a33f3..000000000 --- a/articles/includes/code/dotnet-formflow-advanced.cs +++ /dev/null @@ -1,88 +0,0 @@ -// -public static IForm BuildForm() -{ - ... - return new FormBuilder() - .Message("Welcome to the sandwich order bot!") - .Field(nameof(Sandwich)) - .Field(nameof(Length)) - .Field(nameof(Bread)) - .Field(nameof(Cheese)) - .Field(nameof(Toppings), - validate: async (state, value) => - { - var values = ((List)value).OfType(); - var result = new ValidateResult { IsValid = true, Value = values }; - if (values != null && values.Contains(ToppingOptions.Everything)) - { - result.Value = (from ToppingOptions topping in Enum.GetValues(typeof(ToppingOptions)) - where topping != ToppingOptions.Everything && !values.Contains(topping) - select topping).ToList(); - } - return result; - }) - .Message("For sandwich toppings you have selected {Toppings}.") - ... - .Build(); -} -// - - -// -public enum ToppingOptions -{ - // This starts at 1 because 0 is the "no value" value - [Terms("except", "but", "not", "no", "all", "everything")] - Everything = 1, - ... -} -// - - -// -[Prompt("What kind of {&} would you like? {||}")] -public SandwichOptions? Sandwich; -// - - -// -[Prompt("What kind of {&} would you like? {||}", ChoiceFormat="{1}")] -public SandwichOptions? Sandwich; -// - - -// -[Template(TemplateUsage.EnumSelectOne, "What kind of {&} would you like on your sandwich? {||}", ChoiceStyle = ChoiceStyleOptions.PerLine)] -public class SandwichOrder -// - - -// -[Template(TemplateUsage.NotUnderstood, "I do not understand \"{0}\".", "Try again, I don't get \"{0}\".")] -[Template(TemplateUsage.EnumSelectOne, "What kind of {&} would you like on your sandwich? {||}")] -public class SandwichOrder -// - - -// -[Optional] -public CheeseOptions? Cheese; -// - - -// -[Terms(@"rotis\w* style chicken", MaxPhrase = 3)] -RotisserieStyleChicken, SpicyItalian, SteakAndCheese, SweetOnionTeriyaki, Tuna,... -// - - -// -[Numeric(1, 5)] -public double? Rating; -// - - -// -[Pattern(@"(\d)?\s*\d{3}(-|\s*)\d{4}")] -public string PhoneNumber; -// diff --git a/articles/includes/code/dotnet-formflow-formbuilder.cs b/articles/includes/code/dotnet-formflow-formbuilder.cs deleted file mode 100644 index df2b28d65..000000000 --- a/articles/includes/code/dotnet-formflow-formbuilder.cs +++ /dev/null @@ -1,108 +0,0 @@ -// -[Optional] -[Template(TemplateUsage.NoPreference, "None")] -public string Specials; -// - - -// -.Field(new FieldReflector(nameof(Specials)) - .SetType(null) - .SetActive((state) => state.Length == LengthOptions.FootLong) - .SetDefine(async (state, field) => - { - field - .AddDescription("cookie", "Free cookie") - .AddTerms("cookie", "cookie", "free cookie") - .AddDescription("drink", "Free large drink") - .AddTerms("drink", "drink", "free drink"); - return true; - })) -// - - -// -.Confirm(async (state) => -{ - var cost = 0.0; - switch (state.Length) - { - case LengthOptions.SixInch: cost = 5.0; break; - case LengthOptions.FootLong: cost = 6.50; break; - } - return new PromptAttribute($"Total for your sandwich is {cost:C2} is that ok?"); -}) -// - - -// -public static IForm BuildForm() -{ - OnCompletionAsyncDelegate processOrder = async (context, state) => - { - await context.PostAsync("We are currently processing your sandwich. We will message you the status."); - }; - - return new FormBuilder() - .Message("Welcome to the sandwich order bot!") - .Field(nameof(Sandwich)) - .Field(nameof(Length)) - .Field(nameof(Bread)) - .Field(nameof(Cheese)) - .Field(nameof(Toppings), - validate: async (state, value) => - { - var values = ((List)value).OfType(); - var result = new ValidateResult { IsValid = true, Value = values }; - if (values != null && values.Contains(ToppingOptions.Everything)) - { - result.Value = (from ToppingOptions topping in Enum.GetValues(typeof(ToppingOptions)) - where topping != ToppingOptions.Everything && !values.Contains(topping) - select topping).ToList(); - } - return result; - }) - .Message("For sandwich toppings you have selected {Toppings}.") - .Field(nameof(SandwichOrder.Sauces)) - .Field(new FieldReflector(nameof(Specials)) - .SetType(null) - .SetActive((state) => state.Length == LengthOptions.FootLong) - .SetDefine(async (state, field) => - { - field - .AddDescription("cookie", "Free cookie") - .AddTerms("cookie", "cookie", "free cookie") - .AddDescription("drink", "Free large drink") - .AddTerms("drink", "drink", "free drink"); - return true; - })) - .Confirm(async (state) => - { - var cost = 0.0; - switch (state.Length) - { - case LengthOptions.SixInch: cost = 5.0; break; - case LengthOptions.FootLong: cost = 6.50; break; - } - return new PromptAttribute($"Total for your sandwich is {cost:C2} is that ok?"); - }) - .Field(nameof(SandwichOrder.DeliveryAddress), - validate: async (state, response) => - { - var result = new ValidateResult { IsValid = true, Value = response }; - var address = (response as string).Trim(); - if (address.Length > 0 && (address[0] < '0' || address[0] > '9')) - { - result.Feedback = "Address must start with a number."; - result.IsValid = false; - } - return result; - }) - .Field(nameof(SandwichOrder.DeliveryTime), "What time do you want your sandwich delivered? {||}") - .Confirm("Do you want to order your {Length} {Sandwich} on {Bread} {&Bread} with {[{Cheese} {Toppings} {Sauces}]} to be sent to {DeliveryAddress} {?at {DeliveryTime:t}}?") - .AddRemainingFields() - .Message("Thanks for ordering a sandwich!") - .OnCompletion(processOrder) - .Build(); -} -// diff --git a/articles/includes/code/dotnet-formflow-json-schema.cs b/articles/includes/code/dotnet-formflow-json-schema.cs deleted file mode 100644 index 924b1f1f2..000000000 --- a/articles/includes/code/dotnet-formflow-json-schema.cs +++ /dev/null @@ -1,13 +0,0 @@ -// -public static IForm BuildJsonForm() -{ - using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Microsoft.Bot.Sample.AnnotatedSandwichBot.AnnotatedSandwich.json")) - { - var schema = JObject.Parse(new StreamReader(stream).ReadToEnd()); - return new FormBuilderJson(schema) - .AddRemainingFields() - .Build(); - } - ... -} -// \ No newline at end of file diff --git a/articles/includes/code/dotnet-formflow-localize.cs b/articles/includes/code/dotnet-formflow-localize.cs deleted file mode 100644 index 30c9780fa..000000000 --- a/articles/includes/code/dotnet-formflow-localize.cs +++ /dev/null @@ -1,80 +0,0 @@ -// -public static IForm BuildLocalizedForm() -{ - var culture = Thread.CurrentThread.CurrentUICulture; - IForm form; - if (!_forms.TryGetValue(culture, out form)) - { - OnCompletionAsyncDelegate processOrder = async (context, state) => - { - await context.PostAsync(DynamicSandwich.Processing); - }; - // FormBuilder uses the thread culture to automatically switch framework strings and static strings. - // Dynamically defined fields must do their own localization. - var builder = new FormBuilder() - .Message("Welcome to the sandwich order bot!") - .Field(nameof(Sandwich)) - .Field(nameof(Length)) - .Field(nameof(Bread)) - .Field(nameof(Cheese)) - .Field(nameof(Toppings), - validate: async (state, value) => - { - var values = ((List)value).OfType(); - var result = new ValidateResult { IsValid = true, Value = values }; - if (values != null && values.Contains(ToppingOptions.Everything)) - { - result.Value = (from ToppingOptions topping in Enum.GetValues(typeof(ToppingOptions)) - where topping != ToppingOptions.Everything && !values.Contains(topping) - select topping).ToList(); - } - return result; - }) - .Message("For sandwich toppings you have selected {Toppings}.") - .Field(nameof(SandwichOrder.Sauces)) - .Field(new FieldReflector(nameof(Specials)) - .SetType(null) - .SetActive((state) => state.Length == LengthOptions.FootLong) - .SetDefine(async (state, field) => - { - field - .AddDescription("cookie", DynamicSandwich.FreeCookie) - .AddTerms("cookie", Language.GenerateTerms(DynamicSandwich.FreeCookie, 2)) - .AddDescription("drink", DynamicSandwich.FreeDrink) - .AddTerms("drink", Language.GenerateTerms(DynamicSandwich.FreeDrink, 2)); - return true; - })) - .Confirm(async (state) => - { - var cost = 0.0; - switch (state.Length) - { - case LengthOptions.SixInch: cost = 5.0; break; - case LengthOptions.FootLong: cost = 6.50; break; - } - return new PromptAttribute(string.Format(DynamicSandwich.Cost, cost) + "{||}"); - }) - .Field(nameof(SandwichOrder.DeliveryAddress), - validate: async (state, response) => - { - var result = new ValidateResult { IsValid = true, Value = response }; - var address = (response as string).Trim(); - if (address.Length > 0 && address[0] < '0' || address[0] > '9') - { - result.Feedback = DynamicSandwich.BadAddress; - result.IsValid = false; - } - return result; - }) - .Field(nameof(SandwichOrder.DeliveryTime), "What time do you want your sandwich delivered? {||}") - .Confirm("Do you want to order your {Length} {Sandwich} on {Bread} {&Bread} with {[{Cheese} {Toppings} {Sauces}]} to be sent to {DeliveryAddress} {?at {DeliveryTime:t}}?") - .AddRemainingFields() - .Message("Thanks for ordering a sandwich!") - .OnCompletion(processOrder); - builder.Configuration.DefaultPrompt.ChoiceStyle = ChoiceStyleOptions.Auto; - form = builder.Build(); - _forms[culture] = form; - } - return form; -} -// \ No newline at end of file diff --git a/articles/includes/code/dotnet-formflow-pattern-language.cs b/articles/includes/code/dotnet-formflow-pattern-language.cs deleted file mode 100644 index 22623d4eb..000000000 --- a/articles/includes/code/dotnet-formflow-pattern-language.cs +++ /dev/null @@ -1,10 +0,0 @@ -// -[Prompt("What kind of {&} would you like? {||}")] -public SandwichOptions? Sandwich; -// - - -// -[Prompt("What kind of {&} would you like? {||}", ChoiceFormat="{1}")] -public SandwichOptions? Sandwich; -// \ No newline at end of file diff --git a/articles/includes/code/dotnet-formflow.cs b/articles/includes/code/dotnet-formflow.cs deleted file mode 100644 index 625edc9bf..000000000 --- a/articles/includes/code/dotnet-formflow.cs +++ /dev/null @@ -1,120 +0,0 @@ -// -using Microsoft.Bot.Builder.FormFlow; -using System; -using System.Collections.Generic; - -// The SandwichOrder class represents the form that you want to complete -// using information that is collected from the user. -// It must be serializable so the bot can be stateless. -// The order of fields defines the default sequence in which the user is asked questions. - -// The enumerations define the valid options for each field in SandwichOrder, and the order -// of the values represents the sequence in which they are presented to the user in a conversation. - -namespace Microsoft.Bot.Sample.SimpleSandwichBot -{ - public enum SandwichOptions - { - BLT, BlackForestHam, BuffaloChicken, ChickenAndBaconRanchMelt, ColdCutCombo, MeatballMarinara, - OvenRoastedChicken, RoastBeef, RotisserieStyleChicken, SpicyItalian, SteakAndCheese, SweetOnionTeriyaki, Tuna, - TurkeyBreast, Veggie - }; - public enum LengthOptions { SixInch, FootLong }; - public enum BreadOptions { NineGrainWheat, NineGrainHoneyOat, Italian, ItalianHerbsAndCheese, Flatbread }; - public enum CheeseOptions { American, MontereyCheddar, Pepperjack }; - public enum ToppingOptions - { - Avocado, BananaPeppers, Cucumbers, GreenBellPeppers, Jalapenos, - Lettuce, Olives, Pickles, RedOnion, Spinach, Tomatoes - }; - public enum SauceOptions - { - ChipotleSouthwest, HoneyMustard, LightMayonnaise, RegularMayonnaise, - Mustard, Oil, Pepper, Ranch, SweetOnion, Vinegar - }; - - [Serializable] - public class SandwichOrder - { - public SandwichOptions? Sandwich; - public LengthOptions? Length; - public BreadOptions? Bread; - public CheeseOptions? Cheese; - public List Toppings; - public List Sauce; - - public static IForm BuildForm() - { - return new FormBuilder() - .Message("Welcome to the simple sandwich order bot!") - .Build(); - } - }; -} -// - - - - -// -internal static IDialog MakeRootDialog() -{ - return Chain.From(() => FormDialog.FromForm(SandwichOrder.BuildForm)); -} - -[ResponseType(typeof(void))] -public virtual async Task Post([FromBody] Activity activity) -{ - if (activity != null) - { - switch (activity.GetActivityType()) - { - case ActivityTypes.Message: - await Conversation.SendAsync(activity, MakeRootDialog); - break; - - case ActivityTypes.ConversationUpdate: - case ActivityTypes.ContactRelationUpdate: - case ActivityTypes.Typing: - case ActivityTypes.DeleteUserData: - default: - Trace.TraceError($"Unknown activity type ignored: {activity.GetActivityType()}"); - break; - } - } - ... -} -// - - - - -// -internal static IDialog MakeRootDialog() -{ - return Chain.From(() => FormDialog.FromForm(SandwichOrder.BuildLocalizedForm)) - .Do(async (context, order) => - { - try - { - var completed = await order; - // Actually process the sandwich order... - await context.PostAsync("Processed your order!"); - } - catch (FormCanceledException e) - { - string reply; - if (e.InnerException == null) - { - reply = $"You quit on {e.Last} -- maybe you can finish next time!"; - } - else - { - reply = "Sorry, I've had a short circuit. Please try again."; - } - await context.PostAsync(reply); - } - }); -} -// - diff --git a/articles/includes/code/dotnet-getstarted.cs b/articles/includes/code/dotnet-getstarted.cs deleted file mode 100644 index be1c892ce..000000000 --- a/articles/includes/code/dotnet-getstarted.cs +++ /dev/null @@ -1,50 +0,0 @@ -// -[BotAuthentication] -public class MessagesController : ApiController -{ - /// - /// POST: api/Messages - /// Receive a message from a user and reply to it - /// - public async Task Post([FromBody]Activity activity) - { - if (activity.Type == ActivityTypes.Message) - { - await Conversation.SendAsync(activity, () => new Dialogs.RootDialog()); - } - else - { - HandleSystemMessage(activity); - } - var response = Request.CreateResponse(HttpStatusCode.OK); - return response; - } - ... -} -// - - -// -[Serializable] -public class RootDialog : IDialog -{ - public Task StartAsync(IDialogContext context) - { - context.Wait(MessageReceivedAsync); - return Task.CompletedTask; - } - - private async Task MessageReceivedAsync(IDialogContext context, IAwaitable result) - { - var activity = await result as Activity; - - // calculate something for us to return - int length = (activity.Text ?? string.Empty).Length; - - // return our reply to the user - await context.PostAsync($"You sent {activity.Text} which was {length} characters"); - - context.Wait(MessageReceivedAsync); - } -} -// \ No newline at end of file diff --git a/articles/includes/code/dotnet-input-hints.cs b/articles/includes/code/dotnet-input-hints.cs deleted file mode 100644 index 72116debe..000000000 --- a/articles/includes/code/dotnet-input-hints.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Bot; -using Microsoft.Bot.Builder; -using Microsoft.Bot.Builder.Core.Extensions; -using Microsoft.Bot.Schema; - -namespace InputHintsPublic -{ - public class EchoBot : IBot - { - /// - /// Every Conversation turn for our EchoBot will call this method. In here - /// the bot checks the Activty type to verify it's a message, bumps the - /// turn conversation 'Turn' count, and then echoes the users typing - /// back to them. - /// - /// Turn scoped context containing all the data needed - /// for processing this conversation turn. - public async Task OnTurn(ITurnContext context) - { - // This bot is only handling Messages - if (context.Activity.Type == ActivityTypes.Message) - { - { - // - var reply = MessageFactory.Text( - "This is the text that will be displayed.", - "This is the text that will be spoken.", - InputHints.AcceptingInput); - await context.SendActivity(reply).ConfigureAwait(false); - // - } - { - // - var reply = MessageFactory.Text( - "This is the text that will be displayed.", - "This is the text that will be spoken.", - InputHints.ExpectingInput); - await context.SendActivity(reply).ConfigureAwait(false); - // - } - { - // - var reply = MessageFactory.Text( - "This is the text that will be displayed.", - "This is the text that will be spoken.", - InputHints.IgnoringInput); - await context.SendActivity(reply).ConfigureAwait(false); - // - } - } - } - } -} \ No newline at end of file diff --git a/articles/includes/code/dotnet-luis-dialogs.cs b/articles/includes/code/dotnet-luis-dialogs.cs deleted file mode 100644 index 027f3f032..000000000 --- a/articles/includes/code/dotnet-luis-dialogs.cs +++ /dev/null @@ -1,606 +0,0 @@ -// -[LuisModel("c413b2ef-382c-45bd-8ff0-f76d60e2a821", "6d0966209c6e4f6b835ce34492f3e6d9", domain: "westus2.api.cognitive.microsoft.com")] -[Serializable] -public class SimpleNoteDialog : LuisDialog -{ - ... -} -// - -// - [LuisModel("", "YOUR_SUBSCRIPTION_KEY", domain: "westus.api.cognitive.microsoft.com")] - [Serializable] - public class SimpleNoteDialog : LuisDialog - { - // ... - } - -// - -// -[LuisModel("", "YOUR_SUBSCRIPTION_KEY", Log = false)] -[Serializable] -public class SimpleNoteDialog : LuisDialog -{ - // ... -} -// - -// -[LuisIntent("builtin.intent.alarm.turn_off_alarm")] -public async Task TurnOffAlarm(IDialogContext context, LuisResult result) -{ - if (TryFindAlarm(result, out this.turnOff)) - { - PromptDialog.Confirm(context, AfterConfirming_TurnOffAlarm, "Are you sure?", promptStyle: PromptStyle.None); - } - else - { - await context.PostAsync("did not find alarm"); - context.Wait(MessageReceived); - } -} -// - -// -[LuisIntent("Note.Delete")] -public async Task DeleteNote(IDialogContext context, LuisResult result) -{ - Note note; - if (TryFindNote(result, out note)) - { - this.noteByTitle.Remove(note.Title); - await context.PostAsync($"Note {note.Title} deleted"); - } - else - { - // Prompt the user for a note title - PromptDialog.Text(context, After_DeleteTitlePrompt, "What is the title of the note you want to delete?"); - } -} -// - -// - public bool TryFindNote(LuisResult result, out Note note) - { - note = null; - - string titleToFind; - - EntityRecommendation title; - if (result.TryFindEntity(Entity_Note_Title, out title)) - { - return this.noteByTitle.TryGetValue(title.Entity, out note); // TryGetValue returns false if no match is found. - } - else - { - return false; - } - } -// - -// -using System; -using System.Threading.Tasks; -using Microsoft.Bot.Builder.Dialogs; -using Microsoft.Bot.Builder.Luis; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Bot.Builder.Luis.Models; - -namespace NotesBot.Dialogs -{ - - [LuisModel("", "YOUR_SUBSCRIPTION_KEY", domain: "westus.api.cognitive.microsoft.com")] - [Serializable] - public class SimpleNoteDialog : LuisDialog - { - // Store notes in a dictionary that uses the title as a key - private readonly Dictionary noteByTitle = new Dictionary(); - - // Default note title - public const string DefaultNoteTitle = "default"; - - // Name of note title entity - public const string Entity_Note_Title = "Note.Title"; - - /// - /// This method overload inspects the result from LUIS to see if a title entity was detected, and finds the note with that title, or the note with the default title, if no title entity was found. - /// - /// The result from LUIS that contains intents and entities that LUIS recognized. - /// This parameter returns any note that is found in the list of notes that has a matching title. - /// true if a note was found, otherwise false - public bool TryFindNote(LuisResult result, out Note note) - { - note = null; - - string titleToFind; - - EntityRecommendation title; - if (result.TryFindEntity(Entity_Note_Title, out title)) - { - titleToFind = title.Entity; - } - else - { - titleToFind = DefaultNoteTitle; - } - - return this.noteByTitle.TryGetValue(titleToFind, out note); // TryGetValue returns false if no match is found. - } - - /// - /// This method overload takes a string and finds the note with that title. - /// - /// A string containing the title of the note to search for. - /// This parameter returns any note that is found in the list of notes that has a matching title. - /// true if a note was found, otherwise false - public bool TryFindNote(string noteTitle, out Note note) - { - bool foundNote = this.noteByTitle.TryGetValue(noteTitle, out note); // TryGetValue returns false if no match is found. - return foundNote; - } - - - /// - /// Send a generic help message if an intent without an intent handler is detected. - /// - /// Dialog context. - /// The result from LUIS. - [LuisIntent("")] - public async Task None(IDialogContext context, LuisResult result) - { - - string message = $"I'm the Notes bot. I can understand requests to create, delete, and read notes. \n\n Detected intent: " + string.Join(", ", result.Intents.Select(i => i.Intent)); - await context.PostAsync(message); - context.Wait(MessageReceived); - } - - /// - /// Handle the Note.Delete intent. If a title isn't detected in the LUIS result, prompt the user for a title. - /// - /// Dialog context. - /// The result from LUIS. - [LuisIntent("Note.Delete")] - public async Task DeleteNote(IDialogContext context, LuisResult result) - { - Note note; - if (TryFindNote(result, out note)) - { - this.noteByTitle.Remove(note.Title); - await context.PostAsync($"Note {note.Title} deleted"); - } - else - { - // Prompt the user for a note title - PromptDialog.Text(context, After_DeleteTitlePrompt, "What is the title of the note you want to delete?"); - } - - } - - // Try to delete note that the user specified in response to the prompt. - private async Task After_DeleteTitlePrompt(IDialogContext context, IAwaitable result) - { - Note note; - string titleToDelete = await result; - bool foundNote = this.noteByTitle.TryGetValue(titleToDelete, out note); - - if (foundNote) - { - this.noteByTitle.Remove(note.Title); - await context.PostAsync($"Note {note.Title} deleted"); - } - else - { - await context.PostAsync($"Did not find note named {titleToDelete}."); - } - - context.Wait(MessageReceived); - } - - /// - /// Handles the Note.ReadAloud intent by displaying a note or notes. - /// If a title of an existing note is found in the LuisResult, that note is displayed. - /// If no title is detected in the LuisResult, all of the notes are displayed. - /// - /// Dialog context. - /// LUIS result. - [LuisIntent("Note.ReadAloud")] - public async Task ReadNote(IDialogContext context, LuisResult result) - { - Note note; - if (TryFindNote(result, out note)) - { - await context.PostAsync($"**{note.Title}**: {note.Text}."); - } - else - { - // Print out all the notes if no specific note name was detected - string NoteList = "Here's the list of all notes: \n\n"; - foreach (KeyValuePair entry in noteByTitle) - { - Note noteInList = entry.Value; - NoteList += $"**{noteInList.Title}**: {noteInList.Text}.\n\n"; - } - await context.PostAsync(NoteList); - } - - context.Wait(MessageReceived); - } - - private Note noteToCreate; - private string currentTitle; - - /// - /// Handles the Note.Create intent. Prompts the user for the note title if the title isn't detected in the LuisResult. - /// - /// Dialog context. - /// LUIS result. - [LuisIntent("Note.Create")] - public Task CreateNote(IDialogContext context, LuisResult result) - { - EntityRecommendation title; - if (!result.TryFindEntity(Entity_Note_Title, out title)) - { - // Prompt the user for a note title - PromptDialog.Text(context, After_TitlePrompt, "What is the title of the note you want to create?"); - } - else - { - var note = new Note() { Title = title.Entity }; - noteToCreate = this.noteByTitle[note.Title] = note; - - // Prompt the user for what they want to say in the note - PromptDialog.Text(context, After_TextPrompt, "What do you want to say in your note?"); - } - - return Task.CompletedTask; - } - - // Creates a new note using the user's response to the prompt for a title - private async Task After_TitlePrompt(IDialogContext context, IAwaitable result) - { - EntityRecommendation title; - - // Set the title to the user's response - currentTitle = await result; - if (currentTitle != null) - { - title = new EntityRecommendation(type: Entity_Note_Title) { Entity = currentTitle }; - } - else - { - // Use the default note title - title = new EntityRecommendation(type: Entity_Note_Title) { Entity = DefaultNoteTitle }; - } - - // Create a new note object - var note = new Note() { Title = title.Entity }; - // Add the new note to the list of notes and also save it in order to add text to it later - noteToCreate = this.noteByTitle[note.Title] = note; - - // Prompt the user for what they want to say in the note - PromptDialog.Text(context, After_TextPrompt, "What do you want to say in your note?"); - - } - - // Sets the text of a newly created note using the user's response to the prompt for the text of the note. - private async Task After_TextPrompt(IDialogContext context, IAwaitable result) - { - // Set the text of the note - noteToCreate.Text = await result; - - await context.PostAsync($"Created note **{this.noteToCreate.Title}** that says \"{this.noteToCreate.Text}\"."); - - context.Wait(MessageReceived); - } - - - public SimpleNoteDialog() - { - - } - - public SimpleNoteDialog(ILuisService service) - : base(service) - { - } - - [Serializable] - public sealed class Note : IEquatable - { - - public string Title { get; set; } - public string Text { get; set; } - - public override string ToString() - { - return $"[{this.Title} : {this.Text}]"; - } - - public bool Equals(Note other) - { - return other != null - && this.Text == other.Text - && this.Title == other.Title; - } - - public override bool Equals(object other) - { - return Equals(other as Note); - } - - public override int GetHashCode() - { - return this.Title.GetHashCode(); - } - } - } - - -} -// - -// -public async Task Post([FromBody]Activity activity) -{ - if (activity.Type == ActivityTypes.Message) - { - await Conversation.SendAsync(activity, () => new Dialogs.SimpleNoteDialog()); - } - else - { - HandleSystemMessage(activity); - } - var response = Request.CreateResponse(HttpStatusCode.OK); - return response; -} -// - -// -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -using Microsoft.Bot.Builder.Dialogs; -using Microsoft.Bot.Builder.Luis; -using Microsoft.Bot.Builder.Luis.Models; - -namespace Microsoft.Bot.Sample.SimpleAlarmBot -{ - // domain defaults to westus2.api.cognitive.microsoft.com if not provided - [LuisModel("c413b2ef-382c-45bd-8ff0-f76d60e2a821", "6d0966209c6e4f6b835ce34492f3e6d9", domain: "westus2.api.cognitive.microsoft.com", staging: true)] - [Serializable] - public class SimpleAlarmDialog : LuisDialog - { - private readonly Dictionary alarmByWhat = new Dictionary(); - - public const string DefaultAlarmWhat = "default"; - - public bool TryFindAlarm(LuisResult result, out Alarm alarm) - { - alarm = null; - - string what; - - EntityRecommendation title; - if (result.TryFindEntity(Entity_Alarm_Title, out title)) - { - what = title.Entity; - } - else - { - what = DefaultAlarmWhat; - } - - return this.alarmByWhat.TryGetValue(what, out alarm); - } - - public const string Entity_Alarm_Title = "builtin.alarm.title"; - public const string Entity_Alarm_Start_Time = "builtin.alarm.start_time"; - public const string Entity_Alarm_Start_Date = "builtin.alarm.start_date"; - - [LuisIntent("")] - public async Task None(IDialogContext context, LuisResult result) - { - string message = $"Sorry I did not understand: " + string.Join(", ", result.Intents.Select(i => i.Intent)); - await context.PostAsync(message); - context.Wait(MessageReceived); - } - - [LuisIntent("builtin.intent.alarm.delete_alarm")] - public async Task DeleteAlarm(IDialogContext context, LuisResult result) - { - Alarm alarm; - if (TryFindAlarm(result, out alarm)) - { - this.alarmByWhat.Remove(alarm.What); - await context.PostAsync($"alarm {alarm} deleted"); - } - else - { - await context.PostAsync("did not find alarm"); - } - - context.Wait(MessageReceived); - } - - [LuisIntent("builtin.intent.alarm.find_alarm")] - public async Task FindAlarm(IDialogContext context, LuisResult result) - { - Alarm alarm; - if (TryFindAlarm(result, out alarm)) - { - await context.PostAsync($"found alarm {alarm}"); - } - else - { - await context.PostAsync("did not find alarm"); - } - - context.Wait(MessageReceived); - } - - [LuisIntent("builtin.intent.alarm.set_alarm")] - public async Task SetAlarm(IDialogContext context, LuisResult result) - { - EntityRecommendation title; - if (!result.TryFindEntity(Entity_Alarm_Title, out title)) - { - title = new EntityRecommendation(type: Entity_Alarm_Title) { Entity = DefaultAlarmWhat }; - } - - EntityRecommendation date; - if (!result.TryFindEntity(Entity_Alarm_Start_Date, out date)) - { - date = new EntityRecommendation(type: Entity_Alarm_Start_Date) { Entity = string.Empty }; - } - - EntityRecommendation time; - if (!result.TryFindEntity(Entity_Alarm_Start_Time, out time)) - { - time = new EntityRecommendation(type: Entity_Alarm_Start_Time) { Entity = string.Empty }; - } - - var parser = new Chronic.Parser(); - var span = parser.Parse(date.Entity + " " + time.Entity); - - if (span != null) - { - var when = span.Start ?? span.End; - var alarm = new Alarm() { What = title.Entity, When = when.Value }; - this.alarmByWhat[alarm.What] = alarm; - - string reply = $"alarm {alarm} created"; - await context.PostAsync(reply); - } - else - { - await context.PostAsync("could not find time for alarm"); - } - - context.Wait(MessageReceived); - } - - [LuisIntent("builtin.intent.alarm.snooze")] - public async Task AlarmSnooze(IDialogContext context, LuisResult result) - { - Alarm alarm; - if (TryFindAlarm(result, out alarm)) - { - alarm.When = alarm.When.Add(TimeSpan.FromMinutes(7)); - await context.PostAsync($"alarm {alarm} snoozed!"); - } - else - { - await context.PostAsync("did not find alarm"); - } - - context.Wait(MessageReceived); - } - - [LuisIntent("builtin.intent.alarm.time_remaining")] - public async Task TimeRemaining(IDialogContext context, LuisResult result) - { - Alarm alarm; - if (TryFindAlarm(result, out alarm)) - { - var now = DateTime.UtcNow; - if (alarm.When > now) - { - var remaining = alarm.When.Subtract(DateTime.UtcNow); - await context.PostAsync($"There is {remaining} remaining for alarm {alarm}."); - } - else - { - await context.PostAsync($"The alarm {alarm} expired already."); - } - } - else - { - await context.PostAsync("did not find alarm"); - } - - context.Wait(MessageReceived); - } - - private Alarm turnOff; - - [LuisIntent("builtin.intent.alarm.turn_off_alarm")] - public async Task TurnOffAlarm(IDialogContext context, LuisResult result) - { - if (TryFindAlarm(result, out this.turnOff)) - { - PromptDialog.Confirm(context, AfterConfirming_TurnOffAlarm, "Are you sure?", promptStyle: PromptStyle.None); - } - else - { - await context.PostAsync("did not find alarm"); - context.Wait(MessageReceived); - } - } - - public async Task AfterConfirming_TurnOffAlarm(IDialogContext context, IAwaitable confirmation) - { - if (await confirmation) - { - this.alarmByWhat.Remove(this.turnOff.What); - await context.PostAsync($"Ok, alarm {this.turnOff} disabled."); - } - else - { - await context.PostAsync("Ok! We haven't modified your alarms!"); - } - - context.Wait(MessageReceived); - } - - [LuisIntent("builtin.intent.alarm.alarm_other")] - public async Task AlarmOther(IDialogContext context, LuisResult result) - { - await context.PostAsync("what ?"); - context.Wait(MessageReceived); - } - - public SimpleAlarmDialog() - { - - } - - public SimpleAlarmDialog(ILuisService service) - : base(service) - { - } - - [Serializable] - public sealed class Alarm : IEquatable - { - public DateTime When { get; set; } - public string What { get; set; } - - public override string ToString() - { - return $"[{this.What} at {this.When}]"; - } - - public bool Equals(Alarm other) - { - return other != null - && this.When == other.When - && this.What == other.What; - } - - public override bool Equals(object other) - { - return Equals(other as Alarm); - } - - public override int GetHashCode() - { - return this.What.GetHashCode(); - } - } - } -} -// \ No newline at end of file diff --git a/articles/includes/code/dotnet-request-payment.cs b/articles/includes/code/dotnet-request-payment.cs deleted file mode 100644 index 71204d84c..000000000 --- a/articles/includes/code/dotnet-request-payment.cs +++ /dev/null @@ -1,99 +0,0 @@ -// -var replyMessage = context.MakeMessage(); - -replyMessage.Attachments = new List(); - -var displayedItem = await new CatalogService().GetRandomItemAsync(); - -var cartId = displayedItem.Id.ToString(); -context.ConversationData.SetValue(CART_KEY, cartId); -context.ConversationData.SetValue(cartId, context.Activity.From.Id); - -var heroCard = new HeroCard -{ - Title = displayedItem.Title, - Subtitle = $"{displayedItem.Currency} {displayedItem.Price.ToString("F")}", - Text = displayedItem.Description, - Images = new List - { - new CardImage - { - Url = displayedItem.ImageUrl - } - }, - Buttons = new List - { - new CardAction - { - Title = "Buy", - Type = PaymentRequest.PaymentActionType, - Value = BuildPaymentRequest(cartId, displayedItem, MethodData) - } - } -}; - -replyMessage.Attachments.Add(heroCard.ToAttachment()); - -await context.PostAsync(replyMessage); -// - - -// -[MethodBind] -[ScorableGroup(1)] -private async Task OnInvoke(IInvokeActivity invoke, IConnectorClient connectorClient, IStateClient stateClient, HttpResponseMessage response, CancellationToken token) -{ - MicrosoftAppCredentials.TrustServiceUrl(invoke.RelatesTo.ServiceUrl); - - var jobject = invoke.Value as JObject; - if (jobject == null) - { - throw new ArgumentException("Request payload must be a valid json object."); - } - - // This is a temporary workaround for the issue that the channelId for "webchat" is mapped to "directline" in the incoming RelatesTo object - invoke.RelatesTo.ChannelId = (invoke.RelatesTo.ChannelId == "directline") ? "webchat" : invoke.RelatesTo.ChannelId; - - if (invoke.RelatesTo.User == null) - { - // Bot keeps the userId in context.ConversationData[cartId] - var conversationData = await stateClient.BotState.GetConversationDataAsync(invoke.RelatesTo.ChannelId, invoke.RelatesTo.Conversation.Id, token); - var cartId = conversationData.GetProperty(RootDialog.CARTKEY); - - if (!string.IsNullOrEmpty(cartId)) - { - invoke.RelatesTo.User = new ChannelAccount - { - Id = conversationData.GetProperty(cartId) - }; - } - } - - var updateResponse = default(object); - - switch (invoke.Name) - { - case PaymentOperations.UpdateShippingAddressOperationName: - updateResponse = await ProcessShippingAddressUpdate(jobject.ToObject(), token); - break; - - case PaymentOperations.UpdateShippingOptionOperationName: - updateResponse = await ProcessShippingOptionUpdate(jobject.ToObject(), token); - break; - - case PaymentOperations.PaymentCompleteOperationName: - updateResponse = await ProcessPaymentComplete(invoke, jobject.ToObject(), token); - break; - - default: - throw new ArgumentException("Invoke activity name is not a supported request type."); - } - - response.Content = new ObjectContent( - updateResponse, - this.Configuration.Formatters.JsonFormatter, - JsonMediaTypeFormatter.DefaultMediaType); - - response.StatusCode = HttpStatusCode.OK; -} -// \ No newline at end of file diff --git a/articles/includes/code/dotnet-security.cs b/articles/includes/code/dotnet-security.cs deleted file mode 100644 index bca7a69b9..000000000 --- a/articles/includes/code/dotnet-security.cs +++ /dev/null @@ -1,13 +0,0 @@ -// -[BotAuthentication] -public class MessagesController : ApiController -{ -} -// - -// -[BotAuthentication(MicrosoftAppId = "_appIdValue_", MicrosoftAppPassword="_passwordValue_")] -public class MessagesController : ApiController -{ -} -// \ No newline at end of file diff --git a/articles/includes/code/dotnet-send-and-receive.cs b/articles/includes/code/dotnet-send-and-receive.cs deleted file mode 100644 index 9c5bd9dd0..000000000 --- a/articles/includes/code/dotnet-send-and-receive.cs +++ /dev/null @@ -1,54 +0,0 @@ -// -public async Task Post([FromBody]Activity activity) -{ - var connector = new ConnectorClient(new Uri(activity.ServiceUrl)); - . . . -} -// - -// -Activity reply = activity.CreateReply($"You sent {activity.Text} which was {length} characters"); -// - -// -await connector.Conversations.ReplyToActivityAsync(reply); -// - -// -await connector.Conversations.SendToConversationAsync((Activity)newMessage); -// - -// -var userAccount = new ChannelAccount(name: "Larry", id: "@UV357341"); -var connector = new ConnectorClient(new Uri(activity.ServiceUrl)); -var conversationId = await connector.Conversations.CreateDirectConversationAsync(botAccount, userAccount); - -IMessageActivity message = Activity.CreateMessageActivity(); -message.From = botAccount; -message.Recipient = userAccount; -message.Conversation = new ConversationAccount(id: conversationId.Id); -message.Text = "Hello, Larry!"; -message.Locale = "en-Us"; -await connector.Conversations.SendToConversationAsync((Activity)message); -// - -// -var connector = new ConnectorClient(new Uri(incomingMessage.ServiceUrl)); - -List participants = new List(); -participants.Add(new ChannelAccount("joe@contoso.com", "Joe the Engineer")); -participants.Add(new ChannelAccount("sara@contoso.com", "Sara in Finance")); - -ConversationParameters cpMessage = new ConversationParameters(message.Recipient, true, participants, "Quarter End Discussion"); -var conversationId = await connector.Conversations.CreateConversationAsync(cpMessage); - -IMessageActivity message = Activity.CreateMessageActivity(); -message.From = botAccount; -message.Recipient = new ChannelAccount("lydia@contoso.com", "Lydia the CFO")); -message.Conversation = new ConversationAccount(id: conversationId.Id); -message.ChannelId = incomingMessage.ChannelId; -message.Text = "Hello, everyone!"; -message.Locale = "en-Us"; - -await connector.Conversations.SendToConversationAsync((Activity)message); -// diff --git a/articles/includes/code/dotnet-state.cs b/articles/includes/code/dotnet-state.cs deleted file mode 100644 index 643b6ae02..000000000 --- a/articles/includes/code/dotnet-state.cs +++ /dev/null @@ -1,46 +0,0 @@ -// -StateClient stateClient = activity.GetStateClient(); -// - - -// -StateClient stateClient = new StateClient(new MicrosoftAppCredentials(microsoftAppId, microsoftAppPassword)); -// - - -// -BotData userData = await stateClient.BotState.GetUserDataAsync(activity.ChannelId, activity.From.Id); -var sentGreeting = userData.GetProperty("SentGreeting"); -// - - -// -MyCustomType myUserData = new MyCustomType(); -BotData botData = await botState.GetUserDataAsync(activity.ChannelId, activity.From.Id); -myUserData = botData.GetProperty("UserData"); -// - - -// -BotData userData = await stateClient.BotState.GetUserDataAsync(activity.ChannelId, activity.From.Id); -userData.SetProperty("SentGreeting", true); -await stateClient.BotState.SetUserDataAsync(activity.ChannelId, activity.From.Id, userData); -// - - -// -BotData userData = await stateClient.BotState.GetUserDataAsync(activity.ChannelId, activity.From.Id); -userData.SetProperty("UserData", myUserData); -await stateClient.BotState.SetUserDataAsync(activity.ChannelId, activity.From.Id, userData); -// - - -// -var builder = new ContainerBuilder(); -builder - .Register(c => new CachingBotDataStore(c.Resolve(), CachingBotDataStoreConsistencyPolicy.LastWriteWins)) - .As>() - .AsSelf() - .InstancePerLifetimeScope(); -builder.Update(Conversation.Container); -// \ No newline at end of file diff --git a/articles/includes/code/dotnet-text-to-speech.cs b/articles/includes/code/dotnet-text-to-speech.cs deleted file mode 100644 index d7a8098b9..000000000 --- a/articles/includes/code/dotnet-text-to-speech.cs +++ /dev/null @@ -1,21 +0,0 @@ -// -Activity reply = activity.CreateReply("This is the text that will be displayed."); -reply.Speak = "This is the text that will be spoken."; -reply.InputHint = InputHints.AcceptingInput; -await connector.Conversations.ReplyToActivityAsync(reply); -// - - - -// -await context.SayAsync(text: "Thank you for your order!", speak: "Thank you for your order!"); -// - - - -// -PromptDialog.Confirm(context, AfterResetAsync,  - new PromptOptions(prompt: "Are you sure that you want to cancel this transaction?",  - speak: "Are you sure that you want to cancel this transaction?", - retrySpeak: "Are you sure that you want to cancel this transaction?")); -// diff --git a/articles/includes/code/intelligence-location-control.cs b/articles/includes/code/intelligence-location-control.cs deleted file mode 100644 index 2a8686636..000000000 --- a/articles/includes/code/intelligence-location-control.cs +++ /dev/null @@ -1,6 +0,0 @@ -// -var apiKey = WebConfigurationManager.AppSettings["BingMapsApiKey"]; -var prompt = "Where should I ship your order? Type or say an address."; -var locationDialog = new LocationDialog(apiKey, message.ChannelId, prompt, LocationOptions.None, LocationRequiredFields.StreetAddress | LocationRequiredFields.PostalCode); -context.Call(locationDialog, (dialogContext, result) => {...}); -// diff --git a/articles/includes/code/intelligence-location-control.js b/articles/includes/code/intelligence-location-control.js deleted file mode 100644 index 9860e9f09..000000000 --- a/articles/includes/code/intelligence-location-control.js +++ /dev/null @@ -1,36 +0,0 @@ -// -var options = { - prompt: "Where should I ship your order? Type or say an address.", - requiredFields: - locationDialog.LocationRequiredFields.streetAddress | - locationDialog.LocationRequiredFields.postalCode -} -locationDialog.getLocation(session, options); -// - -// -locationDialog.create(bot); - -bot.dialog("/", [ - function (session) { - locationDialog.getLocation(session, { - prompt: "Where should I ship your order? Type or say an address.", - requiredFields: - locationDialog.LocationRequiredFields.streetAddress | - locationDialog.LocationRequiredFields.locality | - locationDialog.LocationRequiredFields.region | - locationDialog.LocationRequiredFields.postalCode | - locationDialog.LocationRequiredFields.country - }); - }, - function (session, results) { - if (results.response) { - var place = results.response; - session.send(place.streetAddress + ", " + place.locality + ", " + place.region + ", " + place.country + " (" + place.postalCode + ")"); - } - else { - session.send("OK, I won't be shipping it"); - } - } -]); -// diff --git a/articles/includes/code/node-basicNote-intentDialog.js b/articles/includes/code/node-basicNote-intentDialog.js deleted file mode 100644 index 1460dbd42..000000000 --- a/articles/includes/code/node-basicNote-intentDialog.js +++ /dev/null @@ -1,195 +0,0 @@ - -/*----------------------------------------------------------------------------- - -This bot demonstrates how to use dialogs with a LuisRecognizer to add LUIS support to a bot. -LUIS identifies intents and entities from user messages, or utterances. - -Intents map utterances to functionality in your bot. -In this example, the intents provide the following mappings: - * The Notes.Create intent maps to the CreateNote dialog - * The Notes.Delete intent maps to the DeleteNote dialog - * The Notes.ReadAloud intent maps to the ReadNote dialog - ------------------------------------------------------------------------------*/ -var restify = require('restify'); -var builder = require('botbuilder'); - -// Setup Restify Server -var server = restify.createServer(); -server.listen(process.env.port || process.env.PORT || 3978, function () { - console.log('%s listening to %s', server.name, server.url); -}); - - -// Create chat connector for communicating with the Bot Framework Service -// See https://aka.ms/node-env-var for information on setting environment variables in launch.json if you are using VSCode -var connector = new builder.ChatConnector({ - appId: process.env.MICROSOFT_APP_ID, - appPassword: process.env.MICROSOFT_APP_PASSWORD -}); - -// Listen for messages from users -server.post('/api/messages', connector.listen()); - -// -// Create your bot -var bot = new builder.UniversalBot(connector); -// - - -// -// Add global LUIS recognizer to bot -var luisAppUrl = process.env.LUIS_APP_URL || 'https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/?subscription-key='; -var notesRecognizer = bot.recognizer(new builder.LuisRecognizer(luisAppUrl)); -// - -// -var noteIntentsDialog = new builder.IntentDialog({ - recognizers: [notesRecognizer] -}); - -bot.dialog('/', noteIntentsDialog); -// - -// -// Handle the None intent -// This default message handler is invoked if the user's utterance doesn't -// match any other intents defined in the LUIS app. -noteIntentsDialog.matches('None', [ - function (session, args) { - session.send("Hi... I'm the note bot sample. I can create new notes, read saved notes to you and delete notes."); - - // If the object for storing notes in session.userData doesn't exist yet, initialize it - if (!session.userData.notes) { - session.userData.notes = {}; - console.log("initializing userData.notes in default message handler"); - } -}]); -// - -// -// Handle the Note.Create intent -noteIntentsDialog.matches('Note.Create', [ - function (session, args, next) { - // Resolve and store any Note.Title entity passed from LUIS. - var intent = args.intent; - var title = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title'); - - var note = session.dialogData.note = { - title: title ? title.entity : null, - }; - - // Prompt for title - if (!note.title) { - builder.Prompts.text(session, 'What would you like to call your note?'); - } else { - next(); - } - }, - function (session, results, next) { - var note = session.dialogData.note; - if (results.response) { - note.title = results.response; - } - - // Prompt for the text of the note - if (!note.text) { - builder.Prompts.text(session, 'What would you like to say in your note?'); - } else { - next(); - } - }, - function (session, results) { - var note = session.dialogData.note; - if (results.response) { - note.text = results.response; - } - - // If the object for storing notes in session.userData doesn't exist yet, initialize it - if (!session.userData.notes) { - session.userData.notes = {}; - console.log("initializing session.userData.notes in CreateNote dialog"); - } - // Save notes in the notes object - session.userData.notes[note.title] = note; - - // Send confirmation to user - session.endDialog('Creating note named "%s" with text "%s"', - note.title, note.text); - } -]); -// - -// -// Handle the Note.Delete intent -noteIntentsDialog.matches('Note.Delete', [ - function (session, args, next) { - if (noteCount(session.userData.notes) > 0) { - // Resolve and store any Note.Title entity passed from LUIS. - var title; - var intent = args.intent; - var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title'); - if (entity) { - // Verify that the title is in our set of notes. - title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity); - } - - // Prompt for note name - if (!title) { - builder.Prompts.choice(session, 'Which note would you like to delete?', session.userData.notes); - } else { - next({ response: title }); - } - } else { - session.endDialog("No notes to delete."); - } - }, - function (session, results) { - delete session.userData.notes[results.response.entity]; - session.endDialog("Deleted the '%s' note.", results.response.entity); - } -]); -// - -// -// Handle the Notes.ReadAloud intent -noteIntentsDialog.matches('Note.ReadAloud', [ - function (session, args, next) { - if (noteCount(session.userData.notes) > 0) { - - // Resolve and store any Note.Title entity passed from LUIS. - var title; - var intent = args.intent; - var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title'); - if (entity) { - // Verify it's in our set of notes. - title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity); - } - - // Prompt for note name - if (!title) { - builder.Prompts.choice(session, 'Which note would you like to read?', session.userData.notes); - } else { - next({ response: title }); - } - } else { - session.endDialog("No notes to read."); - } - }, - function (session, results) { - session.endDialog("Here's the '%s' note: '%s'.", results.response.entity, session.userData.notes[results.response.entity].text); - } -]); -// - -// -// Helper function to count the number of notes stored in session.userData.notes -function noteCount(notes) { - - var i = 0; - for (var name in notes) { - i++; - } - return i; -} -// diff --git a/articles/includes/code/node-basicNote.js b/articles/includes/code/node-basicNote.js deleted file mode 100644 index 539190c5c..000000000 --- a/articles/includes/code/node-basicNote.js +++ /dev/null @@ -1,194 +0,0 @@ - -/*----------------------------------------------------------------------------- - -This bot demonstrates how to use dialogs with a LuisRecognizer to add LUIS support to a bot. -LUIS identifies intents and entities from user messages, or utterances. - -Intents map utterances to functionality in your bot. -In this example, the intents provide the following mappings: - * The Notes.Create intent maps to the CreateNote dialog - * The Notes.Delete intent maps to the DeleteNote dialog - * The Notes.ReadAloud intent maps to the ReadNote dialog - ------------------------------------------------------------------------------*/ -var restify = require('restify'); -var builder = require('botbuilder'); - -// Setup Restify Server -var server = restify.createServer(); -server.listen(process.env.port || process.env.PORT || 3978, function () { - console.log('%s listening to %s', server.name, server.url); -}); - - -// Create chat connector for communicating with the Bot Framework Service -// See https://aka.ms/node-env-var for information on setting environment variables in launch.json if you are using VSCode -var connector = new builder.ChatConnector({ - appId: process.env.MICROSOFT_APP_ID, - appPassword: process.env.MICROSOFT_APP_PASSWORD -}); - -// Listen for messages from users -server.post('/api/messages', connector.listen()); - -// -// Create your bot with a function to receive messages from the user. -// This default message handler is invoked if the user's utterance doesn't -// match any intents handled by other dialogs. -var bot = new builder.UniversalBot(connector, function (session, args) { - session.send("Hi... I'm the note bot sample. I can create new notes, read saved notes to you and delete notes."); - - // If the object for storing notes in session.userData doesn't exist yet, initialize it - if (!session.userData.notes) { - session.userData.notes = {}; - console.log("initializing userData.notes in default message handler"); - } -}); -// - -// -// Add global LUIS recognizer to bot -var luisAppUrl = process.env.LUIS_APP_URL || 'https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/?subscription-key='; -bot.recognizer(new builder.LuisRecognizer(luisAppUrl)); -// - -// -// CreateNote dialog -bot.dialog('CreateNote', [ - function (session, args, next) { - // Resolve and store any Note.Title entity passed from LUIS. - var intent = args.intent; - var title = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title'); - - var note = session.dialogData.note = { - title: title ? title.entity : null, - }; - - // Prompt for title - if (!note.title) { - builder.Prompts.text(session, 'What would you like to call your note?'); - } else { - next(); - } - }, - function (session, results, next) { - var note = session.dialogData.note; - if (results.response) { - note.title = results.response; - } - - // Prompt for the text of the note - if (!note.text) { - builder.Prompts.text(session, 'What would you like to say in your note?'); - } else { - next(); - } - }, - function (session, results) { - var note = session.dialogData.note; - if (results.response) { - note.text = results.response; - } - - // If the object for storing notes in session.userData doesn't exist yet, initialize it - if (!session.userData.notes) { - session.userData.notes = {}; - console.log("initializing session.userData.notes in CreateNote dialog"); - } - // Save notes in the notes object - session.userData.notes[note.title] = note; - - // Send confirmation to user - session.endDialog('Creating note named "%s" with text "%s"', - note.title, note.text); - } -]).triggerAction({ - matches: 'Note.Create', - confirmPrompt: "This will cancel the creation of the note you started. Are you sure?" -}).cancelAction('cancelCreateNote', "Note canceled.", { - matches: /^(cancel|nevermind)/i, - confirmPrompt: "Are you sure?" -}); -// - -// -// Delete note dialog -bot.dialog('DeleteNote', [ - function (session, args, next) { - if (noteCount(session.userData.notes) > 0) { - // Resolve and store any Note.Title entity passed from LUIS. - var title; - var intent = args.intent; - var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title'); - if (entity) { - // Verify that the title is in our set of notes. - title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity); - } - - // Prompt for note name - if (!title) { - builder.Prompts.choice(session, 'Which note would you like to delete?', session.userData.notes); - } else { - next({ response: title }); - } - } else { - session.endDialog("No notes to delete."); - } - }, - function (session, results) { - delete session.userData.notes[results.response.entity]; - session.endDialog("Deleted the '%s' note.", results.response.entity); - } -]).triggerAction({ - matches: 'Note.Delete' -}).cancelAction('cancelDeleteNote', "Ok - canceled note deletion.", { - matches: /^(cancel|nevermind)/i -}); -// - -// -// Read note dialog -bot.dialog('ReadNote', [ - function (session, args, next) { - if (noteCount(session.userData.notes) > 0) { - - // Resolve and store any Note.Title entity passed from LUIS. - var title; - var intent = args.intent; - var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title'); - if (entity) { - // Verify it's in our set of notes. - title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity); - } - - // Prompt for note name - if (!title) { - builder.Prompts.choice(session, 'Which note would you like to read?', session.userData.notes); - } else { - next({ response: title }); - } - } else { - session.endDialog("No notes to read."); - } - }, - function (session, results) { - session.endDialog("Here's the '%s' note: '%s'.", results.response.entity, session.userData.notes[results.response.entity].text); - } -]).triggerAction({ - matches: 'Note.ReadAloud' -}).cancelAction('cancelReadNote', "Ok.", { - matches: /^(cancel|nevermind)/i -}); -// - -// -// Helper function to count the number of notes stored in session.userData.notes -function noteCount(notes) { - - var i = 0; - for (var name in notes) { - i++; - } - return i; -} -// diff --git a/articles/includes/code/node-getstarted.js b/articles/includes/code/node-getstarted.js deleted file mode 100644 index 011be9993..000000000 --- a/articles/includes/code/node-getstarted.js +++ /dev/null @@ -1,35 +0,0 @@ -// - -var builder = require('botbuilder'); - -var connector = new builder.ConsoleConnector().listen(); -var bot = new builder.UniversalBot(connector, function (session) { - session.send("You said: %s", session.message.text); -}); -// - -// - -var restify = require('restify'); -var builder = require('botbuilder'); - -// Setup Restify Server -var server = restify.createServer(); -server.listen(process.env.port || process.env.PORT || 3978, function () { - console.log('%s listening to %s', server.name, server.url); -}); - -// Create chat connector for communicating with the Bot Framework Service -var connector = new builder.ChatConnector({ - appId: process.env.MicrosoftAppId, - appPassword: process.env.MicrosoftAppPassword -}); - -// Listen for messages from users -server.post('/api/messages', connector.listen()); - -// Receive messages from the user and respond by echoing each message back (prefixed with 'You said:') -var bot = new builder.UniversalBot(connector, function (session) { - session.send("You said: %s", session.message.text); -}); -// diff --git a/articles/includes/code/node-howto-recognize-intent.js b/articles/includes/code/node-howto-recognize-intent.js deleted file mode 100644 index a5fa2768b..000000000 --- a/articles/includes/code/node-howto-recognize-intent.js +++ /dev/null @@ -1,41 +0,0 @@ -// -var builder = require('../../core/'); - -// Create bot and default message handler -var connector = new builder.ConsoleConnector().listen(); -var bot = new builder.UniversalBot(connector, function (session) { - session.send("You said: '%s'. Try asking for 'help' or say 'goodbye' to quit", session.message.text); -}); - - -// Install a custom recognizer to look for user saying 'help' or 'goodbye'. -bot.recognizer({ - recognize: function (context, done) { - var intent = { score: 0.0 }; - - if (context.message.text) { - switch (context.message.text.toLowerCase()) { - case 'help': - intent = { score: 1.0, intent: 'Help' }; - break; - case 'goodbye': - intent = { score: 1.0, intent: 'Goodbye' }; - break; - } - } - done(null, intent); - } -}); - -// - -// -// Add a help dialog with a trigger action that is bound to the 'Help' intent -bot.dialog('helpDialog', function (session) { - session.endDialog("This bot will echo back anything you say. Say 'goodbye' to quit."); -}).triggerAction({ matches: 'Help' }); - - -// Add a global endConversation() action that is bound to the 'Goodbye' intent -bot.endConversationAction('goodbyeAction', "Ok... See you later.", { matches: 'Goodbye' }); -// \ No newline at end of file diff --git a/articles/includes/code/node-input-hints.js b/articles/includes/code/node-input-hints.js deleted file mode 100644 index a5ec2ae4a..000000000 --- a/articles/includes/code/node-input-hints.js +++ /dev/null @@ -1,25 +0,0 @@ -// -var msg = new builder.Message(session) - .speak('This is the text that will be spoken.') - .inputHint(builder.InputHint.acceptingInput); -session.send(msg).endDialog(); -// - - - -// -session.say('Please hold while I calculate a response. Thanks!', - 'Please hold while I calculate a response. Thanks!', - { inputHint: builder.InputHint.ignoringInput } -); -// - - - -// -builder.Prompts.text(session, 'This is the text that will be displayed.', { - speak: 'This is the text that will be spoken initially.', - retrySpeak: 'This is the text that is spoken after waiting a while for user input.', - inputHint: builder.InputHint.expectingInput -}); -// diff --git a/articles/includes/code/node-regex-recognizer.js b/articles/includes/code/node-regex-recognizer.js deleted file mode 100644 index c0210b4a2..000000000 --- a/articles/includes/code/node-regex-recognizer.js +++ /dev/null @@ -1,147 +0,0 @@ -/*----------------------------------------------------------------------------- -Note - this sample should only be used for snippets. -Don't use the whole sample as is. -Tested that code compiles 5/23. ------------------------------------------------------------------------------*/ - -var builder = require('../../core/'); - -// Create bot and bind to console -var connector = new builder.ConsoleConnector().listen(); - -// -var bot = new builder.UniversalBot(connector, function (session) { - session.send("Hi... I'm a sample bot."); -}); - -// Add a global LUIS recognizer to the bot by using the endpoint URL of the LUIS app -var model = 'https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/c413b2ef-382c-45bd-8ff0-f76d60e2a821?subscription-key=6d0966209c6e4f6b835ce34492f3e6d9'; -bot.recognizer(new builder.LuisRecognizer(model)); -// - -// -bot.recognizer(new builder.RegExpRecognizer( "CancelIntent", { en_us: /^(cancel|nevermind)/i, ja_jp: /^(キャンセル)/ })); -// - -// -bot.dialog('CancelDialog', function (session) { - session.endConversation("Ok, I'm canceling your order."); -}).triggerAction({ matches: 'CancelIntent' }); -// - -// Set Alarm dialog -bot.dialog('/setAlarm', [ - function (session, args, next) { - // Resolve and store any entities passed from LUIS. - var intent = args.intent; - var title = builder.EntityRecognizer.findEntity(intent.entities, 'builtin.alarm.title'); - var time = builder.EntityRecognizer.resolveTime(intent.entities); - var alarm = session.dialogData.alarm = { - title: title ? title.entity : null, - timestamp: time ? time.getTime() : null - }; - - // Prompt for title - if (!alarm.title) { - builder.Prompts.text(session, 'What would you like to call your alarm?'); - } else { - next(); - } - }, - function (session, results, next) { - var alarm = session.dialogData.alarm; - if (results.response) { - alarm.title = results.response; - } - - // Prompt for time - if (!alarm.timestamp) { - builder.Prompts.time(session, 'What time would you like to set the alarm for?'); - } else { - next(); - } - }, - function (session, results) { - var alarm = session.dialogData.alarm; - if (results.response) { - var time = builder.EntityRecognizer.resolveTime([results.response]); - alarm.timestamp = time ? time.getTime() : null; - } - - // Save address of who to notify and write to scheduler. - alarm.address = session.message.address; - alarms[alarm.title] = alarm; - - // Send confirmation to user - var date = new Date(alarm.timestamp); - var isAM = date.getHours() < 12; - session.endDialog('Creating alarm named "%s" for %d/%d/%d %d:%02d%s', - alarm.title, - date.getMonth() + 1, date.getDate(), date.getFullYear(), - isAM ? date.getHours() : date.getHours() - 12, date.getMinutes(), isAM ? 'am' : 'pm'); - } -]).triggerAction({ - matches: 'builtin.intent.alarm.set_alarm', - confirmPrompt: "This will cancel the current alarm. Are you sure?" -}).cancelAction('cancelSetAlarm', "Alarm canceled.", { - matches: /^(cancel|nevermind)/i, - confirmPrompt: "Are you sure?" -}); - -// Delete Alarm dialog -bot.dialog('/deleteAlarm', [ - function (session, args, next) { - if (alarmCount() > 0) { - // Resolve entities passed from LUIS. - var title; - var intent = args.intent; - var entity = builder.EntityRecognizer.findEntity(intent.entities, 'builtin.alarm.title'); - if (entity) { - // Verify its in our set of alarms. - title = builder.EntityRecognizer.findBestMatch(alarms, entity.entity); - } - - // Prompt for alarm name - if (!title) { - builder.Prompts.choice(session, 'Which alarm would you like to delete?', alarms); - } else { - next({ response: title }); - } - } else { - session.endDialog("No alarms to delete."); - } - }, - function (session, results) { - delete alarms[results.response.entity]; - session.endDialog("Deleted the '%s' alarm.", results.response.entity); - } -]).triggerAction({ - matches: 'builtin.intent.alarm.delete_alarm' -}).cancelAction('cancelDeleteAlarm', "Ok.", { - matches: 'CancelIntent' /* /^(cancel|nevermind)/i */ -}); - -// Very simple alarm scheduler -var alarms = {}; -setInterval(function () { - var now = new Date().getTime(); - for (var key in alarms) { - var alarm = alarms[key]; - if (now >= alarm.timestamp) { - var msg = new builder.Message() - .address(alarm.address) - .text("Here's your '%s' alarm.", alarm.title); - bot.send(msg); - delete alarms[key]; - } - } -}, 15000); - -// Helpers -function alarmCount() { - var i = 0; - for (var name in alarms) { - i++; - } - return i; -} diff --git a/articles/includes/code/node-request-payment.js b/articles/includes/code/node-request-payment.js deleted file mode 100644 index 35d43b0cb..000000000 --- a/articles/includes/code/node-request-payment.js +++ /dev/null @@ -1,116 +0,0 @@ -// -var bot = new builder.UniversalBot(connector, (session) => { - - catalog.getPromotedItem().then(product => { - - // Store userId for later, when reading relatedTo to resume dialog with the receipt. - var cartId = product.id; - session.conversationData[CartIdKey] = cartId; - session.conversationData[cartId] = session.message.address.user.id; - - // Create PaymentRequest obj based on product information. - var paymentRequest = createPaymentRequest(cartId, product); - - var buyCard = new builder.HeroCard(session) - .title(product.name) - .subtitle(util.format('%s %s', product.currency, product.price)) - .text(product.description) - .images([ - new builder.CardImage(session).url(product.imageUrl) - ]) - .buttons([ - new builder.CardAction(session) - .title('Buy') - .type(payments.PaymentActionType) - .value(paymentRequest) - ]); - - session.send(new builder.Message(session) - .addAttachment(buyCard)); - }); -}); -// - - -// -connector.onInvoke((invoke, callback) => { - console.log('onInvoke', invoke); - - // This is a temporary workaround for the issue that the channelId for "webchat" is mapped to "directline" in the incoming RelatesTo object - invoke.relatesTo.channelId = invoke.relatesTo.channelId === 'directline' ? 'webchat' : invoke.relatesTo.channelId; - - var storageCtx = { - address: invoke.relatesTo, - persistConversationData: true, - conversationId: invoke.relatesTo.conversation.id - }; - - connector.getData(storageCtx, (err, data) => { - var cartId = data.conversationData[CartIdKey]; - if (!invoke.relatesTo.user && cartId) { - // Bot keeps the userId in context.ConversationData[cartId] - var userId = data.conversationData[cartId]; - invoke.relatesTo.useAuth = true; - invoke.relatesTo.user = { id: userId }; - } - - // Continue based on PaymentRequest event. - var paymentRequest = null; - switch (invoke.name) { - case payments.Operations.UpdateShippingAddressOperation: - case payments.Operations.UpdateShippingOptionOperation: - paymentRequest = invoke.value; - - // Validate address AND shipping method (if selected). - checkout - .validateAndCalculateDetails(paymentRequest, paymentRequest.shippingAddress, paymentRequest.shippingOption) - .then(updatedPaymentRequest => { - // Return new paymentRequest with updated details. - callback(null, updatedPaymentRequest, 200); - }).catch(err => { - // Return error to onInvoke handler. - callback(err); - // Send error message back to user. - bot.beginDialog(invoke.relatesTo, 'checkout_failed', { - errorMessage: err.message - }); - }); - - break; - - case payments.Operations.PaymentCompleteOperation: - var paymentRequestComplete = invoke.value; - paymentRequest = paymentRequestComplete.paymentRequest; - var paymentResponse = paymentRequestComplete.paymentResponse; - - // Validate address AND shipping method. - checkout - .validateAndCalculateDetails(paymentRequest, paymentResponse.shippingAddress, paymentResponse.shippingOption) - .then(updatedPaymentRequest => - // Process payment. - checkout - .processPayment(updatedPaymentRequest, paymentResponse) - .then(chargeResult => { - // Return success. - callback(null, { result: "success" }, 200); - // Send receipt to user. - bot.beginDialog(invoke.relatesTo, 'checkout_receipt', { - paymentRequest: updatedPaymentRequest, - chargeResult: chargeResult - }); - }) - ).catch(err => { - // Return error to onInvoke handler. - callback(err); - // Send error message back to user. - bot.beginDialog(invoke.relatesTo, 'checkout_failed', { - errorMessage: err.message - }); - }); - - break; - } - - }); -}); -// diff --git a/articles/includes/code/node-send-card-buttons.js b/articles/includes/code/node-send-card-buttons.js deleted file mode 100644 index ab17432b3..000000000 --- a/articles/includes/code/node-send-card-buttons.js +++ /dev/null @@ -1,71 +0,0 @@ -// -var msg = new builder.Message(session) - .addAttachment({ - contentType: "application/vnd.microsoft.card.adaptive", - content: { - type: "AdaptiveCard", - speak: "Your meeting about \"Adaptive Card design session\" is starting at 12:30pmDo you want to snooze or do you want to send a late notification to the attendees?", -              body: [ - { - "type": "TextBlock", - "text": "Adaptive Card design session", - "size": "large", - "weight": "bolder" - }, - { - "type": "TextBlock", - "text": "Conf Room 112/3377 (10)" - }, - { - "type": "TextBlock", - "text": "12:30 PM - 1:30 PM" - }, - { - "type": "TextBlock", - "text": "Snooze for" - }, - { - "type": "Input.ChoiceSet", - "id": "snooze", - "style":"compact", - "choices": [ - { - "title": "5 minutes", - "value": "5", - "isSelected": true - }, - { - "title": "15 minutes", - "value": "15" - }, - { - "title": "30 minutes", - "value": "30" - } - ] - } - ], - "actions": [ - { - "type": "Action.OpenUrl", - "method": "POST", - "url": "http://foo.com", - "title": "Snooze" - }, - { - "type": "Action.OpenUrl", - "method": "POST", - "url": "http://foo.com", - "title": "I'll be late" - }, - { - "type": "Action.OpenUrl", - "method": "POST", - "url": "http://foo.com", - "title": "Dismiss" - } - ] - } - }); -session.send(msg); -// diff --git a/articles/includes/code/node-send-suggested-actions.js b/articles/includes/code/node-send-suggested-actions.js deleted file mode 100644 index 0149fe912..000000000 --- a/articles/includes/code/node-send-suggested-actions.js +++ /dev/null @@ -1,14 +0,0 @@ -// -var msg = new builder.Message(session) - .text("Thank you for expressing interest in our premium golf shirt! What color of shirt would you like?") - .suggestedActions( - builder.SuggestedActions.create( - session, [ - builder.CardAction.imBack(session, "productId=1&color=green", "Green"), - builder.CardAction.imBack(session, "productId=1&color=blue", "Blue"), - builder.CardAction.imBack(session, "productId=1&color=red", "Red") - ] - )); -session.send(msg); -// - diff --git a/articles/includes/code/node-text-to-speech.js b/articles/includes/code/node-text-to-speech.js deleted file mode 100644 index 9d35a35ee..000000000 --- a/articles/includes/code/node-text-to-speech.js +++ /dev/null @@ -1,25 +0,0 @@ -// -var msg = new builder.Message(session) - .speak('This is the text that will be spoken.') - .inputHint(builder.InputHint.acceptingInput); -session.send(msg).endDialog(); -// - - - -// -session.say('Please hold while I calculate a response.', - 'Please hold while I calculate a response.', - { inputHint: builder.InputHint.ignoringInput } -); -// - - - -// -builder.Prompts.text(session, 'Are you sure that you want to cancel this transaction?', { - speak: 'Are you sure that you want to cancel this transaction?', - retrySpeak: 'Are you sure that you want to cancel this transaction?', - inputHint: builder.InputHint.expectingInput -}); -// diff --git a/articles/includes/deploy/snippet-ARM-existing-resource-group.md b/articles/includes/deploy/snippet-ARM-existing-resource-group.md deleted file mode 100644 index bbff7d127..000000000 --- a/articles/includes/deploy/snippet-ARM-existing-resource-group.md +++ /dev/null @@ -1,40 +0,0 @@ -In this step, you create a bot application service which sets the deployment stage for the bot. When using an existing resource group, you can either use an existing app service plan or create a new one. Steps for both options are listed below. - -From the resulting JSON output, copy the value of the **id** field to use as the value for the **registration subscription id** in the next step. - -> [!NOTE] -> This step can take a few minutes to complete. - -**Option 1: Existing App Service Plan** - -In this case, we are using an existing App Service Plan, but creating new a Web App and Bot Channels Registration. - -> [!NOTE] -> This command sets the bot's ID and display name. The `botId` parameter should be globally unique and is used as the immutable bot ID. The bot's display name is mutable. - -```cmd -az group deployment create --resource-group "" --template-file "" --parameters appId="" appSecret="" botId="" newWebAppName="" existingAppServicePlan="" appServicePlanLocation="" --name "" -``` - -**Option 2: New App Service Plan** - -In this case, we are creating App Service Plan, Web App, and Bot Channels Registration. - -```cmd -az group deployment create --resource-group "" --template-file "" --parameters appId="" appSecret="" botId="" newWebAppName="" newAppServicePlanName="" appServicePlanLocation="" --name "" -``` - -| Option | Description | -|:---------|:------------| -| name | The display name to use for your bot channels registration. Default is the value of the `botId` parameter.| -| resource-group | Name of the azure resource group. | -| template-file | The path to the ARM template. Usually, the `template-with-preexisting-rg.json` file is provided in the `deploymentTemplates` folder of the project. This is a path to an existing template file. It can be an absolute path, or relative to the current directory. All bot templates generate ARM template files.| -| location |Location. Values from: `az account list-locations`. You can configure the default location using `az configure --defaults location=`. | -| parameters | Deployment parameters, provided as a list of key=value pairs. Enter the following parameter values: - -- `appId` - The *app id* value generated by the previous step. -- `appSecret` - The password you provided in the previous step. -- `botId` - A name for the Bot Channels Registration resource to create. It must be globally unique. It is used as the immutable bot ID. It is also used as the default display name, which is mutable. -- `newWebAppName` - A name for the bot application service. -- `newAppServicePlanName` - A name for the application service plan resource to create. -- `newAppServicePlanLocation` - The location of the application service plan. \ No newline at end of file diff --git a/articles/includes/deploy/snippet-ARM-new-resource-group.md b/articles/includes/deploy/snippet-ARM-new-resource-group.md deleted file mode 100644 index d5ac2e0bc..000000000 --- a/articles/includes/deploy/snippet-ARM-new-resource-group.md +++ /dev/null @@ -1,27 +0,0 @@ -In this step, you create a bot application service which sets the deployment stage for the bot. You use an ARM template, a new service plan and a new resource group. - -From the resulting JSON output, copy the numeric value of the **id** field to use as the value for the **registration subscription id** in the next step. - -> [!NOTE] -> This step can take a few minutes to complete. - -```cmd -az deployment create --template-file " --parameters appId="" appSecret="" botId="" botSku=F0 newAppServicePlanName="" newWebAppName="" groupName="" groupLocation="" newAppServicePlanLocation="" --name "" -``` - -| Option | Description | -|:---------|:------------| -| name | The display name to use for your bot channels registration. Default is the value of the `botId` parameter.| -| template-file | The path to the ARM template. Usually, the `template-with-new-rg.json` file is provided in the `deploymentTemplates` folder of the bot project. This is a path to an existing template file. It can be an absolute path, or relative to the current directory. All bot templates generate ARM template files.| -| location |Location. Values from: `az account list-locations`. You can configure the default location using `az configure --defaults location=`. | -| parameters | Deployment parameters, provided as a list of key=value pairs. Enter the following parameter values: - -- `appId` - The *app id* value generated by the previous step. -- `appSecret` - The password you provided in the previous step. -- `botId` - A name for the Bot Channels Registration resource to create. It must be globally unique. It is used as the immutable bot ID. It is also used as the default display name, which is mutable. -- `botSku` - The pricing tier; it can be F0 (Free) or S1 (Standard). -- `newAppServicePlanName` - The name of the new application service plan. -- `newWebAppName` - A name for the bot application service. -- `groupName` - A name for the new resource group. -- `groupLocation` - The location of the Azure resource group. -- `newAppServicePlanLocation` - The location of the application service plan. \ No newline at end of file diff --git a/articles/includes/deploy/snippet-IIS-Kudu-files.md b/articles/includes/deploy/snippet-IIS-Kudu-files.md deleted file mode 100644 index 50ce3fc5a..000000000 --- a/articles/includes/deploy/snippet-IIS-Kudu-files.md +++ /dev/null @@ -1,38 +0,0 @@ - -You need to prepare your project files before you can deploy your C#, Javascript, or Typescript bot. If you are deploying a Python bot you can skip this step. - - -##### [C#](#tab/csharp) - -```cmd -az bot prepare-deploy --lang Csharp --code-dir "." --proj-file-path "MyBot.csproj" -``` - -You must provide the path to the .csproj file relative to --code-dir. This can be performed via the --proj-file-path argument. The command would resolve --code-dir and --proj-file-path to "./MyBot.csproj" - - -##### [JavaScript](#tab/javascript) - -```cmd -az bot prepare-deploy --code-dir "." --lang Javascript -``` - -This command will fetch a web.config which is needed for Node.js apps to work with IIS on Azure App Services. Make sure web.config is saved to the root of your bot. - - -##### [TypeScript](#tab/typescript) - -```cmd -az bot prepare-deploy --code-dir "." --lang Typescript -``` - -This command works similarly to JavaScript above, but for a Typescript bot. - ---- - -> [!NOTE] -> For C# bots, the `az bot prepare-deploy` command generate sa `.deployment` file in your bot project folder. -> For JavaScript bots, the command generates two `web.config` file in your project folder. -> For TypeScript bots, the command generates two `web.config` files. One is in your project folder and another in the **src** folder within your project folder. - - diff --git a/articles/includes/deploy/snippet-additional-resources.md b/articles/includes/deploy/snippet-additional-resources.md deleted file mode 100644 index 1522da000..000000000 --- a/articles/includes/deploy/snippet-additional-resources.md +++ /dev/null @@ -1,13 +0,0 @@ -When you deploy a bot, typically these resources are created in the Azure portal: - -| Resources | Description | -|----------------|-------------| -| Web App Bot | An Azure Bot Service bot that is deployed to an Azure App Service.| -| [App Service](https://docs.microsoft.com/azure/app-service/)| Enables you to build and host web applications.| -| [App Service plan](https://docs.microsoft.com/azure/app-service/azure-web-sites-web-hosting-plans-in-depth-overview)| Defines a set of compute resources for a web app to run.| - -If you create your bot through the Azure portal, you are able to provision additional resources, like [Application Insights for telemetry](~/v4sdk/bot-builder-telemetry.md). - -To see documentation on `az bot` commands, see the [reference](https://docs.microsoft.com/cli/azure/bot?view=azure-cli-latest) topic. - -If you are unfamiliar with Azure resource group, see this [terminology](https://docs.microsoft.com/azure/azure-resource-manager/resource-group-overview#terminology) topic. \ No newline at end of file diff --git a/articles/includes/deploy/snippet-az-create-group.md b/articles/includes/deploy/snippet-az-create-group.md deleted file mode 100644 index 797a00312..000000000 --- a/articles/includes/deploy/snippet-az-create-group.md +++ /dev/null @@ -1,8 +0,0 @@ -```cmd -az group create --name --location --verbose -``` - -| Option | Description | -|:---|:---| -| --name | A unique name for the resource group. DO NOT include spaces or underscores in the name. | -| --location | Geographic location used to create the resource group. For example, `eastus`, `westus`, `westus2`, and so on. Use `az account list-locations` for a list of locations. | \ No newline at end of file diff --git a/articles/includes/deploy/snippet-az-login.md b/articles/includes/deploy/snippet-az-login.md deleted file mode 100644 index 5121af940..000000000 --- a/articles/includes/deploy/snippet-az-login.md +++ /dev/null @@ -1,9 +0,0 @@ -Once you've created and tested a bot locally, you can deploy it to Azure. Open a command prompt to log in to the Azure portal. - -```cmd -az login -``` -A browser window will open, allowing you to sign in. - -> [!NOTE] -> If you deploy your bot to a non-Azure cloud such as US Gov, you need to run `az cloud set --name ` before `az login`, where <name-of-cloud> is the name of a registered cloud, such as `AzureUSGovernment`. If you want to go back to public cloud, you can run `az cloud set --name AzureCloud`. diff --git a/articles/includes/deploy/snippet-az-set-subscription.md b/articles/includes/deploy/snippet-az-set-subscription.md deleted file mode 100644 index 2119ed36c..000000000 --- a/articles/includes/deploy/snippet-az-set-subscription.md +++ /dev/null @@ -1,7 +0,0 @@ -Set the default subscription to use. - -```cmd -az account set --subscription "" -``` - -If you are not sure which subscription to use for deploying the bot, you can view the list of subscriptions for your account by using `az account list` command. \ No newline at end of file diff --git a/articles/includes/deploy/snippet-clear-encryption.md b/articles/includes/deploy/snippet-clear-encryption.md deleted file mode 100644 index 66921151f..000000000 --- a/articles/includes/deploy/snippet-clear-encryption.md +++ /dev/null @@ -1,8 +0,0 @@ -Clear the encryption key setting. - -1. Log into the [Azure portal](http://portal.azure.com/). -1. Open the Web App Bot resource for your bot. -1. Open the bot's **Application Settings**. -1. In the **Application Settings** window, scroll down to the **Application settings**. -1. Locate the **botFileSecret** and delete it. -1. Click *Save* at the top of this page to save your changes. diff --git a/articles/includes/deploy/snippet-create-app-registration.md b/articles/includes/deploy/snippet-create-app-registration.md deleted file mode 100644 index 4ddfccdb3..000000000 --- a/articles/includes/deploy/snippet-create-app-registration.md +++ /dev/null @@ -1,19 +0,0 @@ -In this step you create an Azure Active Directory application, which will allow: - -- The user to interact with the bot via a set of channels such as *Web Chat*. -- The definition of *OAuth Connection Settings* to authenticate a user and to create a *token* used by the bot to access protected resources on behalf of the user. - -To create an Azure Active Directory application, execute the following command: - -```cmd -az ad app create --display-name "displayName" --password "AtLeastSixteenCharacters_0" --available-to-other-tenants -``` - -| Option | Description | -|:---------|:------------| -| display-name | The display name of the application. It is listed in the Azure portal in the general resources list and in the resource group it belongs.| -| password | The password, also known as **client secret**, for the application. This is a password you create for this resource. It must be at least 16 characters long, contain at least 1 upper or lower case alphabetical character, and contain at least 1 special character.| -| available-to-other-tenants| Indicates that the application can be used from any Azure AD tenant. Set this to enable your bot to work with the Azure Bot Service channels.| - -The above command outputs JSON with the key `appId`, copy and save it. -You are going to use this `appId` and the password you entered in the ARM deployment step, to assign values to the `appId` and the `appSecret` parameters, respectively. diff --git a/articles/includes/deploy/snippet-create-bot-msa.md b/articles/includes/deploy/snippet-create-bot-msa.md deleted file mode 100644 index d72308398..000000000 --- a/articles/includes/deploy/snippet-create-bot-msa.md +++ /dev/null @@ -1,16 +0,0 @@ -1. Go to the [**Application Registration Portal**](https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade). -1. Click on **Add an app** to register your application, create **Application Id**, and **Generate New Password**. If you already have an application and password but don't remember the password, you will have to generate a new password in the Application secrets section. -1. Save both application ID and the new password you just generated, so you that can use them with the `az bot create` command. - -```cmd -az bot create --kind webapp --name --location --version v4 --lang --verbose --resource-group --appid "" --password "" --verbose -``` - -| Option | Description | -|:---|:---| -| --name | A unique name that is used to deploy the bot in Azure. It could be the same name as your local bot. DO NOT include spaces or underscores in the name. | -| --location | Geographic location used to create the bot service resources. For example, `eastus`, `westus`, `westus2`, and so on. | -| --lang | The language to use to create the bot: `Csharp`, or `Node`; default is `Csharp`. | -| --resource-group | Name of resource group in which to create the bot. You can configure the default group using `az configure --defaults group=`. | -| --appid | The Microsoft account ID (MSA ID) to be used with the bot. | -| --password | The Microsoft account (MSA) password for the bot. | diff --git a/articles/includes/deploy/snippet-create-bot.md b/articles/includes/deploy/snippet-create-bot.md deleted file mode 100644 index 77ebdd181..000000000 --- a/articles/includes/deploy/snippet-create-bot.md +++ /dev/null @@ -1,10 +0,0 @@ -```cmd -az bot create --kind webapp --name --location --version v4 --lang --verbose --resource-group -``` - -| Option | Description | -|:---|:---| -| --name | A unique name that is used to deploy the bot in Azure. It could be the same name as your local bot. DO NOT include spaces or underscores in the name. | -| --location | Geographic location used to create the bot service resources. For example, `eastus`, `westus`, `westus2`, and so on. | -| --lang | The language to use to create the bot: `Csharp`, or `Node`; default is `Csharp`. | -| --resource-group | Name of resource group in which to create the bot. You can configure the default group using `az configure --defaults group=`. | \ No newline at end of file diff --git a/articles/includes/deploy/snippet-create-web-app.md b/articles/includes/deploy/snippet-create-web-app.md deleted file mode 100644 index 4ab0a7e58..000000000 --- a/articles/includes/deploy/snippet-create-web-app.md +++ /dev/null @@ -1,5 +0,0 @@ -Then, create the bot resource into which you will publish your bot. This will provision the necessary resources in Azure and create a bot web app, which you will overwrite with your local bot. - -> [!NOTE] -> This isn't the only way to achieve this, but it tends to be the easiest way to create all the parts you will need for deploying a functioning bot. - diff --git a/articles/includes/deploy/snippet-decrypt-bot.md b/articles/includes/deploy/snippet-decrypt-bot.md deleted file mode 100644 index be4de19bf..000000000 --- a/articles/includes/deploy/snippet-decrypt-bot.md +++ /dev/null @@ -1,32 +0,0 @@ -Get the encryption key. - -1. Log into the [Azure portal](http://portal.azure.com/). -1. Open the Web App Bot resource for your bot. -1. Open the bot's **Application Settings**. -1. In the **Application Settings** window, scroll down to the **Application settings**. -1. Locate the **botFileSecret** and copy its value. - -Decrypt the .bot file. - -```cmd -msbot secret --bot --secret "" --clear -``` - -| Option | Description | -|:---|:---| -| --bot | The relative path to the downloaded .bot file. | -| --secret | The encryption key. | - -Copy the decrypted `.bot` file to the directory that contains your local bot project, update your bot to use this new `.bot` file, and remove your old `.bot` file. - -# [C#](#tab/csharp) - -In **appsettings.json**, update the **botFilePath** property to point to the new `.bot` file you've added to your local directory. - -# [JavaScript](#tab/javascript) - -In **.env**, update the **botFilePath** property to point to the new `.bot` file you've added to your local directory. - ---- - -Once your bot has been updated, delete the temporary directory of the downloaded bot. \ No newline at end of file diff --git a/articles/includes/deploy/snippet-deploy-code-to-az.md b/articles/includes/deploy/snippet-deploy-code-to-az.md deleted file mode 100644 index 44450139b..000000000 --- a/articles/includes/deploy/snippet-deploy-code-to-az.md +++ /dev/null @@ -1,15 +0,0 @@ -At this point we are ready to deploy the code to the Azure Web App. Run the following command from the command line to perform deployment using the kudu zip push deployment for a web app. - -```cmd -az webapp deployment source config-zip --resource-group "" --name "" --src -``` - -| Option | Description | -|:---------|:------------| -| resource-group | The name of the Azure resource group that contains your bot. (This will be the resource group you used or created when creating the app registration for your bot.) | -| name | Name of the Web App you used earlier. | -| src | The path to the zipped project file you created. | - -> [!NOTE] -> This step can take a few minutes to complete. -> Also it can take a few more minutes between when the deployment finishes and when your bot is available to test. \ No newline at end of file diff --git a/articles/includes/deploy/snippet-download-bot.md b/articles/includes/deploy/snippet-download-bot.md deleted file mode 100644 index 3272f6f6a..000000000 --- a/articles/includes/deploy/snippet-download-bot.md +++ /dev/null @@ -1,13 +0,0 @@ -Use a temporary directory outside of your current project directory. - -This command will create a subdirectory under the save-path; however, the specified path must already exist. - -```cmd -az bot download --name --resource-group --save-path "" -``` - -| Option | Description | -|:---|:---| -| --name | The name of the bot in Azure. | -| --resource-group | Name of resource group the bot is in. | -| --save-path | An existing directory to download bot code to. | \ No newline at end of file diff --git a/articles/includes/deploy/snippet-prepare-deploy-intro.md b/articles/includes/deploy/snippet-prepare-deploy-intro.md deleted file mode 100644 index 752681427..000000000 --- a/articles/includes/deploy/snippet-prepare-deploy-intro.md +++ /dev/null @@ -1,12 +0,0 @@ -When you create a bot using the [Visual Studio template](https://docs.microsoft.com/azure/bot-service/dotnet/bot-builder-dotnet-sdk-quickstart?view=azure-bot-service-4.0), [Yeoman template](https://docs.microsoft.com/azure/bot-service/javascript/bot-builder-javascript-quickstart?view=azure-bot-service-4.0), or [Cookiecutter template](https://docs.microsoft.com/azure/bot-service/python/bot-builder-python-quickstart?view=azure-bot-service-4.0) the source code generated includes a `deploymentTemplates` folder that contains ARM templates. The deployment process documented here uses one of the ARM templates to provision required resources for the bot in Azure by using the Azure CLI. - -> [!NOTE] -> With the release of Bot Framework SDK 4.3, we have _deprecated_ the use of a .bot file. Instead, we use an appsettings.json or .env file to manage bot resources. For information on migrating settings from the .bot file to appsettings.json or .env file, see [managing bot resources](https://docs.microsoft.com/azure/bot-service/bot-file-basics?view=azure-bot-service-4.0). - -### Bot ready to deploy - -This article assumes that you have a bot ready to be deployed and the **path** to the related project. You need the path to access the deployment templates and also to create a *zip* file to deploy. - -For information on how to create a simple echo bot, see the quick start [CSharp sample](~/dotnet/bot-builder-dotnet-sdk-quickstart.md) or [JavaScript sample](~/javascript/bot-builder-javascript-quickstart.md) or [Python sample](~/python/bot-builder-python-quickstart.md). - -You can also use one of the samples provided in the [Bot Framework Samples](https://github.com/Microsoft/BotBuilder-Samples/blob/master/README.md) repository. \ No newline at end of file diff --git a/articles/includes/deploy/snippet-prerequisite.md b/articles/includes/deploy/snippet-prerequisite.md deleted file mode 100644 index 18e9adaae..000000000 --- a/articles/includes/deploy/snippet-prerequisite.md +++ /dev/null @@ -1,17 +0,0 @@ -- A subscription to [Microsoft Azure](https://azure.microsoft.com/free/) -- A C#, JavaScript, TypeScript, or Python bot that you have developed on your local machine -- Latest version of the [Azure CLI](https://docs.microsoft.com/cli/azure/?view=azure-cli-latest) -- Familiarity with [Azure CLI and ARM templates](https://docs.microsoft.com/azure/azure-resource-manager/resource-group-overview) - - diff --git a/articles/includes/deploy/snippet-publish-js.md b/articles/includes/deploy/snippet-publish-js.md deleted file mode 100644 index 75a27aadd..000000000 --- a/articles/includes/deploy/snippet-publish-js.md +++ /dev/null @@ -1,17 +0,0 @@ -To publish your local JavaScript bot back to Azure, you must first manually create a single zipped file containing all files used to locally build and run your bot. This includes all npm libraries downloaded into your `node_modules` folder. When creating this zip file _make sure that the root directory you use is the same directory where your index.js file resides_. - -Once a zip file containing all of your bot's source code has been created, open a command prompt window and run the following _Az cli_ command. - -This step might take a while. - -```cmd -az webapp deployment source config-zip --resource-group --name --src -``` - -| Option | Description | -|:---|:---| -| --resource-group | Name of resource group in Azure. | -| --name | The resource name of the bot in Azure. | -| --src | The full directory path to upload your zipped bot code from. For example `c:\my-local-repository\this-app-folder\my-zipped-code.zip` | - -Once this completes successfully, your bot is deployed in Azure. diff --git a/articles/includes/deploy/snippet-publish.md b/articles/includes/deploy/snippet-publish.md deleted file mode 100644 index 0acc56110..000000000 --- a/articles/includes/deploy/snippet-publish.md +++ /dev/null @@ -1,14 +0,0 @@ -Publish your local bot to Azure. This step might take a while. - -```cmd -az bot publish --name --proj-file-path "" --resource-group --code-dir --verbose --version v4 -``` - -| Option | Description | -|:---|:---| -| --name | The resource name of the bot in Azure. | -| --proj-file-path | For C#, use the startup project file name (without the .csproj) that needs to be published. For example: `EnterpriseBot`. For Node.js, use the main entry point for the bot. For example, `index.js`. | -| --resource-group | Name of resource group. | -| --code-dir | The directory to upload bot code from. | - -Once this completes with a "Deployment successful!" message, your bot is deployed in Azure. diff --git a/articles/includes/deploy/snippet-test-in-web-chat.md b/articles/includes/deploy/snippet-test-in-web-chat.md deleted file mode 100644 index 6d8917d63..000000000 --- a/articles/includes/deploy/snippet-test-in-web-chat.md +++ /dev/null @@ -1,9 +0,0 @@ -1. In your browser, navigate to the [Azure portal](https://ms.portal.azure.com). -2. In the left panel, click **Resource groups**. -3. In the right panel, search for your group. -4. Click on your group name. -5. Click the link of your Bot Channels Registration. -6. In the **Bot Channels Registration** panel, click **Test in Web Chat**. -Alternatively, in the right panel, click the **Test** box. - -For more information about bot channels registration, see [Register a bot with Bot Service](https://docs.microsoft.com/azure/bot-service/bot-service-quickstart-registration?view=azure-bot-service-3.0). diff --git a/articles/includes/deploy/snippet-zip-code.md b/articles/includes/deploy/snippet-zip-code.md deleted file mode 100644 index 5f36041cd..000000000 --- a/articles/includes/deploy/snippet-zip-code.md +++ /dev/null @@ -1,15 +0,0 @@ -When using the non-configured [zip deploy API](https://github.com/projectkudu/kudu/wiki/Deploying-from-a-zip-file-or-url) to deploy your bot's code, Web App/Kudu's behavior is as follows: - -_Kudu assumes by default that deployments from zip files are ready to run and do not require additional build steps during deployment, such as npm install or dotnet restore/dotnet publish._ - -It is important to include your built code with all necessary dependencies in the zip file being deployed, otherwise your bot will not work as intended. - -> [!IMPORTANT] -> Before zipping your project files, make sure that you are _in_ the project folder. -> - For C# bots, it is the folder that has the .csproj file. -> - For JavaScript bots, it is the folder that has the app.js or index.js file. -> - For TypeScript bots, it is the folder that includes the _src_ folder (where the bot.ts and index.ts files are). -> - For Python bots, it is the folder that has the app.py file. - ->**Within** the project folder, select all the files and folders you want included in your zip file before running the command to create the zip file, this will create a single zip file containing all selected files and folders. -> If your root folder location is incorrect, the **bot will fail to run in the Azure portal**. diff --git a/articles/includes/deployment-note-cli.md b/articles/includes/deployment-note-cli.md deleted file mode 100644 index 47dbcdccc..000000000 --- a/articles/includes/deployment-note-cli.md +++ /dev/null @@ -1,15 +0,0 @@ -If you are using services such as LUIS, you will also need to pass `luisAuthoringKey`. If you want to use existing resource group in Azure, use the `groupName` argument with the above command. - -It is highly recommended that you use the `verbose` option to help troubleshoot problems that might occur during the deployment of the bot. Additional options used with the `msbot clone services` command are described below: - -| Arguments | Description | -|--------------|-------------| -| `folder` | Location of the `bot.recipe` file. By default the recipe file is created in the `DeploymentsScript/MSBotClone`. DO NOT MODIFY this file.| -| `location` | Geographic location used to create the bot service resources. For example, eastus, westus, westus2 etc.| -| `proj-file` | For C# bot it is the .csproj file. For JS bot it is the startup project file name (e.g. index.js) of your local bot.| -| `name` | A unique name that is used to deploy the bot in Azure. It could be the same name as your local bot. DO NOT include spaces or underscores in the name.| -| `luisAuthoringKey` | Your authoring key for the appropriate LUIS authoring region for the LUIS resources. | - -Before Azure resources can be created, you'll be prompted to complete authentication. Follow the instructions that appear on the screen to complete this step. - -Note that the above step takes _few seconds to minutes_ to complete, and the resource that are created in Azure have their names mangled. To learn more about name mangling, see [issue# 796](https://github.com/Microsoft/botbuilder-tools/issues/796) in the GitHub repo. diff --git a/articles/includes/pre-release-label-v3.md b/articles/includes/pre-release-label-v3.md deleted file mode 100644 index 35d50d50c..000000000 --- a/articles/includes/pre-release-label-v3.md +++ /dev/null @@ -1,2 +0,0 @@ -> [!NOTE] -> This topic applies to SDK v3 release. You can find the documentation for the latest version of the SDK v4 [here.](https://docs.microsoft.com/azure/bot-service/?view=azure-bot-service-4.0) diff --git a/articles/includes/pre-release-label.md b/articles/includes/pre-release-label.md deleted file mode 100644 index 612139215..000000000 --- a/articles/includes/pre-release-label.md +++ /dev/null @@ -1,2 +0,0 @@ -> [!NOTE] -> This topic is for the latest release of the SDK (v4). You can find content for the older version of the SDK (v3) [here.](https://docs.microsoft.com/azure/bot-service/?view=azure-bot-service-3.0) diff --git a/articles/includes/quickstart-dotnet.md b/articles/includes/quickstart-dotnet.md deleted file mode 100644 index 2220058cc..000000000 --- a/articles/includes/quickstart-dotnet.md +++ /dev/null @@ -1,38 +0,0 @@ -## Prerequisites -- [Visual Studio 2017 or later](https://www.visualstudio.com/downloads) -- [Bot Framework SDK v4 template for C#](https://aka.ms/bot-vsix) -- [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme) -- Knowledge of [ASP.Net Core](https://docs.microsoft.com/aspnet/core/) and [asynchronous programming in C#](https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/async/index) - -## Create a bot -Install [BotBuilderVSIX.vsix template](https://aka.ms/bot-vsix) that you downloaded in the prerequisites section. - -In Visual Studio, create a new bot project using the **Echo Bot (Bot Framework v4)** template. Enter _bot framework v4_ in the search box to show only bot templates. - -![Visual Studio create a new project dialog](../media/azure-bot-quickstarts/bot-builder-dotnet-project-vs2019.png) - -> [!TIP] -> If using Visual Studio 2017, make sure that the project build type is ``.Net Core 2.1`` or later. Also if needed, update the `Microsoft.Bot.Builder` [NuGet packages](https://docs.microsoft.com/nuget/quickstart/install-and-use-a-package-in-visual-studio). - -Thanks to the template, your project contains all the code that's necessary to create the bot in this quickstart. You won't actually need to write any additional code. - -## Start your bot in Visual Studio - -When you click the run button, Visual Studio will build the application, deploy it to localhost, and launch the web browser to display the application's `default.htm` page. At this point, your bot is running locally. - -## Start the emulator and connect your bot - -Next, start the emulator and then connect to your bot in the emulator: - -1. Click the **Create a new bot configuration** link in the emulator "Welcome" tab. -2. Fill out the fields for your bot. Use your bot's welcome page address (typically http://localhost:3978) and append routing info '/api/messages' to this address. -3. then click **Save and connect**. - -## Interact with your bot - -Send a message to your bot, and the bot will respond back with a message. - -![Emulator running](~/media/emulator-v4/emulator-running.png) - -> [!NOTE] -> If you see that the message cannot be sent, you might need to restart your machine as ngrok didn't get the needed privileges on your system yet (only needs to be done one time). diff --git a/articles/includes/quickstart-javascript.md b/articles/includes/quickstart-javascript.md deleted file mode 100644 index 12662bfec..000000000 --- a/articles/includes/quickstart-javascript.md +++ /dev/null @@ -1,75 +0,0 @@ -## Prerequisites - -- [Visual Studio Code](https://www.visualstudio.com/downloads) -- [Node.js](https://nodejs.org/) -- [Yeoman](http://yeoman.io/), which uses a generator to create a bot for you -- [git](https://git-scm.com/) -- [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme) -- Knowledge of [restify](http://restify.com/) and asynchronous programming in JavaScript - -> [!NOTE] -> The install of Windows build tools listed below is only required if you use Windows as your development operating system. -> For some installations the install step for restify is giving an error related to node-gyp. -> If this is the case you can try running this command with elevated permissions. -> This call may also hang without exiting if python is already installed on your system: - -> ```bash -> # only run this command if you are on Windows. Read the above note. -> npm install -g windows-build-tools -> ``` - -## Create a bot - -To create your bot and initialize its packages - -1. Open a terminal or elevated command prompt. -1. If you don't already have a directory for your JavaScript bots, create one and change directories to it. (We're creating a directory for your JavaScript bots in general, even though we're only creating one bot in this tutorial.) - - ```bash - mkdir myJsBots - cd myJsBots - ``` - -1. Ensure your version of npm is up to date. - - ```bash - npm install -g npm - ``` - -1. Next, install Yeoman and the generator for JavaScript. - - ```bash - npm install -g yo generator-botbuilder - ``` - -1. Then, use the generator to create an echo bot. - - ```bash - yo botbuilder - ``` - -Yeoman prompts you for some information with which to create your bot. For this tutorial, use the default values. - -- Enter a name for your bot. (my-chat-bot) -- Enter a description. (Demonstrate the core capabilities of the Microsoft Bot Framework) -- Choose the language for your bot. (JavaScript) -- Choose the template to use. (Echo Bot - https://aka.ms/generator-botbuilder-templates) - -Thanks to the template, your project contains all the code that's necessary to create the bot in this quickstart. You won't actually need to write any additional code. - -> [!NOTE] -> If you choose to create a `Core` bot, you'll need a LUIS language model. You can create one on [luis.ai](https://www.luis.ai). After creating the model, update the configuration file. - -## Start your bot - -In a terminal or command prompt change directories to the one created for your bot, and start it with `npm start`. At this point, your bot is running locally. - -## Start the Emulator and connect your bot - -1. Start the Bot Framework Emulator. -2. Click the **Create a new bot configuration** link in the emulator "Welcome" tab. -3. Fill out the fields for your bot. Use your bot's welcome page address (typically http://localhost:3978) and append routing info '/api/messages' to this address. -4. Then click **Save and connect**. - -Send a message to your bot, and the bot will respond back with a message. -![Emulator running](../media/emulator-v4/js-quickstart.png) diff --git a/articles/includes/quickstart-python.md b/articles/includes/quickstart-python.md deleted file mode 100644 index 15878fad7..000000000 --- a/articles/includes/quickstart-python.md +++ /dev/null @@ -1,46 +0,0 @@ -## Prerequisites -- Python [3.6](https://www.python.org/downloads/release/python-369/) or [3.7](https://www.python.org/downloads/release/python-375/) -- [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme) -- [git](https://git-scm.com/) -- knowledge of ansynchronous programming in Python - -## Create a bot -1. Open a terminal and navigate to the folder where you're saving your bot locally. Install the necessary packages by running the following commands: -- `pip install botbuilder-core` -- `pip install asyncio` -- `pip install -r requirements.txt` -- `pip install cookiecutter` - -The last package, cookiecutter, will be used to generate your bot. Verify that cookiecutter was installed correctly by running `cookiecutter --help`. - -2. To create your bot run: - -```cmd -cookiecutter https://github.com/microsoft/botbuilder-python/releases/download/Templates/echo.zip -``` - -This command creates an Echo Bot based on the Python [echo template](https://github.com/microsoft/botbuilder-python/tree/master/generators/app/templates/echo). - -3. You will then be prompted for the *name* of the bot and a *description*. Name your bot `echo-bot` and set the description to `A bot that echoes back user response.` as shown below: - -![set name and description](~/media/python/quickstart/set-name-description.png) - -Copy the last for digits in the address on the last line (usually 3978) since you will be using them in the next step. You are now ready to start your bot. - -## Start you bot -1. From a terminal navigate to the `echo-bot` folder where you saved your bot. Run `pip install -r requirements.txt` to install any required packages to run your bot. - -2. Once the packages are installted run `python app.py` to start your bot. You will know your bot is ready to test when you see the last line shown in the screenshot below: - -![bot running locally](~/media/python/quickstart/bot-running-locally.png) - -## Start the Emulator and connect your bot -1. Start the Emulator and click the **Open Bot** button. - -2. After clicking the button a box window will open where you set the necessary values to run the bot. Use the number you saved earlier and set the **Bot URL** to `http://localhost:/api/messages` as seen below: - -![open a bot screen](~/media/python/quickstart/open-bot.png) - -3. Click the **Connect** button and your bot should start. Try testing the bot by typing anything and clicking *Enter* as seen below: - -![connect and test](~/media/python/quickstart/connect-and-start.png) diff --git a/articles/includes/snippet-abs-hosting-plans.md b/articles/includes/snippet-abs-hosting-plans.md deleted file mode 100644 index 16b0c51b2..000000000 --- a/articles/includes/snippet-abs-hosting-plans.md +++ /dev/null @@ -1,14 +0,0 @@ -Bot Service offers two different hosting plans for bots. Converting bot source code from one plan to the other is a manual process. - -## App Service plan - -A bot that uses an App Service plan is a standard Azure web app you can set to allocate a predefined capacity with predictable costs and scaling. With a bot that uses this hosting plan, you can: - -* Edit bot source code online using an advanced in-browser code editor. -* Download, debug, and re-publish your C# bot using Visual Studio. -* Set up continuous deployment easily for Visual Studio Online and Github. -* Use sample code prepared for the Bot Framework SDK. - -## Consumption plan - -A bot that uses a Consumption plan is a serverless bot that runs on Azure Functions, and uses the pay-per-run Azure Functions pricing. A bot that uses this hosting plan can scale to handle huge traffic spikes. You can edit bot source code online using a basic in-browser code editor. For more information about the runtime environment of a Consumption plan bot, see Azure Functions Consumption and App Service plans. diff --git a/articles/includes/snippet-abs-key-download.md b/articles/includes/snippet-abs-key-download.md deleted file mode 100644 index 6134ebe1d..000000000 --- a/articles/includes/snippet-abs-key-download.md +++ /dev/null @@ -1 +0,0 @@ -When downloading your bot, you will be given the option to include the settings (containing the keys and secrets) for your bot in your download, which may be necessary for your bot to work. If you choose **Yes**, the `appsettings.json` or `.env` file will have the keys. \ No newline at end of file diff --git a/articles/includes/snippet-abs-templates.md b/articles/includes/snippet-abs-templates.md deleted file mode 100644 index e68a3030e..000000000 --- a/articles/includes/snippet-abs-templates.md +++ /dev/null @@ -1,8 +0,0 @@ -| Template | Description | -|------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Basic | Creates a bot that uses dialogs to respond to user input. | -| Form | Creates a bot that collects input from a user via a guided conversation that is created using [FormFlow](~/dotnet/bot-builder-dotnet-formflow.md) in C# or [waterfalls](~/nodejs/bot-builder-nodejs-prompts.md) in Node.js. | -| Language understanding | Creates a bot that uses natural language models (LUIS) to understand user intent. | -| QnA Maker | Creates a bot that uses the QnA Maker service to answer user's FAQs. | -| Proactive | Creates a bot that uses Azure Functions to alert users of events. | - diff --git a/articles/includes/snippet-audio-call-intro.md b/articles/includes/snippet-audio-call-intro.md deleted file mode 100644 index 68b5f4bda..000000000 --- a/articles/includes/snippet-audio-call-intro.md +++ /dev/null @@ -1,4 +0,0 @@ -If you are building a bot for Skype, your bot can communicate with users via audio call. -Audio calls are useful when the user does not want to or cannot provide input by typing, tapping, or clicking. - -A bot may support other user controls such as rich cards or text in addition to audio calls, or communicate through audio calls only. \ No newline at end of file diff --git a/articles/includes/snippet-backchannel.md b/articles/includes/snippet-backchannel.md deleted file mode 100644 index 679d2c9cd..000000000 --- a/articles/includes/snippet-backchannel.md +++ /dev/null @@ -1,7 +0,0 @@ -The open source web chat control -communicates with bots by using the [Direct Line API](https://docs.botframework.com/restapi/directline3/#navtitle), -which allows `activities` to be sent back and forth between client and bot. -The most common type of activity is `message`, but there are other types as well. -For example, the activity type `typing` indicates that a user is typing or that the bot is working to compile a response. - -You can use the backchannel mechanism to exchange information between client and bot without presenting it to the user by setting the activity type to `event`. The web chat control will automatically ignore any activities where `type="event"`. \ No newline at end of file diff --git a/articles/includes/snippet-channel-inspector.md b/articles/includes/snippet-channel-inspector.md deleted file mode 100644 index a455166d0..000000000 --- a/articles/includes/snippet-channel-inspector.md +++ /dev/null @@ -1,2 +0,0 @@ -> [!TIP] -> For tables describing which features are supported on each channel, see the [channels reference](../bot-service-channels-reference.md) article. \ No newline at end of file diff --git a/articles/includes/snippet-channelData-email.md b/articles/includes/snippet-channelData-email.md deleted file mode 100644 index 469133ee0..000000000 --- a/articles/includes/snippet-channelData-email.md +++ /dev/null @@ -1,8 +0,0 @@ -| Property | Description | -| :--- | :--- | -| htmlBody | The HTML to use for the body of the message. | -| subject | The subject to use for the message. | -| importance | The importance flag to use for the message: `low`, `normal`, or `high`. | -| toRecipients | A semicolon (;) delimited string of email addresses to add to the message's To field. | -| ccRecipients | A semicolon (;) delimited string of email addresses to add to the message's Cc (carbon copy) field. | -| bccRecipients | A semicolon (;) delimited string of email addresses to add to the message's Bcc (blind carbon copy) field. | diff --git a/articles/includes/snippet-channeldata.md b/articles/includes/snippet-channeldata.md deleted file mode 100644 index 8413f3dc6..000000000 --- a/articles/includes/snippet-channeldata.md +++ /dev/null @@ -1,505 +0,0 @@ -Some channels provide features that cannot be implemented by using only message text and attachments. To implement channel-specific functionality, you can pass native metadata to a channel in the activity object's _channel data_ property. For example, your bot can use the channel data property to instruct Telegram to send a sticker or to instruct Office365 to send an email. - -This article describes how to use a message activity's channel data property to implement this channel-specific functionality: - -| Channel | Functionality | -|----|----| -| Email | Send and receive an email that contains body, subject, and importance metadata | -| Slack | Send full fidelity Slack messages | -| Facebook | Send Facebook notifications natively | -| Telegram | Perform Telegram-specific actions, such as sharing a voice memo or a sticker | -| Kik | Send and receive native Kik messages | - -> [!NOTE] -> The value of an activity object's channel data property is a JSON object. -> Therefore, the examples in this article show the expected format of the -> `channelData` JSON property in various scenarios. -> To create a JSON object using .NET, use the `JObject` (.NET) class. - -## Create a custom Email message - -To create an email message, set the activity object's channel data property -to a JSON object that contains these properties: - -| Property | Description | -|----|----| -| bccRecipients | A semicolon (;) delimited string of email addresses to add to the message's Bcc (blind carbon copy) field. | -| ccRecipients | A semicolon (;) delimited string of email addresses to add to the message's Cc (carbon copy) field. | -| htmlBody | An HTML document that specifies the body of the email message. See the channel's documentation for information about supported HTML elements and attributes. | -| importance | The email's importance level. Valid values are **high**, **normal**, and **low**. The default value is **normal**. | -| subject | The email's subject. See the channel's documentation for information about field requirements. | -| toRecipients | A semicolon (;) delimited string of email addresses to add to the message's To field. | - -> [!NOTE] -> Messages that your bot receives from users via the Email channel may -> contain a channel data property that is populated with a JSON object like the one described above. - -This snippet shows an example of the `channelData` property for a custom email message. - -```json -"channelData": { - "type": "message", - "locale": "en-Us", - "channelID": "email", - "from": { "id": "mybot@mydomain.com", "name": "My bot"}, - "recipient": { "id": "joe@otherdomain.com", "name": "Joe Doe"}, - "conversation": { "id": "123123123123", "topic": "awesome chat" }, - "channelData": - { - "htmlBody": "This is more than awesome.", - "subject": "Super awesome message subject", - "importance": "high", - "ccRecipients": "Yasemin@adatum.com;Temel@adventure-works.com" - } -} -``` - -## Create a full-fidelity Slack message - -To create a full-fidelity Slack message, -set the activity object's channel data property to a JSON object that specifies -Slack messages, -Slack attachments, and/or -Slack buttons. - -> [!NOTE] -> To support buttons in Slack messages, you must enable **Interactive Messages** when you -> [connect your bot](../bot-service-manage-channels.md) to the Slack channel. - -This snippet shows an example of the `channelData` property for a custom Slack message. - -```json -"channelData": { - "text": "Now back in stock! :tada:", - "attachments": [ - { - "title": "The Further Adventures of Slackbot", - "author_name": "Stanford S. Strickland", - "author_icon": "https://api.slack.com/img/api/homepage_custom_integrations-2x.png", - "image_url": "http://i.imgur.com/OJkaVOI.jpg?1" - }, - { - "fields": [ - { - "title": "Volume", - "value": "1", - "short": true - }, - { - "title": "Issue", - "value": "3", - "short": true - } - ] - }, - { - "title": "Synopsis", - "text": "After @episod pushed exciting changes to a devious new branch back in Issue 1, Slackbot notifies @don about an unexpected deploy..." - }, - { - "fallback": "Would you recommend it to customers?", - "title": "Would you recommend it to customers?", - "callback_id": "comic_1234_xyz", - "color": "#3AA3E3", - "attachment_type": "default", - "actions": [ - { - "name": "recommend", - "text": "Recommend", - "type": "button", - "value": "recommend" - }, - { - "name": "no", - "text": "No", - "type": "button", - "value": "bad" - } - ] - } - ] -} -``` - -When a user clicks a button within a Slack message, your bot will receive a response message -in which the channel data property is populated with a `payload` JSON object. -The `payload` object specifies contents of the original message, -identifies the button that was clicked, and identifies the user who clicked the button. - -This snippet shows an example of the `channelData` property in the message that a bot receives -when a user clicks a button in the Slack message. - -```json -"channelData": { - "payload": { - "actions": [ - { - "name": "recommend", - "value": "yes" - } - ], - . . . - "original_message": "{…}", - "response_url": "https://hooks.slack.com/actions/..." - } -} -``` - -Your bot can reply to this message in the normal manner, -or it can post its response directly to the endpoint that is specified by -the `payload` object's `response_url` property. -For information about when and how to post a response to the `response_url`, see -Slack Buttons. - -You can create dynamic buttons using the following JSON. - -```json -{ - "text": "Would you like to play a game ? ", - "attachments": [ - { - "text": "Choose a game to play!", - "fallback": "You are unable to choose a game", - "callback_id": "wopr_game", - "color": "#3AA3E3", - "attachment_type": "default", - "actions": [ - { - "name": "game", - "text": "Chess", - "type": "button", - "value": "chess" - }, - { - "name": "game", - "text": "Falken's Maze", - "type": "button", - "value": "maze" - }, - { - "name": "game", - "text": "Thermonuclear War", - "style": "danger", - "type": "button", - "value": "war", - "confirm": { - "title": "Are you sure?", - "text": "Wouldn't you prefer a good game of chess?", - "ok_text": "Yes", - "dismiss_text": "No" - } - } - ] - } - ] -} -``` - -To create interactive menus, use the following JSON: - -```json -{ - "text": "Would you like to play a game ? ", - "response_type": "in_channel", - "attachments": [ - { - "text": "Choose a game to play", - "fallback": "If you could read this message, you'd be choosing something fun to do right now.", - "color": "#3AA3E3", - "attachment_type": "default", - "callback_id": "game_selection", - "actions": [ - { - "name": "games_list", - "text": "Pick a game...", - "type": "select", - "options": [ - { - "text": "Hearts", - "value": "menu_id_hearts" - }, - { - "text": "Bridge", - "value": "menu_id_bridge" - }, - { - "text": "Checkers", - "value": "menu_id_checkers" - }, - { - "text": "Chess", - "value": "menu_id_chess" - }, - { - "text": "Poker", - "value": "menu_id_poker" - }, - { - "text": "Falken's Maze", - "value": "menu_id_maze" - }, - { - "text": "Global Thermonuclear War", - "value": "menu_id_war" - } - ] - } - ] - } - ] -} -``` - -## Create a Facebook notification - -To create a Facebook notification, -set the activity object's channel data property to a JSON object that specifies these properties: - -| Property | Description | -|----|----| -| notification_type | The type of notification (e.g., **REGULAR**, **SILENT_PUSH**, **NO_PUSH**). -| attachment | An attachment that specifies an image, video, or other multimedia type, or a templated attachment such as a receipt. | - -> [!NOTE] -> For details about format and contents of the `notification_type` property and `attachment` property, see the -> Facebook API documentation. - -This snippet shows an example of the `channelData` property for a Facebook receipt attachment. - -```json -"channelData": { - "notification_type": "NO_PUSH", - "attachment": { - "type": "template" - "payload": { - "template_type": "receipt", - . . . - } - } -} -``` - -## Create a Telegram message - -To create a message that implements Telegram-specific actions, -such as sharing a voice memo or a sticker, -set the activity object's channel data property to a JSON object that specifies these properties: - -| Property | Description | -|----|----| -| method | The Telegram Bot API method to call. | -| parameters | The parameters of the specified method. | - -These Telegram methods are supported: - -- answerInlineQuery -- editMessageCaption -- editMessageReplyMarkup -- editMessageText -- forwardMessage -- kickChatMember -- sendAudio -- sendChatAction -- sendContact -- sendDocument -- sendLocation -- sendMessage -- sendPhoto -- sendSticker -- sendVenue -- sendVideo -- sendVoice -- unbanChateMember - -For details about these Telegram methods and their parameters, see the -Telegram Bot API documentation. - -> [!NOTE] ->
  • The chat_id parameter is common to all Telegram methods. If you do not specify chat_id as a parameter, the framework will provide the ID for you.
  • ->
  • Instead of passing file contents inline, specify the file using a URL and media type as shown in the example below.
  • ->
  • Within each message that your bot receives from the Telegram channel, the ChannelData property will include the message that your bot sent previously.
- -This snippet shows an example of a `channelData` property that specifies a single Telegram method. - -```json -"channelData": { - "method": "sendSticker", - "parameters": { - "sticker": { - "url": "https://domain.com/path/gif", - "mediaType": "image/gif", - } - } -} -``` - -This snippet shows an example of a `channelData` property that specifies an array of Telegram methods. - -```json -"channelData": [ - { - "method": "sendSticker", - "parameters": { - "sticker": { - "url": "https://domain.com/path/gif", - "mediaType": "image/gif", - } - } - }, - { - "method": "sendMessage", - "parameters": { - "text": "This message is HTML formatted.", - "parse_mode": "HTML" - } - } -] -``` - -## Create a native Kik message - -To create a native Kik message, set the activity object's channel data property to a JSON object that specifies this property: - -| Property | Description | -|----|----| -| messages | An array of Kik messages. For details about Kik message format, see Kik Message Formats. | - -This snippet shows an example of the `channelData` property for a native Kik message. - -```json -"channelData": { - "messages": [ - { - "chatId": "c6dd8165…", - "type": "link", - "to": "kikhandle", - "title": "My Webpage", - "text": "Some text to display", - "url": "http://botframework.com", - "picUrl": "http://lorempixel.com/400/200/", - "attribution": { - "name": "My App", - "iconUrl": "http://lorempixel.com/50/50/" - }, - "noForward": true, - "kikJsData": { - "key": "value" - } - } - ] -} -``` - -## Create a LINE message - -To create a message that implements LINE-specific message types (such as sticker, templates, or LINE specific action types like opening the phone camera), set the activity object's channel data property to a JSON object that specifies LINE message types and action types. - -| Property | Description | -|----|----| -| type | The LINE action/message type name | - -These LINE message types are supported: -* Sticker -* Imagemap -* Template (Button, confirm, carousel) -* Flex - -These LINE actions can be specified in the action field of the message type JSON object: -* Postback -* Message -* URI -* Datetimerpicker -* Camera -* Camera roll -* Location - -For details about these LINE methods and their parameters, see the [LINE Bot API documentation](https://developers.line.biz/en/docs/messaging-api/). - -This snippet shows an example of a `channelData` property that specifies a channel message type `ButtonTemplate` and 3 action types: camera, cameraRoll, Datetimepicker. - -```json -"channelData": { - "type": "ButtonsTemplate", - "altText": "This is a buttons template", - "template": { - "type": "buttons", - "thumbnailImageUrl": "https://example.com/bot/images/image.jpg", - "imageAspectRatio": "rectangle", - "imageSize": "cover", - "imageBackgroundColor": "#FFFFFF", - "title": "Menu", - "text": "Please select", - "defaultAction": { - "type": "uri", - "label": "View detail", - "uri": "http://example.com/page/123" - }, - "actions": [{ - "type": "cameraRoll", - "label": "Camera roll" - }, - { - "type": "camera", - "label": "Camera" - }, - { - "type": "datetimepicker", - "label": "Select date", - "data": "storeId=12345", - "mode": "datetime", - "initial": "2017-12-25t00:00", - "max": "2018-01-24t23:59", - "min": "2017-12-25t00:00" - } - ] - } -} -``` - -## Adding a bot to Teams - -Bots added to a team become another team member, who can be `@mentioned` as part of the conversation. In fact, bots only receive messages when they are `@mentioned`, so other conversations on the channel are not sent to the bot. -For more information, see [Channel and Group chat conversations with a Microsoft Teams bot](https://aka.ms/bots-con-channel). - -Because bots in a group or channel respond only when they are mentioned (`@botname`) in a message, every message received by a bot in a group channel contains its own name, and you must ensure your message parsing handles that. In addition, bots can parse out other users mentioned and mention users as part of their messages. - -### Check for and strip @bot mention - -```csharp - -Mention[] m = sourceMessage.GetMentions(); -var messageText = sourceMessage.Text; - -for (int i = 0;i < m.Length;i++) -{ - if (m[i].Mentioned.Id == sourceMessage.Recipient.Id) - { - //Bot is in the @mention list. - //The below example will strip the bot name out of the message, so you can parse it as if it wasn't included. Note that the Text object will contain the full bot name, if applicable. - if (m[i].Text != null) - messageText = messageText.Replace(m[i].Text, ""); - } -} -``` - -```javascript -var text = message.text; -if (message.entities) { - message.entities - .filter(entity => ((entity.type === "mention") && (entity.mentioned.id.toLowerCase() === botId))) - .forEach(entity => { - text = text.replace(entity.text, ""); - }); - text = text.trim(); -} - -``` - -> [!IMPORTANT] -> Adding a bot by GUID, for anything other than testing purposes, is not recommended. Doing so severely limits the functionality of a bot. Bots in production should be added to Teams as part of an app. See [Create a bot](https://docs.microsoft.com/microsoftteams/platform/concepts/bots/bots-create) and [Test and debug your Microsoft Teams bot](https://docs.microsoft.com/microsoftteams/platform/concepts/bots/bots-test). - - -## Additional resources - -- [Entities and activity types](../bot-service-activities-entities.md) -- [Bot Framework Activity schema](https://aka.ms/botSpecs-activitySchema) diff --git a/articles/includes/snippet-code-csharp-intelligence-language.md b/articles/includes/snippet-code-csharp-intelligence-language.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/articles/includes/snippet-code-node-contactrelationupdate-1.md b/articles/includes/snippet-code-node-contactrelationupdate-1.md deleted file mode 100644 index 5592e3c2c..000000000 --- a/articles/includes/snippet-code-node-contactrelationupdate-1.md +++ /dev/null @@ -1,11 +0,0 @@ -```javascript -bot.on('contactRelationUpdate', function (message) { - if (message.action === 'add') { - var name = message.user ? message.user.name : null; - var reply = new builder.Message() - .address(message.address) - .text("Hello %s... Thanks for adding me.", name || 'there'); - bot.send(reply); - } -}); -``` \ No newline at end of file diff --git a/articles/includes/snippet-code-node-conversationupdate-1.md b/articles/includes/snippet-code-node-conversationupdate-1.md deleted file mode 100644 index fba92bd41..000000000 --- a/articles/includes/snippet-code-node-conversationupdate-1.md +++ /dev/null @@ -1,26 +0,0 @@ -```javascript -bot.on('conversationUpdate', function (message) { - if (message.membersAdded && message.membersAdded.length > 0) { - // Say hello - var isGroup = message.address.conversation.isGroup; - var txt = isGroup ? "Hello everyone!" : "Hello..."; - var reply = new builder.Message() - .address(message.address) - .text(txt); - bot.send(reply); - } else if (message.membersRemoved) { - // See if bot was removed - var botId = message.address.bot.id; - for (var i = 0; i < message.membersRemoved.length; i++) { - if (message.membersRemoved[i].id === botId) { - // Say goodbye - var reply = new builder.Message() - .address(message.address) - .text("Goodbye"); - bot.send(reply); - break; - } - } - } -}); -``` diff --git a/articles/includes/snippet-code-node-first-run-dialog-1.md b/articles/includes/snippet-code-node-first-run-dialog-1.md deleted file mode 100644 index bf46fe00a..000000000 --- a/articles/includes/snippet-code-node-first-run-dialog-1.md +++ /dev/null @@ -1,18 +0,0 @@ -```javascript -// Add first run dialog -bot.dialog('firstRun', function (session) { - session.userData.firstRun = true; - session.send("Hello...").endDialog(); -}).triggerAction({ - onFindAction: function (context, callback) { - // Only trigger if we've never seen user before - if (!context.userData.firstRun) { - // Return a score of 1.1 to ensure the first run dialog wins - callback(null, 1.1); - } else { - callback(null, 0.0); - } - } -}); - -``` \ No newline at end of file diff --git a/articles/includes/snippet-definition-turn.md b/articles/includes/snippet-definition-turn.md deleted file mode 100644 index 1f5ba9342..000000000 --- a/articles/includes/snippet-definition-turn.md +++ /dev/null @@ -1 +0,0 @@ -Receiving an activity, and subsequently processing it through your bot, is called a **turn**; this represents one complete cycle of your bot. A turn ends when all execution is done, the activity is fully processed and all the layers of the bot have completed. \ No newline at end of file diff --git a/articles/includes/snippet-deploy-considerations.md b/articles/includes/snippet-deploy-considerations.md deleted file mode 100644 index 714489d31..000000000 --- a/articles/includes/snippet-deploy-considerations.md +++ /dev/null @@ -1,22 +0,0 @@ -## Application settings and Messaging endpoint - -### Verify application settings - -For your bot to function properly in the cloud, you must ensure that its application settings are correct. -If you have an **appID** and **password**, -update the `Microsoft AppId` and `Microsoft App Password` values in your application's configuration settings as part of the deployment process. To find your bot's **AppID** and **AppPassword**, see [MicrosoftAppID and MicrosoftAppPassword](~/bot-service-manage-overview.md#microsoftappid-and-microsoftapppassword). - -> [!TIP] -> [!INCLUDE [Application configuration settings](~/includes/snippet-tip-bot-config-settings.md)] - -If you have not yet registered your bot with the Bot Framework (and therefore do not yet have an **appID** and **password**), -you can deploy your bot with temporary placeholder values for these settings. -Then later, after you [register your bot](~/bot-service-quickstart-registration.md), update your deployed application's settings with the **appID** and **password** values that were generated for your bot during registration. - -### Verify Messaging endpoint - -Your deployed bot must have an **Messaging endpoint** that can receive messages from the Bot Framework Connector Service. - -> [!NOTE] -> When you deploy your bot to Azure, SSL will automatically be configured for your application, thereby enabling the **Messaging endpoint** that the Bot Framework requires. -> If you deploy to another cloud service, be sure to verify that your application is configured for SSL so that the bot will have a **Messaging endpoint**. diff --git a/articles/includes/snippet-deploy-next-steps.md b/articles/includes/snippet-deploy-next-steps.md deleted file mode 100644 index 03961cd54..000000000 --- a/articles/includes/snippet-deploy-next-steps.md +++ /dev/null @@ -1,16 +0,0 @@ -## Next steps -After you have deployed your bot to the cloud and verified that the deployment was successful by testing the bot using the Bot Framework Emulator, the next step in the bot publication process will depend upon whether or not you've already registered your bot with the Bot Framework. - -### If you have already registered your bot with the Bot Framework: - -1. Return to the Bot Framework Portal and [update your bot's Settings data](~/bot-service-manage-settings.md) to specify the **Messaging endpoint** for the bot. - -2. [Configure the bot to run on one or more channels](~/bot-service-manage-channels.md). - -### If you have not yet registered your bot with the Bot Framework: - -1. [Register your bot with the Bot Framework](~/bot-service-quickstart-registration.md). - -2. Update the Microsoft App Id and Microsoft App Password values in your deployed application's configuration settings to specify the **appID** and **password** values that were generated for your bot during the registration process. To find your bot's **AppID** and **AppPassword**, see [MicrosoftAppID and MicrosoftAppPassword](~/bot-service-manage-overview.md#microsoftappid-and-microsoftapppassword). - -3. [Configure the bot to run on one or more channels](~/bot-service-manage-channels.md). \ No newline at end of file diff --git a/articles/includes/snippet-deploy-without-bot.md b/articles/includes/snippet-deploy-without-bot.md deleted file mode 100644 index 07ffca90b..000000000 --- a/articles/includes/snippet-deploy-without-bot.md +++ /dev/null @@ -1,124 +0,0 @@ -Before beginning the deployment, make sure you have the latest version of [Azure cli](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest) and [dotnet cli](https://dotnet.microsoft.com/download). If you don't have dotnet cli, install it using the .Net Core Runtime option from the link provided above. - -### Login to Azure CLI and set your subscription -You've already created and tested a bot locally, and now you want to deploy it to Azure. Open a command prompt to log in to the Azure portal. - -```cmd -az login -``` -### Set the subscription - -Set the default subscription to use. - -```cmd -az account set --subscription "" -``` - -If you are not sure which subscription to use for deploying the bot, you can view the list of subscriptions for your account by using `az account list` command. - -Navigate to the bot folder. -`cd ` - -### Create a Web App Bot in Azure - -If you don't already have a resource group to which to publish your local bot, create one: - -```cmd -az group create --name --location --verbose -``` - -| Option | Description | -|:-----------|:---| -| name | A unique name for the resource group. DO NOT include spaces or underscores in the name. | -| location | Geographic location used to create the resource group. For example, `eastus`, `westus`, `westus2`, and so on. Use `az account list-locations` for a list of locations. | - -Then, create the bot resource into which you will publish your bot. This will provision the necessary resources in Azure and create a bot web app, which you will overwrite with your local bot. - -Before proceeding, read the instructions that apply to you based on the type of email account you use to log in to Azure. - -#### MSA email account -If you are using an MSA email account, you will need to create the app ID and app password on the Application Registration Portal to use with `az bot create` command. -1. Go to the [**Application Registration Portal**](https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade). -1. Click on **Add an app** to register your application, create **Application Id**, and **Generate New Password**. If you already have an application and password but don't remember the password, you will have to generate a new password in the Application secrets section. -1. Save both application ID and the new password you just generated, so you that can use them with the `az bot create` command. - -```cmd -az bot create --kind webapp --name --location --version v4 --lang --verbose --resource-group --appid "" --password "" --verbose -``` - -| Option | Description | -|:---|:---| -| name | A unique name that is used to deploy the bot in Azure. It could be the same name as your local bot. DO NOT include spaces or underscores in the name. | -| location | Geographic location used to create the bot service resources. For example, `eastus`, `westus`, `westus2`, and so on. | -| resource-group | Name of resource group in which to create the bot. You can configure the default group using `az configure --defaults group=`. | -| appid | The Microsoft account ID (MSA ID) to be used with the bot. | -| password | The Microsoft account (MSA) password for the bot. | - -#### Business or school account - -```cmd -az bot create --kind webapp --name --location --version v4 --lang --verbose --resource-group -``` -| Option | Description | -|:---|:---| -| name | A unique name that is used to deploy the bot in Azure. It could be the same name as your local bot. DO NOT include spaces or underscores in the name. | -| location | Geographic location used to create the bot service resources. For example, `eastus`, `westus`, `westus2`, and so on. | -| lang | The language to use to create the bot: `Csharp`, or `Node`; default is `Csharp`. | -| resource-group | Name of resource group in which to create the bot. You can configure the default group using `az configure --defaults group=`. | - -#### Update appsettings.json or .env file -After the bot is created, you should see the following information displayed in the console window: - -```JSON -{ - "appId": "as234-345b-4def-9047-a8a44b4s", - "appPassword": "34$#w%^$%23@334343", - "endpoint": "https://mybot.azurewebsites.net/api/messages", - "id": "mybot", - "name": "mybot", - "resourceGroup": "botresourcegroup", - "serviceName": "mybot", - "subscriptionId": "234532-8720-5632-a3e2-a1qw234", - "tenantId": "32f955bf-33f1-43af-3ab-23d009defs47", - "type": "abs" -} -``` - -You'll need to copy the `appId` and `appPassword` values and paste them into the appsettings.json or .env file. For example: - -```JSON -{ - MicrosoftAppId: "as234-345b-4def-9047-a8a44b4s", - MicrosoftAppPassword: "34$#w%^$%23@334343" -} -``` -Note that if your appsettings.json or .env file has additional keys for other services you've provisioned for your bot, don't delete those entries. - -Save the file. - -Next, depending on the programming langauge (**C#** or **JS**) you used to create the bot, follow the steps that apply to you. - -**C# Bot:** - -Open a command-prompt, and navigate to the project folder. Run the following commands from the command line. - -| Task | Command | -|:-----|:--------| -| 1. Restore project dependencies | `dotnet restore`| -| 2. Build the project | `dotnet build` | -| 3. Zip project files | Use any utility to zip the project files. Go to the folder that has the .csproj file and select all the files and folder at this level to create the zipped folder. | -| 4. Set build deployment setting | `az webapp config appsettings set --resource-group --name --settings SCM_DO_BUILD_DEPLOYMENT=false`| -| 5. Set the script generator args | `az webapp config appsettings set --resource-group --name --settings SCM_SCRIPT_GENERATOR_ARGS="--aspNetCore mybot.csproj"`| - -**JS Bot:** -1. Download web.config from [here](https://github.com/projectkudu/kudu/wiki/Using-a-custom-web.config-for-Node-apps) and save it into your project folder. -1. Edit the file and replace all occurances of "server.js" with "index.js". -1. Save the file. - -Open a command-prompt, and navigate to the project folder. Run the following commands from the command line. - -| Task | Command | -|:-----|:--------| -| 1. Install node modules | `npm install` | -| 2. Zip project files | Use any utility to zip the project files. Go to the folder that has the .csproj file and select all the files and folder at this level to create the zipped folder. | -| 3. Set build deployment setting | `az webapp config appsettings set --resource-group --name --settings SCM_DO_BUILD_DEPLOYMENT=false`| diff --git a/articles/includes/snippet-dotnet-concept-activity.md b/articles/includes/snippet-dotnet-concept-activity.md deleted file mode 100644 index dfbb58d1f..000000000 --- a/articles/includes/snippet-dotnet-concept-activity.md +++ /dev/null @@ -1,2 +0,0 @@ -The [Connector](~/dotnet/bot-builder-dotnet-concepts.md#connector) uses an Activity object to pass information back and forth between bot and channel (user). -The most common type of activity is **message**, but there are other activity types that can be used to communicate various types of information to a bot or channel. \ No newline at end of file diff --git a/articles/includes/snippet-dotnet-concept-state.md b/articles/includes/snippet-dotnet-concept-state.md deleted file mode 100644 index 4c0d4e4ea..000000000 --- a/articles/includes/snippet-dotnet-concept-state.md +++ /dev/null @@ -1,7 +0,0 @@ -The Bot Builder Framework enables your bot to store and retrieve state data that is associated with a user, a conversation, or a specific user within the context of a specific conversation. -State data can be used for many purposes, such as determining where the prior conversation left off or simply greeting a returning user by name. If you store a user's preferences, you can use that information to customize the conversation the next time you chat. For example, you might alert the user to a news article about a topic that interests them, or alert a user when an appointment becomes available. - -For testing and prototyping purposes, you can use the Bot Builder Framework's in-memory data storage. For production bots, you can implement your own storage adapter or use one of Azure Extensions. The Azure Extensions allow you to store your bot's state data in either Table Storage, CosmosDB, or SQL. This article will show you how to use the in-memory storage adapter to store your bot's state data. - -> [!IMPORTANT] -> The Bot Framework State Service API is not recommended for production environments, and may be deprecated in a future release. It is recommended that you update your bot code to use the in-memory storage adapter for testing purposes or use one of the **Azure Extensions** for production bots. diff --git a/articles/includes/snippet-dotnet-formflow-samples.md b/articles/includes/snippet-dotnet-formflow-samples.md deleted file mode 100644 index 81063db6a..000000000 --- a/articles/includes/snippet-dotnet-formflow-samples.md +++ /dev/null @@ -1,2 +0,0 @@ -For complete samples that show how to implement FormFlow using the Bot Framework SDK for .NET, see the Multi-Dialog Bot sample and the Contoso Flowers Bot sample in GitHub. - diff --git a/articles/includes/snippet-dotnet-manage-conversation-flow-intro.md b/articles/includes/snippet-dotnet-manage-conversation-flow-intro.md deleted file mode 100644 index d5d96ee33..000000000 --- a/articles/includes/snippet-dotnet-manage-conversation-flow-intro.md +++ /dev/null @@ -1,13 +0,0 @@ -This diagram shows the screen flow of a traditional application compared to the dialog flow of a bot. - -![bot](~/media/designing-bots/core/dialogs-screens.png) - -In a traditional application, everything begins with the **main screen**. -The **main screen** invokes the **new order screen**. -The **new order screen** remains in control until it either closes or invokes other screens. -If the **new order screen** closes, the user is returned to the **main screen**. - -In a bot, everything begins with the **root dialog**. -The **root dialog** invokes the **new order dialog**. -At that point, the **new order dialog** takes control of the conversation and remains in control until it either closes or invokes other dialogs. -If the **new order dialog** closes, control of the conversation is returned back to the **root dialog**. \ No newline at end of file diff --git a/articles/includes/snippet-entity-boilerplate.md b/articles/includes/snippet-entity-boilerplate.md deleted file mode 100644 index 94e533d4f..000000000 --- a/articles/includes/snippet-entity-boilerplate.md +++ /dev/null @@ -1,13 +0,0 @@ -::: moniker range="azure-bot-service-3.0" -> [!NOTE] -> Different parts of the SDK define separate Entity classes or elements. -> - For message entities, see [Entity and activity types](https://docs.microsoft.com/azure/bot-service/bot-service-activities-entities?view=azure-bot-service-4.0). -> - For LUIS recognition entities, see [Recognize intents and entities with LUIS](../nodejs/bot-builder-nodejs-recognize-intent-luis.md). -::: moniker-end - -::: moniker range="azure-bot-service-4.0" -> [!NOTE] -> Different parts of the SDK define separate Entity classes or elements. -> - For message entities, see [Entity and activity types](https://docs.microsoft.com/azure/bot-service/bot-service-activities-entities?view=azure-bot-service-4.0). -> - For LUIS recognition entities, see [Extract entities](../v4sdk/bot-builder-howto-v4-luis.md). -::: moniker-end diff --git a/articles/includes/snippet-getstarted-test-bot.md b/articles/includes/snippet-getstarted-test-bot.md deleted file mode 100644 index 55bf2e9a3..000000000 --- a/articles/includes/snippet-getstarted-test-bot.md +++ /dev/null @@ -1,6 +0,0 @@ -Next, test your bot by using the [Bot Framework Emulator](~/bot-service-debug-emulator.md) to see it in action. -The emulator is a desktop application that lets you test and debug your bot on localhost or running remotely through a tunnel. - -First, you'll need to download and install the emulator. -Click [here](https://emulator.botframework.com/) to download the emulator. After the download completes, launch the executable and complete the installation process. - diff --git a/articles/includes/snippet-global-handlers-intro.md b/articles/includes/snippet-global-handlers-intro.md deleted file mode 100644 index 4d41eae68..000000000 --- a/articles/includes/snippet-global-handlers-intro.md +++ /dev/null @@ -1,10 +0,0 @@ -Users commonly attempt to access certain functionality within a bot by using keywords like "help", "cancel", or "start over". -This often occurs in the middle of a conversation, when the bot is expecting a different response. -By implementing **global message handlers**, you can design your bot to gracefully handle such requests. -The handlers will examine user input for the keywords that you specify, such as "help", "cancel", or "start over", and respond appropriately. - -![how users talk](~/media/designing-bots/capabilities/trigger-actions.png) - -> [!NOTE] -> By defining the logic in global message handlers, you're making it accessible to all dialogs. -> Individual dialogs and prompts can be configured to safely ignore the keywords. diff --git a/articles/includes/snippet-message-logging-intro.md b/articles/includes/snippet-message-logging-intro.md deleted file mode 100644 index e173d6a5f..000000000 --- a/articles/includes/snippet-message-logging-intro.md +++ /dev/null @@ -1,11 +0,0 @@ -The **middleware** functionality in the Bot Framework SDK enables your bot to intercept all messages that are exchanged between user and bot. -For each message that is intercepted, you may choose to do things such as -save the message to a data store that you specify, which creates a conversation log, or -inspect the message in some way and take whatever action your code specifies. - -> [!NOTE] -> The Bot Framework does not automatically save conversation details, -> as doing so could potentially capture private information that bots and users do not wish to share -> with outside parties. -> If your bot saves conversation details, -> it should communicate that to the user and describe what will be done with the data. \ No newline at end of file diff --git a/articles/includes/snippet-payment-process-callbacks-1.md b/articles/includes/snippet-payment-process-callbacks-1.md deleted file mode 100644 index c5f21dabe..000000000 --- a/articles/includes/snippet-payment-process-callbacks-1.md +++ /dev/null @@ -1,10 +0,0 @@ -When receiving a Shipping Address Update or a Shipping Option Update callback, -your bot will be provided with the current state of the payment details from the client in the `Activity.Value` property. -As a merchant, you should treat these callbacks as static, given input payment details you will calculate some output payment details and -fail if the input state provided by the client is invalid for any reason.  -If the bot determines the given information is valid as-is, simply send HTTP status code `200 OK` along with the unmodified payment -details. Alternatively, the bot may send HTTP status code `200 OK` along with an updated payment details that should be applied before the order can be processed. -In some cases, your bot may determine that the updated information is invalid and the -order cannot be processed as-is. For example, the user's shipping address may specify a country to which the -product supplier does not ship. In that case, the bot may send HTTP status code `200 OK` and a message populating the error property of the payment details object. -Sending any HTTP status code in the `400` or `500` range to will result in a generic error for the customer. diff --git a/articles/includes/snippet-payment-process-callbacks-overview.md b/articles/includes/snippet-payment-process-callbacks-overview.md deleted file mode 100644 index ba93ae44b..000000000 --- a/articles/includes/snippet-payment-process-callbacks-overview.md +++ /dev/null @@ -1 +0,0 @@ -When your bot receives a callback, it should verify that the information specified in the callback is valid and acknowledge the callback by sending an HTTP response. \ No newline at end of file diff --git a/articles/includes/snippet-payment-process-overview.md b/articles/includes/snippet-payment-process-overview.md deleted file mode 100644 index 478c9be24..000000000 --- a/articles/includes/snippet-payment-process-overview.md +++ /dev/null @@ -1,11 +0,0 @@ -## Payment process overview - -The payment process comprises three distinct parts: - -1. The bot sends a payment request. - -2. The user signs in with a Microsoft account to provide payment, shipping, and contact information. Callbacks are sent to the bot to indicate when the bot needs to perform certain operations (update shipping address, update shipping option, complete payment). - -3. The bot processes the callbacks that it receives, including shipping address update, shipping option update, and payment complete. - -Your bot must implement only step one and step three of this process; step two takes place outside the context of your bot. diff --git a/articles/includes/snippet-payment-test-bot.md b/articles/includes/snippet-payment-test-bot.md deleted file mode 100644 index b2acc691f..000000000 --- a/articles/includes/snippet-payment-test-bot.md +++ /dev/null @@ -1,7 +0,0 @@ -To fully test a bot that requests payment, [configure](~/bot-service-manage-channels.md) -it to run on channels that support Bot Framework payments, like Web Chat and Skype. -Alternatively, you can test your bot locally using the [Bot Framework Emulator](~/bot-service-debug-emulator.md). - -> [!TIP] -> Callbacks are sent to your bot when a user changes data or clicks **Pay** during the payment web experience. -> Therefore, you can test your bot's ability to receive and process callbacks by interacting with the payment web experience yourself. diff --git a/articles/includes/snippet-proactive-messages-intro-1.md b/articles/includes/snippet-proactive-messages-intro-1.md deleted file mode 100644 index 2e4dac275..000000000 --- a/articles/includes/snippet-proactive-messages-intro-1.md +++ /dev/null @@ -1,28 +0,0 @@ -Typically, each message that a bot sends to the user directly relates to the user's prior input. -In some cases, a bot may need to send the user a message that is not directly related to the current topic of conversation or to the last message the user sent. These types of messages are called **proactive messages**. - -Proactive messages can be useful in a variety of scenarios. -If a bot sets a timer or reminder, it will need to notify the user when the time arrives. -Or, if a bot receives a notification from an external system, it may need to communicate that information to the user immediately. -For example, if the user has previously asked the bot to monitor the price of a product, the bot can alert the user if the price of the product has dropped by 20%. Or, if a bot requires some time to compile a response to the user's question, it may inform the user of the delay and allow the conversation to continue in the meantime. When the bot finishes compiling the response to the question, it will share that information with the user. - -When implementing proactive messages in your bot: - -- *Don't* send several proactive messages within a short amount of time. Some channels enforce restrictions on how frequently a bot can send messages to the user, and will disable the bot if it violates those restrictions. -- *Don't* send proactive messages to users who have not previously interacted with the bot or solicited contact with the bot through another means such as e-mail or SMS. - -Proactive messages can create unexpected behavior. Consider the following scenario. - -![how users talk](~/media/designing-bots/capabilities/proactive1.png) - -In this example, the user has previously asked the bot to monitor prices of a hotel in Las Vegas. -The bot launched a background monitoring task, which has been running continuously for the past several days. -In the conversation, the user is currently booking a trip to London when the background task triggers a notification message about a discount for the Las Vegas hotel. The bot interjects this information into the conversation, making for a confusing user experience. - -How should the bot have handled this situation? - -- Wait for the current travel booking to finish, then deliver the notification. This approach would be minimally disruptive, but the delay in communicating the information might cause the user to miss out on the low-price opportunity for the Las Vegas hotel. -- Cancel the current travel booking flow and deliver the notification immediately. This approach delivers the information in a timely fashion but would likely frustrate the user by forcing them start over with their travel booking. -- Interrupt the current booking, clearly change the topic of conversation to the hotel in Las Vegas until the user responds, and then switch back to the in-progress travel booking and continue from where it was interrupted. This approach may seem like the best choice, but it introduces complexity both for the bot developer and the user. - -Most commonly, your bot will use some combination of **ad hoc proactive messages** and other techniques to handle situations like this. diff --git a/articles/includes/snippet-proactive-messages-intro-2.md b/articles/includes/snippet-proactive-messages-intro-2.md deleted file mode 100644 index c0ee7794a..000000000 --- a/articles/includes/snippet-proactive-messages-intro-2.md +++ /dev/null @@ -1,22 +0,0 @@ -An **ad hoc proactive message** is the simplest type of proactive message. -The bot simply interjects the message into the conversation whenever it is triggered, without any regard for whether the user is currently engaged in a separate topic of conversation with the bot and will not attempt to change the conversation in any way. - -To handle notifications more smoothly, consider other ways to integrate the notification into the conversation flow, such as setting a flag in the conversation state or adding the notification to a queue. - - \ No newline at end of file diff --git a/articles/includes/snippet-publish-to-channel.md b/articles/includes/snippet-publish-to-channel.md deleted file mode 100644 index 039c0268a..000000000 --- a/articles/includes/snippet-publish-to-channel.md +++ /dev/null @@ -1,12 +0,0 @@ -### Cortana -Bots are published to Cortana from the [dashboard](https://aka.ms/cortana-publish) and are used to power Cortana skills. Publishing a bot submits it for review. Cortana skills can be deployed for your own use, deployed to a small group, or published to the world. - -### Skype -Bots are published to Skype from the [configuration page](~/bot-service-channel-connect-skype.md). Publishing a bot submits it for review. Before review, the bot is limited to 100 contacts. Approved bots do not have limited contacts and you may opt to have the bot included in the Skype bot directory. - -### Skype for Business -Skype for Business bots are registered with a [Skype for Business Online tenant](https://msdn.microsoft.com/skype/Skype-For-Business-Bot-Framework/docs/overview) by a Tenant Administrator. - -> [!TIP] -> To view the status of a review, open the bot in the [Bot Framework Portal](https://dev.botframework.com/) and click **Channels**. -> If the bot is not approved, the result will link to the reason why. After making the required changes, resubmit the bot for review. diff --git a/articles/includes/snippet-quickstart-paths.md b/articles/includes/snippet-quickstart-paths.md deleted file mode 100644 index 8dc343eb8..000000000 --- a/articles/includes/snippet-quickstart-paths.md +++ /dev/null @@ -1 +0,0 @@ -Creating a bot with Azure Bot Service and creating a bot locally are independent, parallel ways to create a bot. \ No newline at end of file diff --git a/articles/includes/snippet-suggested-actions-intro.md b/articles/includes/snippet-suggested-actions-intro.md deleted file mode 100644 index 36a043537..000000000 --- a/articles/includes/snippet-suggested-actions-intro.md +++ /dev/null @@ -1,3 +0,0 @@ -Suggested actions enable your bot to present buttons that the user can tap to provide input. -Suggested actions appear close to the composer and enhance user experience by enabling the user to answer a question or make a selection with a simple tap of a button, rather than having to type a response with a keyboard. -Unlike buttons that appear within rich cards (which remain visible and accessible to the user even after being tapped), buttons that appear within the suggested actions pane will disappear after the user makes a selection. This prevents the user from tapping stale buttons within a conversation and simplifies bot development (since you will not need to account for that scenario). \ No newline at end of file diff --git a/articles/includes/snippet-tip-bot-config-settings.md b/articles/includes/snippet-tip-bot-config-settings.md deleted file mode 100644 index 220d7884f..000000000 --- a/articles/includes/snippet-tip-bot-config-settings.md +++ /dev/null @@ -1,7 +0,0 @@ -> If you're using the Bot Framework SDK for Node.js, set the following environment variables: ->
  • MICROSOFT_APP_ID
  • MICROSOFT_APP_PASSWORD
-> If you're using the Bot Framework SDK for .NET, set the following key values in the web.config file: ->
  • MicrosoftAppId
  • MicrosoftAppPassword
- -> [!NOTE] -> To find your bot's **AppID** and **AppPassword**, see [MicrosoftAppID and MicrosoftAppPassword](~/bot-service-manage-overview.md#microsoftappid-and-microsoftapppassword). \ No newline at end of file diff --git a/articles/includes/snippet-verify-deployment-using-emulator.md b/articles/includes/snippet-verify-deployment-using-emulator.md deleted file mode 100644 index c520f782f..000000000 --- a/articles/includes/snippet-verify-deployment-using-emulator.md +++ /dev/null @@ -1,5 +0,0 @@ -Verify the deployment of your bot by using the [Bot Framework Emulator](~/bot-service-debug-emulator.md). - -Enter the bot's **Messaging endpoint** into the address bar of the Emulator. If you built your bot with the Bot Framework SDK, the endpoint should end with */api/messages*. - -Example: `https://.azurewebsites.net/api/messages` diff --git a/articles/index.yml b/articles/index.yml deleted file mode 100644 index a016ffe82..000000000 --- a/articles/index.yml +++ /dev/null @@ -1,88 +0,0 @@ -### YamlMime:YamlDocument -documentType: LandingData -title: Azure Bot Service Documentation -metadata: - document_id: 1d934240-28c7-635f-d41b-3e43ae02970c - title: Azure Bot Service Documentation - Tutorials, API Reference - meta.description: Learn how to create bots. Documentation helps you create, deploy, and manage bots in the cloud. - author: ivorb - manager: kamrani - ms.service: bot-service - ms.tgt_pltfrm: na - ms.devlang: na - ms.topic: landing-page - ms.date: 11/11/2019 - ms.author: ivorb -abstract: - description: Azure Bot Service provides an integrated environment that is purpose-built for bot development, enabling you to build, connect, test, deploy, and manage intelligent bots, all from one place. Azure Bot Service leverages the Bot Framework SDK with support for C# and JavaScript. Learn how to use Bot Service with our quickstarts, tutorials, and samples. - aside: - image: - alt: - height: 110 - src: media/video/satya-video.png - width: 250 - title: Ignite 2019 keynote by Satya Nadella. (1:52) - href: https://myignite.techcommunity.microsoft.com/sessions/77831?source=sessions - width: 250 -sections: -- items: - - type: list - style: cards - className: cardsM - columns: 3 - items: - - href: https://docs.microsoft.com/azure/bot-service/what-is-new - html:

What's new in Azure Bot Service.

- image: - src: media/index/i_guidelines.png - title: What's new? - - href: https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction - html:

Learn about Azure Bot Service.

- image: - src: media/index/i_overview.png - title: What is Azure Bot Service? - - href: https://docs.microsoft.com/azure/bot-service/bot-builder-basics - html:

Understand how bots work.

- image: - src: media/index/i_guidelines.png - title: How bots work -- title: 5-Minute Quickstarts - items: - - type: paragraph - text: 'Learn how to create your first bot:' - - type: list - style: icon48 - items: - - image: - src: v4sdk/media/logo_csharp.svg - text: C# - href: https://docs.microsoft.com/azure/bot-service/dotnet/bot-builder-dotnet-sdk-quickstart - - image: - src: v4sdk/media/logo_js.svg - text: JavaScript - href: https://docs.microsoft.com/azure/bot-service/javascript/bot-builder-javascript-quickstart - - image: - src: v4sdk/media/logo_python.svg - text: Python - href: https://docs.microsoft.com/azure/bot-service/python/bot-builder-python-quickstart - - image: - src: media/index/azure_portal.png - text: Azure Portal - href: https://docs.microsoft.com/azure/bot-service/bot-service-quickstart -- title: Step-by-Step Tutorials - items: - - type: paragraph - text: Learn how to create and deploy bots on Azure. - - type: list - style: ordered - items: - - html: Create and deploy a simple bot - - html: Add QnA Maker and redeploy a bot -- title: Reference - items: - - type: list - style: cards - className: cardsD - items: - - title: Languages - html:

.NET

JavaScript

diff --git a/articles/java/bot-builder-java-samples.md b/articles/java/bot-builder-java-samples.md deleted file mode 100644 index e95b2e159..000000000 --- a/articles/java/bot-builder-java-samples.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: Sample bots for Bot Framework SDK for Java - Bot Service -description: Explore sample bots that can help kickstart your bot development with the Bot Framework SDK for Java. -author: jonathanfingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Bot Framework SDK v4 Java samples -[!INCLUDE [pre-release-label](../includes/pre-release-label.md)] - -You can use the samples to help you build bots using Java SDK v4, which is currently in preview. - -## Get the samples -To get the samples, clone the [botbuilder-java](https://github.com/Microsoft/botbuilder-java) GitHub repository using Git. - -```cmd -git clone https://github.com/Microsoft/botbuilder-java.git -cd samples -``` -The sample bots built with the Bot Framework SDK for Java are organized in the **samples** directory. diff --git a/articles/javascript/bot-builder-javascript-quickstart.md b/articles/javascript/bot-builder-javascript-quickstart.md deleted file mode 100644 index eb0d3a857..000000000 --- a/articles/javascript/bot-builder-javascript-quickstart.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: Create a bot using Bot Framework SDK for JavaScript - Bot Service -description: Quickly create a bot using the Bot Framework SDK for JavaScript. -keywords: quickstart, bot framework sdk, getting started -author: jonathanfingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Create a bot with the Bot Framework SDK for JavaScript - -[!INCLUDE [applies-to-v4](../includes/applies-to.md)] - -This quickstart walks you through building a single bot by using the Yeoman Bot Builder generator and the Bot Framework SDK for JavaScript, and then testing it with the Bot Framework Emulator. - -[!INCLUDE [Azure vs local development](~/includes/snippet-quickstart-paths.md)] - -[!INCLUDE [javascript quickstart](~/includes/quickstart-javascript.md)] - -## Additional resources - -See [tunneling (ngrok)](https://github.com/Microsoft/BotFramework-Emulator/wiki/Tunneling-(ngrok)) for how to connect to a bot hosted remotely. - -## Next steps - -> [!div class="nextstepaction"] -> [Deploy your bot to Azure](../bot-builder-deploy-az-cli.md) diff --git a/articles/javascript/bot-builder-javascript-samples.md b/articles/javascript/bot-builder-javascript-samples.md deleted file mode 100644 index 97ab30938..000000000 --- a/articles/javascript/bot-builder-javascript-samples.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: Sample bots for Bot Framework SDK for JavaScript - Bot Service -description: Explore a large selection of sample bots that can help kickstart your bot development with the Bot Framework SDK for JavaScript. -author: jonathanfingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# JavaScript samples for Bot Framework SDK -[!INCLUDE [pre-release-label](../includes/pre-release-label.md)] - -Samples in the Bot Builder Samples repo demonstrate task-focused bots that show how to take advantage of features provided in the SDK for JavaScript. You can use the samples to help you quickly get started with building great bots with rich capabilities. Refer to [readme](https://github.com/Microsoft/BotBuilder-Samples/blob/master/README.md) file for sample list and additional informaiton. - -To get the samples, clone the [botbuilder-samples](https://github.com/Microsoft/botbuilder-samples) GitHub repository using Git. -```cmd -git clone https://github.com/Microsoft/botbuilder-dotnet.git -``` diff --git a/articles/manage/TOC.md b/articles/manage/TOC.md deleted file mode 100644 index 6d243dc27..000000000 --- a/articles/manage/TOC.md +++ /dev/null @@ -1,36 +0,0 @@ -# [Manage a bot](../bot-service-manage-overview.md) -# [Bot analytics](../bot-service-manage-analytics.md) -# Channels -## [Connect a bot to channels](../bot-service-manage-channels.md) -## [Implement channel-specific functionality](../v4sdk/bot-builder-channeldata.md) -## [Cortana](../bot-service-channel-connect-cortana.md) -## Direct Line -### [About Direct Line](../bot-service-channel-directline.md) -### [Connect to Direct Line](../bot-service-channel-connect-directline.md) -### [Connect to Direct Line Speech](../bot-service-channel-connect-directlinespeech.md) -### [Direct Line App Service Extension](../bot-service-channel-directline-extension.md) -#### [Configure .NET bot for extension](../bot-service-channel-directline-extension-net-bot.md) -#### [Configure Node.js bot for extension](../bot-service-channel-directline-extension-node-bot.md) -#### [Create .NET Client with extension](../bot-service-channel-directline-extension-net-client.md) -#### [Use extension with WebChat](../bot-service-channel-directline-extension-webchat-client.md) -#### [Use extenson within VNET](../bot-service-channel-directline-extension-vnet.md) -## [Email](../bot-service-channel-connect-email.md) -## [Enable speech in Web Chat](../bot-service-channel-connect-webchat-speech.md) -## [Facebook](../bot-service-channel-connect-facebook.md) -## [GroupMe](../bot-service-channel-connect-groupme.md) -## [Kik](../bot-service-channel-connect-kik.md) -## [LINE](../bot-service-channel-connect-line.md) -## [Microsoft Teams](../channel-connect-teams.md) -## [Skype](../bot-service-channel-connect-skype.md) -## [Skype for Business](../bot-service-channel-connect-skypeforbusiness.md) -## [Slack](../bot-service-channel-connect-slack.md) -## [Telegram](../bot-service-channel-connect-telegram.md) -## [Twilio](../bot-service-channel-connect-twilio.md) -## [WeChat](../bot-service-channel-connect-wechat.md) -## [Web Chat](../bot-service-channel-connect-webchat.md) -## [Webex](../bot-service-adapter-connect-webex.md) -## [Additional channels](../bot-service-channel-additional-channels.md) -# [Configure bot settings](../bot-service-manage-settings.md) -# [Configure speech priming](../bot-service-manage-speech-priming.md) -# [Register a bot with Azure Bot Service](../bot-service-quickstart-registration.md) -# [Migrate your bot](../bot-service-migrate-bot.md) diff --git a/articles/media/Robot-clip-art-book-covers-feJCV3-clipart.png b/articles/media/Robot-clip-art-book-covers-feJCV3-clipart.png deleted file mode 100644 index 75929d462..000000000 Binary files a/articles/media/Robot-clip-art-book-covers-feJCV3-clipart.png and /dev/null differ diff --git a/articles/media/adaptive-card-reminder.png b/articles/media/adaptive-card-reminder.png deleted file mode 100644 index 77ea004df..000000000 Binary files a/articles/media/adaptive-card-reminder.png and /dev/null differ diff --git a/articles/media/adaptive-card.png b/articles/media/adaptive-card.png deleted file mode 100644 index 355903d13..000000000 Binary files a/articles/media/adaptive-card.png and /dev/null differ diff --git a/articles/media/analytics-activities.png b/articles/media/analytics-activities.png deleted file mode 100644 index 72fab1e8a..000000000 Binary files a/articles/media/analytics-activities.png and /dev/null differ diff --git a/articles/media/analytics-channels.png b/articles/media/analytics-channels.png deleted file mode 100644 index ab876045d..000000000 Binary files a/articles/media/analytics-channels.png and /dev/null differ diff --git a/articles/media/analytics-enable.png b/articles/media/analytics-enable.png deleted file mode 100644 index febc48b66..000000000 Binary files a/articles/media/analytics-enable.png and /dev/null differ diff --git a/articles/media/analytics-messages.png b/articles/media/analytics-messages.png deleted file mode 100644 index d23ea3561..000000000 Binary files a/articles/media/analytics-messages.png and /dev/null differ diff --git a/articles/media/analytics-retention.png b/articles/media/analytics-retention.png deleted file mode 100644 index a0d22a86e..000000000 Binary files a/articles/media/analytics-retention.png and /dev/null differ diff --git a/articles/media/analytics-timepick.png b/articles/media/analytics-timepick.png deleted file mode 100644 index 2bd7b01b0..000000000 Binary files a/articles/media/analytics-timepick.png and /dev/null differ diff --git a/articles/media/analytics-users.png b/articles/media/analytics-users.png deleted file mode 100644 index 7487b6e79..000000000 Binary files a/articles/media/analytics-users.png and /dev/null differ diff --git a/articles/media/animation-card.png b/articles/media/animation-card.png deleted file mode 100644 index 505bb770a..000000000 Binary files a/articles/media/animation-card.png and /dev/null differ diff --git a/articles/media/animation-card1.png b/articles/media/animation-card1.png deleted file mode 100644 index 33d7219e6..000000000 Binary files a/articles/media/animation-card1.png and /dev/null differ diff --git a/articles/media/app-registration/app-id.png b/articles/media/app-registration/app-id.png deleted file mode 100644 index f116e1d6c..000000000 Binary files a/articles/media/app-registration/app-id.png and /dev/null differ diff --git a/articles/media/app-registration/create-app-id.png b/articles/media/app-registration/create-app-id.png deleted file mode 100644 index f4435a63d..000000000 Binary files a/articles/media/app-registration/create-app-id.png and /dev/null differ diff --git a/articles/media/app-registration/new-registration.png b/articles/media/app-registration/new-registration.png deleted file mode 100644 index 8e5bc5f3c..000000000 Binary files a/articles/media/app-registration/new-registration.png and /dev/null differ diff --git a/articles/media/app-registration/new-secret.png b/articles/media/app-registration/new-secret.png deleted file mode 100644 index c02c02bcb..000000000 Binary files a/articles/media/app-registration/new-secret.png and /dev/null differ diff --git a/articles/media/app-registration/registration-details.png b/articles/media/app-registration/registration-details.png deleted file mode 100644 index 8952e787e..000000000 Binary files a/articles/media/app-registration/registration-details.png and /dev/null differ diff --git a/articles/media/audio-card.png b/articles/media/audio-card.png deleted file mode 100644 index 169fdb2c4..000000000 Binary files a/articles/media/audio-card.png and /dev/null differ diff --git a/articles/media/azure-active-directory/admin_center.png b/articles/media/azure-active-directory/admin_center.png deleted file mode 100644 index 0f8cf1a0a..000000000 Binary files a/articles/media/azure-active-directory/admin_center.png and /dev/null differ diff --git a/articles/media/azure-active-directory/user_type.png b/articles/media/azure-active-directory/user_type.png deleted file mode 100644 index 9c2f2d361..000000000 Binary files a/articles/media/azure-active-directory/user_type.png and /dev/null differ diff --git a/articles/media/azure-bot-build/azure-csharp-publish.png b/articles/media/azure-bot-build/azure-csharp-publish.png deleted file mode 100644 index a24e9642d..000000000 Binary files a/articles/media/azure-bot-build/azure-csharp-publish.png and /dev/null differ diff --git a/articles/media/azure-bot-build/azure-deployment-github.png b/articles/media/azure-bot-build/azure-deployment-github.png deleted file mode 100644 index 673faa8dd..000000000 Binary files a/articles/media/azure-bot-build/azure-deployment-github.png and /dev/null differ diff --git a/articles/media/azure-bot-build/azure-deployment.png b/articles/media/azure-bot-build/azure-deployment.png deleted file mode 100644 index 55690d3fa..000000000 Binary files a/articles/media/azure-bot-build/azure-deployment.png and /dev/null differ diff --git a/articles/media/azure-bot-build/continuous-deployment-setup-github.png b/articles/media/azure-bot-build/continuous-deployment-setup-github.png deleted file mode 100644 index 4cf47d866..000000000 Binary files a/articles/media/azure-bot-build/continuous-deployment-setup-github.png and /dev/null differ diff --git a/articles/media/azure-bot-build/continuous-deployment-setup-vs-configuration.png b/articles/media/azure-bot-build/continuous-deployment-setup-vs-configuration.png deleted file mode 100644 index 23d2ca0fc..000000000 Binary files a/articles/media/azure-bot-build/continuous-deployment-setup-vs-configuration.png and /dev/null differ diff --git a/articles/media/azure-bot-build/continuous-deployment-setup-vs.png b/articles/media/azure-bot-build/continuous-deployment-setup-vs.png deleted file mode 100644 index 7221bd30b..000000000 Binary files a/articles/media/azure-bot-build/continuous-deployment-setup-vs.png and /dev/null differ diff --git a/articles/media/azure-bot-build/continuous-deployment-setup.png b/articles/media/azure-bot-build/continuous-deployment-setup.png deleted file mode 100644 index 63fec7749..000000000 Binary files a/articles/media/azure-bot-build/continuous-deployment-setup.png and /dev/null differ diff --git a/articles/media/azure-bot-build/cs-console-build-cmd.png b/articles/media/azure-bot-build/cs-console-build-cmd.png deleted file mode 100644 index cb3e580d5..000000000 Binary files a/articles/media/azure-bot-build/cs-console-build-cmd.png and /dev/null differ diff --git a/articles/media/azure-bot-build/cs-wwwroot-structure.png b/articles/media/azure-bot-build/cs-wwwroot-structure.png deleted file mode 100644 index babcb81ca..000000000 Binary files a/articles/media/azure-bot-build/cs-wwwroot-structure.png and /dev/null differ diff --git a/articles/media/azure-bot-build/functions-messages-code.png b/articles/media/azure-bot-build/functions-messages-code.png deleted file mode 100644 index 2141bc9bf..000000000 Binary files a/articles/media/azure-bot-build/functions-messages-code.png and /dev/null differ diff --git a/articles/media/azure-bot-build/node-wwwroot-structure.png b/articles/media/azure-bot-build/node-wwwroot-structure.png deleted file mode 100644 index 9437d0fda..000000000 Binary files a/articles/media/azure-bot-build/node-wwwroot-structure.png and /dev/null differ diff --git a/articles/media/azure-bot-build/open-online-code-editor-restart-appservice.png b/articles/media/azure-bot-build/open-online-code-editor-restart-appservice.png deleted file mode 100644 index 38c8e117a..000000000 Binary files a/articles/media/azure-bot-build/open-online-code-editor-restart-appservice.png and /dev/null differ diff --git a/articles/media/azure-bot-build/open-online-code-editor.png b/articles/media/azure-bot-build/open-online-code-editor.png deleted file mode 100644 index d25ceb55a..000000000 Binary files a/articles/media/azure-bot-build/open-online-code-editor.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/abs-create-blade.png b/articles/media/azure-bot-quickstarts/abs-create-blade.png deleted file mode 100644 index d45286a1f..000000000 Binary files a/articles/media/azure-bot-quickstarts/abs-create-blade.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/abs-keys-download.png b/articles/media/azure-bot-quickstarts/abs-keys-download.png deleted file mode 100644 index 4fc6c59e3..000000000 Binary files a/articles/media/azure-bot-quickstarts/abs-keys-download.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/azure-webchat-test.png b/articles/media/azure-bot-quickstarts/azure-webchat-test.png deleted file mode 100644 index 46e12ec4f..000000000 Binary files a/articles/media/azure-bot-quickstarts/azure-webchat-test.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/bot-builder-dotnet-project-vs2019.png b/articles/media/azure-bot-quickstarts/bot-builder-dotnet-project-vs2019.png deleted file mode 100644 index 8d9ceb493..000000000 Binary files a/articles/media/azure-bot-quickstarts/bot-builder-dotnet-project-vs2019.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/bot-builder-dotnet-project.png b/articles/media/azure-bot-quickstarts/bot-builder-dotnet-project.png deleted file mode 100644 index 6ca0ed968..000000000 Binary files a/articles/media/azure-bot-quickstarts/bot-builder-dotnet-project.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/bot-channels-registration-app-complete.PNG b/articles/media/azure-bot-quickstarts/bot-channels-registration-app-complete.PNG deleted file mode 100644 index 1b4c02ac6..000000000 Binary files a/articles/media/azure-bot-quickstarts/bot-channels-registration-app-complete.PNG and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/bot-channels-registration-app-secrets-create.PNG b/articles/media/azure-bot-quickstarts/bot-channels-registration-app-secrets-create.PNG deleted file mode 100644 index 74d01be14..000000000 Binary files a/articles/media/azure-bot-quickstarts/bot-channels-registration-app-secrets-create.PNG and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/bot-channels-registration-app-secrets.PNG b/articles/media/azure-bot-quickstarts/bot-channels-registration-app-secrets.PNG deleted file mode 100644 index 352963313..000000000 Binary files a/articles/media/azure-bot-quickstarts/bot-channels-registration-app-secrets.PNG and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/bot-channels-registration-app-settings.PNG b/articles/media/azure-bot-quickstarts/bot-channels-registration-app-settings.PNG deleted file mode 100644 index bbe556254..000000000 Binary files a/articles/media/azure-bot-quickstarts/bot-channels-registration-app-settings.PNG and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/bot-channels-registration-app.png b/articles/media/azure-bot-quickstarts/bot-channels-registration-app.png deleted file mode 100644 index f59783cce..000000000 Binary files a/articles/media/azure-bot-quickstarts/bot-channels-registration-app.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/bot-channels-registration.png b/articles/media/azure-bot-quickstarts/bot-channels-registration.png deleted file mode 100644 index 97d7bfd0f..000000000 Binary files a/articles/media/azure-bot-quickstarts/bot-channels-registration.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/bot-web-app-registration.png b/articles/media/azure-bot-quickstarts/bot-web-app-registration.png deleted file mode 100644 index 1447bfea9..000000000 Binary files a/articles/media/azure-bot-quickstarts/bot-web-app-registration.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/echobot-js.png b/articles/media/azure-bot-quickstarts/echobot-js.png deleted file mode 100644 index 95866ee85..000000000 Binary files a/articles/media/azure-bot-quickstarts/echobot-js.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/function-create-bot-service-blade.png b/articles/media/azure-bot-quickstarts/function-create-bot-service-blade.png deleted file mode 100644 index faa08bfd8..000000000 Binary files a/articles/media/azure-bot-quickstarts/function-create-bot-service-blade.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/getting-started-app-service.png b/articles/media/azure-bot-quickstarts/getting-started-app-service.png deleted file mode 100644 index aee65cc65..000000000 Binary files a/articles/media/azure-bot-quickstarts/getting-started-app-service.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/getting-started-app-settings-1.png b/articles/media/azure-bot-quickstarts/getting-started-app-settings-1.png deleted file mode 100644 index 10cbb0454..000000000 Binary files a/articles/media/azure-bot-quickstarts/getting-started-app-settings-1.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/getting-started-app-settings-2.png b/articles/media/azure-bot-quickstarts/getting-started-app-settings-2.png deleted file mode 100644 index cd8535dc5..000000000 Binary files a/articles/media/azure-bot-quickstarts/getting-started-app-settings-2.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/getting-started-bot-registration.png b/articles/media/azure-bot-quickstarts/getting-started-bot-registration.png deleted file mode 100644 index ad55f20d4..000000000 Binary files a/articles/media/azure-bot-quickstarts/getting-started-bot-registration.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/getting-started-msa.png b/articles/media/azure-bot-quickstarts/getting-started-msa.png deleted file mode 100644 index e6f5adef2..000000000 Binary files a/articles/media/azure-bot-quickstarts/getting-started-msa.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/getting-started-publish-main.png b/articles/media/azure-bot-quickstarts/getting-started-publish-main.png deleted file mode 100644 index 143092d75..000000000 Binary files a/articles/media/azure-bot-quickstarts/getting-started-publish-main.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/getting-started-publish-setting.png b/articles/media/azure-bot-quickstarts/getting-started-publish-setting.png deleted file mode 100644 index e60e7d9b0..000000000 Binary files a/articles/media/azure-bot-quickstarts/getting-started-publish-setting.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/getting-started-test-webchat.png b/articles/media/azure-bot-quickstarts/getting-started-test-webchat.png deleted file mode 100644 index 13a91303a..000000000 Binary files a/articles/media/azure-bot-quickstarts/getting-started-test-webchat.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/notification-deployment-succeeded.png b/articles/media/azure-bot-quickstarts/notification-deployment-succeeded.png deleted file mode 100644 index 5b6c3cdf8..000000000 Binary files a/articles/media/azure-bot-quickstarts/notification-deployment-succeeded.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/notification-registration-deployment-succeeded.png b/articles/media/azure-bot-quickstarts/notification-registration-deployment-succeeded.png deleted file mode 100644 index b1151e203..000000000 Binary files a/articles/media/azure-bot-quickstarts/notification-registration-deployment-succeeded.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/registration-create-bot-service-blade.png b/articles/media/azure-bot-quickstarts/registration-create-bot-service-blade.png deleted file mode 100644 index e0f47bd21..000000000 Binary files a/articles/media/azure-bot-quickstarts/registration-create-bot-service-blade.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/sdk-bot-cs-bot-templates.png b/articles/media/azure-bot-quickstarts/sdk-bot-cs-bot-templates.png deleted file mode 100644 index 9caa06751..000000000 Binary files a/articles/media/azure-bot-quickstarts/sdk-bot-cs-bot-templates.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/sdk-create-bot-service-blade.png b/articles/media/azure-bot-quickstarts/sdk-create-bot-service-blade.png deleted file mode 100644 index f226bf3a3..000000000 Binary files a/articles/media/azure-bot-quickstarts/sdk-create-bot-service-blade.png and /dev/null differ diff --git a/articles/media/azure-bot-quickstarts/test-in-web-chat-control.png b/articles/media/azure-bot-quickstarts/test-in-web-chat-control.png deleted file mode 100644 index 04fb866d2..000000000 Binary files a/articles/media/azure-bot-quickstarts/test-in-web-chat-control.png and /dev/null differ diff --git a/articles/media/azure-bot-service-bf-portal.png b/articles/media/azure-bot-service-bf-portal.png deleted file mode 100644 index 48afd2c6f..000000000 Binary files a/articles/media/azure-bot-service-bf-portal.png and /dev/null differ diff --git a/articles/media/azure-bot-service-coding-language.png b/articles/media/azure-bot-service-coding-language.png deleted file mode 100644 index 25b04eb0e..000000000 Binary files a/articles/media/azure-bot-service-coding-language.png and /dev/null differ diff --git a/articles/media/azure-bot-service-console-icon.png b/articles/media/azure-bot-service-console-icon.png deleted file mode 100644 index 0af4130e8..000000000 Binary files a/articles/media/azure-bot-service-console-icon.png and /dev/null differ diff --git a/articles/media/azure-bot-service-create-app-id.png b/articles/media/azure-bot-service-create-app-id.png deleted file mode 100644 index dceb3905f..000000000 Binary files a/articles/media/azure-bot-service-create-app-id.png and /dev/null differ diff --git a/articles/media/azure-bot-service-create-bot.png b/articles/media/azure-bot-service-create-bot.png deleted file mode 100644 index 8f42102a8..000000000 Binary files a/articles/media/azure-bot-service-create-bot.png and /dev/null differ diff --git a/articles/media/azure-bot-service-editor.png b/articles/media/azure-bot-service-editor.png deleted file mode 100644 index 9971a00e2..000000000 Binary files a/articles/media/azure-bot-service-editor.png and /dev/null differ diff --git a/articles/media/azure-bot-service-first-bot-notification.png b/articles/media/azure-bot-service-first-bot-notification.png deleted file mode 100644 index cca48a7e6..000000000 Binary files a/articles/media/azure-bot-service-first-bot-notification.png and /dev/null differ diff --git a/articles/media/azure-bot-service-password.png b/articles/media/azure-bot-service-password.png deleted file mode 100644 index 0cc744fcd..000000000 Binary files a/articles/media/azure-bot-service-password.png and /dev/null differ diff --git a/articles/media/azure-bot-service-template.png b/articles/media/azure-bot-service-template.png deleted file mode 100644 index cb8447971..000000000 Binary files a/articles/media/azure-bot-service-template.png and /dev/null differ diff --git a/articles/media/azure-browse.png b/articles/media/azure-browse.png deleted file mode 100644 index 1d9387e57..000000000 Binary files a/articles/media/azure-browse.png and /dev/null differ diff --git a/articles/media/azure-create-webapp.png b/articles/media/azure-create-webapp.png deleted file mode 100644 index 7089086c8..000000000 Binary files a/articles/media/azure-create-webapp.png and /dev/null differ diff --git a/articles/media/azure-deployment.png b/articles/media/azure-deployment.png deleted file mode 100644 index f02b40110..000000000 Binary files a/articles/media/azure-deployment.png and /dev/null differ diff --git a/articles/media/azure-manage-a-bot/app-service-settings.png b/articles/media/azure-manage-a-bot/app-service-settings.png deleted file mode 100644 index 939b64043..000000000 Binary files a/articles/media/azure-manage-a-bot/app-service-settings.png and /dev/null differ diff --git a/articles/media/azure-manage-a-bot/app-settings.png b/articles/media/azure-manage-a-bot/app-settings.png deleted file mode 100644 index 29d63db47..000000000 Binary files a/articles/media/azure-manage-a-bot/app-settings.png and /dev/null differ diff --git a/articles/media/azure-manage-a-bot/bot-management.png b/articles/media/azure-manage-a-bot/bot-management.png deleted file mode 100644 index b021bb152..000000000 Binary files a/articles/media/azure-manage-a-bot/bot-management.png and /dev/null differ diff --git a/articles/media/azure-manage-a-bot/overview.png b/articles/media/azure-manage-a-bot/overview.png deleted file mode 100644 index 83e5d83cc..000000000 Binary files a/articles/media/azure-manage-a-bot/overview.png and /dev/null differ diff --git a/articles/media/azure-secrets.png b/articles/media/azure-secrets.png deleted file mode 100644 index 5e0d1f5e5..000000000 Binary files a/articles/media/azure-secrets.png and /dev/null differ diff --git a/articles/media/azure_publish1.png b/articles/media/azure_publish1.png deleted file mode 100644 index eea2723f2..000000000 Binary files a/articles/media/azure_publish1.png and /dev/null differ diff --git a/articles/media/azure_publish2.png b/articles/media/azure_publish2.png deleted file mode 100644 index 4301d6d12..000000000 Binary files a/articles/media/azure_publish2.png and /dev/null differ diff --git a/articles/media/azure_publish3.png b/articles/media/azure_publish3.png deleted file mode 100644 index df9b2282c..000000000 Binary files a/articles/media/azure_publish3.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/bot-builder-dotnet-luis-message-flow-bot-code-notes.png b/articles/media/bot-builder-dotnet-use-luis/bot-builder-dotnet-luis-message-flow-bot-code-notes.png deleted file mode 100644 index db92a5bb2..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/bot-builder-dotnet-luis-message-flow-bot-code-notes.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/bot-service-app-settings.png b/articles/media/bot-builder-dotnet-use-luis/bot-service-app-settings.png deleted file mode 100644 index 533ec9318..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/bot-service-app-settings.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/bot-service-build.png b/articles/media/bot-builder-dotnet-use-luis/bot-service-build.png deleted file mode 100644 index 323abbfe5..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/bot-service-build.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/bot-service-create-notification.png b/articles/media/bot-builder-dotnet-use-luis/bot-service-create-notification.png deleted file mode 100644 index 82f970e40..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/bot-service-create-notification.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/bot-service-creation.png b/articles/media/bot-builder-dotnet-use-luis/bot-service-creation.png deleted file mode 100644 index b92a6f145..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/bot-service-creation.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/bot-service-run-console.png b/articles/media/bot-builder-dotnet-use-luis/bot-service-run-console.png deleted file mode 100644 index 06d721b16..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/bot-service-run-console.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/bot-service-selection.png b/articles/media/bot-builder-dotnet-use-luis/bot-service-selection.png deleted file mode 100644 index b92c372b0..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/bot-service-selection.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/bot-service-setting-callout-appname.png b/articles/media/bot-builder-dotnet-use-luis/bot-service-setting-callout-appname.png deleted file mode 100644 index d7476bf67..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/bot-service-setting-callout-appname.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/bot-service-setting-callout-template.png b/articles/media/bot-builder-dotnet-use-luis/bot-service-setting-callout-template.png deleted file mode 100644 index a71072d58..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/bot-service-setting-callout-template.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/bot-service-test-notebot.png b/articles/media/bot-builder-dotnet-use-luis/bot-service-test-notebot.png deleted file mode 100644 index f29db83e8..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/bot-service-test-notebot.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/bot-service-web-chat.png b/articles/media/bot-builder-dotnet-use-luis/bot-service-web-chat.png deleted file mode 100644 index 5d0baa8b2..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/bot-service-web-chat.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/dotnet-notes-sample-emulator.png b/articles/media/bot-builder-dotnet-use-luis/dotnet-notes-sample-emulator.png deleted file mode 100644 index 510c11d9e..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/dotnet-notes-sample-emulator.png and /dev/null differ diff --git a/articles/media/bot-builder-dotnet-use-luis/luis-intent-list.png b/articles/media/bot-builder-dotnet-use-luis/luis-intent-list.png deleted file mode 100644 index 7894ba16a..000000000 Binary files a/articles/media/bot-builder-dotnet-use-luis/luis-intent-list.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-dialog-manage-conversation/waterfall-results.png b/articles/media/bot-builder-nodejs-dialog-manage-conversation/waterfall-results.png deleted file mode 100644 index 53c959d9d..000000000 Binary files a/articles/media/bot-builder-nodejs-dialog-manage-conversation/waterfall-results.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-state-azure-table-storage/bot-builder-nodejs-state-azure-table-storage-query.png b/articles/media/bot-builder-nodejs-state-azure-table-storage/bot-builder-nodejs-state-azure-table-storage-query.png deleted file mode 100644 index 97d5858c0..000000000 Binary files a/articles/media/bot-builder-nodejs-state-azure-table-storage/bot-builder-nodejs-state-azure-table-storage-query.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/bot-builder-nodejs-luis-message-flow-bot-code-notes.png b/articles/media/bot-builder-nodejs-use-luis/bot-builder-nodejs-luis-message-flow-bot-code-notes.png deleted file mode 100644 index 44c4c37f3..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/bot-builder-nodejs-luis-message-flow-bot-code-notes.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/bot-builder-nodejs-use-luis-create-note-interruption.png b/articles/media/bot-builder-nodejs-use-luis/bot-builder-nodejs-use-luis-create-note-interruption.png deleted file mode 100644 index b5397983b..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/bot-builder-nodejs-use-luis-create-note-interruption.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/bot-builder-nodejs-use-luis-create-note-output.png b/articles/media/bot-builder-nodejs-use-luis/bot-builder-nodejs-use-luis-create-note-output.png deleted file mode 100644 index 6636aca48..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/bot-builder-nodejs-use-luis-create-note-output.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/bot-builder-nodejs-use-luis-read-note-output.png b/articles/media/bot-builder-nodejs-use-luis/bot-builder-nodejs-use-luis-read-note-output.png deleted file mode 100644 index e13ee97ac..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/bot-builder-nodejs-use-luis-read-note-output.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/bot-service-app-settings.png b/articles/media/bot-builder-nodejs-use-luis/bot-service-app-settings.png deleted file mode 100644 index 533ec9318..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/bot-service-app-settings.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/bot-service-build.png b/articles/media/bot-builder-nodejs-use-luis/bot-service-build.png deleted file mode 100644 index 323abbfe5..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/bot-service-build.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/bot-service-creation.png b/articles/media/bot-builder-nodejs-use-luis/bot-service-creation.png deleted file mode 100644 index b92a6f145..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/bot-service-creation.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/bot-service-selection.png b/articles/media/bot-builder-nodejs-use-luis/bot-service-selection.png deleted file mode 100644 index b92c372b0..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/bot-service-selection.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/bot-service-setting-callout-appname.png b/articles/media/bot-builder-nodejs-use-luis/bot-service-setting-callout-appname.png deleted file mode 100644 index d7476bf67..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/bot-service-setting-callout-appname.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/bot-service-setting-callout-template.png b/articles/media/bot-builder-nodejs-use-luis/bot-service-setting-callout-template.png deleted file mode 100644 index 72aad459d..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/bot-service-setting-callout-template.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/bot-service-test-notebot.png b/articles/media/bot-builder-nodejs-use-luis/bot-service-test-notebot.png deleted file mode 100644 index 6a742d053..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/bot-service-test-notebot.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/bot-service-web-chat.png b/articles/media/bot-builder-nodejs-use-luis/bot-service-web-chat.png deleted file mode 100644 index 5d0baa8b2..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/bot-service-web-chat.png and /dev/null differ diff --git a/articles/media/bot-builder-nodejs-use-luis/luis-intent-list.png b/articles/media/bot-builder-nodejs-use-luis/luis-intent-list.png deleted file mode 100644 index 7894ba16a..000000000 Binary files a/articles/media/bot-builder-nodejs-use-luis/luis-intent-list.png and /dev/null differ diff --git a/articles/media/bot-builder-state-data-db/cosmosdb.png b/articles/media/bot-builder-state-data-db/cosmosdb.png deleted file mode 100644 index 4de7bce46..000000000 Binary files a/articles/media/bot-builder-state-data-db/cosmosdb.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/az-browser-login.png b/articles/media/bot-builder-tools/az-browser-login.png deleted file mode 100644 index 455cf853b..000000000 Binary files a/articles/media/bot-builder-tools/az-browser-login.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/az-cli-bot.png b/articles/media/bot-builder-tools/az-cli-bot.png deleted file mode 100644 index d3b4141d6..000000000 Binary files a/articles/media/bot-builder-tools/az-cli-bot.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/az-echo-bot.png b/articles/media/bot-builder-tools/az-echo-bot.png deleted file mode 100644 index b55af3a5f..000000000 Binary files a/articles/media/bot-builder-tools/az-echo-bot.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/az-login-command.png b/articles/media/bot-builder-tools/az-login-command.png deleted file mode 100644 index 60408f00a..000000000 Binary files a/articles/media/bot-builder-tools/az-login-command.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/az-portal-manage-code.png b/articles/media/bot-builder-tools/az-portal-manage-code.png deleted file mode 100644 index 38cf731c3..000000000 Binary files a/articles/media/bot-builder-tools/az-portal-manage-code.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/cli-bot-download-command.png b/articles/media/bot-builder-tools/cli-bot-download-command.png deleted file mode 100644 index 5f59480af..000000000 Binary files a/articles/media/bot-builder-tools/cli-bot-download-command.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/cli-bot-download.png b/articles/media/bot-builder-tools/cli-bot-download.png deleted file mode 100644 index cab2046b7..000000000 Binary files a/articles/media/bot-builder-tools/cli-bot-download.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/ludown-luis-create.png b/articles/media/bot-builder-tools/ludown-luis-create.png deleted file mode 100644 index a859f781d..000000000 Binary files a/articles/media/bot-builder-tools/ludown-luis-create.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/ludown-options.png b/articles/media/bot-builder-tools/ludown-options.png deleted file mode 100644 index c53332428..000000000 Binary files a/articles/media/bot-builder-tools/ludown-options.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/ludown-qna-create.png b/articles/media/bot-builder-tools/ludown-qna-create.png deleted file mode 100644 index a17f6008d..000000000 Binary files a/articles/media/bot-builder-tools/ludown-qna-create.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/luis-init.png b/articles/media/bot-builder-tools/luis-init.png deleted file mode 100644 index 279972aa3..000000000 Binary files a/articles/media/bot-builder-tools/luis-init.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/ms-device-login.png b/articles/media/bot-builder-tools/ms-device-login.png deleted file mode 100644 index 26bc02356..000000000 Binary files a/articles/media/bot-builder-tools/ms-device-login.png and /dev/null differ diff --git a/articles/media/bot-builder-tools/qnamaker-init.png b/articles/media/bot-builder-tools/qnamaker-init.png deleted file mode 100644 index c30314167..000000000 Binary files a/articles/media/bot-builder-tools/qnamaker-init.png and /dev/null differ diff --git a/articles/media/bot-connector-service-slide.png b/articles/media/bot-connector-service-slide.png deleted file mode 100644 index 851962d9d..000000000 Binary files a/articles/media/bot-connector-service-slide.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-bot-state.png b/articles/media/bot-debug-inspection-middleware/bot-debug-bot-state.png deleted file mode 100644 index d81cdfc90..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-bot-state.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-channels-setting-ngrok.png b/articles/media/bot-debug-inspection-middleware/bot-debug-channels-setting-ngrok.png deleted file mode 100644 index 203a9c8a6..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-channels-setting-ngrok.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-check-emulator-version.png b/articles/media/bot-debug-inspection-middleware/bot-debug-check-emulator-version.png deleted file mode 100644 index 92d91f31e..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-check-emulator-version.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-debugmode-ngrok-emulator.png b/articles/media/bot-debug-inspection-middleware/bot-debug-debugmode-ngrok-emulator.png deleted file mode 100644 index 81b77cb40..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-debugmode-ngrok-emulator.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-emulator-values.png b/articles/media/bot-debug-inspection-middleware/bot-debug-emulator-values.png deleted file mode 100644 index 1e529b7ae..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-emulator-values.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-get-inputs-id-secret.png b/articles/media/bot-debug-inspection-middleware/bot-debug-get-inputs-id-secret.png deleted file mode 100644 index b35e37e76..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-get-inputs-id-secret.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-get-latest-version.png b/articles/media/bot-debug-inspection-middleware/bot-debug-get-latest-version.png deleted file mode 100644 index 514ea8633..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-get-latest-version.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-inspector-middleware-result.gif b/articles/media/bot-debug-inspection-middleware/bot-debug-inspector-middleware-result.gif deleted file mode 100644 index c3df5ca48..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-inspector-middleware-result.gif and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-ngrok.png b/articles/media/bot-debug-inspection-middleware/bot-debug-ngrok.png deleted file mode 100644 index 6a7a7152b..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-ngrok.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-notification.png b/articles/media/bot-debug-inspection-middleware/bot-debug-notification.png deleted file mode 100644 index b3468b0ef..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-notification.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-run-bot.png b/articles/media/bot-debug-inspection-middleware/bot-debug-run-bot.png deleted file mode 100644 index e1428dc28..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-run-bot.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-run-ngrok.png b/articles/media/bot-debug-inspection-middleware/bot-debug-run-ngrok.png deleted file mode 100644 index b45eca114..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-run-ngrok.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-test-webchat.png b/articles/media/bot-debug-inspection-middleware/bot-debug-test-webchat.png deleted file mode 100644 index 8332ebbd6..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-test-webchat.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-update-download.png b/articles/media/bot-debug-inspection-middleware/bot-debug-update-download.png deleted file mode 100644 index 0185cf6e0..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-update-download.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-uuid-success.png b/articles/media/bot-debug-inspection-middleware/bot-debug-uuid-success.png deleted file mode 100644 index 048cf9d22..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-uuid-success.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/bot-debug-uuid.png b/articles/media/bot-debug-inspection-middleware/bot-debug-uuid.png deleted file mode 100644 index 8f59c1fd1..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/bot-debug-uuid.png and /dev/null differ diff --git a/articles/media/bot-debug-inspection-middleware/debug-state-inspection-channel-chat.gif b/articles/media/bot-debug-inspection-middleware/debug-state-inspection-channel-chat.gif deleted file mode 100644 index 1faac9b91..000000000 Binary files a/articles/media/bot-debug-inspection-middleware/debug-state-inspection-channel-chat.gif and /dev/null differ diff --git a/articles/media/bot-framework-devops/SourceWebAppsBotFramework.png b/articles/media/bot-framework-devops/SourceWebAppsBotFramework.png deleted file mode 100644 index 793f6c0e0..000000000 Binary files a/articles/media/bot-framework-devops/SourceWebAppsBotFramework.png and /dev/null differ diff --git a/articles/media/bot-proactive-diagram.png b/articles/media/bot-proactive-diagram.png deleted file mode 100644 index f722e6d48..000000000 Binary files a/articles/media/bot-proactive-diagram.png and /dev/null differ diff --git a/articles/media/bot-service-adapter-connect-slack/event-subscriptions.PNG b/articles/media/bot-service-adapter-connect-slack/event-subscriptions.PNG deleted file mode 100644 index e4684eb7c..000000000 Binary files a/articles/media/bot-service-adapter-connect-slack/event-subscriptions.PNG and /dev/null differ diff --git a/articles/media/bot-service-adapter-connect-slack/redirect-url.PNG b/articles/media/bot-service-adapter-connect-slack/redirect-url.PNG deleted file mode 100644 index 0ca0cb37e..000000000 Binary files a/articles/media/bot-service-adapter-connect-slack/redirect-url.PNG and /dev/null differ diff --git a/articles/media/bot-service-adapter-connect-slack/slack-tokens.PNG b/articles/media/bot-service-adapter-connect-slack/slack-tokens.PNG deleted file mode 100644 index aeced4d77..000000000 Binary files a/articles/media/bot-service-adapter-connect-slack/slack-tokens.PNG and /dev/null differ diff --git a/articles/media/bot-service-adapter-connect-webex/create-bot-settings.PNG b/articles/media/bot-service-adapter-connect-webex/create-bot-settings.PNG deleted file mode 100644 index f0160863e..000000000 Binary files a/articles/media/bot-service-adapter-connect-webex/create-bot-settings.PNG and /dev/null differ diff --git a/articles/media/bot-service-adapter-connect-webex/create-bot.PNG b/articles/media/bot-service-adapter-connect-webex/create-bot.PNG deleted file mode 100644 index 48993fbf3..000000000 Binary files a/articles/media/bot-service-adapter-connect-webex/create-bot.PNG and /dev/null differ diff --git a/articles/media/bot-service-adapter-connect-webex/webex-contact-person.PNG b/articles/media/bot-service-adapter-connect-webex/webex-contact-person.PNG deleted file mode 100644 index 3e52ab936..000000000 Binary files a/articles/media/bot-service-adapter-connect-webex/webex-contact-person.PNG and /dev/null differ diff --git a/articles/media/bot-service-adapter-connect-webex/webex-webhook-form.PNG b/articles/media/bot-service-adapter-connect-webex/webex-webhook-form.PNG deleted file mode 100644 index af2d68caf..000000000 Binary files a/articles/media/bot-service-adapter-connect-webex/webex-webhook-form.PNG and /dev/null differ diff --git a/articles/media/bot-service-adapter-connect-webex/webex-webhook-put-endpoint.PNG b/articles/media/bot-service-adapter-connect-webex/webex-webhook-put-endpoint.PNG deleted file mode 100644 index 16ffd3800..000000000 Binary files a/articles/media/bot-service-adapter-connect-webex/webex-webhook-put-endpoint.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-directline/directline-addchannel.png b/articles/media/bot-service-channel-connect-directline/directline-addchannel.png deleted file mode 100644 index 189640687..000000000 Binary files a/articles/media/bot-service-channel-connect-directline/directline-addchannel.png and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-directline/directline-addsite.png b/articles/media/bot-service-channel-connect-directline/directline-addsite.png deleted file mode 100644 index 887400727..000000000 Binary files a/articles/media/bot-service-channel-connect-directline/directline-addsite.png and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-directline/directline-copykey.png b/articles/media/bot-service-channel-connect-directline/directline-copykey.png deleted file mode 100644 index d3ac1bf75..000000000 Binary files a/articles/media/bot-service-channel-connect-directline/directline-copykey.png and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-directline/directline-showkey.png b/articles/media/bot-service-channel-connect-directline/directline-showkey.png deleted file mode 100644 index 5c5c2aabc..000000000 Binary files a/articles/media/bot-service-channel-connect-directline/directline-showkey.png and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-email/bot-service-channel-connect-email-credentials.png b/articles/media/bot-service-channel-connect-email/bot-service-channel-connect-email-credentials.png deleted file mode 100644 index ef5569bff..000000000 Binary files a/articles/media/bot-service-channel-connect-email/bot-service-channel-connect-email-credentials.png and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-facebook/add-button.PNG b/articles/media/bot-service-channel-connect-facebook/add-button.PNG deleted file mode 100644 index 86aee2805..000000000 Binary files a/articles/media/bot-service-channel-connect-facebook/add-button.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-facebook/add-product.PNG b/articles/media/bot-service-channel-connect-facebook/add-product.PNG deleted file mode 100644 index dee37ecbf..000000000 Binary files a/articles/media/bot-service-channel-connect-facebook/add-product.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-facebook/api_settings.png b/articles/media/bot-service-channel-connect-facebook/api_settings.png deleted file mode 100644 index cb6c8b27c..000000000 Binary files a/articles/media/bot-service-channel-connect-facebook/api_settings.png and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-facebook/app-name.PNG b/articles/media/bot-service-channel-connect-facebook/app-name.PNG deleted file mode 100644 index 10dd7fe78..000000000 Binary files a/articles/media/bot-service-channel-connect-facebook/app-name.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-facebook/app-page-permissions.PNG b/articles/media/bot-service-channel-connect-facebook/app-page-permissions.PNG deleted file mode 100644 index 509e6ebb5..000000000 Binary files a/articles/media/bot-service-channel-connect-facebook/app-page-permissions.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-facebook/button-settings-2.PNG b/articles/media/bot-service-channel-connect-facebook/button-settings-2.PNG deleted file mode 100644 index c6b70e7d8..000000000 Binary files a/articles/media/bot-service-channel-connect-facebook/button-settings-2.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-facebook/button-settings.PNG b/articles/media/bot-service-channel-connect-facebook/button-settings.PNG deleted file mode 100644 index 51a23d7f8..000000000 Binary files a/articles/media/bot-service-channel-connect-facebook/button-settings.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-facebook/create-app-button.PNG b/articles/media/bot-service-channel-connect-facebook/create-app-button.PNG deleted file mode 100644 index c3fe35e62..000000000 Binary files a/articles/media/bot-service-channel-connect-facebook/create-app-button.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-facebook/create-page.PNG b/articles/media/bot-service-channel-connect-facebook/create-page.PNG deleted file mode 100644 index f536562b8..000000000 Binary files a/articles/media/bot-service-channel-connect-facebook/create-page.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-facebook/edit-callback-url.PNG b/articles/media/bot-service-channel-connect-facebook/edit-callback-url.PNG deleted file mode 100644 index 873db63cd..000000000 Binary files a/articles/media/bot-service-channel-connect-facebook/edit-callback-url.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-facebook/subscribe-webhook.png b/articles/media/bot-service-channel-connect-facebook/subscribe-webhook.png deleted file mode 100644 index 7081d8bc8..000000000 Binary files a/articles/media/bot-service-channel-connect-facebook/subscribe-webhook.png and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-facebook/webhook-subscriptions.PNG b/articles/media/bot-service-channel-connect-facebook/webhook-subscriptions.PNG deleted file mode 100644 index a3be06899..000000000 Binary files a/articles/media/bot-service-channel-connect-facebook/webhook-subscriptions.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-twilio/get-phone-number.PNG b/articles/media/bot-service-channel-connect-twilio/get-phone-number.PNG deleted file mode 100644 index dd25d6a39..000000000 Binary files a/articles/media/bot-service-channel-connect-twilio/get-phone-number.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-twilio/get-started-voice.png b/articles/media/bot-service-channel-connect-twilio/get-started-voice.png deleted file mode 100644 index c80ac9048..000000000 Binary files a/articles/media/bot-service-channel-connect-twilio/get-started-voice.png and /dev/null differ diff --git a/articles/media/bot-service-channel-connect-twilio/twilio-number-messaging-settings.PNG b/articles/media/bot-service-channel-connect-twilio/twilio-number-messaging-settings.PNG deleted file mode 100644 index fd63a2a36..000000000 Binary files a/articles/media/bot-service-channel-connect-twilio/twilio-number-messaging-settings.PNG and /dev/null differ diff --git a/articles/media/bot-service-channel-inspector.png b/articles/media/bot-service-channel-inspector.png deleted file mode 100644 index 2bf6fe1dc..000000000 Binary files a/articles/media/bot-service-channel-inspector.png and /dev/null differ diff --git a/articles/media/bot-service-channel-webchat/blob-storage-keys.png b/articles/media/bot-service-channel-webchat/blob-storage-keys.png deleted file mode 100644 index d3bdfc5e0..000000000 Binary files a/articles/media/bot-service-channel-webchat/blob-storage-keys.png and /dev/null differ diff --git a/articles/media/bot-service-channel-webchat/bot-service-channel-list.png b/articles/media/bot-service-channel-webchat/bot-service-channel-list.png deleted file mode 100644 index b2abdec4a..000000000 Binary files a/articles/media/bot-service-channel-webchat/bot-service-channel-list.png and /dev/null differ diff --git a/articles/media/bot-service-channel-webchat/create-a-bot.png b/articles/media/bot-service-channel-webchat/create-a-bot.png deleted file mode 100644 index dfcf4f680..000000000 Binary files a/articles/media/bot-service-channel-webchat/create-a-bot.png and /dev/null differ diff --git a/articles/media/bot-service-channel-webchat/secret-key.png b/articles/media/bot-service-channel-webchat/secret-key.png deleted file mode 100644 index 3ee2e664a..000000000 Binary files a/articles/media/bot-service-channel-webchat/secret-key.png and /dev/null differ diff --git a/articles/media/bot-service-channel-webchat/webchat-sample-speech.png b/articles/media/bot-service-channel-webchat/webchat-sample-speech.png deleted file mode 100644 index 200ba6535..000000000 Binary files a/articles/media/bot-service-channel-webchat/webchat-sample-speech.png and /dev/null differ diff --git a/articles/media/bot-service-channel-webchat/webchat-sample.png b/articles/media/bot-service-channel-webchat/webchat-sample.png deleted file mode 100644 index 4b273ee27..000000000 Binary files a/articles/media/bot-service-channel-webchat/webchat-sample.png and /dev/null differ diff --git a/articles/media/bot-service-concept-templates/sdk-bot-cs-templates.png b/articles/media/bot-service-concept-templates/sdk-bot-cs-templates.png deleted file mode 100644 index 9caa06751..000000000 Binary files a/articles/media/bot-service-concept-templates/sdk-bot-cs-templates.png and /dev/null differ diff --git a/articles/media/bot-service-debug-bot/bot-debug-python-breakpoint-caught.png b/articles/media/bot-service-debug-bot/bot-debug-python-breakpoint-caught.png deleted file mode 100644 index 905a8bd3b..000000000 Binary files a/articles/media/bot-service-debug-bot/bot-debug-python-breakpoint-caught.png and /dev/null differ diff --git a/articles/media/bot-service-debug-bot/bot-debug-python-breakpoints.png b/articles/media/bot-service-debug-bot/bot-debug-python-breakpoints.png deleted file mode 100644 index 79ddd0a1e..000000000 Binary files a/articles/media/bot-service-debug-bot/bot-debug-python-breakpoints.png and /dev/null differ diff --git a/articles/media/bot-service-debug-bot/breakpoint-caught-vs.png b/articles/media/bot-service-debug-bot/breakpoint-caught-vs.png deleted file mode 100644 index bf9d4c9bd..000000000 Binary files a/articles/media/bot-service-debug-bot/breakpoint-caught-vs.png and /dev/null differ diff --git a/articles/media/bot-service-debug-bot/breakpoint-caught.png b/articles/media/bot-service-debug-bot/breakpoint-caught.png deleted file mode 100644 index 5ff328e7a..000000000 Binary files a/articles/media/bot-service-debug-bot/breakpoint-caught.png and /dev/null differ diff --git a/articles/media/bot-service-debug-bot/breakpoint-set-vs.png b/articles/media/bot-service-debug-bot/breakpoint-set-vs.png deleted file mode 100644 index c4c61762a..000000000 Binary files a/articles/media/bot-service-debug-bot/breakpoint-set-vs.png and /dev/null differ diff --git a/articles/media/bot-service-debug-bot/breakpoint-set.png b/articles/media/bot-service-debug-bot/breakpoint-set.png deleted file mode 100644 index a5d1a40ff..000000000 Binary files a/articles/media/bot-service-debug-bot/breakpoint-set.png and /dev/null differ diff --git a/articles/media/bot-service-debug-bot/csharp-azureservice-debug-debughost.png b/articles/media/bot-service-debug-bot/csharp-azureservice-debug-debughost.png deleted file mode 100644 index fa0aa825b..000000000 Binary files a/articles/media/bot-service-debug-bot/csharp-azureservice-debug-debughost.png and /dev/null differ diff --git a/articles/media/bot-service-debug-bot/csharp-azureservice-debug-debughostlogging.png b/articles/media/bot-service-debug-bot/csharp-azureservice-debug-debughostlogging.png deleted file mode 100644 index 06fdfb57a..000000000 Binary files a/articles/media/bot-service-debug-bot/csharp-azureservice-debug-debughostlogging.png and /dev/null differ diff --git a/articles/media/bot-service-debug-bot/csharp-azureservice-debug-envconfig.png b/articles/media/bot-service-debug-bot/csharp-azureservice-debug-envconfig.png deleted file mode 100644 index 9a177673b..000000000 Binary files a/articles/media/bot-service-debug-bot/csharp-azureservice-debug-envconfig.png and /dev/null differ diff --git a/articles/media/bot-service-debug-bot/emulator_inspector.png b/articles/media/bot-service-debug-bot/emulator_inspector.png deleted file mode 100644 index a1d253702..000000000 Binary files a/articles/media/bot-service-debug-bot/emulator_inspector.png and /dev/null differ diff --git a/articles/media/bot-service-debug-bot/mac-azureservice-debug-emulator.png b/articles/media/bot-service-debug-bot/mac-azureservice-debug-emulator.png deleted file mode 100644 index 0625f5d09..000000000 Binary files a/articles/media/bot-service-debug-bot/mac-azureservice-debug-emulator.png and /dev/null differ diff --git a/articles/media/bot-service-debug-bot/mac-azureservice-emulator-config.png b/articles/media/bot-service-debug-bot/mac-azureservice-emulator-config.png deleted file mode 100644 index ef6b3b209..000000000 Binary files a/articles/media/bot-service-debug-bot/mac-azureservice-emulator-config.png and /dev/null differ diff --git a/articles/media/bot-service-debug-emulator/csharp_port_number.png b/articles/media/bot-service-debug-emulator/csharp_port_number.png deleted file mode 100644 index 2b154960f..000000000 Binary files a/articles/media/bot-service-debug-emulator/csharp_port_number.png and /dev/null differ diff --git a/articles/media/bot-service-debug-emulator/js_port_number.png b/articles/media/bot-service-debug-emulator/js_port_number.png deleted file mode 100644 index 3499b25a7..000000000 Binary files a/articles/media/bot-service-debug-emulator/js_port_number.png and /dev/null differ diff --git a/articles/media/bot-service-debug-emulator/open_bot_emulator.png b/articles/media/bot-service-debug-emulator/open_bot_emulator.png deleted file mode 100644 index 71427782a..000000000 Binary files a/articles/media/bot-service-debug-emulator/open_bot_emulator.png and /dev/null differ diff --git a/articles/media/bot-service-design-conversation-flow/stack-issue.png b/articles/media/bot-service-design-conversation-flow/stack-issue.png deleted file mode 100644 index 21139fcb0..000000000 Binary files a/articles/media/bot-service-design-conversation-flow/stack-issue.png and /dev/null differ diff --git a/articles/media/bot-service-design-first-interaction/Hello1.png b/articles/media/bot-service-design-first-interaction/Hello1.png deleted file mode 100644 index 5954b6cfd..000000000 Binary files a/articles/media/bot-service-design-first-interaction/Hello1.png and /dev/null differ diff --git a/articles/media/bot-service-design-first-interaction/Hello2.png b/articles/media/bot-service-design-first-interaction/Hello2.png deleted file mode 100644 index 4dea0c76e..000000000 Binary files a/articles/media/bot-service-design-first-interaction/Hello2.png and /dev/null differ diff --git a/articles/media/bot-service-design-navigation/captainobvious-bot.png b/articles/media/bot-service-design-navigation/captainobvious-bot.png deleted file mode 100644 index fa81b15bb..000000000 Binary files a/articles/media/bot-service-design-navigation/captainobvious-bot.png and /dev/null differ diff --git a/articles/media/bot-service-design-navigation/clueless-bot.png b/articles/media/bot-service-design-navigation/clueless-bot.png deleted file mode 100644 index efa679fa3..000000000 Binary files a/articles/media/bot-service-design-navigation/clueless-bot.png and /dev/null differ diff --git a/articles/media/bot-service-design-navigation/mysterious-bot.png b/articles/media/bot-service-design-navigation/mysterious-bot.png deleted file mode 100644 index 9c87d0a5d..000000000 Binary files a/articles/media/bot-service-design-navigation/mysterious-bot.png and /dev/null differ diff --git a/articles/media/bot-service-design-navigation/rememberall-bot.png b/articles/media/bot-service-design-navigation/rememberall-bot.png deleted file mode 100644 index 56a7d095f..000000000 Binary files a/articles/media/bot-service-design-navigation/rememberall-bot.png and /dev/null differ diff --git a/articles/media/bot-service-design-navigation/stubborn-bot-new.png b/articles/media/bot-service-design-navigation/stubborn-bot-new.png deleted file mode 100644 index a808aa39e..000000000 Binary files a/articles/media/bot-service-design-navigation/stubborn-bot-new.png and /dev/null differ diff --git a/articles/media/bot-service-design-navigation/stubborn-bot.png b/articles/media/bot-service-design-navigation/stubborn-bot.png deleted file mode 100644 index 7d5176a83..000000000 Binary files a/articles/media/bot-service-design-navigation/stubborn-bot.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-embed-app/webchat-channel.png b/articles/media/bot-service-design-pattern-embed-app/webchat-channel.png deleted file mode 100644 index 0dff6a62e..000000000 Binary files a/articles/media/bot-service-design-pattern-embed-app/webchat-channel.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-embed-app/xamarin-apps.png b/articles/media/bot-service-design-pattern-embed-app/xamarin-apps.png deleted file mode 100644 index a51be515f..000000000 Binary files a/articles/media/bot-service-design-pattern-embed-app/xamarin-apps.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-integrate-browser/bot-to-web1.png b/articles/media/bot-service-design-pattern-integrate-browser/bot-to-web1.png deleted file mode 100644 index 5fbc4afca..000000000 Binary files a/articles/media/bot-service-design-pattern-integrate-browser/bot-to-web1.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/KnowledgeBaseConfig.PNG b/articles/media/bot-service-design-pattern-knowledge-base/KnowledgeBaseConfig.PNG deleted file mode 100644 index 150d418aa..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/KnowledgeBaseConfig.PNG and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/answerGenre.PNG b/articles/media/bot-service-design-pattern-knowledge-base/answerGenre.PNG deleted file mode 100644 index c01c1e87b..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/answerGenre.PNG and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/answerGenreOneWord.PNG b/articles/media/bot-service-design-pattern-knowledge-base/answerGenreOneWord.PNG deleted file mode 100644 index 5fa2672a8..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/answerGenreOneWord.PNG and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/devilMakesThreeScore.PNG b/articles/media/bot-service-design-pattern-knowledge-base/devilMakesThreeScore.PNG deleted file mode 100644 index ba31bcd09..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/devilMakesThreeScore.PNG and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/exampleQnAConvo.PNG b/articles/media/bot-service-design-pattern-knowledge-base/exampleQnAConvo.PNG deleted file mode 100644 index 7bba40363..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/exampleQnAConvo.PNG and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/facet.PNG b/articles/media/bot-service-design-pattern-knowledge-base/facet.PNG deleted file mode 100644 index 3b1fef89a..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/facet.PNG and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/fuzzySearch.png b/articles/media/bot-service-design-pattern-knowledge-base/fuzzySearch.png deleted file mode 100644 index a35db0a9b..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/fuzzySearch.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/fuzzySearch2.png b/articles/media/bot-service-design-pattern-knowledge-base/fuzzySearch2.png deleted file mode 100644 index b1b2c8908..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/fuzzySearch2.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/guidedConvo1.png b/articles/media/bot-service-design-pattern-knowledge-base/guidedConvo1.png deleted file mode 100644 index 55c91f359..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/guidedConvo1.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/guidedConvo2.png b/articles/media/bot-service-design-pattern-knowledge-base/guidedConvo2.png deleted file mode 100644 index 15def5d73..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/guidedConvo2.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/guidedConvo3.png b/articles/media/bot-service-design-pattern-knowledge-base/guidedConvo3.png deleted file mode 100644 index c0fd371a4..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/guidedConvo3.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/guidedConvo4.png b/articles/media/bot-service-design-pattern-knowledge-base/guidedConvo4.png deleted file mode 100644 index 83dce59dc..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/guidedConvo4.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/search3.PNG b/articles/media/bot-service-design-pattern-knowledge-base/search3.PNG deleted file mode 100644 index 0dc0790da..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/search3.PNG and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/searchScore1.png b/articles/media/bot-service-design-pattern-knowledge-base/searchScore1.png deleted file mode 100644 index 7170ac7ae..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/searchScore1.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/searchScore2.png b/articles/media/bot-service-design-pattern-knowledge-base/searchScore2.png deleted file mode 100644 index 84bbf444d..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/searchScore2.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-knowledge-base/training.png b/articles/media/bot-service-design-pattern-knowledge-base/training.png deleted file mode 100644 index 8b6133131..000000000 Binary files a/articles/media/bot-service-design-pattern-knowledge-base/training.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-task-automation/simple-task1.png b/articles/media/bot-service-design-pattern-task-automation/simple-task1.png deleted file mode 100644 index f061ebec8..000000000 Binary files a/articles/media/bot-service-design-pattern-task-automation/simple-task1.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-task-automation/simple-task2.png b/articles/media/bot-service-design-pattern-task-automation/simple-task2.png deleted file mode 100644 index e5ea80897..000000000 Binary files a/articles/media/bot-service-design-pattern-task-automation/simple-task2.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-task-automation/simple-task3.png b/articles/media/bot-service-design-pattern-task-automation/simple-task3.png deleted file mode 100644 index bb05fdbd3..000000000 Binary files a/articles/media/bot-service-design-pattern-task-automation/simple-task3.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-task-automation/simple-task4.png b/articles/media/bot-service-design-pattern-task-automation/simple-task4.png deleted file mode 100644 index 7a09a6d21..000000000 Binary files a/articles/media/bot-service-design-pattern-task-automation/simple-task4.png and /dev/null differ diff --git a/articles/media/bot-service-design-pattern-task-automation/simple-task5.png b/articles/media/bot-service-design-pattern-task-automation/simple-task5.png deleted file mode 100644 index 9886ba9d3..000000000 Binary files a/articles/media/bot-service-design-pattern-task-automation/simple-task5.png and /dev/null differ diff --git a/articles/media/bot-service-design-user-experience/buy-house.png b/articles/media/bot-service-design-user-experience/buy-house.png deleted file mode 100644 index 159eb7239..000000000 Binary files a/articles/media/bot-service-design-user-experience/buy-house.png and /dev/null differ diff --git a/articles/media/bot-service-manage-speech-priming/speech-priming.png b/articles/media/bot-service-manage-speech-priming/speech-priming.png deleted file mode 100644 index c0dc22ad7..000000000 Binary files a/articles/media/bot-service-manage-speech-priming/speech-priming.png and /dev/null differ diff --git a/articles/media/bot-service-migrate-bot/channel-registration-bot.png b/articles/media/bot-service-migrate-bot/channel-registration-bot.png deleted file mode 100644 index d106a938d..000000000 Binary files a/articles/media/bot-service-migrate-bot/channel-registration-bot.png and /dev/null differ diff --git a/articles/media/bot-service-migrate-bot/functions-bot.png b/articles/media/bot-service-migrate-bot/functions-bot.png deleted file mode 100644 index 806a590a9..000000000 Binary files a/articles/media/bot-service-migrate-bot/functions-bot.png and /dev/null differ diff --git a/articles/media/bot-service-migrate-bot/web-app-bot.png b/articles/media/bot-service-migrate-bot/web-app-bot.png deleted file mode 100644 index f3c909858..000000000 Binary files a/articles/media/bot-service-migrate-bot/web-app-bot.png and /dev/null differ diff --git a/articles/media/bot-service-overview.png b/articles/media/bot-service-overview.png deleted file mode 100644 index 24e7b92cb..000000000 Binary files a/articles/media/bot-service-overview.png and /dev/null differ diff --git a/articles/media/bot-service-portal-configure-settings/bot-settings-blade.png b/articles/media/bot-service-portal-configure-settings/bot-settings-blade.png deleted file mode 100644 index 4855c7371..000000000 Binary files a/articles/media/bot-service-portal-configure-settings/bot-settings-blade.png and /dev/null differ diff --git a/articles/media/botbuilder-templates/cli-bot-download.png b/articles/media/botbuilder-templates/cli-bot-download.png deleted file mode 100644 index cab2046b7..000000000 Binary files a/articles/media/botbuilder-templates/cli-bot-download.png and /dev/null differ diff --git a/articles/media/botbuilder-templates/ludown-options.png b/articles/media/botbuilder-templates/ludown-options.png deleted file mode 100644 index c53332428..000000000 Binary files a/articles/media/botbuilder-templates/ludown-options.png and /dev/null differ diff --git a/articles/media/botbuilder-templates/msbot-cli-window.png b/articles/media/botbuilder-templates/msbot-cli-window.png deleted file mode 100644 index 550f1318a..000000000 Binary files a/articles/media/botbuilder-templates/msbot-cli-window.png and /dev/null differ diff --git a/articles/media/botbuilder-templates/qnamaker-init.png b/articles/media/botbuilder-templates/qnamaker-init.png deleted file mode 100644 index c7dbbe8e4..000000000 Binary files a/articles/media/botbuilder-templates/qnamaker-init.png and /dev/null differ diff --git a/articles/media/card-carousel.png b/articles/media/card-carousel.png deleted file mode 100644 index e54c24374..000000000 Binary files a/articles/media/card-carousel.png and /dev/null differ diff --git a/articles/media/channels/GM-StepApp.png b/articles/media/channels/GM-StepApp.png deleted file mode 100644 index 9dd77ac92..000000000 Binary files a/articles/media/channels/GM-StepApp.png and /dev/null differ diff --git a/articles/media/channels/GM-StepClientIDToken.png b/articles/media/channels/GM-StepClientIDToken.png deleted file mode 100644 index d5a2070e0..000000000 Binary files a/articles/media/channels/GM-StepClientIDToken.png and /dev/null differ diff --git a/articles/media/channels/GM-StepClientId.png b/articles/media/channels/GM-StepClientId.png deleted file mode 100644 index d7dbe95ed..000000000 Binary files a/articles/media/channels/GM-StepClientId.png and /dev/null differ diff --git a/articles/media/channels/GM-StepPasteClientId.png b/articles/media/channels/GM-StepPasteClientId.png deleted file mode 100644 index 87940d823..000000000 Binary files a/articles/media/channels/GM-StepPasteClientId.png and /dev/null differ diff --git a/articles/media/channels/LINE-channel-setting-1.png b/articles/media/channels/LINE-channel-setting-1.png deleted file mode 100644 index 3381bcfab..000000000 Binary files a/articles/media/channels/LINE-channel-setting-1.png and /dev/null differ diff --git a/articles/media/channels/LINE-channel-setting-2.png b/articles/media/channels/LINE-channel-setting-2.png deleted file mode 100644 index 38006f362..000000000 Binary files a/articles/media/channels/LINE-channel-setting-2.png and /dev/null differ diff --git a/articles/media/channels/LINE-channel-type-selection.png b/articles/media/channels/LINE-channel-type-selection.png deleted file mode 100644 index ae8b80da3..000000000 Binary files a/articles/media/channels/LINE-channel-type-selection.png and /dev/null differ diff --git a/articles/media/channels/LINE-create-channel.png b/articles/media/channels/LINE-create-channel.png deleted file mode 100644 index a41d8636c..000000000 Binary files a/articles/media/channels/LINE-create-channel.png and /dev/null differ diff --git a/articles/media/channels/LINE-screenshot-1.png b/articles/media/channels/LINE-screenshot-1.png deleted file mode 100644 index bbe263961..000000000 Binary files a/articles/media/channels/LINE-screenshot-1.png and /dev/null differ diff --git a/articles/media/channels/LINE-screenshot-10.png b/articles/media/channels/LINE-screenshot-10.png deleted file mode 100644 index 412d1a301..000000000 Binary files a/articles/media/channels/LINE-screenshot-10.png and /dev/null differ diff --git a/articles/media/channels/LINE-screenshot-11.png b/articles/media/channels/LINE-screenshot-11.png deleted file mode 100644 index e8a3da515..000000000 Binary files a/articles/media/channels/LINE-screenshot-11.png and /dev/null differ diff --git a/articles/media/channels/LINE-screenshot-12.jpg b/articles/media/channels/LINE-screenshot-12.jpg deleted file mode 100644 index 172ba9d42..000000000 Binary files a/articles/media/channels/LINE-screenshot-12.jpg and /dev/null differ diff --git a/articles/media/channels/LINE-screenshot-2.png b/articles/media/channels/LINE-screenshot-2.png deleted file mode 100644 index 85519f182..000000000 Binary files a/articles/media/channels/LINE-screenshot-2.png and /dev/null differ diff --git a/articles/media/channels/LINE-screenshot-4.png b/articles/media/channels/LINE-screenshot-4.png deleted file mode 100644 index ee3d3a785..000000000 Binary files a/articles/media/channels/LINE-screenshot-4.png and /dev/null differ diff --git a/articles/media/channels/LINE-screenshot-5.png b/articles/media/channels/LINE-screenshot-5.png deleted file mode 100644 index 5800903e5..000000000 Binary files a/articles/media/channels/LINE-screenshot-5.png and /dev/null differ diff --git a/articles/media/channels/LINE-screenshot-6.png b/articles/media/channels/LINE-screenshot-6.png deleted file mode 100644 index 3396b7851..000000000 Binary files a/articles/media/channels/LINE-screenshot-6.png and /dev/null differ diff --git a/articles/media/channels/LINE-screenshot-7.png b/articles/media/channels/LINE-screenshot-7.png deleted file mode 100644 index c7dea64fd..000000000 Binary files a/articles/media/channels/LINE-screenshot-7.png and /dev/null differ diff --git a/articles/media/channels/LINE-screenshot-8.png b/articles/media/channels/LINE-screenshot-8.png deleted file mode 100644 index 0d8e87dbe..000000000 Binary files a/articles/media/channels/LINE-screenshot-8.png and /dev/null differ diff --git a/articles/media/channels/LINE-screenshot-9.png b/articles/media/channels/LINE-screenshot-9.png deleted file mode 100644 index 44f2bdced..000000000 Binary files a/articles/media/channels/LINE-screenshot-9.png and /dev/null differ diff --git a/articles/media/channels/LINE-screenshot-conversation.jpg b/articles/media/channels/LINE-screenshot-conversation.jpg deleted file mode 100644 index e6bcfc7a8..000000000 Binary files a/articles/media/channels/LINE-screenshot-conversation.jpg and /dev/null differ diff --git a/articles/media/channels/bing-category.png b/articles/media/channels/bing-category.png deleted file mode 100644 index ff4e39b7a..000000000 Binary files a/articles/media/channels/bing-category.png and /dev/null differ diff --git a/articles/media/channels/bing-contosoResult.png b/articles/media/channels/bing-contosoResult.png deleted file mode 100644 index d64dd5b58..000000000 Binary files a/articles/media/channels/bing-contosoResult.png and /dev/null differ diff --git a/articles/media/channels/bing-contosoWeb.png b/articles/media/channels/bing-contosoWeb.png deleted file mode 100644 index d856f55f3..000000000 Binary files a/articles/media/channels/bing-contosoWeb.png and /dev/null differ diff --git a/articles/media/channels/bing-general.png b/articles/media/channels/bing-general.png deleted file mode 100644 index 44e473fad..000000000 Binary files a/articles/media/channels/bing-general.png and /dev/null differ diff --git a/articles/media/channels/bing-language.png b/articles/media/channels/bing-language.png deleted file mode 100644 index cbb041dd8..000000000 Binary files a/articles/media/channels/bing-language.png and /dev/null differ diff --git a/articles/media/channels/bing-privacy.png b/articles/media/channels/bing-privacy.png deleted file mode 100644 index 317e81224..000000000 Binary files a/articles/media/channels/bing-privacy.png and /dev/null differ diff --git a/articles/media/channels/bing-publisher.png b/articles/media/channels/bing-publisher.png deleted file mode 100644 index 9660a0747..000000000 Binary files a/articles/media/channels/bing-publisher.png and /dev/null differ diff --git a/articles/media/channels/bing-toggle.png b/articles/media/channels/bing-toggle.png deleted file mode 100644 index 351f0a398..000000000 Binary files a/articles/media/channels/bing-toggle.png and /dev/null differ diff --git a/articles/media/channels/bing_business_bot.png b/articles/media/channels/bing_business_bot.png deleted file mode 100644 index f3e54db94..000000000 Binary files a/articles/media/channels/bing_business_bot.png and /dev/null differ diff --git a/articles/media/channels/connect-to-bing.png b/articles/media/channels/connect-to-bing.png deleted file mode 100644 index fe2a01391..000000000 Binary files a/articles/media/channels/connect-to-bing.png and /dev/null differ diff --git a/articles/media/channels/connect-to-channels.png b/articles/media/channels/connect-to-channels.png deleted file mode 100644 index 31f682ac8..000000000 Binary files a/articles/media/channels/connect-to-channels.png and /dev/null differ diff --git a/articles/media/channels/cortana-AddUserProfile.png b/articles/media/channels/cortana-AddUserProfile.png deleted file mode 100644 index f7e4f9265..000000000 Binary files a/articles/media/channels/cortana-AddUserProfile.png and /dev/null differ diff --git a/articles/media/channels/cortana-addchannel.png b/articles/media/channels/cortana-addchannel.png deleted file mode 100644 index 33dff537a..000000000 Binary files a/articles/media/channels/cortana-addchannel.png and /dev/null differ diff --git a/articles/media/channels/cortana-connectedAccount.png b/articles/media/channels/cortana-connectedAccount.png deleted file mode 100644 index b0a74102f..000000000 Binary files a/articles/media/channels/cortana-connectedAccount.png and /dev/null differ diff --git a/articles/media/channels/cortana-defaultsettings.png b/articles/media/channels/cortana-defaultsettings.png deleted file mode 100644 index 857ed1913..000000000 Binary files a/articles/media/channels/cortana-defaultsettings.png and /dev/null differ diff --git a/articles/media/channels/cortana-manage-knowledge-store.png b/articles/media/channels/cortana-manage-knowledge-store.png deleted file mode 100644 index 06a21dfd5..000000000 Binary files a/articles/media/channels/cortana-manage-knowledge-store.png and /dev/null differ diff --git a/articles/media/channels/cortana-manageidentity-1.png b/articles/media/channels/cortana-manageidentity-1.png deleted file mode 100644 index cc5fcbc9b..000000000 Binary files a/articles/media/channels/cortana-manageidentity-1.png and /dev/null differ diff --git a/articles/media/channels/cortana-manageidentity-2.png b/articles/media/channels/cortana-manageidentity-2.png deleted file mode 100644 index 546821dd3..000000000 Binary files a/articles/media/channels/cortana-manageidentity-2.png and /dev/null differ diff --git a/articles/media/channels/cortana_generalInfo.png b/articles/media/channels/cortana_generalInfo.png deleted file mode 100644 index af0bb0e30..000000000 Binary files a/articles/media/channels/cortana_generalInfo.png and /dev/null differ diff --git a/articles/media/channels/cortana_skills-slide-02.png b/articles/media/channels/cortana_skills-slide-02.png deleted file mode 100644 index 7c53463e0..000000000 Binary files a/articles/media/channels/cortana_skills-slide-02.png and /dev/null differ diff --git a/articles/media/channels/cortana_skills-slide-03.png b/articles/media/channels/cortana_skills-slide-03.png deleted file mode 100644 index 980034c2f..000000000 Binary files a/articles/media/channels/cortana_skills-slide-03.png and /dev/null differ diff --git a/articles/media/channels/cortana_skills-slide-04.png b/articles/media/channels/cortana_skills-slide-04.png deleted file mode 100644 index 2afc19d34..000000000 Binary files a/articles/media/channels/cortana_skills-slide-04.png and /dev/null differ diff --git a/articles/media/channels/cortana_skills-slide-05.png b/articles/media/channels/cortana_skills-slide-05.png deleted file mode 100644 index 9dcdc70fc..000000000 Binary files a/articles/media/channels/cortana_skills-slide-05.png and /dev/null differ diff --git a/articles/media/channels/cortana_skills-slide-06.png b/articles/media/channels/cortana_skills-slide-06.png deleted file mode 100644 index a397aa666..000000000 Binary files a/articles/media/channels/cortana_skills-slide-06.png and /dev/null differ diff --git a/articles/media/channels/create_new_botlet1.png b/articles/media/channels/create_new_botlet1.png deleted file mode 100644 index 85cf1f259..000000000 Binary files a/articles/media/channels/create_new_botlet1.png and /dev/null differ diff --git a/articles/media/channels/direct-line-extension-architecture.png b/articles/media/channels/direct-line-extension-architecture.png deleted file mode 100644 index b28640157..000000000 Binary files a/articles/media/channels/direct-line-extension-architecture.png and /dev/null differ diff --git a/articles/media/channels/direct-line-extension-extension-keys-net-client.png b/articles/media/channels/direct-line-extension-extension-keys-net-client.png deleted file mode 100644 index 82c3399e1..000000000 Binary files a/articles/media/channels/direct-line-extension-extension-keys-net-client.png and /dev/null differ diff --git a/articles/media/channels/direct-line-extension-extension-keys.png b/articles/media/channels/direct-line-extension-extension-keys.png deleted file mode 100644 index 56f33c260..000000000 Binary files a/articles/media/channels/direct-line-extension-extension-keys.png and /dev/null differ diff --git a/articles/media/channels/direct-line-extension-vnet.png b/articles/media/channels/direct-line-extension-vnet.png deleted file mode 100644 index 257673876..000000000 Binary files a/articles/media/channels/direct-line-extension-vnet.png and /dev/null differ diff --git a/articles/media/channels/fb-create-messenger-bot-app-id.png b/articles/media/channels/fb-create-messenger-bot-app-id.png deleted file mode 100644 index 4495af6f6..000000000 Binary files a/articles/media/channels/fb-create-messenger-bot-app-id.png and /dev/null differ diff --git a/articles/media/channels/fb-create-messenger-bot-app.png b/articles/media/channels/fb-create-messenger-bot-app.png deleted file mode 100644 index bccc6df20..000000000 Binary files a/articles/media/channels/fb-create-messenger-bot-app.png and /dev/null differ diff --git a/articles/media/channels/fb-credentials2.png b/articles/media/channels/fb-credentials2.png deleted file mode 100644 index 0cb29a2eb..000000000 Binary files a/articles/media/channels/fb-credentials2.png and /dev/null differ diff --git a/articles/media/channels/fb-integration.png b/articles/media/channels/fb-integration.png deleted file mode 100644 index bcf9ff2d6..000000000 Binary files a/articles/media/channels/fb-integration.png and /dev/null differ diff --git a/articles/media/channels/fb-keys.png b/articles/media/channels/fb-keys.png deleted file mode 100644 index f3430acb5..000000000 Binary files a/articles/media/channels/fb-keys.png and /dev/null differ diff --git a/articles/media/channels/fb-messenger-bot-api-settings.PNG b/articles/media/channels/fb-messenger-bot-api-settings.PNG deleted file mode 100644 index 05022ede7..000000000 Binary files a/articles/media/channels/fb-messenger-bot-api-settings.PNG and /dev/null differ diff --git a/articles/media/channels/fb-messenger-bot-config-channel.PNG b/articles/media/channels/fb-messenger-bot-config-channel.PNG deleted file mode 100644 index 3ffd29625..000000000 Binary files a/articles/media/channels/fb-messenger-bot-config-channel.PNG and /dev/null differ diff --git a/articles/media/channels/fb-messenger-bot-config-webhooks-page.PNG b/articles/media/channels/fb-messenger-bot-config-webhooks-page.PNG deleted file mode 100644 index e6e838533..000000000 Binary files a/articles/media/channels/fb-messenger-bot-config-webhooks-page.PNG and /dev/null differ diff --git a/articles/media/channels/fb-messenger-bot-config-webhooks.png b/articles/media/channels/fb-messenger-bot-config-webhooks.png deleted file mode 100644 index c66b4a80e..000000000 Binary files a/articles/media/channels/fb-messenger-bot-config-webhooks.png and /dev/null differ diff --git a/articles/media/channels/fb-messenger-bot-enable-messenger.PNG b/articles/media/channels/fb-messenger-bot-enable-messenger.PNG deleted file mode 100644 index de02ec9f6..000000000 Binary files a/articles/media/channels/fb-messenger-bot-enable-messenger.PNG and /dev/null differ diff --git a/articles/media/channels/fb-messenger-bot-get-appid-secret.png b/articles/media/channels/fb-messenger-bot-get-appid-secret.png deleted file mode 100644 index 0d0aa1892..000000000 Binary files a/articles/media/channels/fb-messenger-bot-get-appid-secret.png and /dev/null differ diff --git a/articles/media/channels/fb-messenger-bot-permissions.png b/articles/media/channels/fb-messenger-bot-permissions.png deleted file mode 100644 index 1b3eb40e2..000000000 Binary files a/articles/media/channels/fb-messenger-bot-permissions.png and /dev/null differ diff --git a/articles/media/channels/fb-messenger-bot-select-messenger-page.PNG b/articles/media/channels/fb-messenger-bot-select-messenger-page.PNG deleted file mode 100644 index 926c29950..000000000 Binary files a/articles/media/channels/fb-messenger-bot-select-messenger-page.PNG and /dev/null differ diff --git a/articles/media/channels/fb-messenger-bot-webhooks.PNG b/articles/media/channels/fb-messenger-bot-webhooks.PNG deleted file mode 100644 index 68b9231a9..000000000 Binary files a/articles/media/channels/fb-messenger-bot-webhooks.PNG and /dev/null differ diff --git a/articles/media/channels/fb-page.png b/articles/media/channels/fb-page.png deleted file mode 100644 index d56725cf4..000000000 Binary files a/articles/media/channels/fb-page.png and /dev/null differ diff --git a/articles/media/channels/fb-version-upgrade.png b/articles/media/channels/fb-version-upgrade.png deleted file mode 100644 index 2c4ab0e59..000000000 Binary files a/articles/media/channels/fb-version-upgrade.png and /dev/null differ diff --git a/articles/media/channels/kik-configure.png b/articles/media/channels/kik-configure.png deleted file mode 100644 index 842894faf..000000000 Binary files a/articles/media/channels/kik-configure.png and /dev/null differ diff --git a/articles/media/channels/kik-creds.png b/articles/media/channels/kik-creds.png deleted file mode 100644 index 469a42213..000000000 Binary files a/articles/media/channels/kik-creds.png and /dev/null differ diff --git a/articles/media/channels/kik-dev-portal.png b/articles/media/channels/kik-dev-portal.png deleted file mode 100644 index eef5d21ed..000000000 Binary files a/articles/media/channels/kik-dev-portal.png and /dev/null differ diff --git a/articles/media/channels/kik-phone.png b/articles/media/channels/kik-phone.png deleted file mode 100644 index eebda4887..000000000 Binary files a/articles/media/channels/kik-phone.png and /dev/null differ diff --git a/articles/media/channels/kik-signup.png b/articles/media/channels/kik-signup.png deleted file mode 100644 index 7d29b1bee..000000000 Binary files a/articles/media/channels/kik-signup.png and /dev/null differ diff --git a/articles/media/channels/new_botlet_1of2.png b/articles/media/channels/new_botlet_1of2.png deleted file mode 100644 index ecc28b4f4..000000000 Binary files a/articles/media/channels/new_botlet_1of2.png and /dev/null differ diff --git a/articles/media/channels/new_botlet_2of2.png b/articles/media/channels/new_botlet_2of2.png deleted file mode 100644 index b288700c6..000000000 Binary files a/articles/media/channels/new_botlet_2of2.png and /dev/null differ diff --git a/articles/media/channels/new_organization.png b/articles/media/channels/new_organization.png deleted file mode 100644 index 62a527cc2..000000000 Binary files a/articles/media/channels/new_organization.png and /dev/null differ diff --git a/articles/media/channels/publish_menu_tab_2.png b/articles/media/channels/publish_menu_tab_2.png deleted file mode 100644 index 232055705..000000000 Binary files a/articles/media/channels/publish_menu_tab_2.png and /dev/null differ diff --git a/articles/media/channels/s4b-enable.png b/articles/media/channels/s4b-enable.png deleted file mode 100644 index dcb5367d8..000000000 Binary files a/articles/media/channels/s4b-enable.png and /dev/null differ diff --git a/articles/media/channels/skype-addchannel.png b/articles/media/channels/skype-addchannel.png deleted file mode 100644 index 34c6b76da..000000000 Binary files a/articles/media/channels/skype-addchannel.png and /dev/null differ diff --git a/articles/media/channels/skype_configure.PNG b/articles/media/channels/skype_configure.PNG deleted file mode 100644 index 7bcac3212..000000000 Binary files a/articles/media/channels/skype_configure.PNG and /dev/null differ diff --git a/articles/media/channels/slack-AppCredentials.png b/articles/media/channels/slack-AppCredentials.png deleted file mode 100644 index cc469e681..000000000 Binary files a/articles/media/channels/slack-AppCredentials.png and /dev/null differ diff --git a/articles/media/channels/slack-CreateApp-AddBotUser.png b/articles/media/channels/slack-CreateApp-AddBotUser.png deleted file mode 100644 index 24bf1cb91..000000000 Binary files a/articles/media/channels/slack-CreateApp-AddBotUser.png and /dev/null differ diff --git a/articles/media/channels/slack-CreateApp.png b/articles/media/channels/slack-CreateApp.png deleted file mode 100644 index bdd475505..000000000 Binary files a/articles/media/channels/slack-CreateApp.png and /dev/null differ diff --git a/articles/media/channels/slack-CreateBot.png b/articles/media/channels/slack-CreateBot.png deleted file mode 100644 index 6e4fc4a6f..000000000 Binary files a/articles/media/channels/slack-CreateBot.png and /dev/null differ diff --git a/articles/media/channels/slack-EnableEvents.png b/articles/media/channels/slack-EnableEvents.png deleted file mode 100644 index 6067b28f8..000000000 Binary files a/articles/media/channels/slack-EnableEvents.png and /dev/null differ diff --git a/articles/media/channels/slack-EnableMessages.png b/articles/media/channels/slack-EnableMessages.png deleted file mode 100644 index 84fb0ed07..000000000 Binary files a/articles/media/channels/slack-EnableMessages.png and /dev/null differ diff --git a/articles/media/channels/slack-MessageURL.png b/articles/media/channels/slack-MessageURL.png deleted file mode 100644 index 1d50122da..000000000 Binary files a/articles/media/channels/slack-MessageURL.png and /dev/null differ diff --git a/articles/media/channels/slack-NewApp.png b/articles/media/channels/slack-NewApp.png deleted file mode 100644 index e68479a4d..000000000 Binary files a/articles/media/channels/slack-NewApp.png and /dev/null differ diff --git a/articles/media/channels/slack-RedirectURL.png b/articles/media/channels/slack-RedirectURL.png deleted file mode 100644 index 043bcf2e0..000000000 Binary files a/articles/media/channels/slack-RedirectURL.png and /dev/null differ diff --git a/articles/media/channels/slack-StepAuth.png b/articles/media/channels/slack-StepAuth.png deleted file mode 100644 index 9ec29228e..000000000 Binary files a/articles/media/channels/slack-StepAuth.png and /dev/null differ diff --git a/articles/media/channels/slack-SubmitCredentials.png b/articles/media/channels/slack-SubmitCredentials.png deleted file mode 100644 index 265f970ed..000000000 Binary files a/articles/media/channels/slack-SubmitCredentials.png and /dev/null differ diff --git a/articles/media/channels/slack-SubscribeEvents-a.PNG b/articles/media/channels/slack-SubscribeEvents-a.PNG deleted file mode 100644 index 23dfdf930..000000000 Binary files a/articles/media/channels/slack-SubscribeEvents-a.PNG and /dev/null differ diff --git a/articles/media/channels/slack-SubscribeEvents-b.PNG b/articles/media/channels/slack-SubscribeEvents-b.PNG deleted file mode 100644 index ccdc16d57..000000000 Binary files a/articles/media/channels/slack-SubscribeEvents-b.PNG and /dev/null differ diff --git a/articles/media/channels/slack-SubscribeEvents-c.PNG b/articles/media/channels/slack-SubscribeEvents-c.PNG deleted file mode 100644 index 5d423218d..000000000 Binary files a/articles/media/channels/slack-SubscribeEvents-c.PNG and /dev/null differ diff --git a/articles/media/channels/tg-StepBotCreated.png b/articles/media/channels/tg-StepBotCreated.png deleted file mode 100644 index df830b0cd..000000000 Binary files a/articles/media/channels/tg-StepBotCreated.png and /dev/null differ diff --git a/articles/media/channels/tg-StepNameBot.png b/articles/media/channels/tg-StepNameBot.png deleted file mode 100644 index 9a6cce37d..000000000 Binary files a/articles/media/channels/tg-StepNameBot.png and /dev/null differ diff --git a/articles/media/channels/tg-StepNewBot.png b/articles/media/channels/tg-StepNewBot.png deleted file mode 100644 index be03ce4e1..000000000 Binary files a/articles/media/channels/tg-StepNewBot.png and /dev/null differ diff --git a/articles/media/channels/tg-StepUsername.png b/articles/media/channels/tg-StepUsername.png deleted file mode 100644 index 668817f5e..000000000 Binary files a/articles/media/channels/tg-StepUsername.png and /dev/null differ diff --git a/articles/media/channels/tg-StepVisitBotFather.png b/articles/media/channels/tg-StepVisitBotFather.png deleted file mode 100644 index 758b7e835..000000000 Binary files a/articles/media/channels/tg-StepVisitBotFather.png and /dev/null differ diff --git a/articles/media/channels/tg-accessToken-Azure.png b/articles/media/channels/tg-accessToken-Azure.png deleted file mode 100644 index cca77b016..000000000 Binary files a/articles/media/channels/tg-accessToken-Azure.png and /dev/null differ diff --git a/articles/media/channels/tg-botEnabled-Azure.png b/articles/media/channels/tg-botEnabled-Azure.png deleted file mode 100644 index 8a86340a5..000000000 Binary files a/articles/media/channels/tg-botEnabled-Azure.png and /dev/null differ diff --git a/articles/media/channels/tg-connectBot-Azure.png b/articles/media/channels/tg-connectBot-Azure.png deleted file mode 100644 index d5b1bdca9..000000000 Binary files a/articles/media/channels/tg-connectBot-Azure.png and /dev/null differ diff --git a/articles/media/channels/tree_create_new_botlet.png b/articles/media/channels/tree_create_new_botlet.png deleted file mode 100644 index 424181599..000000000 Binary files a/articles/media/channels/tree_create_new_botlet.png and /dev/null differ diff --git a/articles/media/channels/twi-StepAuth.png b/articles/media/channels/twi-StepAuth.png deleted file mode 100644 index 79efa7a12..000000000 Binary files a/articles/media/channels/twi-StepAuth.png and /dev/null differ diff --git a/articles/media/channels/twi-StepPhone.png b/articles/media/channels/twi-StepPhone.png deleted file mode 100644 index 6fb3a87e5..000000000 Binary files a/articles/media/channels/twi-StepPhone.png and /dev/null differ diff --git a/articles/media/channels/twi-StepPhone2.png b/articles/media/channels/twi-StepPhone2.png deleted file mode 100644 index 66f9d6a8c..000000000 Binary files a/articles/media/channels/twi-StepPhone2.png and /dev/null differ diff --git a/articles/media/channels/twi-StepPhone3.PNG b/articles/media/channels/twi-StepPhone3.PNG deleted file mode 100644 index 9bb160a37..000000000 Binary files a/articles/media/channels/twi-StepPhone3.PNG and /dev/null differ diff --git a/articles/media/channels/twi-StepSubmit.png b/articles/media/channels/twi-StepSubmit.png deleted file mode 100644 index c2fc3ec3c..000000000 Binary files a/articles/media/channels/twi-StepSubmit.png and /dev/null differ diff --git a/articles/media/channels/twi-StepTwiml.png b/articles/media/channels/twi-StepTwiml.png deleted file mode 100644 index 910febca4..000000000 Binary files a/articles/media/channels/twi-StepTwiml.png and /dev/null differ diff --git a/articles/media/channels/wechat-change-language.png b/articles/media/channels/wechat-change-language.png deleted file mode 100644 index 3b2cb21c7..000000000 Binary files a/articles/media/channels/wechat-change-language.png and /dev/null differ diff --git a/articles/media/channels/wechat-chat.png b/articles/media/channels/wechat-chat.png deleted file mode 100644 index 05502f2b1..000000000 Binary files a/articles/media/channels/wechat-chat.png and /dev/null differ diff --git a/articles/media/channels/wechat-register-account.png b/articles/media/channels/wechat-register-account.png deleted file mode 100644 index aa459f5a0..000000000 Binary files a/articles/media/channels/wechat-register-account.png and /dev/null differ diff --git a/articles/media/channels/wechat-sandbox-account-2.png b/articles/media/channels/wechat-sandbox-account-2.png deleted file mode 100644 index 013aad9b7..000000000 Binary files a/articles/media/channels/wechat-sandbox-account-2.png and /dev/null differ diff --git a/articles/media/channels/wechat-sandbox-account.png b/articles/media/channels/wechat-sandbox-account.png deleted file mode 100644 index 7fd436873..000000000 Binary files a/articles/media/channels/wechat-sandbox-account.png and /dev/null differ diff --git a/articles/media/channels/wechat-serviceaccount-console.png b/articles/media/channels/wechat-serviceaccount-console.png deleted file mode 100644 index 7ac33954a..000000000 Binary files a/articles/media/channels/wechat-serviceaccount-console.png and /dev/null differ diff --git a/articles/media/channels/wechat-subscribe.png b/articles/media/channels/wechat-subscribe.png deleted file mode 100644 index 412768fe6..000000000 Binary files a/articles/media/channels/wechat-subscribe.png and /dev/null differ diff --git a/articles/media/chatwidget-channel.png b/articles/media/chatwidget-channel.png deleted file mode 100644 index b0231f5f7..000000000 Binary files a/articles/media/chatwidget-channel.png and /dev/null differ diff --git a/articles/media/chatwidget-client.png b/articles/media/chatwidget-client.png deleted file mode 100644 index 0f82b9161..000000000 Binary files a/articles/media/chatwidget-client.png and /dev/null differ diff --git a/articles/media/chatwidget-overview.png b/articles/media/chatwidget-overview.png deleted file mode 100644 index f1f55ad28..000000000 Binary files a/articles/media/chatwidget-overview.png and /dev/null differ diff --git a/articles/media/complex-conversation-flows.png b/articles/media/complex-conversation-flows.png deleted file mode 100644 index 877e54974..000000000 Binary files a/articles/media/complex-conversation-flows.png and /dev/null differ diff --git a/articles/media/connector-getstarted-bot-running-localhost.png b/articles/media/connector-getstarted-bot-running-localhost.png deleted file mode 100644 index 1525bc259..000000000 Binary files a/articles/media/connector-getstarted-bot-running-localhost.png and /dev/null differ diff --git a/articles/media/connector-getstarted-create-project.png b/articles/media/connector-getstarted-create-project.png deleted file mode 100644 index e0baba586..000000000 Binary files a/articles/media/connector-getstarted-create-project.png and /dev/null differ diff --git a/articles/media/connector-getstarted-start-bot-locally.png b/articles/media/connector-getstarted-start-bot-locally.png deleted file mode 100644 index c566cbf72..000000000 Binary files a/articles/media/connector-getstarted-start-bot-locally.png and /dev/null differ diff --git a/articles/media/connector/auth_bot_connector_to_bot.png b/articles/media/connector/auth_bot_connector_to_bot.png deleted file mode 100644 index 3ca0ad168..000000000 Binary files a/articles/media/connector/auth_bot_connector_to_bot.png and /dev/null differ diff --git a/articles/media/connector/auth_bot_framework_emulator_to_bot.png b/articles/media/connector/auth_bot_framework_emulator_to_bot.png deleted file mode 100644 index 555faf93d..000000000 Binary files a/articles/media/connector/auth_bot_framework_emulator_to_bot.png and /dev/null differ diff --git a/articles/media/connector/auth_bot_to_bot_connector.png b/articles/media/connector/auth_bot_to_bot_connector.png deleted file mode 100644 index 0d395e135..000000000 Binary files a/articles/media/connector/auth_bot_to_bot_connector.png and /dev/null differ diff --git a/articles/media/continuous-deployment-consumption-download.png b/articles/media/continuous-deployment-consumption-download.png deleted file mode 100644 index 4db1dfd0e..000000000 Binary files a/articles/media/continuous-deployment-consumption-download.png and /dev/null differ diff --git a/articles/media/continuous-integration-disconnect.png b/articles/media/continuous-integration-disconnect.png deleted file mode 100644 index ffc32e8d0..000000000 Binary files a/articles/media/continuous-integration-disconnect.png and /dev/null differ diff --git a/articles/media/continuous-integration-sourcecontrolsystem.png b/articles/media/continuous-integration-sourcecontrolsystem.png deleted file mode 100644 index a4673a911..000000000 Binary files a/articles/media/continuous-integration-sourcecontrolsystem.png and /dev/null differ diff --git a/articles/media/continuous-integration-sources.png b/articles/media/continuous-integration-sources.png deleted file mode 100644 index 696614768..000000000 Binary files a/articles/media/continuous-integration-sources.png and /dev/null differ diff --git a/articles/media/cortana-add.png b/articles/media/cortana-add.png deleted file mode 100644 index 22aec25fd..000000000 Binary files a/articles/media/cortana-add.png and /dev/null differ diff --git a/articles/media/cortana/add-user-profile-data.png b/articles/media/cortana/add-user-profile-data.png deleted file mode 100644 index b39c3b320..000000000 Binary files a/articles/media/cortana/add-user-profile-data.png and /dev/null differ diff --git a/articles/media/cortana/cortana-add.png b/articles/media/cortana/cortana-add.png deleted file mode 100644 index de8b09612..000000000 Binary files a/articles/media/cortana/cortana-add.png and /dev/null differ diff --git a/articles/media/cortana/cortana-edit.png b/articles/media/cortana/cortana-edit.png deleted file mode 100644 index e9b64f3a0..000000000 Binary files a/articles/media/cortana/cortana-edit.png and /dev/null differ diff --git a/articles/media/cortana/cortana-invocation-name-callout.png b/articles/media/cortana/cortana-invocation-name-callout.png deleted file mode 100644 index 026530366..000000000 Binary files a/articles/media/cortana/cortana-invocation-name-callout.png and /dev/null differ diff --git a/articles/media/cortana/cortana-notebook.png b/articles/media/cortana/cortana-notebook.png deleted file mode 100644 index f969c21dc..000000000 Binary files a/articles/media/cortana/cortana-notebook.png and /dev/null differ diff --git a/articles/media/cortana/cortana-register.png b/articles/media/cortana/cortana-register.png deleted file mode 100644 index 76562bd7a..000000000 Binary files a/articles/media/cortana/cortana-register.png and /dev/null differ diff --git a/articles/media/cortana/cortana-speech-luis-priming.png b/articles/media/cortana/cortana-speech-luis-priming.png deleted file mode 100644 index ce1390ca2..000000000 Binary files a/articles/media/cortana/cortana-speech-luis-priming.png and /dev/null differ diff --git a/articles/media/debug-vscode/builder-debug-step1.png b/articles/media/debug-vscode/builder-debug-step1.png deleted file mode 100644 index 8b8bc09d6..000000000 Binary files a/articles/media/debug-vscode/builder-debug-step1.png and /dev/null differ diff --git a/articles/media/debug-vscode/builder-debug-step2.png b/articles/media/debug-vscode/builder-debug-step2.png deleted file mode 100644 index 8a7c950a4..000000000 Binary files a/articles/media/debug-vscode/builder-debug-step2.png and /dev/null differ diff --git a/articles/media/debug-vscode/builder-debug-step3.png b/articles/media/debug-vscode/builder-debug-step3.png deleted file mode 100644 index ec5da5753..000000000 Binary files a/articles/media/debug-vscode/builder-debug-step3.png and /dev/null differ diff --git a/articles/media/debug-vscode/builder-debug-step4.png b/articles/media/debug-vscode/builder-debug-step4.png deleted file mode 100644 index e337e2f4b..000000000 Binary files a/articles/media/debug-vscode/builder-debug-step4.png and /dev/null differ diff --git a/articles/media/debug-vscode/builder-debug-step5.png b/articles/media/debug-vscode/builder-debug-step5.png deleted file mode 100644 index 038d1e97e..000000000 Binary files a/articles/media/debug-vscode/builder-debug-step5.png and /dev/null differ diff --git a/articles/media/deploy-bot-visual-studio/net-app-service-create.png b/articles/media/deploy-bot-visual-studio/net-app-service-create.png deleted file mode 100644 index d5b4f4169..000000000 Binary files a/articles/media/deploy-bot-visual-studio/net-app-service-create.png and /dev/null differ diff --git a/articles/media/deploy-bot-visual-studio/net-configuration.png b/articles/media/deploy-bot-visual-studio/net-configuration.png deleted file mode 100644 index 9b026e728..000000000 Binary files a/articles/media/deploy-bot-visual-studio/net-configuration.png and /dev/null differ diff --git a/articles/media/deploy-bot-visual-studio/net-destination.png b/articles/media/deploy-bot-visual-studio/net-destination.png deleted file mode 100644 index edd96520e..000000000 Binary files a/articles/media/deploy-bot-visual-studio/net-destination.png and /dev/null differ diff --git a/articles/media/deploy-bot-visual-studio/net-dialog.png b/articles/media/deploy-bot-visual-studio/net-dialog.png deleted file mode 100644 index dbcc073d6..000000000 Binary files a/articles/media/deploy-bot-visual-studio/net-dialog.png and /dev/null differ diff --git a/articles/media/deploy-bot-visual-studio/net-publish.png b/articles/media/deploy-bot-visual-studio/net-publish.png deleted file mode 100644 index 36ee396a0..000000000 Binary files a/articles/media/deploy-bot-visual-studio/net-publish.png and /dev/null differ diff --git a/articles/media/deploy-bot-visual-studio/node-app-service-create.png b/articles/media/deploy-bot-visual-studio/node-app-service-create.png deleted file mode 100644 index c182236da..000000000 Binary files a/articles/media/deploy-bot-visual-studio/node-app-service-create.png and /dev/null differ diff --git a/articles/media/deploy-bot-visual-studio/node-app-service.png b/articles/media/deploy-bot-visual-studio/node-app-service.png deleted file mode 100644 index 76ee41898..000000000 Binary files a/articles/media/deploy-bot-visual-studio/node-app-service.png and /dev/null differ diff --git a/articles/media/deploy-bot-visual-studio/node-configuration.png b/articles/media/deploy-bot-visual-studio/node-configuration.png deleted file mode 100644 index 6b45ae141..000000000 Binary files a/articles/media/deploy-bot-visual-studio/node-configuration.png and /dev/null differ diff --git a/articles/media/deploy-bot-visual-studio/node-create-project.png b/articles/media/deploy-bot-visual-studio/node-create-project.png deleted file mode 100644 index 816f457a5..000000000 Binary files a/articles/media/deploy-bot-visual-studio/node-create-project.png and /dev/null differ diff --git a/articles/media/deploy-bot-visual-studio/node-dialog.png b/articles/media/deploy-bot-visual-studio/node-dialog.png deleted file mode 100644 index dbcc073d6..000000000 Binary files a/articles/media/deploy-bot-visual-studio/node-dialog.png and /dev/null differ diff --git a/articles/media/deploy-bot-visual-studio/node-publish-to-azure.png b/articles/media/deploy-bot-visual-studio/node-publish-to-azure.png deleted file mode 100644 index 8770421f7..000000000 Binary files a/articles/media/deploy-bot-visual-studio/node-publish-to-azure.png and /dev/null differ diff --git a/articles/media/deploy-bot-visual-studio/node-publish.png b/articles/media/deploy-bot-visual-studio/node-publish.png deleted file mode 100644 index d6baedd0c..000000000 Binary files a/articles/media/deploy-bot-visual-studio/node-publish.png and /dev/null differ diff --git a/articles/media/designing-bots/bot-dunno.png b/articles/media/designing-bots/bot-dunno.png deleted file mode 100644 index 363c15ac8..000000000 Binary files a/articles/media/designing-bots/bot-dunno.png and /dev/null differ diff --git a/articles/media/designing-bots/bot1.png b/articles/media/designing-bots/bot1.png deleted file mode 100644 index 68ce598ad..000000000 Binary files a/articles/media/designing-bots/bot1.png and /dev/null differ diff --git a/articles/media/designing-bots/capabilities/proactive1.png b/articles/media/designing-bots/capabilities/proactive1.png deleted file mode 100644 index ca9b6b488..000000000 Binary files a/articles/media/designing-bots/capabilities/proactive1.png and /dev/null differ diff --git a/articles/media/designing-bots/capabilities/trigger-actions.png b/articles/media/designing-bots/capabilities/trigger-actions.png deleted file mode 100644 index e063944b8..000000000 Binary files a/articles/media/designing-bots/capabilities/trigger-actions.png and /dev/null differ diff --git a/articles/media/designing-bots/core/Slide.png b/articles/media/designing-bots/core/Slide.png deleted file mode 100644 index eeba3bde3..000000000 Binary files a/articles/media/designing-bots/core/Slide.png and /dev/null differ diff --git a/articles/media/designing-bots/core/dialogs-screens-small.png b/articles/media/designing-bots/core/dialogs-screens-small.png deleted file mode 100644 index 66bc8fc35..000000000 Binary files a/articles/media/designing-bots/core/dialogs-screens-small.png and /dev/null differ diff --git a/articles/media/designing-bots/core/dialogs-screens.png b/articles/media/designing-bots/core/dialogs-screens.png deleted file mode 100644 index 17cfe8ec4..000000000 Binary files a/articles/media/designing-bots/core/dialogs-screens.png and /dev/null differ diff --git a/articles/media/designing-bots/core/hello-bot.png b/articles/media/designing-bots/core/hello-bot.png deleted file mode 100644 index 1ad0d6db7..000000000 Binary files a/articles/media/designing-bots/core/hello-bot.png and /dev/null differ diff --git a/articles/media/designing-bots/core/speech-limit1.png b/articles/media/designing-bots/core/speech-limit1.png deleted file mode 100644 index 94bd23dc3..000000000 Binary files a/articles/media/designing-bots/core/speech-limit1.png and /dev/null differ diff --git a/articles/media/designing-bots/core/speech-limit2.png b/articles/media/designing-bots/core/speech-limit2.png deleted file mode 100644 index 14bacf8e1..000000000 Binary files a/articles/media/designing-bots/core/speech-limit2.png and /dev/null differ diff --git a/articles/media/designing-bots/core/speech-limit3.png b/articles/media/designing-bots/core/speech-limit3.png deleted file mode 100644 index 77ae41b06..000000000 Binary files a/articles/media/designing-bots/core/speech-limit3.png and /dev/null differ diff --git a/articles/media/designing-bots/core/speech-limit4.png b/articles/media/designing-bots/core/speech-limit4.png deleted file mode 100644 index e3d9309af..000000000 Binary files a/articles/media/designing-bots/core/speech-limit4.png and /dev/null differ diff --git a/articles/media/designing-bots/gotit-bot.png b/articles/media/designing-bots/gotit-bot.png deleted file mode 100644 index df2b5e070..000000000 Binary files a/articles/media/designing-bots/gotit-bot.png and /dev/null differ diff --git a/articles/media/designing-bots/happy-bot.png b/articles/media/designing-bots/happy-bot.png deleted file mode 100644 index e06d49434..000000000 Binary files a/articles/media/designing-bots/happy-bot.png and /dev/null differ diff --git a/articles/media/designing-bots/patterns/QnAMakerAlternatives.PNG b/articles/media/designing-bots/patterns/QnAMakerAlternatives.PNG deleted file mode 100644 index cec82ea62..000000000 Binary files a/articles/media/designing-bots/patterns/QnAMakerAlternatives.PNG and /dev/null differ diff --git a/articles/media/designing-bots/patterns/Unity3D.png b/articles/media/designing-bots/patterns/Unity3D.png deleted file mode 100644 index 89930becb..000000000 Binary files a/articles/media/designing-bots/patterns/Unity3D.png and /dev/null differ diff --git a/articles/media/designing-bots/patterns/back-channel.png b/articles/media/designing-bots/patterns/back-channel.png deleted file mode 100644 index 881483f56..000000000 Binary files a/articles/media/designing-bots/patterns/back-channel.png and /dev/null differ diff --git a/articles/media/designing-bots/patterns/bot-to-web1.png b/articles/media/designing-bots/patterns/bot-to-web1.png deleted file mode 100644 index 5fbc4afca..000000000 Binary files a/articles/media/designing-bots/patterns/bot-to-web1.png and /dev/null differ diff --git a/articles/media/designing-bots/patterns/devilMakesThree.PNG b/articles/media/designing-bots/patterns/devilMakesThree.PNG deleted file mode 100644 index 411219a8e..000000000 Binary files a/articles/media/designing-bots/patterns/devilMakesThree.PNG and /dev/null differ diff --git a/articles/media/designing-bots/sad-bot.png b/articles/media/designing-bots/sad-bot.png deleted file mode 100644 index 24fa9ec41..000000000 Binary files a/articles/media/designing-bots/sad-bot.png and /dev/null differ diff --git a/articles/media/designing-bots/thinking-bot.png b/articles/media/designing-bots/thinking-bot.png deleted file mode 100644 index 88013fa05..000000000 Binary files a/articles/media/designing-bots/thinking-bot.png and /dev/null differ diff --git a/articles/media/direct-line-configure.png b/articles/media/direct-line-configure.png deleted file mode 100644 index a2058b857..000000000 Binary files a/articles/media/direct-line-configure.png and /dev/null differ diff --git a/articles/media/directline/channels-registrated-resource.PNG b/articles/media/directline/channels-registrated-resource.PNG deleted file mode 100644 index 60f06c409..000000000 Binary files a/articles/media/directline/channels-registrated-resource.PNG and /dev/null differ diff --git a/articles/media/directline/channels-registration-config.PNG b/articles/media/directline/channels-registration-config.PNG deleted file mode 100644 index c2fe8ea2b..000000000 Binary files a/articles/media/directline/channels-registration-config.PNG and /dev/null differ diff --git a/articles/media/directline/channels-registration.PNG b/articles/media/directline/channels-registration.PNG deleted file mode 100644 index c462a15e1..000000000 Binary files a/articles/media/directline/channels-registration.PNG and /dev/null differ diff --git a/articles/media/directline/channels-resource-group-deployments.PNG b/articles/media/directline/channels-resource-group-deployments.PNG deleted file mode 100644 index edbf3eb93..000000000 Binary files a/articles/media/directline/channels-resource-group-deployments.PNG and /dev/null differ diff --git a/articles/media/directline/channels-resource-group-inputs.PNG b/articles/media/directline/channels-resource-group-inputs.PNG deleted file mode 100644 index 2e21a941c..000000000 Binary files a/articles/media/directline/channels-resource-group-inputs.PNG and /dev/null differ diff --git a/articles/media/directory.jpg b/articles/media/directory.jpg deleted file mode 100644 index 098846fb6..000000000 Binary files a/articles/media/directory.jpg and /dev/null differ diff --git a/articles/media/dotnet-core-authentication/create-asp-net-core-2x-project.png b/articles/media/dotnet-core-authentication/create-asp-net-core-2x-project.png deleted file mode 100644 index 5e0bacc0e..000000000 Binary files a/articles/media/dotnet-core-authentication/create-asp-net-core-2x-project.png and /dev/null differ diff --git a/articles/media/dotnet-core-authentication/nuget-package-net-core-version.png b/articles/media/dotnet-core-authentication/nuget-package-net-core-version.png deleted file mode 100644 index 89af8a075..000000000 Binary files a/articles/media/dotnet-core-authentication/nuget-package-net-core-version.png and /dev/null differ diff --git a/articles/media/emulator-v4/bot-file-dropdown.png b/articles/media/emulator-v4/bot-file-dropdown.png deleted file mode 100644 index 7dc212599..000000000 Binary files a/articles/media/emulator-v4/bot-file-dropdown.png and /dev/null differ diff --git a/articles/media/emulator-v4/botfile-generated.png b/articles/media/emulator-v4/botfile-generated.png deleted file mode 100644 index 7c167303e..000000000 Binary files a/articles/media/emulator-v4/botfile-generated.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-azure-login-success.png b/articles/media/emulator-v4/emulator-azure-login-success.png deleted file mode 100644 index 60687f855..000000000 Binary files a/articles/media/emulator-v4/emulator-azure-login-success.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-azure-login.PNG b/articles/media/emulator-v4/emulator-azure-login.PNG deleted file mode 100644 index 97836c14c..000000000 Binary files a/articles/media/emulator-v4/emulator-azure-login.PNG and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-connect-luis-btn.png b/articles/media/emulator-v4/emulator-connect-luis-btn.png deleted file mode 100644 index 74f9d2b9f..000000000 Binary files a/articles/media/emulator-v4/emulator-connect-luis-btn.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-connect-qna-btn.png b/articles/media/emulator-v4/emulator-connect-qna-btn.png deleted file mode 100644 index fa531669b..000000000 Binary files a/articles/media/emulator-v4/emulator-connect-qna-btn.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-disable-data-1.png b/articles/media/emulator-v4/emulator-disable-data-1.png deleted file mode 100644 index ed692d05f..000000000 Binary files a/articles/media/emulator-v4/emulator-disable-data-1.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-disable-data-2.png b/articles/media/emulator-v4/emulator-disable-data-2.png deleted file mode 100644 index f5e9b2e5a..000000000 Binary files a/articles/media/emulator-v4/emulator-disable-data-2.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-disable-data-3.png b/articles/media/emulator-v4/emulator-disable-data-3.png deleted file mode 100644 index bb17b5102..000000000 Binary files a/articles/media/emulator-v4/emulator-disable-data-3.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-endpoint.png b/articles/media/emulator-v4/emulator-endpoint.png deleted file mode 100644 index 233fc4fae..000000000 Binary files a/articles/media/emulator-v4/emulator-endpoint.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-live-chat.png b/articles/media/emulator-v4/emulator-live-chat.png deleted file mode 100644 index 344e51f8e..000000000 Binary files a/articles/media/emulator-v4/emulator-live-chat.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-load-transcript.png b/articles/media/emulator-v4/emulator-load-transcript.png deleted file mode 100644 index 3703eacd1..000000000 Binary files a/articles/media/emulator-v4/emulator-load-transcript.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-localhost-settings.png b/articles/media/emulator-v4/emulator-localhost-settings.png deleted file mode 100644 index 448f60fee..000000000 Binary files a/articles/media/emulator-v4/emulator-localhost-settings.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-luis-inspector.png b/articles/media/emulator-v4/emulator-luis-inspector.png deleted file mode 100644 index 8b3afbb9d..000000000 Binary files a/articles/media/emulator-v4/emulator-luis-inspector.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-ngrok-path.png b/articles/media/emulator-v4/emulator-ngrok-path.png deleted file mode 100644 index e86c20d2e..000000000 Binary files a/articles/media/emulator-v4/emulator-ngrok-path.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-open-bot.png b/articles/media/emulator-v4/emulator-open-bot.png deleted file mode 100644 index 4eab91310..000000000 Binary files a/articles/media/emulator-v4/emulator-open-bot.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-qna-inspector.png b/articles/media/emulator-v4/emulator-qna-inspector.png deleted file mode 100644 index de149982c..000000000 Binary files a/articles/media/emulator-v4/emulator-qna-inspector.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-running-manage-state.png b/articles/media/emulator-v4/emulator-running-manage-state.png deleted file mode 100644 index aa4ba4d6e..000000000 Binary files a/articles/media/emulator-v4/emulator-running-manage-state.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-running.png b/articles/media/emulator-v4/emulator-running.png deleted file mode 100644 index a0e90a7a7..000000000 Binary files a/articles/media/emulator-v4/emulator-running.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-save-transcript.png b/articles/media/emulator-v4/emulator-save-transcript.png deleted file mode 100644 index af0b73502..000000000 Binary files a/articles/media/emulator-v4/emulator-save-transcript.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-services.png b/articles/media/emulator-v4/emulator-services.png deleted file mode 100644 index 80742bc00..000000000 Binary files a/articles/media/emulator-v4/emulator-services.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-view-message-activity-02.png b/articles/media/emulator-v4/emulator-view-message-activity-02.png deleted file mode 100644 index 4ded0fe30..000000000 Binary files a/articles/media/emulator-v4/emulator-view-message-activity-02.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-view-message-activity-03.png b/articles/media/emulator-v4/emulator-view-message-activity-03.png deleted file mode 100644 index 53559e6ac..000000000 Binary files a/articles/media/emulator-v4/emulator-view-message-activity-03.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-view-message-activity.png b/articles/media/emulator-v4/emulator-view-message-activity.png deleted file mode 100644 index 7665a2695..000000000 Binary files a/articles/media/emulator-v4/emulator-view-message-activity.png and /dev/null differ diff --git a/articles/media/emulator-v4/emulator-welcome.png b/articles/media/emulator-v4/emulator-welcome.png deleted file mode 100644 index 39324b79b..000000000 Binary files a/articles/media/emulator-v4/emulator-welcome.png and /dev/null differ diff --git a/articles/media/emulator-v4/js-quickstart.png b/articles/media/emulator-v4/js-quickstart.png deleted file mode 100644 index 3e63364f3..000000000 Binary files a/articles/media/emulator-v4/js-quickstart.png and /dev/null differ diff --git a/articles/media/emulator-v4/msbot-cli-window.png b/articles/media/emulator-v4/msbot-cli-window.png deleted file mode 100644 index 550f1318a..000000000 Binary files a/articles/media/emulator-v4/msbot-cli-window.png and /dev/null differ diff --git a/articles/media/emulator-v4/multi-turn-prompt-validation.png b/articles/media/emulator-v4/multi-turn-prompt-validation.png deleted file mode 100644 index 2b5211d43..000000000 Binary files a/articles/media/emulator-v4/multi-turn-prompt-validation.png and /dev/null differ diff --git a/articles/media/emulator-v4/multi-turn-prompt.png b/articles/media/emulator-v4/multi-turn-prompt.png deleted file mode 100644 index 86b506cbe..000000000 Binary files a/articles/media/emulator-v4/multi-turn-prompt.png and /dev/null differ diff --git a/articles/media/emulator-v4/nlp-luis-sample-testing.png b/articles/media/emulator-v4/nlp-luis-sample-testing.png deleted file mode 100644 index 9bbfdc626..000000000 Binary files a/articles/media/emulator-v4/nlp-luis-sample-testing.png and /dev/null differ diff --git a/articles/media/emulator-v4/qna-test-bot.png b/articles/media/emulator-v4/qna-test-bot.png deleted file mode 100644 index b8a35aefb..000000000 Binary files a/articles/media/emulator-v4/qna-test-bot.png and /dev/null differ diff --git a/articles/media/emulator-v4/test-complex-dialog.png b/articles/media/emulator-v4/test-complex-dialog.png deleted file mode 100644 index eae6b42a7..000000000 Binary files a/articles/media/emulator-v4/test-complex-dialog.png and /dev/null differ diff --git a/articles/media/emulator-v4/test-dialog-prompt.png b/articles/media/emulator-v4/test-dialog-prompt.png deleted file mode 100644 index 2d066a306..000000000 Binary files a/articles/media/emulator-v4/test-dialog-prompt.png and /dev/null differ diff --git a/articles/media/emulator/EmulatorUI.png b/articles/media/emulator/EmulatorUI.png deleted file mode 100644 index 3308ddf50..000000000 Binary files a/articles/media/emulator/EmulatorUI.png and /dev/null differ diff --git a/articles/media/emulator/dashboard.png b/articles/media/emulator/dashboard.png deleted file mode 100644 index 9b2a5f0a5..000000000 Binary files a/articles/media/emulator/dashboard.png and /dev/null differ diff --git a/articles/media/emulator/emulator-configure.jpg b/articles/media/emulator/emulator-configure.jpg deleted file mode 100644 index 36619f611..000000000 Binary files a/articles/media/emulator/emulator-configure.jpg and /dev/null differ diff --git a/articles/media/emulator/emulator-configure.png b/articles/media/emulator/emulator-configure.png deleted file mode 100644 index 78a004393..000000000 Binary files a/articles/media/emulator/emulator-configure.png and /dev/null differ diff --git a/articles/media/emulator/emulator-configure_ngrok_path.png b/articles/media/emulator/emulator-configure_ngrok_path.png deleted file mode 100644 index b80c2461a..000000000 Binary files a/articles/media/emulator/emulator-configure_ngrok_path.png and /dev/null differ diff --git a/articles/media/emulator/emulator-connect_localhost_credentials-original.png b/articles/media/emulator/emulator-connect_localhost_credentials-original.png deleted file mode 100644 index dc9ade3c3..000000000 Binary files a/articles/media/emulator/emulator-connect_localhost_credentials-original.png and /dev/null differ diff --git a/articles/media/emulator/emulator-connect_localhost_credentials.png b/articles/media/emulator/emulator-connect_localhost_credentials.png deleted file mode 100644 index 5284f8374..000000000 Binary files a/articles/media/emulator/emulator-connect_localhost_credentials.png and /dev/null differ diff --git a/articles/media/emulator/emulator-helloworld.jpg b/articles/media/emulator/emulator-helloworld.jpg deleted file mode 100644 index 105b993a6..000000000 Binary files a/articles/media/emulator/emulator-helloworld.jpg and /dev/null differ diff --git a/articles/media/emulator/emulator-helloworld.png b/articles/media/emulator/emulator-helloworld.png deleted file mode 100644 index 7dd06ce14..000000000 Binary files a/articles/media/emulator/emulator-helloworld.png and /dev/null differ diff --git a/articles/media/emulator/emulator-json.jpg b/articles/media/emulator/emulator-json.jpg deleted file mode 100644 index 7e5e02113..000000000 Binary files a/articles/media/emulator/emulator-json.jpg and /dev/null differ diff --git a/articles/media/emulator/emulator-ngrok-config.png b/articles/media/emulator/emulator-ngrok-config.png deleted file mode 100644 index 9884ec616..000000000 Binary files a/articles/media/emulator/emulator-ngrok-config.png and /dev/null differ diff --git a/articles/media/emulator/emulator-response.jpg b/articles/media/emulator/emulator-response.jpg deleted file mode 100644 index c51e0c1ac..000000000 Binary files a/articles/media/emulator/emulator-response.jpg and /dev/null differ diff --git a/articles/media/emulator/emulator-system-activities.png b/articles/media/emulator/emulator-system-activities.png deleted file mode 100644 index b27335ee2..000000000 Binary files a/articles/media/emulator/emulator-system-activities.png and /dev/null differ diff --git a/articles/media/emulator/emulator-testbot-cloud-config.png b/articles/media/emulator/emulator-testbot-cloud-config.png deleted file mode 100644 index ba4cf08f8..000000000 Binary files a/articles/media/emulator/emulator-testbot-cloud-config.png and /dev/null differ diff --git a/articles/media/emulator/emulator-testbot-ngrok-monitoring.png b/articles/media/emulator/emulator-testbot-ngrok-monitoring.png deleted file mode 100644 index 48fa4707b..000000000 Binary files a/articles/media/emulator/emulator-testbot-ngrok-monitoring.png and /dev/null differ diff --git a/articles/media/emulator/emulator-ui-new.png b/articles/media/emulator/emulator-ui-new.png deleted file mode 100644 index 5cf7c96c2..000000000 Binary files a/articles/media/emulator/emulator-ui-new.png and /dev/null differ diff --git a/articles/media/emulator/emulator-url.jpg b/articles/media/emulator/emulator-url.jpg deleted file mode 100644 index 7c91b6129..000000000 Binary files a/articles/media/emulator/emulator-url.jpg and /dev/null differ diff --git a/articles/media/emulator/emulator-url.png b/articles/media/emulator/emulator-url.png deleted file mode 100644 index e9af0059e..000000000 Binary files a/articles/media/emulator/emulator-url.png and /dev/null differ diff --git a/articles/media/emulator/newemulator-ubuntu.png b/articles/media/emulator/newemulator-ubuntu.png deleted file mode 100644 index 3340a20f9..000000000 Binary files a/articles/media/emulator/newemulator-ubuntu.png and /dev/null differ diff --git a/articles/media/hero-card.png b/articles/media/hero-card.png deleted file mode 100644 index 39601bd63..000000000 Binary files a/articles/media/hero-card.png and /dev/null differ diff --git a/articles/media/hero-card1.png b/articles/media/hero-card1.png deleted file mode 100644 index 3781764b4..000000000 Binary files a/articles/media/hero-card1.png and /dev/null differ diff --git a/articles/media/how-it-works/architecture-resize.png b/articles/media/how-it-works/architecture-resize.png deleted file mode 100644 index e6c419be7..000000000 Binary files a/articles/media/how-it-works/architecture-resize.png and /dev/null differ diff --git a/articles/media/how-it-works/architecture.png b/articles/media/how-it-works/architecture.png deleted file mode 100644 index c0b314bf2..000000000 Binary files a/articles/media/how-it-works/architecture.png and /dev/null differ diff --git a/articles/media/how-it-works/overview.png b/articles/media/how-it-works/overview.png deleted file mode 100644 index b5dda59be..000000000 Binary files a/articles/media/how-it-works/overview.png and /dev/null differ diff --git a/articles/media/index/azure_portal.png b/articles/media/index/azure_portal.png deleted file mode 100644 index 9b7e35cc7..000000000 Binary files a/articles/media/index/azure_portal.png and /dev/null differ diff --git a/articles/media/index/i_guidelines.png b/articles/media/index/i_guidelines.png deleted file mode 100644 index 84fa73bc2..000000000 Binary files a/articles/media/index/i_guidelines.png and /dev/null differ diff --git a/articles/media/index/i_overview.png b/articles/media/index/i_overview.png deleted file mode 100644 index b926e63bd..000000000 Binary files a/articles/media/index/i_overview.png and /dev/null differ diff --git a/articles/media/index/logo_bot.svg b/articles/media/index/logo_bot.svg deleted file mode 100644 index 3fd22c8b5..000000000 --- a/articles/media/index/logo_bot.svg +++ /dev/null @@ -1 +0,0 @@ -azure-bot-service-square-circle \ No newline at end of file diff --git a/articles/media/index/logo_csharp.svg b/articles/media/index/logo_csharp.svg deleted file mode 100644 index 8e4362033..000000000 --- a/articles/media/index/logo_csharp.svg +++ /dev/null @@ -1 +0,0 @@ -logo_Csharp \ No newline at end of file diff --git a/articles/media/index/logo_java.svg b/articles/media/index/logo_java.svg deleted file mode 100644 index 4d87bef86..000000000 --- a/articles/media/index/logo_java.svg +++ /dev/null @@ -1 +0,0 @@ -logo_java \ No newline at end of file diff --git a/articles/media/index/logo_js.svg b/articles/media/index/logo_js.svg deleted file mode 100644 index db5904c4b..000000000 --- a/articles/media/index/logo_js.svg +++ /dev/null @@ -1 +0,0 @@ -logo_js \ No newline at end of file diff --git a/articles/media/index/logo_nodejs.svg b/articles/media/index/logo_nodejs.svg deleted file mode 100644 index 2deab0dd1..000000000 --- a/articles/media/index/logo_nodejs.svg +++ /dev/null @@ -1 +0,0 @@ -logo_nodejs \ No newline at end of file diff --git a/articles/media/index/logo_python.svg b/articles/media/index/logo_python.svg deleted file mode 100644 index 7292d8814..000000000 --- a/articles/media/index/logo_python.svg +++ /dev/null @@ -1 +0,0 @@ -logo_python \ No newline at end of file diff --git a/articles/media/kik-signup.png b/articles/media/kik-signup.png deleted file mode 100644 index 7d29b1bee..000000000 Binary files a/articles/media/kik-signup.png and /dev/null differ diff --git a/articles/media/locale-dir.png b/articles/media/locale-dir.png deleted file mode 100644 index 2786d5ccb..000000000 Binary files a/articles/media/locale-dir.png and /dev/null differ diff --git a/articles/media/locale-namespacing.png b/articles/media/locale-namespacing.png deleted file mode 100644 index 40be78594..000000000 Binary files a/articles/media/locale-namespacing.png and /dev/null differ diff --git a/articles/media/logo-ms-dark.png b/articles/media/logo-ms-dark.png deleted file mode 100644 index edde52a63..000000000 Binary files a/articles/media/logo-ms-dark.png and /dev/null differ diff --git a/articles/media/messenger_locationdialog_1.png b/articles/media/messenger_locationdialog_1.png deleted file mode 100644 index 58e76a889..000000000 Binary files a/articles/media/messenger_locationdialog_1.png and /dev/null differ diff --git a/articles/media/microsoft-payment.png b/articles/media/microsoft-payment.png deleted file mode 100644 index 6fb532d94..000000000 Binary files a/articles/media/microsoft-payment.png and /dev/null differ diff --git a/articles/media/msa-password-update-devportal-dashboard.png b/articles/media/msa-password-update-devportal-dashboard.png deleted file mode 100644 index 81ee03b88..000000000 Binary files a/articles/media/msa-password-update-devportal-dashboard.png and /dev/null differ diff --git a/articles/media/msa-password-update-devportal-edit.png b/articles/media/msa-password-update-devportal-edit.png deleted file mode 100644 index 9d7100a5b..000000000 Binary files a/articles/media/msa-password-update-devportal-edit.png and /dev/null differ diff --git a/articles/media/msa-password-update-msa-createnew.png b/articles/media/msa-password-update-msa-createnew.png deleted file mode 100644 index 2a0db71e0..000000000 Binary files a/articles/media/msa-password-update-msa-createnew.png and /dev/null differ diff --git a/articles/media/msa-password-update-msa-pwdcreated-copy.png b/articles/media/msa-password-update-msa-pwdcreated-copy.png deleted file mode 100644 index 44b1816df..000000000 Binary files a/articles/media/msa-password-update-msa-pwdcreated-copy.png and /dev/null differ diff --git a/articles/media/msa-password-update-msa-pwdcreated.png b/articles/media/msa-password-update-msa-pwdcreated.png deleted file mode 100644 index 44b1816df..000000000 Binary files a/articles/media/msa-password-update-msa-pwdcreated.png and /dev/null differ diff --git a/articles/media/msa-password-update-msa-pwddelete.png b/articles/media/msa-password-update-msa-pwddelete.png deleted file mode 100644 index a2b8add86..000000000 Binary files a/articles/media/msa-password-update-msa-pwddelete.png and /dev/null differ diff --git a/articles/media/msa-password-update-portal.png b/articles/media/msa-password-update-portal.png deleted file mode 100644 index 43af72f8b..000000000 Binary files a/articles/media/msa-password-update-portal.png and /dev/null differ diff --git a/articles/media/no.png b/articles/media/no.png deleted file mode 100644 index 1aa084e6a..000000000 Binary files a/articles/media/no.png and /dev/null differ diff --git a/articles/media/payments-bot-buy.png b/articles/media/payments-bot-buy.png deleted file mode 100644 index 06f87ab96..000000000 Binary files a/articles/media/payments-bot-buy.png and /dev/null differ diff --git a/articles/media/portal-app-insights-add-new.png b/articles/media/portal-app-insights-add-new.png deleted file mode 100644 index a9ccbe0b0..000000000 Binary files a/articles/media/portal-app-insights-add-new.png and /dev/null differ diff --git a/articles/media/portal-app-insights-analytics.png b/articles/media/portal-app-insights-analytics.png deleted file mode 100644 index b306dffb8..000000000 Binary files a/articles/media/portal-app-insights-analytics.png and /dev/null differ diff --git a/articles/media/portal-app-insights-appid-apikey.png b/articles/media/portal-app-insights-appid-apikey.png deleted file mode 100644 index 9438a727d..000000000 Binary files a/articles/media/portal-app-insights-appid-apikey.png and /dev/null differ diff --git a/articles/media/portal-app-insights-appid.png b/articles/media/portal-app-insights-appid.png deleted file mode 100644 index 2541be5b6..000000000 Binary files a/articles/media/portal-app-insights-appid.png and /dev/null differ diff --git a/articles/media/portal-app-insights-instrumentation-key-dropdown.png b/articles/media/portal-app-insights-instrumentation-key-dropdown.png deleted file mode 100644 index c0c8f37c8..000000000 Binary files a/articles/media/portal-app-insights-instrumentation-key-dropdown.png and /dev/null differ diff --git a/articles/media/portal-app-insights-instrumentation-key.png b/articles/media/portal-app-insights-instrumentation-key.png deleted file mode 100644 index b8451726a..000000000 Binary files a/articles/media/portal-app-insights-instrumentation-key.png and /dev/null differ diff --git a/articles/media/portal-channels-list.png b/articles/media/portal-channels-list.png deleted file mode 100644 index 65b1ec3a3..000000000 Binary files a/articles/media/portal-channels-list.png and /dev/null differ diff --git a/articles/media/portal-configure-bot.png b/articles/media/portal-configure-bot.png deleted file mode 100644 index aa1ba08c8..000000000 Binary files a/articles/media/portal-configure-bot.png and /dev/null differ diff --git a/articles/media/publishing-your-bot-deployment-credentials.png b/articles/media/publishing-your-bot-deployment-credentials.png deleted file mode 100644 index 9bffed0e0..000000000 Binary files a/articles/media/publishing-your-bot-deployment-credentials.png and /dev/null differ diff --git a/articles/media/python/quickstart/bot-running-locally.png b/articles/media/python/quickstart/bot-running-locally.png deleted file mode 100644 index 9d483395f..000000000 Binary files a/articles/media/python/quickstart/bot-running-locally.png and /dev/null differ diff --git a/articles/media/python/quickstart/connect-and-start.gif b/articles/media/python/quickstart/connect-and-start.gif deleted file mode 100644 index 32bbe1609..000000000 Binary files a/articles/media/python/quickstart/connect-and-start.gif and /dev/null differ diff --git a/articles/media/python/quickstart/connect-and-start.png b/articles/media/python/quickstart/connect-and-start.png deleted file mode 100644 index d4dd2b6c0..000000000 Binary files a/articles/media/python/quickstart/connect-and-start.png and /dev/null differ diff --git a/articles/media/python/quickstart/open-bot.png b/articles/media/python/quickstart/open-bot.png deleted file mode 100644 index 1a078574c..000000000 Binary files a/articles/media/python/quickstart/open-bot.png and /dev/null differ diff --git a/articles/media/python/quickstart/set-name-description.png b/articles/media/python/quickstart/set-name-description.png deleted file mode 100644 index a2a9afbdf..000000000 Binary files a/articles/media/python/quickstart/set-name-description.png and /dev/null differ diff --git a/articles/media/real-time-media-bot-portal-certificates.png b/articles/media/real-time-media-bot-portal-certificates.png deleted file mode 100644 index c165e7bc6..000000000 Binary files a/articles/media/real-time-media-bot-portal-certificates.png and /dev/null differ diff --git a/articles/media/real-time-media-bot-portal-service-creation.png b/articles/media/real-time-media-bot-portal-service-creation.png deleted file mode 100644 index ab396e8a9..000000000 Binary files a/articles/media/real-time-media-bot-portal-service-creation.png and /dev/null differ diff --git a/articles/media/real-time-media-bot-publish-advanced-settings.png b/articles/media/real-time-media-bot-publish-advanced-settings.png deleted file mode 100644 index a6bc967fe..000000000 Binary files a/articles/media/real-time-media-bot-publish-advanced-settings.png and /dev/null differ diff --git a/articles/media/real-time-media-bot-publish-settings.png b/articles/media/real-time-media-bot-publish-settings.png deleted file mode 100644 index a8b47e30f..000000000 Binary files a/articles/media/real-time-media-bot-publish-settings.png and /dev/null differ diff --git a/articles/media/real-time-media-bot-publish-signin.png b/articles/media/real-time-media-bot-publish-signin.png deleted file mode 100644 index 146fa6ba1..000000000 Binary files a/articles/media/real-time-media-bot-publish-signin.png and /dev/null differ diff --git a/articles/media/receipt-card.png b/articles/media/receipt-card.png deleted file mode 100644 index 25cb6a204..000000000 Binary files a/articles/media/receipt-card.png and /dev/null differ diff --git a/articles/media/receipt-card1.png b/articles/media/receipt-card1.png deleted file mode 100644 index 16e0deb72..000000000 Binary files a/articles/media/receipt-card1.png and /dev/null differ diff --git a/articles/media/salon_bot_example.png b/articles/media/salon_bot_example.png deleted file mode 100644 index aad020589..000000000 Binary files a/articles/media/salon_bot_example.png and /dev/null differ diff --git a/articles/media/scale-out/scale-out-buffer.png b/articles/media/scale-out/scale-out-buffer.png deleted file mode 100644 index 80c306cb8..000000000 Binary files a/articles/media/scale-out/scale-out-buffer.png and /dev/null differ diff --git a/articles/media/scale-out/scale-out-default.png b/articles/media/scale-out/scale-out-default.png deleted file mode 100644 index 764415d9b..000000000 Binary files a/articles/media/scale-out/scale-out-default.png and /dev/null differ diff --git a/articles/media/scale-out/scale-out-interaction.png b/articles/media/scale-out/scale-out-interaction.png deleted file mode 100644 index 74142e973..000000000 Binary files a/articles/media/scale-out/scale-out-interaction.png and /dev/null differ diff --git a/articles/media/scale-out/scale-out-precondition-failed.png b/articles/media/scale-out/scale-out-precondition-failed.png deleted file mode 100644 index c5316a8f4..000000000 Binary files a/articles/media/scale-out/scale-out-precondition-failed.png and /dev/null differ diff --git a/articles/media/scale-out/scale-out-save.png b/articles/media/scale-out/scale-out-save.png deleted file mode 100644 index 9d4d33692..000000000 Binary files a/articles/media/scale-out/scale-out-save.png and /dev/null differ diff --git a/articles/media/scenarios/bot-service-scenario-application-bot.png b/articles/media/scenarios/bot-service-scenario-application-bot.png deleted file mode 100644 index 572bf1d05..000000000 Binary files a/articles/media/scenarios/bot-service-scenario-application-bot.png and /dev/null differ diff --git a/articles/media/scenarios/bot-service-scenario-commerce-bot.png b/articles/media/scenarios/bot-service-scenario-commerce-bot.png deleted file mode 100644 index fad24a4c9..000000000 Binary files a/articles/media/scenarios/bot-service-scenario-commerce-bot.png and /dev/null differ diff --git a/articles/media/scenarios/bot-service-scenario-cortana-skill.png b/articles/media/scenarios/bot-service-scenario-cortana-skill.png deleted file mode 100644 index b2693c791..000000000 Binary files a/articles/media/scenarios/bot-service-scenario-cortana-skill.png and /dev/null differ diff --git a/articles/media/scenarios/bot-service-scenario-enterprise-bot.png b/articles/media/scenarios/bot-service-scenario-enterprise-bot.png deleted file mode 100644 index 67e8ead4a..000000000 Binary files a/articles/media/scenarios/bot-service-scenario-enterprise-bot.png and /dev/null differ diff --git a/articles/media/scenarios/bot-service-scenario-informational-bot.png b/articles/media/scenarios/bot-service-scenario-informational-bot.png deleted file mode 100644 index 265c614ce..000000000 Binary files a/articles/media/scenarios/bot-service-scenario-informational-bot.png and /dev/null differ diff --git a/articles/media/scenarios/bot-service-scenario-informational.png b/articles/media/scenarios/bot-service-scenario-informational.png deleted file mode 100644 index a1630ab1d..000000000 Binary files a/articles/media/scenarios/bot-service-scenario-informational.png and /dev/null differ diff --git a/articles/media/scenarios/bot-service-scenario-iot-bot.png b/articles/media/scenarios/bot-service-scenario-iot-bot.png deleted file mode 100644 index 15b52927d..000000000 Binary files a/articles/media/scenarios/bot-service-scenario-iot-bot.png and /dev/null differ diff --git a/articles/media/sign-in-card.png b/articles/media/sign-in-card.png deleted file mode 100644 index d3b760abc..000000000 Binary files a/articles/media/sign-in-card.png and /dev/null differ diff --git a/articles/media/skype_multiaddress_1.png b/articles/media/skype_multiaddress_1.png deleted file mode 100644 index 02c6a3309..000000000 Binary files a/articles/media/skype_multiaddress_1.png and /dev/null differ diff --git a/articles/media/skype_multiresult_1.png b/articles/media/skype_multiresult_1.png deleted file mode 100644 index 02c6a3309..000000000 Binary files a/articles/media/skype_multiresult_1.png and /dev/null differ diff --git a/articles/media/skype_requiredaddress_1.png b/articles/media/skype_requiredaddress_1.png deleted file mode 100644 index f8f7a8374..000000000 Binary files a/articles/media/skype_requiredaddress_1.png and /dev/null differ diff --git a/articles/media/skype_singleaddress_1.png b/articles/media/skype_singleaddress_1.png deleted file mode 100644 index 5b3680e10..000000000 Binary files a/articles/media/skype_singleaddress_1.png and /dev/null differ diff --git a/articles/media/skype_singleaddress_2.png b/articles/media/skype_singleaddress_2.png deleted file mode 100644 index 06fca2558..000000000 Binary files a/articles/media/skype_singleaddress_2.png and /dev/null differ diff --git a/articles/media/suggested-actions.png b/articles/media/suggested-actions.png deleted file mode 100644 index 98e01abcc..000000000 Binary files a/articles/media/suggested-actions.png and /dev/null differ diff --git a/articles/media/teams/connect-teams-channel.png b/articles/media/teams/connect-teams-channel.png deleted file mode 100644 index fa52d8f35..000000000 Binary files a/articles/media/teams/connect-teams-channel.png and /dev/null differ diff --git a/articles/media/teams/get-embed-code.png b/articles/media/teams/get-embed-code.png deleted file mode 100644 index 019b772db..000000000 Binary files a/articles/media/teams/get-embed-code.png and /dev/null differ diff --git a/articles/media/teams/save-teams-channel.png b/articles/media/teams/save-teams-channel.png deleted file mode 100644 index 91bf2580f..000000000 Binary files a/articles/media/teams/save-teams-channel.png and /dev/null differ diff --git a/articles/media/test-in-webchat.png b/articles/media/test-in-webchat.png deleted file mode 100644 index 1d3a61b9f..000000000 Binary files a/articles/media/test-in-webchat.png and /dev/null differ diff --git a/articles/media/thumbnail-card.png b/articles/media/thumbnail-card.png deleted file mode 100644 index a6040f757..000000000 Binary files a/articles/media/thumbnail-card.png and /dev/null differ diff --git a/articles/media/troubleshooting-bot-framework-authentication_1.png b/articles/media/troubleshooting-bot-framework-authentication_1.png deleted file mode 100644 index d9bfc4313..000000000 Binary files a/articles/media/troubleshooting-bot-framework-authentication_1.png and /dev/null differ diff --git a/articles/media/troubleshooting-bot-framework-authentication_2.png b/articles/media/troubleshooting-bot-framework-authentication_2.png deleted file mode 100644 index 464a7f9e8..000000000 Binary files a/articles/media/troubleshooting-bot-framework-authentication_2.png and /dev/null differ diff --git a/articles/media/troubleshooting-bot-framework-authentication_3.png b/articles/media/troubleshooting-bot-framework-authentication_3.png deleted file mode 100644 index 057ad3eb2..000000000 Binary files a/articles/media/troubleshooting-bot-framework-authentication_3.png and /dev/null differ diff --git a/articles/media/upgrade/generate-new-password.png b/articles/media/upgrade/generate-new-password.png deleted file mode 100644 index 277c20272..000000000 Binary files a/articles/media/upgrade/generate-new-password.png and /dev/null differ diff --git a/articles/media/upgrade/manage-app-id.png b/articles/media/upgrade/manage-app-id.png deleted file mode 100644 index ecd0ea7fe..000000000 Binary files a/articles/media/upgrade/manage-app-id.png and /dev/null differ diff --git a/articles/media/upgrade/new-password-generated.png b/articles/media/upgrade/new-password-generated.png deleted file mode 100644 index e730b87ac..000000000 Binary files a/articles/media/upgrade/new-password-generated.png and /dev/null differ diff --git a/articles/media/video-card.png b/articles/media/video-card.png deleted file mode 100644 index 31294acc1..000000000 Binary files a/articles/media/video-card.png and /dev/null differ diff --git a/articles/media/video/satya-video.png b/articles/media/video/satya-video.png deleted file mode 100644 index 23a81066c..000000000 Binary files a/articles/media/video/satya-video.png and /dev/null differ diff --git a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-cognitivesericesaccount-selection.png b/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-cognitivesericesaccount-selection.png deleted file mode 100644 index 5ec9e1408..000000000 Binary files a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-cognitivesericesaccount-selection.png and /dev/null differ diff --git a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-configureappservice.png b/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-configureappservice.png deleted file mode 100644 index de40c1f1c..000000000 Binary files a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-configureappservice.png and /dev/null differ diff --git a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-connectspeechchannel.png b/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-connectspeechchannel.png deleted file mode 100644 index b54e60a03..000000000 Binary files a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-connectspeechchannel.png and /dev/null differ diff --git a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-enablestreamingsupport.png b/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-enablestreamingsupport.png deleted file mode 100644 index f31f9d31a..000000000 Binary files a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-enablestreamingsupport.png and /dev/null differ diff --git a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-enablewebsockets.png b/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-enablewebsockets.png deleted file mode 100644 index 4c0635a82..000000000 Binary files a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-enablewebsockets.png and /dev/null differ diff --git a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-getspeechsecretkeys.png b/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-getspeechsecretkeys.png deleted file mode 100644 index 41b57da4e..000000000 Binary files a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-getspeechsecretkeys.png and /dev/null differ diff --git a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-getspeechsecretkeys1.PNG b/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-getspeechsecretkeys1.PNG deleted file mode 100644 index cb3399a6b..000000000 Binary files a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-getspeechsecretkeys1.PNG and /dev/null differ diff --git a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-savechannel.png b/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-savechannel.png deleted file mode 100644 index f932124ed..000000000 Binary files a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-savechannel.png and /dev/null differ diff --git a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-selectchannel.png b/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-selectchannel.png deleted file mode 100644 index 46df65322..000000000 Binary files a/articles/media/voice-first-virtual-assistants/bot-service-channel-directlinespeech-selectchannel.png and /dev/null differ diff --git a/articles/media/what-is-bot-framework-components-placeholder.png b/articles/media/what-is-bot-framework-components-placeholder.png deleted file mode 100644 index e43765c2b..000000000 Binary files a/articles/media/what-is-bot-framework-components-placeholder.png and /dev/null differ diff --git a/articles/media/yes.png b/articles/media/yes.png deleted file mode 100644 index d2285c5c4..000000000 Binary files a/articles/media/yes.png and /dev/null differ diff --git a/articles/nodejs/TOC.md b/articles/nodejs/TOC.md deleted file mode 100644 index f018e4bb9..000000000 --- a/articles/nodejs/TOC.md +++ /dev/null @@ -1,33 +0,0 @@ -# [Bot Framework SDK for Node.js](bot-builder-nodejs-overview.md) -# [Key concepts](bot-builder-nodejs-concepts.md) -# Dialogs -## [Dialogs overview](bot-builder-nodejs-dialog-overview.md) -## [Define conversation steps](bot-builder-nodejs-dialog-waterfall.md) -## [Prompt for user input](bot-builder-nodejs-dialog-prompt.md) -## [Manage conversation flow](bot-builder-nodejs-dialog-manage-conversation-flow.md) -## [Replace dialogs](bot-builder-nodejs-dialog-replace.md) -## [Handle user actions](bot-builder-nodejs-dialog-actions.md) -# Messages -## [Create messages](bot-builder-nodejs-message-create.md) -## [Send and receive attachments](bot-builder-nodejs-send-receive-attachments.md) -## [Send proactive messages](bot-builder-nodejs-proactive-messages.md) -## [Add rich cards to messages](bot-builder-nodejs-send-rich-cards.md) -## [Add speech to messages](bot-builder-nodejs-text-to-speech.md) -## [Add input hints to messages](bot-builder-nodejs-send-input-hints.md) -## [Add suggested actions to messages](bot-builder-nodejs-send-suggested-actions.md) -## [Send a typing indicator](bot-builder-nodejs-send-typing-indicator.md) -## [Intercept messages](bot-builder-nodejs-intercept-messages.md) -# Channels -## [Build a Cortana skill](bot-builder-nodejs-cortana-skill.md) -## [Conduct Skype calls](bot-builder-nodejs-conduct-audio-calls.md) -# State Data -## [Manage state data](bot-builder-nodejs-state.md) -## [Manage state data with Cosmos DB](bot-builder-nodejs-state-azure-cosmosdb.md) -## [Manage state data with Table storage](bot-builder-nodejs-state-azure-table-storage.md) -# [Recognize intent from message content](bot-builder-nodejs-recognize-intent-messages.md) -# [Recognize intent with LUIS](bot-builder-nodejs-recognize-intent-luis.md) -# [Handle user and conversation events](bot-builder-nodejs-handle-conversation-events.md) -# [Support localization](bot-builder-nodejs-localization.md) -# [Use backchannel mechanism](bot-builder-nodejs-backchannel.md) -# [Request payment](bot-builder-nodejs-request-payment.md) -# [Add Azure Search](bot-builder-nodejs-search-azure.md) diff --git a/articles/nodejs/bot-builder-nodejs-backchannel.md b/articles/nodejs/bot-builder-nodejs-backchannel.md deleted file mode 100644 index 6e2467aea..000000000 --- a/articles/nodejs/bot-builder-nodejs-backchannel.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -title: Exchange information using the web control - Bot Service -description: Learn how to exchange information between the bot and a web page using the Bot Framework SDK for Node.js. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Use the backchannel mechanism - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -[!INCLUDE [Introduction to backchannel mechanism](../includes/snippet-backchannel.md)] - -## Walk through - -The open source web chat control accesses the Direct Line API by using a JavaScript class -called DirectLineJS. -The control can either create its own instance of Direct Line, or it can share one with the hosting page. -If the control shares an instance of Direct Line with the hosting page, -both the control and the page will be capable of sending and receiving activities. -The following diagram shows the high-level architecture of a website that supports bot functionality by -using the open source web (chat) control and the Direct Line API. - -![Backchannel](../media/designing-bots/patterns/back-channel.png) - -### Sample code - -In this example, the bot and web page will use the backchannel mechanism to exchange information that is invisible to the user. -The bot will request that the web page change its background color, and the -web page will notify the bot when the user clicks a button on the page. - -> [!NOTE] -> The code snippets in this article originate from -> the backchannel sample -> and the backchannel bot. - -#### Client-side code - -First, the web page creates a **DirectLine** object. - -```javascript -var botConnection = new BotChat.DirectLine(...); -``` - -Then, it shares the **DirectLine** object when creating the WebChat instance. - -```javascript -BotChat.App({ - botConnection: botConnection, - user: user, - bot: bot -}, document.getElementById("BotChatGoesHere")); -``` - -When the user clicks a button on the web page, the web page posts an activity of type "event" -to notify the bot that the button was clicked. - -```javascript -const postButtonMessage = () => { - botConnection - .postActivity({type: "event", value: "", from: {id: "me" }, name: "buttonClicked"}) - .subscribe(id => console.log("success")); - } -``` - -> [!TIP] -> Use the attributes `name` and `value` to communicate any information that the bot may need in order -> to properly interpret and/or respond to the event. - -Finally, the web page also listens for a specific event from the bot. -In this example, the web page listens for an activity where type="event" and name="changeBackground". -When it receives this type of activity, it changes the background color of the web page to the `value` specified by the activity. - -```javascript -botConnection.activity$ - .filter(activity => activity.type === "event" && activity.name === "changeBackground") - .subscribe(activity => changeBackgroundColor(activity.value)) -``` - -#### Server-side code - -The backchannel bot -creates an event by using a helper function. - -```javascript -var bot = new builder.UniversalBot(connector, - function (session) { - var reply = createEvent("changeBackground", session.message.text, session.message.address); - session.endDialog(reply); - } -); - -const createEvent = (eventName, value, address) => { - var msg = new builder.Message().address(address); - msg.data.type = "event"; - msg.data.name = eventName; - msg.data.value = value; - return msg; -} -``` - -Likewise, the bot also listens for events from the client. -In this example, if the bot receives an event with `name="buttonClicked"`, -it will send a message to the user to say "I see that you clicked a button." - -```javascript -bot.on("event", function (event) { - var msg = new builder.Message().address(event.address); - msg.data.textLocale = "en-us"; - if (event.name === "buttonClicked") { - msg.data.text = "I see that you clicked a button."; - } - bot.send(msg); -}) -``` - -## Additional resources - -- [Direct Line API][directLineAPI] -- Microsoft Bot Framework WebChat control -- Backchannel sample -- Backchannel bot - -[directLineAPI]: https://docs.botframework.com/restapi/directline3/#navtitle diff --git a/articles/nodejs/bot-builder-nodejs-concepts.md b/articles/nodejs/bot-builder-nodejs-concepts.md deleted file mode 100644 index d6ead5f87..000000000 --- a/articles/nodejs/bot-builder-nodejs-concepts.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: Key concepts in the Bot Framework SDK for Node.js - Bot Service -description: Understand the key concepts and tools for building and deploying conversational bots available in the Bot Framework SDK for Node.js. -author: DeniseMak -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Key concepts in the Bot Framework SDK for Node.js - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-concepts.md) -> - [Node.js](../nodejs/bot-builder-nodejs-concepts.md) - -This article introduces key concepts in the Bot Framework SDK for Node.js. For an introduction to Bot Framework, see [Bot Framework overview](../overview-introduction-bot-framework.md). - -## Connector -The Bot Framework Connector is a service that connects your bot to multiple *channels*, which are clients like [Teams](https://docs.microsoft.com/microsoftteams/platform/concepts/bots/bots-create), Skype, Facebook, Slack, and SMS. - -The Connector facilitates communication between bot and user by relaying messages from bot to channel and from channel to bot. -Your bot's logic is hosted as a web service that receives messages from users through the Connector service, and your bot's replies are sent to the Connector using HTTPS POST. - -The Bot Framework SDK for Node.js provides the [UniversalBot][UniversalBot] and [ChatConnector][ChatConnector] classes for configuring the bot to send and receive messages through the Bot Framework Connector. The `UniversalBot` class forms the brains of your bot. It's responsible for managing all the conversations your bot has with a user. The `ChatConnector` class connects your bot to the Bot Framework Connector Service. -For an example that demonstrates using these classes, see [Create a bot with the Bot Framework SDK for Node.js](bot-builder-nodejs-quickstart.md). - -The Connector also normalizes the messages that the bot sends to channels so that you can develop your bot in a platform-agnostic way. Normalizing a message involves converting it from the Bot Framework’s schema into the channel’s schema. In cases where the channel does not support all aspects of the framework’s schema, the Connector will try to convert the message to a format that the channel supports. For example, if the bot sends a message that contains a card with action buttons to the SMS channel, the Connector may render the card as an image and include the actions as links in the message’s text. - -[!INCLUDE [Channel Inspector intro](~/includes/snippet-channel-inspector.md)] - -The `ChatConnector` requires an API endpoint to be setup within your bot. With the Node.js SDK, this is usually accomplished by installing the `restify` Node.js module. Bots can also be created for the console using the [ConsoleConnector][ConsoleConnector], which does not require an API endpoint. - -## Messages - -Messages can consist of text to be displayed, text to be spoken, attachments, rich cards, and suggested actions. You use the [session.send][SessionSend] method to send messages in response to a message from the user. Your bot may call `send` as many times as it likes in response to a message from the user. For an example that demonstrates this, see [Respond to user messages][RespondMessages]. - -For an example that demonstrates how to send a rich graphical card containing interactive buttons that the user clicks to initiate an action, see [Add rich cards to messages](bot-builder-nodejs-send-rich-cards.md). For an example that demonstrates how to send and receive attachments, see [Send attachments](bot-builder-nodejs-send-receive-attachments.md). For an example that demonstrates how to send a message that specifies text to be spoken by your bot on a speech-enabled channel, see [Add speech to messages](bot-builder-nodejs-text-to-speech.md). For an example that demonstrates how to send suggested actions, see [Send suggested actions](bot-builder-nodejs-send-suggested-actions.md). - -## Dialogs -Dialogs help you organize the conversational logic in your bot and are fundamental to [designing conversation flow](../bot-service-design-conversation-flow.md). For an introduction to dialogs, see [Manage a conversation with dialogs](bot-builder-nodejs-dialog-manage-conversation.md). - -## Actions -You'll want to design your bot to be able to handle interruptions like requests for cancellation or help at any time during the conversation flow. The Bot Framework SDK for Node.js provides global message handlers that trigger actions like cancellation or invoking other dialogs. - See [Handle user actions](bot-builder-nodejs-dialog-actions.md) for examples of how to use [triggerAction][triggerAction] handlers. - - - -## Recognizers -When users ask your bot for something, like "help" or "find news", your bot needs to understand what the user is asking for and then take the appropriate action. You can design your bot to recognize intents based on the user’s input and associate that intent with actions. - -You can use the built-in regular expression recognizer that the Bot Framework SDK provides, call an external service such as the LUIS API, or implement a custom recognizer to determine the user's intent. -See [Recognize user intent](bot-builder-nodejs-recognize-intent-messages.md) for examples that demonstrate how to add recognizers to your bot and use them to trigger actions. - - -## Saving State - -A key to good bot design is to track the context of a conversation, so that your bot remembers things like the last question the user asked. -Bots built using Bot Framework SDK are designed to be be stateless so that they can easily be scaled to run across multiple compute nodes. The Bot Framework provides a storage system that stores bot data, so that the bot web service can be scaled. Because of that you should generally avoid saving state using a global variable or function closure. Doing so will create issues when you want to scale out your bot. Instead, use the following properties of your bot's [session][Session] object to save data relative to a user or conversation: - -* **userData** stores information globally for the user across all conversations. -* **conversationData** stores information globally for a single conversation. This data is visible to everyone within the conversation so exercise with care when storing data to this property. It’s enabled by default and you can disable it using the bot's [persistConversationData][PersistConversationData] setting. -* **privateConversationData** stores information globally for a single conversation but it is private data specific to the current user. This data spans all dialogs so it’s useful for storing temporary state that you want cleaned up when the conversation ends. -* **dialogData** persists information for a single dialog instance. This is essential for storing temporary information in between the steps of a [waterfall](bot-builder-nodejs-dialog-waterfall.md) in a dialog. - -For examples that demonstrate how to use these properties to store and retrieve data, see [Manage state data](bot-builder-nodejs-state.md). - -## Natural language understanding - -Bot Builder lets you use LUIS to add natural language understanding to your bot using the [LuisRecognizer][LuisRecognizer] class. You can add an instance of a **LuisRecognizer** that references your published language model and then add handlers to take actions in response to the user's utterances. To see LUIS in action watch the following 10 minute tutorial: - -* [Microsoft LUIS Tutorial][LUISVideo] (video) - -## Next steps -> [!div class="nextstepaction"] -> [Dialogs overview](bot-builder-nodejs-dialog-overview.md) - - - -[PersistConversationData]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.iuniversalbotsettings.html#persistconversationdata -[UniversalBot]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.universalbot.html -[ChatConnector]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.chatconnector.html -[ConsoleConnector]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.consoleconnector.html - -[ChannelInspector]: ../bot-service-channels-reference.md - -[Session]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html -[SessionSend]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#send - -[triggerAction]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html#triggeraction -[waterfall]: bot-builder-nodejs-prompts.md - -[RespondMessages]:bot-builder-nodejs-use-default-message-handler.md - -[LUISRecognizer]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.luisrecognizer -[LUISVideo]: https://vimeo.com/145499419 \ No newline at end of file diff --git a/articles/nodejs/bot-builder-nodejs-conduct-audio-calls.md b/articles/nodejs/bot-builder-nodejs-conduct-audio-calls.md deleted file mode 100644 index 94abd06ec..000000000 --- a/articles/nodejs/bot-builder-nodejs-conduct-audio-calls.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: Conduct audio calls - Bot Service -description: Learn how to conduct audio calls with Skype in a bot using Node.js -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Support audio calls with Skype - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -Skype supports a rich feature called Calling Bots. When enabled, users can place a voice call to your bot and interact with it using Interactive Voice Response (IVR). The Bot Builder for Node.js SDK includes a special [Calling SDK][calling_sdk] which developers can use to add calling features to their chat bot. - -The Calling SDK is very similar to the [Chat SDK][chat_sdk]. They have similar classes, share common constructs and you can even use the Chat SDK to send a message to the user you’re on a call with. The two SDKs are designed to run side-by-side but while they are similar, there are some significant differences and you should generally avoid mixing classes from the two libraries. - -## Create a calling bot -The following example code shows how the "Hello World" for a calling bot looks very similar to a regular chat bot. - -```javascript -var restify = require('restify'); -var calling = require('botbuilder-calling'); - -// Setup Restify Server -var server = restify.createServer(); -server.listen(process.env.port || process.env.PORT || 3978, function () { - console.log(`${server.name} listening to ${server.url}`); -}); - -// Create calling bot -var connector = new calling.CallConnector({ - callbackUrl: 'https:///api/calls', - appId: '', - appPassword: '' -}); -var bot = new calling.UniversalCallBot(connector); -server.post('/api/calls', connector.listen()); - -// Add root dialog -bot.dialog('/', function (session) { - session.send('Watson... come here!'); -}); -``` - -> [!NOTE] -> To find your bot's **AppID** and **AppPassword**, see [MicrosoftAppID and MicrosoftAppPassword](~/bot-service-manage-overview.md#microsoftappid-and-microsoftapppassword). - -The emulator doesn’t currently support testing calling bots. To test your bot, you’ll need to go through most of the steps required to publish your bot. You will also need to use a Skype client to interact with the bot. - -### Enable the Skype channel -[Register your bot](../bot-service-quickstart-registration.md) and enable the Skype channel. You will need to provide a messaging endpoint when you register your bot. It is recommended that you pair your calling bot with a chat bot so the chat bot’s endpoint is what you would normally put in that field. If you’re only registering a calling bot you can simply paste your calling endpoint into that field. - -To enable the actual calling feature you’ll need to go into the Skype channel for your bot and turn on the calling feature. You’ll then be provided with a field to copy your calling endpoint into. Make sure you use the https ngrok link for the host portion of your calling endpoint. - -During the registration of your bot you’ll be assigned an app ID & password which you should paste into the connector settings for your hello world bot. You’ll also need to take your full calling link and paste that in for the callbackUrl setting. - -### Add bot to contacts -On your bot's registration page in the developer portal you’ll see an **add to Skype** button next to your bots Skype channel. Click the button to add your bot to your contact list in Skype. Once you do that you (and anyone you give the join link to) will be able to communicate with the bot. - -### Test your bot -You can test your bot using a Skype client. You should notice the call icon light up when you click on your bots contact entry (you may have to search for the bot to see it.) It can take a few minutes for the call icon to light up if you’ve added calling to an existing bot. - -If you press the call button it should dial your bot and you should hear it speak “Watson… come here!” and then hang up. - -## Calling basics -The [UniversalCallBot](http://docs.botframework.com/node/builder/calling-reference/classes/_botbuilder_d_.universalcallbot) and [CallConnector](http://docs.botframework.com/node/builder/calling-reference/classes/_botbuilder_d_.callconnector) classes let you author a calling bot in much the same way you would a chat bot. You add dialogs to your bot that are essentially identical to [chat dialogs](bot-builder-nodejs-manage-conversation-flow.md). You can add [waterfalls](bot-builder-nodejs-prompts.md) to your bot. There is a session object, the [CallSession](http://docs.botframework.com/node/builder/calling-reference/classes/_botbuilder_d_.callsession) class, which contains added [answer()](http://docs.botframework.com/node/builder/calling-reference/classes/_botbuilder_d_.callsession#answer), [hangup()](http://docs.botframework.com/node/builder/calling-reference/classes/_botbuilder_d_.callsession#hangup), and [reject()](http://docs.botframework.com/node/builder/calling-reference/classes/_botbuilder_d_.callsession#reject) methods for managing the current call. In general, you don’t need to worry about these call control methods though as the CallSession has logic to automatically manage the call for you. The session will automatically answer the call if you take an action like sending a message or calling a built-in prompt. It will also automatically hangup/reject the call if you call [endConversation()](http://docs.botframework.com/node/builder/calling-reference/classes/_botbuilder_d_.callsession#endconversation) or it detects that you’ve stopped asking the caller questions (you didn’t call a built-in prompt.) - -Another difference between calling and chat bots is that while chat bots typically send messages, cards, and keyboards to a user a calling bot deals in Actions and Outcomes. Skype calling bots are required to create [workflows](http://docs.botframework.com/node/builder/calling-reference/interfaces/_botbuilder_d_.iworkflow) that are comprised of one or more [actions](http://docs.botframework.com/node/builder/calling-reference/interfaces/_botbuilder_d_.iaction). This is another thing that in practice you don’t have to worry too much about as the Bot Builder calling SDK will manage most of this for you. The [CallSession.send()](http://docs.botframework.com/node/builder/calling-reference/classes/_botbuilder_d_.callsession#send) method lets you pass either actions or strings which it will turn into [PlayPromptActions](http://docs.botframework.com/node/builder/calling-reference/classes/_botbuilder_d_.playpromptaction). The session contains auto batching logic to combine multiple actions into a single workflow that’s submitted to the calling service so you can safely call send() multiple times. And you should rely on the SDK’s built-in [prompts](bot-builder-nodejs-prompts.md) to collect input from the user as they process all of the outcomes. - -[calling_sdk]: http://docs.botframework.com/node/builder/calling-reference/modules/_botbuilder_d_ -[chat_sdk]: http://docs.botframework.com/node/builder/chat-reference/modules/_botbuilder_d_ diff --git a/articles/nodejs/bot-builder-nodejs-cortana-skill.md b/articles/nodejs/bot-builder-nodejs-cortana-skill.md deleted file mode 100644 index a1612bb01..000000000 --- a/articles/nodejs/bot-builder-nodejs-cortana-skill.md +++ /dev/null @@ -1,449 +0,0 @@ ---- -title: Build a speech-enabled bot with Cortana skills - Bot Service -description: Learn how to build a speech-enabled bot with Cortana skills and the Bot Framework SDK for Node.js. -author: DeniseMak -manager: kamrani -ms.author: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 02/10/2019 -monikerRange: 'azure-bot-service-3.0' ---- -# Build a speech-enabled bot with Cortana skills - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-cortana-skill.md) -> - [Node.js](../nodejs/bot-builder-nodejs-cortana-skill.md) - -The Bot Framework SDK for Node.js enables you to a build speech-enabled bot by connecting it to the Cortana channel as a Cortana skill. -Cortana skills let you provide functionality through Cortana in response to spoken input from a user. - -> [!TIP] -> For more information on what a skill is, and what they can do, see [The Cortana Skills Kit][CortanaGetStarted]. - -Creating a Cortana skill using Bot Framework requires very little Cortana-specific knowledge and primarily consists of building a bot. One of the key differences from other bots that you may have created is that Cortana has both visual and audio components. For the visual component, Cortana provides an area of the canvas for rendering content such as cards. For the audio component, you provide text or SSML in your bot's messages, which Cortana reads to the user, giving your bot a voice. - -> [!NOTE] -> Cortana is available on many different devices. Some have a screen while others, like a standalone speaker, might not. You should make sure that your bot is capable of handling both scenarios. See [Cortana-specific entities][CortanaSpecificEntities] to learn how to check device information. - -## Adding speech to your bot - -Spoken messages from your bot are represented as Speech Synthesis Markup Language (SSML). The Bot Framework SDK lets you include SSML in your bot's responses to control what the bot says, in addition to what it shows. - -### session.say - -Your bot uses the **session.say** method to speak to the user, in place of **session.send**. It includes optional parameters for sending SSML output, as well as attachments like cards. - -The method has this format: - -```session.say(displayText: string, speechText: string, options?: object)``` - -| Parameter | Description | -|------|------| -| **displayText** | A textual message to display in Cortana's UI.| -| **speechText** | The text or SSML that Cortana reads to the user. | -| **options** | An [IMessage][IMessage] object that can contain an attachment or input hint. Input hints indicate whether the bot is accepting, expecting, or ignoring input. Card attachments are displayed in Cortana’s canvas below the **displayText** information. | - -The **inputHint** property helps indicate to Cortana whether your bot is expecting input. If you're using a built-in prompt, this value is automatically set to the default of **expectingInput**. - - -| Value | Description | -|------|------| -| **acceptingInput** | Your bot is passively ready for input but is not waiting on a response. Cortana accepts input from the user if the user holds down the microphone button.| -| **expectingInput** | Indicates that the bot is actively expecting a response from the user. Cortana listens for the user to speak into the microphone. | -||NOTE: Do _not_ use **expectingInput** on headless devices (devices without a display). See the [Cortana Skills Kit FAQ](https://review.docs.microsoft.com/cortana/skills/faq).| -| **ignoringInput** | Cortana is ignoring input. Your bot may send this hint if it is actively processing a request, and will ignore input from users until the request is complete. | - -The following example shows how Cortana reads plain text or SSML: - -```javascript - -// Have Cortana read plain text -session.say('This is the text that Cortana displays', 'This is the text that is spoken by Cortana.'); - -// Have Cortana read SSML -session.say('This is the text that Cortana displays', 'This is the text that is spoken by Cortana.'); - -``` - -This example shows how to let Cortana know that user input is expected. The microphone will be left open. - -```javascript - -// Add an InputHint to let Cortana know to expect user input -session.say('Hi there', 'Hi, what’s your name?', { - inputHint: builder.InputHint.expectingInput -}); - -``` - - -### Prompts - -In addition to using the **session.say()** method you can also pass text or SSML to built-in prompts using the **speak** and **retrySpeak** options. - -```javascript - -builder.Prompts.text(session, 'text based prompt', { - speak: 'Cortana reads this out initially', - retrySpeak: 'This message is repeated by Cortana after waiting a while for user input', - inputHint: builder.InputHint.expectingInput -}); - -``` - - - -To present the user with a list of choices, use **Prompts.choice**. The **synonyms** option allows for more flexibility in recognizing user utterances. The **value** option is returned in **results.response.entity**. The **action** option specifies the label that your bot displays for the choice. - -**Prompts.choice** supports ordinal choices. This means that the user can say "the first", "the second" or "the third" to choose an item in a list. For example, given the following prompt, if the user asked Cortana for "the second option", the prompt will return the value of 8. - -```javascript - - var choices = [ - { value: '4', action: { title: '4 Sides' }, synonyms: 'four|for|4 sided|4 sides' }, - { value: '8', action: { title: '8 Sides' }, synonyms: 'eight|ate|8 sided|8 sides' }, - { value: '12', action: { title: '12 Sides' }, synonyms: 'twelve|12 sided|12 sides' }, - { value: '20', action: { title: '20 Sides' }, synonyms: 'twenty|20 sided|20 sides' }, - ]; - builder.Prompts.choice(session, 'choose_sides', choices, { - speak: speak(session, 'choose_sides_ssml') // use helper function to format SSML - }); - -``` - -In the previous example, the SSML for the prompt's **speak** property is formatted by using strings stored in a localized prompts file with the following format. - -```json - -{ - "choose_sides": "__Number of Sides__", - "choose_sides_ssml": [ - "How many sides on the dice?", - "Pick your poison.", - "All the standard sizes are supported." - ] -} - -``` - -A helper function then builds the required root element of a Speech Synthesis Markup Language (SSML) document. - -```javascript - -module.exports.speak = function (template, params, options) { - options = options || {}; - var output = ''; - output += module.exports.vsprintf(template, params); - output += ''; - return output; -} -``` - -> [!TIP] -> You can find a small utility module (ssml.js) for building your bot's SSML-based responses in the [Roller sample skill](https://github.com/Microsoft/BotBuilder-Samples/tree/master/Node/demo-RollerSkill). -> There are also several useful SSML libraries available through [npm](https://www.npmjs.com/search?q=ssml) which make it easy to create well formatted SSML. - -## Display cards in Cortana - -In addition to spoken responses, Cortana can also display card attachments. Cortana supports the following rich cards: -* [HeroCard](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.herocard.html) -* [ReceiptCard](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.receiptcard.html) -* [ThumbnailCard](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.thumbnailcard.html) - -See [Card design best practices][CardDesign] to see what these cards look like inside Cortana. For an example of how to add a rich card to a bot, see [Send rich cards](bot-builder-nodejs-send-rich-cards.md). - -The following code demonstrates how to add the **speak** and **inputHint** properties to a message containing a Hero card. - -```javascript - -bot.dialog('HelpDialog', function (session) { - var card = new builder.HeroCard(session) - .title('help_title') - .buttons([ - builder.CardAction.imBack(session, 'roll some dice', 'Roll Dice'), - builder.CardAction.imBack(session, 'play yahtzee', 'Play Yahtzee') - ]); - var msg = new builder.Message(session) - .speak(speak(session, 'I\'m roller, the dice rolling bot. You can say \'roll some dice\'')) - .addAttachment(card) - .inputHint(builder.InputHint.acceptingInput); // Tell Cortana to accept input - session.send(msg).endDialog(); -}).triggerAction({ matches: /help/i }); - -/** This helper function builds the required root element of a Speech Synthesis Markup Language (SSML) document. */ -module.exports.speak = function (template, params, options) { - options = options || {}; - var output = ''; - output += module.exports.vsprintf(template, params); - output += ''; - return output; -} - -``` -## Sample: RollerSkill -The code in the following sections comes from a sample Cortana skill for rolling dice. Download the full code for the bot from the [BotBuilder-Samples repository](https://github.com/Microsoft/BotBuilder-Samples/tree/master/Node/demo-RollerSkill). - -You invoke the skill by saying its [invocation name][InvocationNameGuidelines] to Cortana. For the roller skill, after you [add the bot to the Cortana channel][CortanaChannel] and register it as a Cortana skill, you can invoke it by telling Cortana "Ask Roller" or "Ask Roller to roll dice". - -### Explore the code - -The RollerSkill sample starts by opening a card with some buttons to tell the user which options are available to them. - -```javascript - -/** - * Create your bot with a default message handler that receive messages from the user. - * - This function is be called anytime the user's utterance isn't - * recognized by the other handlers in the bot. - */ -var bot = new builder.UniversalBot(connector, function (session) { - // Just redirect to our 'HelpDialog'. - session.replaceDialog('HelpDialog'); -}); - -//... - -bot.dialog('HelpDialog', function (session) { - var card = new builder.HeroCard(session) - .title('help_title') - .buttons([ - builder.CardAction.imBack(session, 'roll some dice', 'Roll Dice'), - builder.CardAction.imBack(session, 'play craps', 'Play Craps') - ]); - var msg = new builder.Message(session) - .speak(speak(session, 'help_ssml')) - .addAttachment(card) - .inputHint(builder.InputHint.acceptingInput); - session.send(msg).endDialog(); -}).triggerAction({ matches: /help/i }); -``` - -### Prompt the user for input - -The following dialog sets up a custom game for the bot to play. It -asks the user how many sides they want the dice to have and then -how many should be rolled. Once it has built the game structure -it will pass it to a separate 'PlayGameDialog'. - -To start the dialog, the **triggerAction()** handler on this dialog allows a user to say -something like "I'd like to roll some dice". It uses a regular expression to match the user's input but you could just as easily use a [LUIS intent](./bot-builder-nodejs-recognize-intent-luis.md). - - -```javascript -bot.dialog('CreateGameDialog', [ - function (session) { - // Initialize game structure. - // - dialogData gives us temporary storage of this data in between - // turns with the user. - var game = session.dialogData.game = { - type: 'custom', - sides: null, - count: null, - turns: 0 - }; - - var choices = [ - { value: '4', action: { title: '4 Sides' }, synonyms: 'four|for|4 sided|4 sides' }, - { value: '6', action: { title: '6 Sides' }, synonyms: 'six|sex|6 sided|6 sides' }, - { value: '8', action: { title: '8 Sides' }, synonyms: 'eight|8 sided|8 sides' }, - { value: '10', action: { title: '10 Sides' }, synonyms: 'ten|10 sided|10 sides' }, - { value: '12', action: { title: '12 Sides' }, synonyms: 'twelve|12 sided|12 sides' }, - { value: '20', action: { title: '20 Sides' }, synonyms: 'twenty|20 sided|20 sides' }, - ]; - builder.Prompts.choice(session, 'choose_sides', choices, { - speak: speak(session, 'choose_sides_ssml') - }); - }, - function (session, results) { - // Store users input - // - The response comes back as a find result with index & entity value matched. - var game = session.dialogData.game; - game.sides = Number(results.response.entity); - - /** - * Ask for number of dice. - */ - var prompt = session.gettext('choose_count', game.sides); - builder.Prompts.number(session, prompt, { - speak: speak(session, 'choose_count_ssml'), - minValue: 1, - maxValue: 100, - integerOnly: true - }); - }, - function (session, results) { - // Store users input - // - The response is already a number. - var game = session.dialogData.game; - game.count = results.response; - - /** - * Play the game we just created. - * - * replaceDialog() ends the current dialog and start a new - * one in its place. We can pass arguments to dialogs so we'll pass the - * 'PlayGameDialog' the game we created. - */ - session.replaceDialog('PlayGameDialog', { game: game }); - } -]).triggerAction({ matches: [ - /(roll|role|throw|shoot).*(dice|die|dye|bones)/i, - /new game/i - ]}); - -``` - -### Render results - - This dialog is our main game loop. The bot stores the game structure in - **session.conversationData** so that should the user say "roll again" we - can just re-roll the same set of dice again. - -```javascript - -bot.dialog('PlayGameDialog', function (session, args) { - // Get current or new game structure. - var game = args.game || session.conversationData.game; - if (game) { - // Generate rolls - var total = 0; - var rolls = []; - for (var i = 0; i < game.count; i++) { - var roll = Math.floor(Math.random() * game.sides) + 1; - if (roll > game.sides) { - // Accounts for 1 in a million chance random() generated a 1.0 - roll = game.sides; - } - total += roll; - rolls.push(roll); - } - - // Format roll results - var results = ''; - var multiLine = rolls.length > 5; - for (var i = 0; i < rolls.length; i++) { - if (i > 0) { - results += ' . '; - } - results += rolls[i]; - } - - // Render results using a card - var card = new builder.HeroCard(session) - .subtitle(game.count > 1 ? 'card_subtitle_plural' : 'card_subtitle_singular', game) - .buttons([ - builder.CardAction.imBack(session, 'roll again', 'Roll Again'), - builder.CardAction.imBack(session, 'new game', 'New Game') - ]); - if (multiLine) { - //card.title('card_title').text('\n\n' + results + '\n\n'); - card.text(results); - } else { - card.title(results); - } - var msg = new builder.Message(session).addAttachment(card); - - // Determine bots reaction for speech purposes - var reaction = 'normal'; - var min = game.count; - var max = game.count * game.sides; - var score = total/max; - if (score == 1.0) { - reaction = 'best'; - } else if (score == 0) { - reaction = 'worst'; - } else if (score <= 0.3) { - reaction = 'bad'; - } else if (score >= 0.8) { - reaction = 'good'; - } - - // Check for special craps rolls - if (game.type == 'craps') { - switch (total) { - case 2: - case 3: - case 12: - reaction = 'craps_lose'; - break; - case 7: - reaction = 'craps_seven'; - break; - case 11: - reaction = 'craps_eleven'; - break; - default: - reaction = 'craps_retry'; - break; - } - } - - // Build up spoken response - var spoken = ''; - if (game.turn == 0) { - spoken += session.gettext('start_' + game.type + '_game_ssml') + ' '; - } - spoken += session.gettext(reaction + '_roll_reaction_ssml'); - msg.speak(ssml.speak(spoken)); - - // Increment number of turns and store game to roll again - game.turn++; - session.conversationData.game = game; - - /** - * Send card and bot's reaction to user. - */ - - msg.inputHint(builder.InputHint.acceptingInput); - session.send(msg).endDialog(); - } else { - // User started session with "roll again" so let's just send them to - // the 'CreateGameDialog' - session.replaceDialog('CreateGameDialog'); - } -}).triggerAction({ matches: /(roll|role|throw|shoot) again/i }); - -``` - -## Next steps -If you have a bot running locally or deployed in the cloud, you can invoke it from Cortana. See [Test a Cortana skill](../bot-service-debug-cortana-skill.md) for the steps required to try out your Cortana Skill. - - -## Additional resources -* [The Cortana Skills Kit][CortanaGetStarted] -* [Add speech to messages](bot-builder-nodejs-text-to-speech.md) -* [SSML Reference][SSMLRef] -* [Voice design best practices for Cortana][VoiceDesign] -* [Card design best practices for Cortana][CardDesign] -* [Cortana Dev Center][CortanaDevCenter] -* [Testing and debugging best practices for Cortana][Cortana-TestBestPractice] - - -[CortanaGetStarted]: /cortana/getstarted -[BFPortal]: https://dev.botframework.com/ - - -[SSMLRef]: https://aka.ms/cortana-ssml -[IMessage]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.imessage.html -[Send]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#send -[CortanaDevCenter]: https://developer.microsoft.com/cortana - -[CortanaSpecificEntities]: https://aka.ms/cortana-channel-data -[CortanaAuth]: https://aka.ms/add-auth-cortana-skill - -[InvocationNameGuidelines]: https://aka.ms/cortana-invocation-guidelines -[VoiceDesign]: https://aka.ms/cortana-design-voice -[CardDesign]: https://aka.ms/cortana-design-card -[Cortana-Debug]: https://aka.ms/cortana-enable-debug -[Cortana-Publish]: https://aka.ms/cortana-publish - - -[CortanaChannel]: https://aka.ms/bot-cortana-channel -[Cortana-TestBestPractice]: https://aka.ms/cortana-test-best-practice diff --git a/articles/nodejs/bot-builder-nodejs-dialog-actions.md b/articles/nodejs/bot-builder-nodejs-dialog-actions.md deleted file mode 100644 index e3c9305fd..000000000 --- a/articles/nodejs/bot-builder-nodejs-dialog-actions.md +++ /dev/null @@ -1,290 +0,0 @@ ---- -title: Handle user actions - Bot Service -description: Learn how to handle user actions by enabling your bot to listen for and handle user input containing certain keywords using the Bot Framework SDK for Node.js. -author: DucVo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Handle user actions - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-global-handlers.md) -> - [Node.js](../nodejs/bot-builder-nodejs-dialog-actions.md) - -Users commonly attempt to access certain functionality within a bot by using keywords like "help", "cancel", or "start over." -Users do this in the middle of a conversation, when the bot is expecting a different response. By implementing **actions**, you can design your bot to handle such requests more gracefully. The handlers will examine user input for the keywords that you specify, such as "help", "cancel", or "start over," and respond appropriately. - -![how users talk](../media/designing-bots/capabilities/trigger-actions.png) - -## Action types - -The action types you can attach to a dialog are listed in the table below. The link for each action name will take you to a section that provide more details about that action. - -| Action | Scope | Description | -|------|------| ---- | -| [triggerAction](#bind-a-triggeraction) | Global | Binds an action to the dialog that will clear the dialog stack and push itself onto the bottom of stack. Use `onSelectAction` option to override this default behavior. | -| [customAction](#bind-a-customaction) | Global | Binds a custom action to the bot that can process information or take action without affecting the dialog stack. Use `onSelectAction` option to customize the functionality of this action. | -[beginDialogAction](#bind-a-begindialogaction) | Contextual | Binds an action to the dialog that starts another dialog when it is triggered. The starting dialog will be pushed onto the stack and popped off once it ends. | -[reloadAction](#bind-a-reloadaction) | Contextual | Binds an action to the dialog that causes the dialog to reload when it is triggered. You can use `reloadAction` to handle user utterances like "start over." | -[cancelAction](#bind-a-cancelaction) | Contextual | Binds an action to the dialog that cancels the dialog when it is triggered. You can use `cancelAction` to handle user utterances like "cancel" or "nevermind." | -[endConversationAction](#bind-an-endconversationaction) | Contextual | Binds an action to the dialog that ends the conversation with the user when triggered. You can use `endConversationAction` to handle user utterances like "goodbye." | - -## Action precedence - -When a bot receives an utterance from a user, it checks the utterance against all the registered actions that are on the dialog stack. The matching starts from the top of the stack down to the bottom of the stack. If nothing matches, then it check the utterance against the `matches` option of all global actions. - -The action precedence is important in cases where you use the same command in difference contexts. For example, you can use the "Help" command for the bot as a general help. You can also use "Help" for each of the tasks but these help commands are contextual to each task. For a working sample that elaborates on this point, see [Respond to user input](bot-builder-nodejs-dialog-manage-conversation-flow.md#respond-to-user-input). - -## Bind actions to dialog - -Either user utterances or button clicks can *trigger* an action, which is associated with a [dialog](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html). -If *matches* is specified, the action will listen for the user to say a word or a phrase that triggers the action. The `matches` option can take a regular expression or the name of a [recognizer][RecognizeIntent]. -To bind the action to a button click, use [CardAction.dialogAction()][CardAction] to trigger the action. - -Actions are *chainable*, which allows you to bind as many actions to a dialog as you want. - -### Bind a triggerAction - -To bind a [triggerAction][triggerAction] to a dialog, do the following: - -```javascript -// Order dinner. -bot.dialog('orderDinner', [ - //...waterfall steps... -]) -// Once triggered, will clear the dialog stack and pushes -// the 'orderDinner' dialog onto the bottom of stack. -.triggerAction({ - matches: /^order dinner$/i -}); -``` - -Binding a `triggerAction` to a dialog registers it to the bot. Once triggered, the `triggerAction` will clear the dialog stack and push the triggered dialog onto the stack. This action is best used to switch between [topic of conversation](bot-builder-nodejs-dialog-manage-conversation-flow.md#change-the-topic-of-conversation) or to allow users to request arbitrary stand-alone tasks. If you want to override the behavior where this action clears the dialog stack, add an `onSelectAction` option to the `triggerAction`. - -The code snippet below shows how to provide general help from a global context without clearing the dialog stack. - -```javascript -bot.dialog('help', function (session, args, next) { - //Send a help message - session.endDialog("Global help menu."); -}) -// Once triggered, will start a new dialog as specified by -// the 'onSelectAction' option. -.triggerAction({ - matches: /^help$/i, - onSelectAction: (session, args, next) => { - // Add the help dialog to the top of the dialog stack - // (override the default behavior of replacing the stack) - session.beginDialog(args.action, args); - } -}); -``` - -In this case, the `triggerAction` is attached to the `help` dialog itself (as opposed to the `orderDinner` dialog). The `onSelectAction` option allows you to start this dialog without clearing the dialog stack. This allows you to handle global requests such as "help", "about", "support", etc. Notice that the `onSelectAction` option explicitly calls the `session.beginDialog` method to start the triggered dialog. The ID of the triggered dialog is provided via the `args.action`. Do not hand code the dialog ID (e.g.: 'help') into this method otherwise you may get runtime errors. If you wish to trigger a contextual help message for the `orderDinner` task itself then consider attaching a `beginDialogAction` to the `orderDinner` dialog instead. - -### Bind a customAction - -Unlike other action types, `customAction` does not have any default action defined. It's up to you to define what this action does. The benefit of using `customAction` is that you have the option to process user requests without manipulating the dialog stack. When a `customAction` is triggered, the `onSelectAction` option can process the request without pushing new dialogs onto the stack. Once the action is completed, control is passed back to the dialog that is at the top of the stack and the bot can continue. - -You can use a `customAction` to provide general and quick action requests such as "What is the temperature outside right now?", "What time is it right now in Paris?", "Remind me to buy milk at 5pm today.", etc. These are general actions that the bot can perform with out manipulating the stack. - -Another key difference with `customAction` is that it binds to the bot as opposed to a dialog. - -The follow code sample shows how to bind a `customAction` to the `bot` listening for requests to set a reminder. - -```javascript -bot.customAction({ - matches: /remind|reminder/gi, - onSelectAction: (session, args, next) => { - // Set reminder... - session.send("Reminder is set."); - } -}) -``` - -### Bind a beginDialogAction - -Binding a `beginDialogAction` to a dialog will register the action to the dialog. This method will start another dialog when it is triggered. The behavior of this action is similar to calling the [beginDialog](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#begindialog) method. The new dialog is pushed onto the top of the dialog stack so it does not automatically end the current task. The current task is continued once the new dialog ends. - -The following code snippet shows how to bind a [beginDialogAction][beginDialogAction] to a dialog. - -```javascript -// Order dinner. -bot.dialog('orderDinner', [ - //...waterfall steps... -]) -// Once triggered, will start the 'showDinnerCart' dialog. -// Then, the waterfall will resumed from the step that was interrupted. -.beginDialogAction('showCartAction', 'showDinnerCart', { - matches: /^show cart$/i -}); - -// Show dinner items in cart -bot.dialog('showDinnerCart', function(session){ - for(var i = 1; i < session.conversationData.orders.length; i++){ - session.send(`You ordered: ${session.conversationData.orders[i].Description} for a total of $${session.conversationData.orders[i].Price}.`); - } - - // End this dialog - session.endDialog(`Your total is: $${session.conversationData.orders[0].Price}`); -}); -``` - -In cases where you need to pass additional arguments into the new dialog, you can add a [`dialogArgs`](https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.idialogactionoptions#dialogargs) option to the action. - -Using the sample above, you can modify it to accept arguments passed in via the `dialogArgs`. - -```javascript -// Order dinner. -bot.dialog('orderDinner', [ - //...waterfall steps... -]) -// Once triggered, will start the 'showDinnerCart' dialog. -// Then, the waterfall will resumed from the step that was interrupted. -.beginDialogAction('showCartAction', 'showDinnerCart', { - matches: /^show cart$/i, - dialogArgs: { - showTotal: true; - } -}); - -// Show dinner items in cart with the option to show total or not. -bot.dialog('showDinnerCart', function(session, args){ - for(var i = 1; i < session.conversationData.orders.length; i++){ - session.send(`You ordered: ${session.conversationData.orders[i].Description} for a total of $${session.conversationData.orders[i].Price}.`); - } - - if(args && args.showTotal){ - // End this dialog with total. - session.endDialog(`Your total is: $${session.conversationData.orders[0].Price}`); - } - else{ - session.endDialog(); // Ends without a message. - } -}); -``` - -### Bind a reloadAction - -Binding a `reloadAction` to a dialog will register it to the dialog. Binding this action to a dialog causes the dialog to restart when the action is triggered. Triggering this action is similar to calling the [replaceDialog](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#replacedialog) method. This is useful for implementing logic to handle user utterances like "start over" or to create [loops](bot-builder-nodejs-dialog-replace.md#repeat-an-action). - -The following code snippet shows how to bind a [reloadAction][reloadAction] to a dialog. - -```javascript -// Order dinner. -bot.dialog('orderDinner', [ - //...waterfall steps... -]) -// Once triggered, will restart the dialog. -.reloadAction('startOver', 'Ok, starting over.', { - matches: /^start over$/i -}); -``` - -In cases where you need to pass additional arguments into the reloaded dialog, you can add a [`dialogArgs`](https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.idialogactionoptions#dialogargs) option to the action. This option is passed into the `args` parameter. Rewriting the sample code above to receive an argument on a reload action will look something like this: - -```javascript -// Order dinner. -bot.dialog('orderDinner', [ - function(session, args, next){ - if(args && args.isReloaded){ - // Reload action was triggered. - } - - session.send("Lets order some dinner!"); - builder.Prompts.choice(session, "Dinner menu:", dinnerMenu); - } - //...other waterfall steps... -]) -// Once triggered, will restart the dialog. -.reloadAction('startOver', 'Ok, starting over.', { - matches: /^start over$/i, - dialogArgs: { - isReloaded: true; - } -}); -``` - -### Bind a cancelAction - -Binding a `cancelAction` will register it to the dialog. Once triggered, this action will abruptly end the dialog. Once the dialog ends, the parent dialog will resume with a resumed code indicating that it was `canceled`. This action allows you to handle utterances such as "nevermind" or "cancel." If you need to programmatically cancel a dialog instead, see [Cancel a dialog](bot-builder-nodejs-dialog-replace.md#cancel-a-dialog). For more information on *resumed code*, see [Prompt results](bot-builder-nodejs-dialog-prompt.md#prompt-results). - -The following code snippet shows how to bind a [cancelAction][cancelAction] to a dialog. - -```javascript -// Order dinner. -bot.dialog('orderDinner', [ - //...waterfall steps... -]) -//Once triggered, will end the dialog. -.cancelAction('cancelAction', 'Ok, cancel order.', { - matches: /^nevermind$|^cancel$|^cancel.*order/i -}); -``` - -### Bind an endConversationAction - -Binding an `endConversationAction` will register it to the dialog. Once triggered, this action ends the conversation with the user. Triggering this action is similar to calling the [endConversation](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#endconversation) method. Once a conversation ends, the Bot Framework SDK for Node.js will clear the dialog stack and persisted state data. For more information on persisted state data, see [Manage state data](bot-builder-nodejs-state.md). - -The following code snippet shows how to bind an [endConversationAction][endConversationAction] to a dialog. - -```javascript -// Order dinner. -bot.dialog('orderDinner', [ - //...waterfall steps... -]) -// Once triggered, will end the conversation. -.endConversationAction('endConversationAction', 'Ok, goodbye!', { - matches: /^goodbye$/i -}); -``` - -## Confirm interruptions - -Most, if not, all of these actions interrupt the normal flow of a conversation. Many are disruptive and should be handle with care. For example, the `triggerAction`, `cancelAction`, or the `endConversationAction` will clear the dialog stack. If the user made the mistake of triggering either of these actions, they will have to start the task over again. To make sure the user really intended to trigger these actions, you can add a `confirmPrompt` option to these actions. The `confirmPrompt` will ask if the user is sure about canceling or ending the current task. It allows the user to change their minds and continue the process. - -The code snippet below shows a [cancelAction][cancelAction] with a [confirmPrompt](http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.itriggeractionoptions#confirmprompt) to make sure the user really wants to cancel the order process. - -```javascript -// Order dinner. -bot.dialog('orderDinner', [ - //...waterfall steps... -]) -// Confirm before triggering the action. -// Once triggered, will end the dialog. -.cancelAction('cancelAction', 'Ok, cancel order.', { - matches: /^nevermind$|^cancel$|^cancel.*order/i, - confirmPrompt: "Are you sure?" -}); -``` - -Once this action is triggered, it will ask the user "Are you sure?" The user will have to answer "Yes" to go through with the action or "No" to cancel the action and continue where they were. - -## Next steps - -**Actions** allow you to anticipate user requests and allow the bot to handle those requests gracefully. Many of these actions are disruptive to the current conversation flow. If you want to allow users the ability to switch out and resume a conversation flow, you need to save the user state before switching out. Let's take a closer look at how to save user state and manage state data. - -> [!div class="nextstepaction"] -> [Manage state data](bot-builder-nodejs-state.md) - - -[triggerAction]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html#triggeraction - -[cancelAction]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html#cancelaction - -[reloadAction]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html#reloadaction - -[beginDialogAction]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html#begindialogaction - -[endConversationAction]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html#endconversationaction - -[RecognizeIntent]: bot-builder-nodejs-recognize-intent-messages.md - -[CardAction]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.cardaction#dialogaction diff --git a/articles/nodejs/bot-builder-nodejs-dialog-manage-conversation-flow.md b/articles/nodejs/bot-builder-nodejs-dialog-manage-conversation-flow.md deleted file mode 100644 index 471f7557d..000000000 --- a/articles/nodejs/bot-builder-nodejs-dialog-manage-conversation-flow.md +++ /dev/null @@ -1,383 +0,0 @@ ---- -title: Manage a conversation flow with dialogs - Bot Service -description: Learn how to manage a conversation between a bot and a user with dialogs in the Bot Framework SDK for Node.js. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Manage conversation flow with dialogs - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-manage-conversation-flow.md) -> - [Node.js](../nodejs/bot-builder-nodejs-dialog-manage-conversation-flow.md) - -Managing conversation flow is an essential task in building bots. A bot needs to be able to perform core tasks elegantly and handle interruptions gracefully. With the Bot Framework SDK for Node.js, you can manage conversation flow using dialogs. - -A dialog is like a function in a program. It is generally designed to perform a specific operation and it can be invoked as often as it is needed. You can chain multiple dialogs together to handle just about any conversation flow that you want your bot to handle. The Bot Framework SDK for Node.js includes built-in features such as [prompts](bot-builder-nodejs-dialog-prompt.md) and [waterfalls](bot-builder-nodejs-dialog-waterfall.md) to help you manage conversation flow. - -This article provides a series of examples to explain how to manage both simple conversation flows and complex conversation flows where your bot can handle interruptions and resume the flow gracefully using dialogs. The examples are based on the following scenarios: - -1. Your bot will take a dinner reservation. -2. Your bot can process "Help" request at any time during the reservation. -3. Your bot can process context-sensitive "Help" for current step of the reservation. -4. Your bot can handle multiple topics of conversation. - -## Manage conversation flow with a waterfall - -A [waterfall](bot-builder-nodejs-dialog-waterfall.md) is a dialog that allows the bot to easily walk a user through a series of tasks. In this example, the reservation bot asks the user a series of questions so that the bot can process the reservation request. The bot will prompt the user for the following information: - -1. Reservation date and time -2. Number of people in the party -3. Name of the person making the reservation - -The following code sample shows how to use a waterfall to guide the user through a series of prompts. - -```javascript -var inMemoryStorage = new builder.MemoryBotStorage(); - -// This is a dinner reservation bot that uses a waterfall technique to prompt users for input. -var bot = new builder.UniversalBot(connector, [ - function (session) { - session.send("Welcome to the dinner reservation."); - builder.Prompts.time(session, "Please provide a reservation date and time (e.g.: June 6th at 5pm)"); - }, - function (session, results) { - session.dialogData.reservationDate = builder.EntityRecognizer.resolveTime([results.response]); - builder.Prompts.number(session, "How many people are in your party?"); - }, - function (session, results) { - session.dialogData.partySize = results.response; - builder.Prompts.text(session, "Whose name will this reservation be under?"); - }, - function (session, results) { - session.dialogData.reservationName = results.response; - - // Process request and display reservation details - session.send(`Reservation confirmed. Reservation details:
Date/Time: ${session.dialogData.reservationDate}
Party size: ${session.dialogData.partySize}
Reservation name: ${session.dialogData.reservationName}`); - session.endDialog(); - } -]).set('storage', inMemoryStorage); // Register in-memory storage -``` - -The core functionality of this bot occurs in the default dialog. The default dialog is defined when the bot is created: - -```javascript -var bot = new builder.UniversalBot(connector, [..waterfall steps..]); -``` - -Also, during this creation process, you can set which [data storage](bot-builder-nodejs-state.md) you want to use. For instance, to use the in-memory storage, you can set it as follows: - -```javascript -var inMemoryStorage = new builder.MemoryBotStorage(); -var bot = new builder.UniversalBot(connector, [..waterfall steps..]).set('storage', inMemoryStorage); // Register in-memory storage -``` - -The default dialog is created as an array of functions that define the steps of the waterfall. In the example, there are four functions so the waterfall has four steps. Each step performs a single task and the results are processed in the next step. The process continues until the last step, where the reservation is confirmed and the dialog ends. - -The following screen shot shows the results of this bot running in the [Bot Framework Emulator](../bot-service-debug-emulator.md): - -![Manage conversation flow with waterfall](../media/bot-builder-nodejs-dialog-manage-conversation/waterfall-results.png) - -### Prompt user for input - -Each step of this example uses a prompt to ask the user for input. A prompt is a special type of dialog that asks for user input, waits for a response, and returns the response to the next step in the waterfall. See [Prompt users for input](bot-builder-nodejs-dialog-prompt.md) for information about the many different types of prompts you can use in your bot. - -In this example, the bot uses `Prompts.text()` to solicit a freeform response from the user in text format. The user can respond with any text and the bot must decide how to handle the response. `Prompts.time()` uses the [Chrono](https://github.com/wanasit/chrono) library to parse for date and time information from a string. This allows your bot to understand more natural language for specifying date and time. For example: "June 6th, 2017 at 9pm", "Today at 7:30pm", "next monday at 6pm", and so on. - -> [!TIP] -> The time that the user enters is converted to UTC time based upon the time zone of the server that hosts the bot. Since the server may be located in a different time zone than the user, be sure to take time zones into consideration. To convert date and time to the user's local time, consider asking the user what time zone they are in. - -## Manage a conversation flow with multiple dialogs - -Another technique for managing conversation flow is to use a combination of waterfall and multiple dialogs. The waterfall allows you to chain functions together in a dialog, while dialogs enable you to break a conversation into smaller pieces of functionality that can be reused at any time. - -For example, consider the dinner reservation bot. The following code sample shows the previous example rewritten to use waterfall and multiple dialogs. - -```javascript -var inMemoryStorage = new builder.MemoryBotStorage(); - -// This is a dinner reservation bot that uses multiple dialogs to prompt users for input. -var bot = new builder.UniversalBot(connector, [ - function (session) { - session.send("Welcome to the dinner reservation."); - session.beginDialog('askForDateTime'); - }, - function (session, results) { - session.dialogData.reservationDate = builder.EntityRecognizer.resolveTime([results.response]); - session.beginDialog('askForPartySize'); - }, - function (session, results) { - session.dialogData.partySize = results.response; - session.beginDialog('askForReserverName'); - }, - function (session, results) { - session.dialogData.reservationName = results.response; - - // Process request and display reservation details - session.send(`Reservation confirmed. Reservation details:
Date/Time: ${session.dialogData.reservationDate}
Party size: ${session.dialogData.partySize}
Reservation name: ${session.dialogData.reservationName}`); - session.endDialog(); - } -]).set('storage', inMemoryStorage); // Register in-memory storage - -// Dialog to ask for a date and time -bot.dialog('askForDateTime', [ - function (session) { - builder.Prompts.time(session, "Please provide a reservation date and time (e.g.: June 6th at 5pm)"); - }, - function (session, results) { - session.endDialogWithResult(results); - } -]); - -// Dialog to ask for number of people in the party -bot.dialog('askForPartySize', [ - function (session) { - builder.Prompts.text(session, "How many people are in your party?"); - }, - function (session, results) { - session.endDialogWithResult(results); - } -]) - -// Dialog to ask for the reservation name. -bot.dialog('askForReserverName', [ - function (session) { - builder.Prompts.text(session, "Who's name will this reservation be under?"); - }, - function (session, results) { - session.endDialogWithResult(results); - } -]); -``` - -The results from executing this bot are exactly the same as the previous bot where only waterfall is used. However, programmatically, there are two primary differences: - -1. The default dialog is dedicated to managing the flow of the conversation. -2. The task for each step of the conversation is being managed by a separate dialog. In this case, the bot needed three pieces of information so it prompts the user three times. Each prompt is now contained within its own dialog. - -With this technique, you can separate the conversation flow from the task logic. This allows the dialogs to be reused by different conversation flows if necessary. - -## Respond to user input - -In the process of guiding the user through a series of tasks, if the user has questions or wants to request additional information before answering, how would you handle those requests? For example, regardless of where the user is in the conversation, how would the bot respond if the user enters "Help", "Support" or "Cancel"? What if the user wants additional information about a step? What happens if the user changes their mind and wants to abandon the current task to start a completely different task? - -The Bot Framework SDK for Node.js allows a bot to listen for certain input within a global context or within a local context in the scope of the current dialog. These inputs are called [actions](bot-builder-nodejs-dialog-actions.md), which allow the bot to listen for user input based on a `matches` clause. It's up to the bot to decide how to react to specific user inputs. - -### Handle global action - -If you want your bot to be able to handle actions at any point in a conversation, use `triggerAction`. Triggers allow the bot to invoke a specific dialog when the input matches the specified term. For example, if you want to support a global "Help" option, you can create a help dialog and attach a `triggerAction` that listens for input matching "Help". - -The following code sample shows how to attach a `triggerAction` to a dialog to specify that the dialog should be invoked when the user enters "help". - -```javascript -// The dialog stack is cleared and this dialog is invoked when the user enters 'help'. -bot.dialog('help', function (session, args, next) { - session.endDialog("This is a bot that can help you make a dinner reservation.
Please say 'next' to continue"); -}) -.triggerAction({ - matches: /^help$/i, -}); -``` - -By default, when a `triggerAction` executes, the dialog stack is cleared and the triggered dialog becomes the new default dialog. In this example, when the `triggerAction` executes, the dialog stack is cleared and the `help` dialog is then added to the stack as the new default dialog. If this is not the desired behavior, you can add the `onSelectAction` option to the `triggerAction`. The `onSelectAction` option allows the bot to start a new dialog without clearing the dialog stack, which enables the conversation to be temporarily redirected and later resume where it left off. - -The following code sample shows how to use the `onSelectAction` option with `triggerAction` so that the `help` dialog is added to the existing dialog stack (and the dialog stack is not cleared). - -```javascript -bot.dialog('help', function (session, args, next) { - session.endDialog("This is a bot that can help you make a dinner reservation.
Please say 'next' to continue"); -}) -.triggerAction({ - matches: /^help$/i, - onSelectAction: (session, args, next) => { - // Add the help dialog to the dialog stack - // (override the default behavior of replacing the stack) - session.beginDialog(args.action, args); - } -}); -``` - -In this example, the `help` dialog takes control of the conversation when the user enters "help". Because the `triggerAction` contains the `onSelectAction` option, the `help` dialog is pushed onto the existing dialog stack and the stack is not cleared. When the `help` dialog ends, it is removed from the dialog stack and the conversation resumes from the point at which it was interrupted with the `help` command. - -### Handle contextual action - -In the previous example, the `help` dialog is invoked if the user enters "help" at any point in the conversation. As such, the dialog can only offer general help guidance, as there is no specific context for the user's help request. But, what if the user wants to request help regarding a specific point in the conversation? In that case, the `help` dialog must be triggered within the context of the current dialog. - -For example, consider the dinner reservation bot. What if a user wants to know the maximum party size when they are asked for the number of members in their party? To handle this scenario, you can attach a `beginDialogAction` to the `askForPartySize` dialog, listening for the user input "help". - -The following code sample shows how to attach context-sensitive help to a dialog using `beginDialogAction`. - -```javascript -// Dialog to ask for number of people in the party -bot.dialog('askForPartySize', [ - function (session) { - builder.Prompts.text(session, "How many people are in your party?"); - }, - function (session, results) { - session.endDialogWithResult(results); - } -]) -.beginDialogAction('partySizeHelpAction', 'partySizeHelp', { matches: /^help$/i }); - -// Context Help dialog for party size -bot.dialog('partySizeHelp', function(session, args, next) { - var msg = "Party size help: Our restaurant can support party sizes up to 150 members."; - session.endDialog(msg); -}) -``` - -In this example, whenever the user enters "help", the bot will push the `partySizeHelp` dialog onto the stack. That dialog sends a help message to the user and then ends the dialog, returning control back to the `askForPartySize` dialog which reprompts the user for a party size. - -It is important to note that this context-sensitive help is only executed when the user is in the `askForPartySize` dialog. Otherwise, the general help message from the `triggerAction` will execute instead. In other words, the local `matches` clause always takes precedence over the global `matches` clause. For example, if a `beginDialogAction` matches for **help**, then the matches for **help** in the `triggerAction` will not be executed. For more information, see [Action precedence](bot-builder-nodejs-dialog-actions.md#action-precedence). - -### Change the topic of conversation - -By default, executing a `triggerAction` clears the dialog stack and resets the conversation, starting with the specified dialog. This behavior is often preferable when your bot needs to switch from one topic of conversation to another, such as if a user in the midst of booking a dinner reservation instead decides to order dinner to be delivered to their hotel room. - -The following example builds upon the previous one such that the bot allows the user to either make a dinner reservation or order dinner to be delivered. In this bot, the default dialog is a greeting dialog that presents two options to the user: `Dinner Reservation` and `Order Dinner`. - -```javascript -var inMemoryStorage = new builder.MemoryBotStorage(); - -// This bot enables users to either make a dinner reservation or order dinner. -var bot = new builder.UniversalBot(connector, function(session){ - var msg = "Welcome to the reservation bot. Please say `Dinner Reservation` or `Order Dinner`"; - session.send(msg); -}).set('storage', inMemoryStorage); // Register in-memory storage -``` - -The dinner reservation logic that was in the default dialog of the previous example is now in its own dialog called `dinnerReservation`. The flow of the `dinnerReservation` remains the same as the multiple dialog version discussed earlier. The only difference is that the dialog has a `triggerAction` attached to it. Notice that in this version, the `confirmPrompt` asks the user to confirm that they want to change the topic of conversation, before invoking the new dialog. It is good practice to include a `confirmPrompt` in scenarios like this because once the dialog stack is cleared, the user will be directed to the new topic of conversation, thereby abandoning the topic of conversation that was underway. - -```javascript -// This dialog helps the user make a dinner reservation. -bot.dialog('dinnerReservation', [ - function (session) { - session.send("Welcome to the dinner reservation."); - session.beginDialog('askForDateTime'); - }, - function (session, results) { - session.dialogData.reservationDate = builder.EntityRecognizer.resolveTime([results.response]); - session.beginDialog('askForPartySize'); - }, - function (session, results) { - session.dialogData.partySize = results.response; - session.beginDialog('askForReserverName'); - }, - function (session, results) { - session.dialogData.reservationName = results.response; - - // Process request and display reservation details - session.send(`Reservation confirmed. Reservation details:
Date/Time: ${session.dialogData.reservationDate}
Party size: ${session.dialogData.partySize}
Reservation name: ${session.dialogData.reservationName}`); - session.endDialog(); - } -]) -.triggerAction({ - matches: /^dinner reservation$/i, - confirmPrompt: "This will cancel your current request. Are you sure?" -}); -``` - -The second topic of conversation is defined in the `orderDinner` dialog using a waterfall. This dialog simply displays the dinner menu and prompts the user for a room number after the order is specified. A `triggerAction` is attached to the dialog to specify that it should be invoked when the user enters "order dinner" and to ensure that the user is prompted to confirm their selection, should they indicate a desire to change the topic of conversation. - -```javascript -// This dialog help the user order dinner to be delivered to their hotel room. -var dinnerMenu = { - "Potato Salad - $5.99": { - Description: "Potato Salad", - Price: 5.99 - }, - "Tuna Sandwich - $6.89": { - Description: "Tuna Sandwich", - Price: 6.89 - }, - "Clam Chowder - $4.50":{ - Description: "Clam Chowder", - Price: 4.50 - } -}; - -bot.dialog('orderDinner', [ - function(session){ - session.send("Lets order some dinner!"); - builder.Prompts.choice(session, "Dinner menu:", dinnerMenu); - }, - function (session, results) { - if (results.response) { - var order = dinnerMenu[results.response.entity]; - var msg = `You ordered: ${order.Description} for a total of $${order.Price}.`; - session.dialogData.order = order; - session.send(msg); - builder.Prompts.text(session, "What is your room number?"); - } - }, - function(session, results){ - if(results.response){ - session.dialogData.room = results.response; - var msg = `Thank you. Your order will be delivered to room #${session.dialogData.room}`; - session.endDialog(msg); - } - } -]) -.triggerAction({ - matches: /^order dinner$/i, - confirmPrompt: "This will cancel your order. Are you sure?" -}); -``` - -After the user starts a conversation and selects either `Dinner Reservation` or `Order Dinner`, they may change their mind at any time. For example, if the user is in the middle of making a dinner reservation and enters "order dinner," the bot will confirm by saying, "This will cancel your current request. Are you sure?". If the user types "no," then the request is canceled and the user can continue with the dinner reservation process. If the user types "yes," the bot will clear the dialog stack and transfer control of the conversation to the `orderDinner` dialog. - -## End conversation - -In the examples above, dialogs are closed by either using `session.endDialog` or `session.endDialogWithResult`, both of which end the dialog, remove it from the stack, and return control to the calling dialog. In situations where the user has reached the end of the conversation, you should use `session.endConversation` to indicate that the conversation is finished. - -The [`session.endConversation`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#endconversation) method ends a conversation and optionally sends a message to the user. For example, the `orderDinner` dialog in the previous example could end the conversation by using `session.endConversation`, as shown in the following code sample. - -```javascript -bot.dialog('orderDinner', [ - //...waterfall steps... - // Last step - function(session, results){ - if(results.response){ - session.dialogData.room = results.response; - var msg = `Thank you. Your order will be delivered to room #${session.dialogData.room}`; - session.endConversation(msg); - } - } -]); -``` - -Calling `session.endConversation` will end the conversation by clearing the dialog stack and resetting the [`session.conversationData`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#conversationdata) storage. For more information on data storage, see [Manage state data](bot-builder-nodejs-state.md). - -Calling `session.endConversation` is a logical thing to do when the user completes the conversation flow for which the bot is designed. You may also use `session.endConversation` to end the conversation in situations where the user enters "cancel" or "goodbye" in the midst of a conversation. To do so, simply attach an `endConversationAction` to the dialog and have this trigger listen for input matching "cancel" or "goodbye". - -The following code sample shows how to attach an `endConversationAction` to a dialog to end the conversation if the user enters "cancel" or "goodbye". - -```javascript -bot.dialog('dinnerOrder', [ - //...waterfall steps... -]) -.endConversationAction( - "endOrderDinner", "Ok. Goodbye.", - { - matches: /^cancel$|^goodbye$/i, - confirmPrompt: "This will cancel your order. Are you sure?" - } -); -``` - -Since ending a conversation with `session.endConversation` or `endConversationAction` will clear the dialog stack and force the user to start over, you should include a `confirmPrompt` to ensure that the user really wants to do so. - -## Next steps - -In this article, you explore ways to manage conversations that are sequential in nature. What if you want to repeat a dialog or use looping pattern in your conversation? Let's see how you can do that by replacing dialogs on the stack. - -> [!div class="nextstepaction"] -> [Replace dialogs](bot-builder-nodejs-dialog-replace.md) - diff --git a/articles/nodejs/bot-builder-nodejs-dialog-overview.md b/articles/nodejs/bot-builder-nodejs-dialog-overview.md deleted file mode 100644 index 869534a97..000000000 --- a/articles/nodejs/bot-builder-nodejs-dialog-overview.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Dialogs overview (v3 JS) - Bot Service -description: Learn how to use dialogs within the Bot Framework SDK for Node.js to model conversations and manage conversation flow. -author: DucVo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Dialogs in the Bot Framework SDK for Node.js - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-dialogs.md) -> - [Node.js](../nodejs/bot-builder-nodejs-dialog-overview.md) - -Dialogs in the Bot Framework SDK for Node.js allow you to model conversations and manage conversation flow. A bot communicates with a user via conversations. Conversations are organized into dialogs. Dialogs can contain waterfall steps, and prompts. As the user interacts with the bot, the bot will start, stop, and switch between various dialogs in response to user messages. Understanding how dialogs work is key to successfully designing and creating great bots. - -This article introduces dialog concepts. After you read this article, then follow the links in the [Next steps](#next-steps) section to dive deeper into these concepts. - -## Conversations through dialogs - -Bot Framework SDK for Node.js defines a conversation as the communication between a bot and a user through one or more dialogs. A dialog, at its most basic level, is a reusable module that performs an operation or collects information from a user. You can encapsulate the complex logic of your bot in reusable dialog code. - -A conversation can be structured and changed in many ways: - -- It can originate from your [default dialog](#default-dialog). -- It can be redirected from one dialog to another. -- It can be resumed. -- It can follow a [waterfall](bot-builder-nodejs-dialog-waterfall.md) pattern, which guides the user through a series of steps or [prompts](bot-builder-nodejs-dialog-prompt.md) the user with a series of questions. -- It can use [actions](bot-builder-nodejs-dialog-actions.md) that listen for words or phrases that trigger a different dialog. - -You can think of a conversation like a parent to dialogs. As such, a conversation contains a *dialog stack* and maintain its own set of state data; namely, the `conversationData` and the `privateConversationData`. A dialog, on the other hand, maintains the `dialogData`. For more information on state data, see [Manage state data](bot-builder-nodejs-state.md). - -## Dialog stack - -A bot interacts with a user through a series of dialogs that are maintained on a dialog stack. Dialogs are pushed on and popped off the stack in the course of a conversation. The stack works like a normal LIFO stack; meaning, the last dialog added will be the first one to complete. Once a dialog completes then control is returned to the previous dialog on the stack. - -When a bot conversation first starts or when a conversation ends, the dialog stack is empty. At this point, when the a user sends a message to the bot, the bot will respond with the *default dialog*. - -## Default dialog - -Prior to Bot Framework version 3.5, a *root* dialog is defined by adding a dialog named `/`, which lead to naming conventions similar to that of URLs. This naming convention wasn't appropriate to naming dialogs. - -> [!NOTE] -> Starting with version 3.5 of the Bot Framework, the *default dialog* is registered as the second parameter in the constructor of [`UniversalBot`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.universalbot.html#constructor). - -The following code snippet shows how to define the default dialog when creating the `UniversalBot` object. - -```javascript -var bot = new builder.UniversalBot(connector, [ - //...Default dialog waterfall steps... - ]); -``` - -The default dialog runs whenever the dialog stack is empty and no other dialog is [triggered](bot-builder-nodejs-dialog-actions.md) via LUIS or another [recognizer](bot-builder-nodejs-recognize-intent-messages.md). As the default dialog is the bot's first response to the user, the default dialog should provide some contextual information to the user, such as a list of available commands or an overview of what the bot can do. - -## Dialog handlers - -The dialog handler manages the flow of a conversation. To progress through a conversation, the dialog handler directs the flow by starting and ending dialogs. - -## Starting and ending dialogs - -To start a new dialog (and push it onto the stack), use [`session.beginDialog()`](http://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#begindialog). To end a dialog (and remove it from the stack, returning control to the calling dialog), use either [`session.endDialog()`](http://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#enddialog) or [`session.endDialogWithResult()`](http://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#enddialogwithresult). - -## Using waterfalls and prompts - -[Waterfall](bot-builder-nodejs-dialog-waterfall.md) is a simple way to model and manage conversation flow. A waterfall contains a sequence of steps. In each step, you can either complete an action on behalf of the user or [prompt](bot-builder-nodejs-dialog-prompt.md) the user for information. - -A waterfall is implemented using a dialog that's made up of a collection of functions. Each function defines a step in the waterfall. The following code sample shows a simple conversation that uses a two step waterfall to prompt the user for their name and greet them by name. - -```javascript -// Ask the user for their name and greet them by name. -bot.dialog('greetings', [ - function (session) { - builder.Prompts.text(session, 'Hi! What is your name?'); - }, - function (session, results) { - session.endDialog(`Hello ${results.response}!`); - } -]); -``` - -When a bot reaches the end of the waterfall without ending the dialog, the next message from the user will restart that dialog at step one of the waterfall. This may lead to frustrations as the user may feel like they are trapped in a loop. To avoid this situation, when a conversation or dialog has come to an end, it is best practice to explicitly call `endDialog`, `endDialogWithResult`, or `endConversation`. - -## Next steps - -To dive deeper into dialogs, it is important to understand how waterfall pattern works and how to use it to guide users through a process. - -> [!div class="nextstepaction"] -> [Define conversation steps with waterfalls](bot-builder-nodejs-dialog-waterfall.md) diff --git a/articles/nodejs/bot-builder-nodejs-dialog-prompt.md b/articles/nodejs/bot-builder-nodejs-dialog-prompt.md deleted file mode 100644 index 736f50ed7..000000000 --- a/articles/nodejs/bot-builder-nodejs-dialog-prompt.md +++ /dev/null @@ -1,290 +0,0 @@ ---- -title: Prompt for user input - Bot Service -description: Learn how to use prompts to collect user input with the Bot Framework SDK for Node.js. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Prompt for user input - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -The Bot Framework SDK for Node.js provides a set of built-in prompts to simplify collecting inputs from a user. - -A *prompt* is used whenever a bot needs input from the user. You can use prompts to ask a user for a series of inputs by chaining the prompts in a waterfall. You can use prompts in conjunction with [waterfall](bot-builder-nodejs-dialog-waterfall.md) to help you [manage conversation flow](bot-builder-nodejs-manage-conversation-flow.md) in your bot. - -This article will help you understand how prompts work and how you can use them to collect information from users. - -## Prompts and responses - -Whenever you need input from a user, you can send a prompt, wait for the user to respond with input, and then process the input and send a response to the user. - -The following code sample prompts the user for their name and responds with a greeting message. - -```javascript -bot.dialog('greetings', [ - // Step 1 - function (session) { - builder.Prompts.text(session, 'Hi! What is your name?'); - }, - // Step 2 - function (session, results) { - session.endDialog(`Hello ${results.response}!`); - } -]); -``` - -Using this basic construct, you can model your conversation flow by adding as many prompts and responses as your bot requires. - -## Prompt results - -Built-in prompts are implemented as [dialogs](bot-builder-nodejs-dialog-overview.md) that return the user's response in the `results.response` field. For JSON objects, responses are returned in the `results.response.entity` field. Any type of [dialog handler](bot-builder-nodejs-dialog-overview.md#dialog-handlers) can receive the result of a prompt. Once the bot receives a response, it can consume it or pass it back to the calling dialog by calling the [`session.endDialogWithResult`][EndDialogWithResult] method. - -The following code sample shows how to return a prompt result to the calling dialog by using the `session.endDialogWithResult` method. In this example, the `greetings` dialog uses the prompt result that the `askName` dialog returns to greet the user by name. - -```javascript -// Ask the user for their name and greet them by name. -bot.dialog('greetings', [ - function (session) { - session.beginDialog('askName'); - }, - function (session, results) { - session.endDialog(`Hello ${results.response}!`); - } -]); -bot.dialog('askName', [ - function (session) { - builder.Prompts.text(session, 'Hi! What is your name?'); - }, - function (session, results) { - session.endDialogWithResult(results); - } -]); -``` - -## Prompt types -The Bot Framework SDK for Node.js includes several different types of built-in prompts. - -|**Prompt type** | **Description** | -| ------------------ | --------------- | -|[Prompts.text](#promptstext) | Asks the user to enter a string of text. | -|[Prompts.confirm](#promptsconfirm) | Asks the user to confirm an action.| -|[Prompts.number](#promptsnumber) | Asks the user to enter a number. | -|[Prompts.time](#promptstime) | Asks the user for a time or date/time. | -|[Prompts.choice](#promptschoice) | Asks the user to choose from a list of options. | -|[Prompts.attachment](#promptsattachment) | Asks the user to upload a picture or video.| - -The following sections provide additional details about each type of prompt. - -### Prompts.text - -Use the [Prompts.text()][PromptsText] method to ask the user for a **string of text**. The prompt returns the user's response as an [IPromptTextResult][IPromptTextResult]. - -```javascript -builder.Prompts.text(session, "What is your name?"); -``` - -### Prompts.confirm - -Use the [Prompts.confirm()][PromptsConfirm] method to ask the user to confirm an action with a **yes/no** response. The prompt returns the user's response as an [IPromptConfirmResult](http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptconfirmresult.html). - -```javascript -builder.Prompts.confirm(session, "Are you sure you wish to cancel your order?"); -``` - -### Prompts.number - -Use the [Prompts.number()][PromptsNumber] method to ask the user for a **number**. The prompt returns the user's response as an [IPromptNumberResult](http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptnumberresult.html). - -```javascript -builder.Prompts.number(session, "How many would you like to order?"); -``` - -### Prompts.time - -Use the [Prompts.time()][PromptsTime] method to ask the user for a **time** or **date/time**. The prompt returns the user's response as an [IPromptTimeResult](http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.iprompttimeresult.html). The framework uses the [Chrono](https://github.com/wanasit/chrono) library to parse the user's response and supports both relative responses (e.g., "in 5 minutes") and non-relative responses (e.g., "June 6th at 2pm"). - -The [results.response](http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.iprompttimeresult.html#response) field, which represents the user's response, contains an [entity](http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ientity.html) object that specifies the date and time. To resolve the date and time into a JavaScript `Date` object, use the [EntityRecognizer.resolveTime()](http://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.entityrecognizer.html#resolvetime) method. - -> [!TIP] -> The time that the user enters is converted to UTC time based upon the time zone of the server that hosts the bot. Since the server may be located in a different time zone than the user, be sure to take time zones into consideration. To convert date and time to the user's local time, consider asking the user what time zone they are in. - -```javascript -bot.dialog('createAlarm', [ - function (session) { - session.dialogData.alarm = {}; - builder.Prompts.text(session, "What would you like to name this alarm?"); - }, - function (session, results, next) { - if (results.response) { - session.dialogData.name = results.response; - builder.Prompts.time(session, "What time would you like to set an alarm for?"); - } else { - next(); - } - }, - function (session, results) { - if (results.response) { - session.dialogData.time = builder.EntityRecognizer.resolveTime([results.response]); - } - - // Return alarm to caller - if (session.dialogData.name && session.dialogData.time) { - session.endDialogWithResult({ - response: { name: session.dialogData.name, time: session.dialogData.time } - }); - } else { - session.endDialogWithResult({ - resumed: builder.ResumeReason.notCompleted - }); - } - } -]); -``` - -### Prompts.choice - -Use the [Prompts.choice()][PromptsChoice] method to ask the user to **choose from a list of options**. The user can convey their selection either by entering the number associated with the option that they choose or by entering the name of the option that they choose. Both full and partial matches of the option's name are supported. The prompt returns the user's response as an [IPromptChoiceResult](http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptchoiceresult.html). - -To specify the style of the list that is presented to the user, set the [IPromptOptions.listStyle](http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptoptions.html#liststyle) property. The following table shows the `ListStyle` enumeration values for this property. - - -The `ListStyle` enum values are as follows: - -| Index | Name | Description | -| ---- | ---- | ---- | -| 0 | none | No list is rendered. This is used when the list is included as part of the prompt. | -| 1 | inline | Choices are rendered as an inline list of the form "1. red, 2. green, or 3. blue". | -| 2 | list | Choices are rendered as a numbered list. | -| 3 | button | Choices are rendered as buttons for channels that support buttons. For other channels they will be rendered as text. | -| 4 | auto | The style is selected automatically based on the channel and number of options. | - -You can access this enum from the `builder` object or you can provide an index to choose a `ListStyle`. For example, both statements in the following code snippet accomplish the same thing. - -```javascript -// ListStyle passed in as Enum -builder.Prompts.choice(session, "Which color?", "red|green|blue", { listStyle: builder.ListStyle.button }); - -// ListStyle passed in as index -builder.Prompts.choice(session, "Which color?", "red|green|blue", { listStyle: 3 }); -``` - -To specify the list of options, you can use a pipe-delimited (`|`) string, an array of strings, or an object map. - -A pipe-delimited string: - -```javascript -builder.Prompts.choice(session, "Which color?", "red|green|blue"); -``` - -An array of strings: - -```javascript -builder.Prompts.choice(session, "Which color?", ["red","green","blue"]); -``` - -An object map: - -```javascript -var salesData = { - "west": { - units: 200, - total: "$6,000" - }, - "central": { - units: 100, - total: "$3,000" - }, - "east": { - units: 300, - total: "$9,000" - } -}; - -bot.dialog('getSalesData', [ - function (session) { - builder.Prompts.choice(session, "Which region would you like sales for?", salesData); - }, - function (session, results) { - if (results.response) { - var region = salesData[results.response.entity]; - session.send(`We sold ${region.units} units for a total of ${region.total}.`); - } else { - session.send("OK"); - } - } -]); -``` - -### Prompts.attachment - -Use the [Prompts.attachment()][PromptsAttachment] method to ask the user to upload a file such an image or video. The prompt returns the user's response as an [IPromptAttachmentResult](http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptattachmentresult.html). - -```javascript -builder.Prompts.attachment(session, "Upload a picture for me to transform."); -``` - -## Next steps - -Now that you know how to step users through a waterfall and prompt them for information, lets take a look at ways to help you better manage the conversation flow. - -> [!div class="nextstepaction"] -> [Manage conversation flow](bot-builder-nodejs-dialog-manage-conversation-flow.md) - - -[SendAttachments]: bot-builder-nodejs-send-receive-attachments.md -[SendCardWithButtons]: bot-builder-nodejs-send-rich-cards.md -[RecognizeUserIntent]: bot-builder-nodejs-recognize-intent-messages.md -[SaveUserData]: bot-builder-nodejs-save-user-data.md - -[UniversalBot]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.universalbot.html -[ChatConnector]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.chatconnector.html -[Session]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session - - -[SendTyping]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#sendtyping - -[EndDialogWithResult]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#enddialogwithresult - -[IPromptResult]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptresult.html - -[Result_Response]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptresult.html#response - -[ResumeReason]: https://docs.botframework.com/node/builder/chat-reference/enums/_botbuilder_d_.resumereason.html - -[Result_Resumed]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptresult.html#resumed - -[entity]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ientity.html - -[ResolveTime]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.entityrecognizer.html#resolvetime - -[PromptsRef]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.__global.iprompts.html - -[PromptsText]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.__global.iprompts.html#text - -[IPromptTextResult]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.iprompttextresult.html - -[PromptsConfirm]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.__global.iprompts.html#confirm - -[IPromptConfirmResult]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptconfirmresult.html - -[PromptsNumber]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.__global.iprompts.html#number - -[IPromptNumberResult]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptnumberresult.html - -[PromptsTime]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.__global.iprompts.html#time - -[IPromptTimeResult]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.iprompttimeresult.html - -[PromptsChoice]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.__global.iprompts.html#choice - -[IPromptChoiceResult]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptchoiceresult.html - -[PromptsAttachment]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.__global.iprompts.html#attachment - -[IPromptAttachmentResult]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptattachmentresult.html diff --git a/articles/nodejs/bot-builder-nodejs-dialog-replace.md b/articles/nodejs/bot-builder-nodejs-dialog-replace.md deleted file mode 100644 index 82c15bb5b..000000000 --- a/articles/nodejs/bot-builder-nodejs-dialog-replace.md +++ /dev/null @@ -1,335 +0,0 @@ ---- -title: Replace dialogs - Bot Service -description: Learn how to replace dialogs to re-prompt for input and manage conversation flow using the Bot Framework SDK for Node.js. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Replace dialogs - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -The ability to replace a dialog can be useful when you need to validate user input or repeat an action during the course of a conversation. With the Bot Framework SDK for Node.js, you can replace a dialog by using the [`session.replaceDialog`](http://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#replacedialog) method. This method enables you to end the current dialog and replace it with a new dialog without returning to the caller. - -## Create custom prompts to validate input - -The Bot Framework SDK for Node.js includes input validation for some types of [prompts](bot-builder-nodejs-dialog-prompt.md) such as `Prompts.time` and `Prompts.choice`. To validate text input that you receive in response to `Prompts.text`, you must create your own validation logic and custom prompts. - -You may want to validate an input if the input must comply with a certain value, pattern, range, or criteria that you define. If an input fails validation, the bot can prompt the user for that information again by using the `session.replaceDialog` method. - -The following code sample shows how to create a custom prompt to validate user input for a phone number. - -```javascript -// This dialog prompts the user for a phone number. -// It will re-prompt the user if the input does not match a pattern for phone number. -bot.dialog('phonePrompt', [ - function (session, args) { - if (args && args.reprompt) { - builder.Prompts.text(session, "Enter the number using a format of either: '(555) 123-4567' or '555-123-4567' or '5551234567'") - } else { - builder.Prompts.text(session, "What's your phone number?"); - } - }, - function (session, results) { - var matched = results.response.match(/\d+/g); - var number = matched ? matched.join('') : ''; - if (number.length == 10 || number.length == 11) { - session.userData.phoneNumber = number; // Save the number. - session.endDialogWithResult({ response: number }); - } else { - // Repeat the dialog - session.replaceDialog('phonePrompt', { reprompt: true }); - } - } -]); -``` - -In this example, the user is initially prompted to provide their phone number. The validation logic uses a regular expression that matches a range of digits from the user input. If the input contains 10 or 11 digits, then that number is returned in the response. Otherwise, the `session.replaceDialog` method is executed to repeat the `phonePrompt` dialog, which prompts the user for input again, this time providing more specific guidance regarding the format of input that is expected. - -When you call the `session.replaceDialog` method, you specify the name of the dialog to repeat and an arguments list. In this example, the arguments list contains `{ reprompt: true }`, which enables the bot to provide different prompt messages depending on whether it is an initial prompt or a reprompt, but you can specify whatever arguments your bot may require. - -## Repeat an action - -There may be times in the course of a conversation where you want to repeat a dialog to enable the user to complete a certain action multiple times. For example, if your bot offers a variety of services, you might initially display the menu of services, walk the user through the process of requesting a service, and then display the menu of services again, thereby enabling the user to request another service. To achieve this, you can use the [`session.replaceDialog`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#replacedialog) method to display the menu of services again, rather than ending the conversation with the ['session.endConversation`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#endconversation) method. - -The following example shows how to use the `session.replaceDialog` method to implement this type of scenario. First, the menu of services is defined: - -```javascript -// Main menu -var menuItems = { - "Order dinner": { - item: "orderDinner" - }, - "Dinner reservation": { - item: "dinnerReservation" - }, - "Schedule shuttle": { - item: "scheduleShuttle" - }, - "Request wake-up call": { - item: "wakeupCall" - }, -} -``` - -The `mainMenu` dialog is invoked by the default dialog, so the menu will be presented to the user at the beginning of the conversation. Additionally, a [`triggerAction`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html#triggeraction) is attached to the `mainMenu` dialog so that the menu will also be presented any time the user input is "main menu". When the user is presented with the menu and selects an option, the dialog that corresponds to the user's selection is invoked by using the `session.beginDialog` method. - -```javascript -var inMemoryStorage = new builder.MemoryBotStorage(); - -// This is a reservation bot that has a menu of offerings. -var bot = new builder.UniversalBot(connector, [ - function(session){ - session.send("Welcome to Contoso Hotel and Resort."); - session.beginDialog("mainMenu"); - } -]).set('storage', inMemoryStorage); // Register in-memory storage - -// Display the main menu and start a new request depending on user input. -bot.dialog("mainMenu", [ - function(session){ - builder.Prompts.choice(session, "Main Menu:", menuItems); - }, - function(session, results){ - if(results.response){ - session.beginDialog(menuItems[results.response.entity].item); - } - } -]) -.triggerAction({ - // The user can request this at any time. - // Once triggered, it clears the stack and prompts the main menu again. - matches: /^main menu$/i, - confirmPrompt: "This will cancel your request. Are you sure?" -}); -``` - -In this example, if the user chooses option 1 to order dinner to be delivered to their room, the `orderDinner` dialog will be invoked and will walk the user through the process of ordering dinner. At the end of the process, the bot will confirm the order and display the main menu again by using the `session.replaceDialog` method. - -```javascript -// Menu: "Order dinner" -// This dialog allows user to order dinner to be delivered to their hotel room. -bot.dialog('orderDinner', [ - function(session){ - session.send("Lets order some dinner!"); - builder.Prompts.choice(session, "Dinner menu:", dinnerMenu); - }, - function (session, results) { - if (results.response) { - var order = dinnerMenu[results.response.entity]; - var msg = `You ordered: %(Description)s for a total of $${order.Price}.`; - session.dialogData.order = order; - session.send(msg); - builder.Prompts.text(session, "What is your room number?"); - } - }, - function(session, results){ - if(results.response){ - session.dialogData.room = results.response; - var msg = `Thank you. Your order will be delivered to room #${results.response}.`; - session.send(msg); - session.replaceDialog("mainMenu"); // Display the menu again. - } - } -]) -.reloadAction( - "restartOrderDinner", "Ok. Let's start over.", - { - matches: /^start over$/i - } -) -.cancelAction( - "cancelOrder", "Type 'Main Menu' to continue.", - { - matches: /^cancel$/i, - confirmPrompt: "This will cancel your order. Are you sure?" - } -); -``` - -Two triggers are attached to the `orderDinner` dialog to enable the user to "start over" or "cancel" the order at any time during the ordering process. - -The first trigger is [`reloadAction`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html#reloadaction), which allows the user to start the order process over again by sending the input "start over". When the trigger matches the utterance "start over", the `reloadAction` restarts the dialog from the beginning. - -The second trigger is [`cancelAction`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html#cancelaction), which allows the user to abort the order process completely by sending the input "cancel". This trigger does not automatically display the main menu again, but instead sends a message that tells the user what to do next by saying "Type 'Main Menu' to continue." - -### Dialog loops - -In the example above, the user can only select one item per order. That is, if the user wanted to order two items from the menu, they would have to complete the entire ordering process for the first item and then repeat the entire ordering process again for the second item. - -The following example shows how to improve upon the previous bot by refactoring the dinner menu into a separate dialog. Doing so enables the bot to repeat the dinner menu in a loop and therefore allows the user to select multiple items within a single order. - -First, add a "Check out" option to the menu. This option will allow the user to exit the item selection process and continue with the check out process. - -```javascript -// The dinner menu -var dinnerMenu = { - //...other menu items..., - "Check out": { - Description: "Check out", - Price: 0 // Order total. Updated as items are added to order. - } -}; -``` - -Next, refactor the order prompt into its own dialog so that the bot can repeat the menu and allow user to add multiple items to their order. - -```javascript -// Add dinner items to the list by repeating this dialog until the user says `check out`. -bot.dialog("addDinnerItem", [ - function(session, args){ - if(args && args.reprompt){ - session.send("What else would you like to have for dinner tonight?"); - } - else{ - // New order - // Using the conversationData to store the orders - session.conversationData.orders = new Array(); - session.conversationData.orders.push({ - Description: "Check out", - Price: 0 - }) - } - builder.Prompts.choice(session, "Dinner menu:", dinnerMenu); - }, - function(session, results){ - if(results.response){ - if(results.response.entity.match(/^check out$/i)){ - session.endDialog("Checking out..."); - } - else { - var order = dinnerMenu[results.response.entity]; - session.conversationData.orders[0].Price += order.Price; // Add to total. - var msg = `You ordered: ${order.Description} for a total of $${order.Price}.`; - session.send(msg); - session.conversationData.orders.push(order); - session.replaceDialog("addDinnerItem", { reprompt: true }); // Repeat dinner menu - } - } - } -]) -.reloadAction( - "restartOrderDinner", "Ok. Let's start over.", - { - matches: /^start over$/i - } -); -``` - -In this example, orders are stored in a bot data store that is scoped to the current conversation, `session.conversationData.orders`. For every new order, the variable is re-initialized with a new array and for every item the user chooses, the bot adds that item to the `orders` array and adds the price to the total, which is stored in the checkout's `Price` variable. When the user finishes selecting items for their order, they can say "check out" and then continue with the remainder of the order process. - -> [!NOTE] -> For more information about bot data storage, see [Manage state data](bot-builder-nodejs-state.md). - -Finally, update the second step of the waterfall within the `orderDinner` dialog to process the order with confirmation. - -```javascript -// Menu: "Order dinner" -// This dialog allows user to order dinner and have it delivered to their room. -bot.dialog('orderDinner', [ - function(session){ - session.send("Lets order some dinner!"); - session.beginDialog("addDinnerItem"); - }, - function (session, results) { - if (results.response) { - // Display itemize order with price total. - for(var i = 1; i < session.conversationData.orders.length; i++){ - session.send(`You ordered: ${session.conversationData.orders[i].Description} for a total of $${session.conversationData.orders[i].Price}.`); - } - session.send(`Your total is: $${session.conversationData.orders[0].Price}`); - - // Continue with the check out process. - builder.Prompts.text(session, "What is your room number?"); - } - }, - function(session, results){ - if(results.response){ - session.dialogData.room = results.response; - var msg = `Thank you. Your order will be delivered to room #${results.response}`; - session.send(msg); - session.replaceDialog("mainMenu"); - } - } -]) -//...attached triggers... -; -``` - -## Cancel a dialog - -While the `session.replaceDialog` method can be used to replace the *current* dialog with a new one, it cannot be used to replace a dialog that is located further down the dialog stack. To replace a dialog within the dialog stack that is not the *current* dialog, use the [`session.cancelDialog`](http://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#canceldialog) method instead. - -The `session.cancelDialog` method can be used to end a dialog regardless of where it exists in the dialog stack and optionally invoke a new dialog in its place. To call the `session.cancelDialog` method, specify the ID of the dialog to cancel and optionally, specify the ID of the dialog to invoke in its place. For example, this code snippet cancels the `orderDinner` dialog and replaces it with the `mainMenu` dialog: - -```javascript -session.cancelDialog('orderDinner', 'mainMenu'); -``` - -When the `session.cancelDialog` method is called, the dialog stack will be searched backwards and the first occurrence of that dialog will be canceled, causing that dialog and its child dialogs (if any) to be removed from the dialog stack. Control will then be returned to the calling dialog, which can check for a [`results.resumed`](http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ipromptresult.html#resumed) code equal to [`ResumeReason.notCompleted`](http://docs.botframework.com/node/builder/chat-reference/enums/_botbuilder_d_.resumereason.html#notcompleted) to detect the cancellation. - -As an alternative to specifying the ID of the dialog to cancel when you call the `session.cancelDialog` method, you can instead specify the zero-based index of the dialog to cancel, where the index represents the dialog's position in the dialog stack. For example, the following code snippet terminates the currently active dialog (index = 0) and starts the `mainMenu` dialog in its place. The `mainMenu` dialog is invoked at position 0 of the dialog stack, thereby becoming the new default dialog. - -```javascript -session.cancelDialog(0, 'mainMenu'); -``` - -Consider the sample that is discussed in [dialog loops](#dialog-loops) above. When the user reaches the item selection menu, that dialog (`addDinnerItem`) is the fourth dialog in the dialog stack: `[default dialog, mainMenu, orderDinner, addDinnerItem]`. How can you enable the user to cancel their order from within the `addDinnerItem` dialog? If you attach a `cancelAction` trigger to the `addDinnerItem` dialog, it will only return the user back to the previous dialog (`orderDinner`), which will send the user right back into the `addDinnerItem` dialog. - -This is where the `session.cancelDialog` method is useful. Starting with the [dialog loops example](#dialog-loops), add "Cancel order" as an explicit option within the dinner menu. - -```javascript -// The dinner menu -var dinnerMenu = { - //...other menu items..., - "Check out": { - Description: "Check out", - Price: 0 // Order total. Updated as items are added to order. - }, - "Cancel order": { // Cancel the order and back to Main Menu - Description: "Cancel order", - Price: 0 - } -}; -``` - -Then, update the `addDinnerItem` dialog to check for a "cancel order" request. If "cancel" is detected, use the `session.cancelDialog` method to cancel the default dialog (i.e., the dialog at index 0 of the stack) and invoke the `mainMenu` dialog in its place. - -```javascript -// Add dinner items to the list by repeating this dialog until the user says `check out`. -bot.dialog("addDinnerItem", [ - //...waterfall steps..., - // Last step - function(session, results){ - if(results.response){ - if(results.response.entity.match(/^check out$/i)){ - session.endDialog("Checking out..."); - } - else if(results.response.entity.match(/^cancel/i)){ - // Cancel the order and start "mainMenu" dialog. - session.cancelDialog(0, "mainMenu"); - } - else { - //...add item to list and prompt again... - session.replaceDialog("addDinnerItem", { reprompt: true }); // Repeat dinner menu. - } - } - } -]) -//...attached triggers... -; -``` - -By using the `session.cancelDialog` method in this way, you can implement whatever conversation flow your bot requires. - -## Next steps - -As you can see, to replace dialogs on the stack, you use various types of **actions** to accomplish that task. Actions gives you great flexibilities in managing conversation flow. Let's take a closer look at **actions** and how to better handle user actions. - -> [!div class="nextstepaction"] -> [Handle user actions](bot-builder-nodejs-dialog-actions.md) diff --git a/articles/nodejs/bot-builder-nodejs-dialog-waterfall.md b/articles/nodejs/bot-builder-nodejs-dialog-waterfall.md deleted file mode 100644 index 72f30ddd5..000000000 --- a/articles/nodejs/bot-builder-nodejs-dialog-waterfall.md +++ /dev/null @@ -1,200 +0,0 @@ ---- -title: Define conversation steps with waterfalls - Bot Service -description: Learn how to use waterfalls to define the steps of a conversation with the Bot Framework SDK for Node.js. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Define conversation steps with waterfalls - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -A conversation is a series of messages exchanged between user and bot. When the bot's objective is to lead the user through a series of steps, you can use a waterfall to define the steps of the conversation. - -A waterfall is a specific implementation of a [dialog](bot-builder-nodejs-dialog-overview.md) that is most commonly used to collect information from the user or guide the user through a series of tasks. The tasks are implemented as an array of functions where the results of the first function are passed as input into the next function, and so on. Each function typically represents one step in the overall process. At each step, the bot prompts the user for input, waits for a response, and then passes the result to the next step. - -This article will help you understand how a waterfall works and how you can use it to [manage conversation flow](bot-builder-nodejs-dialog-manage-conversation.md). - -## Conversation steps - -A conversation typically involves several prompt/response exchanges between the user and the bot. Each prompt/response exchange is a step forward in the conversation. You can create a conversation using a waterfall with as few as two steps. - -For example, consider the following `greetings` dialog. The first step of the waterfall prompts for the user's name and the second step uses the response to greet the user by name. - -```javascript -bot.dialog('greetings', [ - // Step 1 - function (session) { - builder.Prompts.text(session, 'Hi! What is your name?'); - }, - // Step 2 - function (session, results) { - session.endDialog(`Hello ${results.response}!`); - } -]); -``` - -What makes this possible is the use of prompts. The Bot Framework SDK for Node.js provides several different types of built-in [prompts](bot-builder-nodejs-dialog-prompt.md) that you can use to ask the user for various types of information. - -The following sample code shows a dialog that uses prompts to collect various pieces of information from the user throughout a 4-step waterfall. - -```javascript -var inMemoryStorage = new builder.MemoryBotStorage(); - -// This is a dinner reservation bot that uses a waterfall technique to prompt users for input. -var bot = new builder.UniversalBot(connector, [ - function (session) { - session.send("Welcome to the dinner reservation."); - builder.Prompts.time(session, "Please provide a reservation date and time (e.g.: June 6th at 5pm)"); - }, - function (session, results) { - session.dialogData.reservationDate = builder.EntityRecognizer.resolveTime([results.response]); - builder.Prompts.text(session, "How many people are in your party?"); - }, - function (session, results) { - session.dialogData.partySize = results.response; - builder.Prompts.text(session, "Whose name will this reservation be under?"); - }, - function (session, results) { - session.dialogData.reservationName = results.response; - - // Process request and display reservation details - session.send(`Reservation confirmed. Reservation details:
Date/Time: ${session.dialogData.reservationDate}
Party size: ${session.dialogData.partySize}
Reservation name: ${session.dialogData.reservationName}`); - session.endDialog(); - } -]).set('storage', inMemoryStorage); // Register in-memory storage -``` - -In this example, the default dialog has four functions, each one representing a step in the waterfall. Each step prompts the user for input and sends the results to the next step to be processed. This process continues until the last step executes, thereby confirming the reservation and ending the dialog. - -The following screenshot shows the results of this bot running in the [Bot Framework Emulator](~/bot-service-debug-emulator.md). - -![Manage conversation flow with waterfall](~/media/bot-builder-nodejs-dialog-manage-conversation/waterfall-results.png) - -## Create a conversation with multiple waterfalls - -You can use multiple waterfalls within a conversation to define whatever conversation structure your bot requires. For example, you might use one waterfall to manage the conversation flow and use additional waterfalls to collect information from the user. Each waterfall is encapsulated in a dialog and can be invoked by calling the `session.beginDialog` function. - -The following code sample shows how to use multiple waterfalls in a conversation. The waterfall within the `greetings` dialog manages the flow of the conversation, while the waterfall within the `askName` dialog collects information from the user. - -```javascript -bot.dialog('greetings', [ - function (session) { - session.beginDialog('askName'); - }, - function (session, results) { - session.endDialog('Hello %s!', results.response); - } -]); -bot.dialog('askName', [ - function (session) { - builder.Prompts.text(session, 'Hi! What is your name?'); - }, - function (session, results) { - session.endDialogWithResult(results); - } -]); -``` - -## Advance the waterfall - -A waterfall progresses from step to step in the sequence that the functions are defined in the array. The first function within a waterfall can receive the arguments that are passed to the dialog. Any function within a waterfall can use the `next` function to proceed to the next step without prompting user for input. - -The following code sample shows how to use the `next` function within a dialog that walks the user through the process of providing information for their user profile. In each step of the waterfall, the bot prompts the user for a piece of information (if necessary), and the user's response (if any) is processed by the subsequent step of the waterfall. The final step of the waterfall in the `ensureProfile` dialog ends that dialog and returns the completed profile information to the calling dialog, which then sends a personalized greeting to the user. - -```javascript -var inMemoryStorage = new builder.MemoryBotStorage(); - -// This bot ensures user's profile is up to date. -var bot = new builder.UniversalBot(connector, [ - function (session) { - session.beginDialog('ensureProfile', session.userData.profile); - }, - function (session, results) { - session.userData.profile = results.response; // Save user profile. - session.send(`Hello ${session.userData.profile.name}! I love ${session.userData.profile.company}!`); - } -]).set('storage', inMemoryStorage); // Register in-memory storage - -bot.dialog('ensureProfile', [ - function (session, args, next) { - session.dialogData.profile = args || {}; // Set the profile or create the object. - if (!session.dialogData.profile.name) { - builder.Prompts.text(session, "What's your name?"); - } else { - next(); // Skip if we already have this info. - } - }, - function (session, results, next) { - if (results.response) { - // Save user's name if we asked for it. - session.dialogData.profile.name = results.response; - } - if (!session.dialogData.profile.company) { - builder.Prompts.text(session, "What company do you work for?"); - } else { - next(); // Skip if we already have this info. - } - }, - function (session, results) { - if (results.response) { - // Save company name if we asked for it. - session.dialogData.profile.company = results.response; - } - session.endDialogWithResult({ response: session.dialogData.profile }); - } -]); -``` - -> [!NOTE] -> This example uses two different data bags to store data: `dialogData` and `userData`. If the bot is distributed across multiple compute nodes, each step of the waterfall could be processed by a different node. For more information about storing bot data, see [Manage state data](bot-builder-nodejs-state.md). - -## End a waterfall - -A dialog that is created using a waterfall must be explicitly ended, otherwise the bot will repeat the waterfall indefinitely. You can end a waterfall by using one of the following methods: - -* `session.endDialog`: Use this method to end the waterfall if there is no data to return to the calling dialog. - -* `session.endDialogWithResult`: Use this method to end the waterfall if there is data to return to the calling dialog. The `response` argument that is returned can be a JSON object or any JavaScript primitive data type. For example: - ```javascript - session.endDialogWithResult({ - response: { name: session.dialogData.name, company: session.dialogData.company } - }); - ``` - -* `session.endConversation`: Use this method to end the waterfall if the end of the waterfall represents the end of the conversation. - -As an alternative to using one of these three methods to end a waterfall, you can attach the `endConversationAction` trigger to the dialog. For example: - -```javascript -bot.dialog('dinnerOrder', [ - //...waterfall steps..., - // Last step - function(session, results){ - if(results.response){ - session.dialogData.room = results.response; - var msg = `Thank you. Your order will be delivered to room #${session.dialogData.room}`; - session.endConversation(msg); - } - } -]) -.endConversationAction( - "endOrderDinner", "Ok. Goodbye.", - { - matches: /^cancel$|^goodbye$/i, - confirmPrompt: "This will cancel your order. Are you sure?" - } -); -``` - -## Next steps - -Using waterfall, you can collect information from the user with *prompts*. Let's dive into how you can prompt user for input. - -> [!div class="nextstepaction"] -> [Prompt user for input](bot-builder-nodejs-dialog-prompt.md) diff --git a/articles/nodejs/bot-builder-nodejs-handle-conversation-events.md b/articles/nodejs/bot-builder-nodejs-handle-conversation-events.md deleted file mode 100644 index 660eb0cfa..000000000 --- a/articles/nodejs/bot-builder-nodejs-handle-conversation-events.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Handle user and conversation events - Bot Service -description: Learn how to handle events such as a user joining a conversation using the Bot Framework SDK for Node.js. -author: DucVo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Handle user and conversation events - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -This article demonstrates how your bot can handle events such as a user joining a conversation, adding a bot to a contacts list, or saying **Goodbye** when a bot is being removed from a conversation. - - -## Greet a user on conversation join -The Bot Framework provides the [conversationUpdate][conversationUpdate] event for notifying your bot whenever a member joins or leaves a conversation. A conversation member can be a user or a bot. - -The following code snippet allows the bot to greet new member(s) to a conversation or say **Goodbye** if it is being removed from the conversation. - -[!INCLUDE [conversationUpdate sample Node.js](../includes/snippet-code-node-conversationupdate-1.md)] - -## Acknowledge add to contacts list - -The [contactRelationUpdate][contactRelationUpdate] event notifies your bot that a user has added you to their contacts list. - -[!INCLUDE [contactRelationUpdate sample Node.js](../includes/snippet-code-node-contactrelationupdate-1.md)] - -## Add a first-run dialog - -Since the **conversationUpdate** and the **contactRelationUpdate** event are not supported by all channels, a universal way to greet a user who joins a conversation is to add a first-run dialog. - -In the following example we’ve added a function that triggers the dialog any time we’ve never seen a user before. You can customize the way an action is triggered by providing an [onFindAction][onFindAction] handler for your action. - -[!INCLUDE [first-run sample Node.js](../includes/snippet-code-node-first-run-dialog-1.md)] - -You can also customize what an action does after its been triggered by providing an [onSelectAction][onSelectAction] handler. For trigger actions you can provide an [onInterrupted][onInterrupted] handler to intercept an interruption before it occurs. For more information, see [Handle user actions](bot-builder-nodejs-dialog-actions.md) - -## Additional resources - -* [conversationUpdate][conversationUpdate] -* [contactRelationUpdate][contactRelationUpdate] - -[conversationUpdate]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.iconversationupdate.html -[contactRelationUpdate]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.icontactrelationupdate.html - -[onFindAction]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.itriggeractionoptions#onfindaction -[onSelectAction]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.itriggeractionoptions#onselectaction -[onInterrupted]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.itriggeractionoptions#oninterrupted - -[SendTyping]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#sendtyping -[IMessage]: http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.imessage -[ChatConnector]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.chatconnector.html -[session_userData]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#userdata diff --git a/articles/nodejs/bot-builder-nodejs-intercept-messages.md b/articles/nodejs/bot-builder-nodejs-intercept-messages.md deleted file mode 100644 index 65c07292c..000000000 --- a/articles/nodejs/bot-builder-nodejs-intercept-messages.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Intercept messages (v3 JS) - Bot Service -description: Learn how to create logs or other records by intercepting and processing information exchanges using the Bot Framework SDK for Node.js. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/02/2018 -monikerRange: 'azure-bot-service-3.0' ---- -# Intercept messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-middleware.md) -> - [Node.js](../nodejs/bot-builder-nodejs-intercept-messages.md) - -[!INCLUDE [Introduction to message logging](../includes/snippet-message-logging-intro.md)] - -## Example - -The following code sample shows how to intercept messages that are exchanged between user and bot by using the concept of **middleware** in the Bot Framework SDK for Node.js. - -First, configure the handler for incoming messages (`botbuilder`) and for outgoing messages (`send`). - -```javascript -server.post('/api/messages', connector.listen()); -var bot = new builder.UniversalBot(connector); -bot.use({ - botbuilder: function (session, next) { - myMiddleware.logIncomingMessage(session, next); - }, - send: function (event, next) { - myMiddleware.logOutgoingMessage(event, next); - } -}) -``` - -Then, implement each of the handlers to define the action to take for each message that is intercepted. - -```javascript -module.exports = { - logIncomingMessage: function (session, next) { - console.log(session.message.text); - next(); - }, - logOutgoingMessage: function (event, next) { - console.log(event.text); - next(); - } -} -``` - -Now, every inbound message (from user to bot) will trigger `logIncomingMessage`, -and every outbound message (from bot to user) will trigger `logOutgoingMessage`. -In this example, the bot simply prints some information about each message, but you can -update `logIncomingMessage` and `logOutgoingMessage` as necessary to define the actions that you want to take for each message. - -## Sample code - -For a complete sample that shows how to intercept and log messages using the Bot Framework SDK for Node.js, see the Middleware and Logging sample in GitHub. diff --git a/articles/nodejs/bot-builder-nodejs-localization.md b/articles/nodejs/bot-builder-nodejs-localization.md deleted file mode 100644 index cd0138c40..000000000 --- a/articles/nodejs/bot-builder-nodejs-localization.md +++ /dev/null @@ -1,166 +0,0 @@ ---- -title: Support localization - Bot Service -description: Learn how to determine where the user is and enable localization functionality using the Bot Framework SDK for Node.js. -author: DeniseMak -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Support localization - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -Bot Builder includes a rich localization system for building bots that can communicate with the user in multiple languages. All of your bot's prompts can be localized using JSON files stored in your bot's directory structure. If you’re using a system like LUIS to perform natural language processing, you can configure your [LuisRecognizer][LUISRecognizer] with a separate model for each language your bot supports and the SDK will automatically select the model that matches the user's preferred locale. - -## Determine the locale by prompting the user -The first step to localizing your bot is adding the ability to identify the user's preferred language. The SDK provides a [session.preferredLocale()][preferredLocal] method to both save and retrieve this preference on a per-user basis. The following example is a dialog to prompt the user for their preferred language and then save their choice. - -``` javascript -bot.dialog('/localePicker', [ - function (session) { - // Prompt the user to select their preferred locale - builder.Prompts.choice(session, "What's your preferred language?", 'English|Español|Italiano'); - }, - function (session, results) { - // Update preferred locale - var locale; - switch (results.response.entity) { - case 'English': - locale = 'en'; - break; - case 'Español': - locale = 'es'; - break; - case 'Italiano': - locale = 'it'; - break; - } - session.preferredLocale(locale, function (err) { - if (!err) { - // Locale files loaded - session.endDialog(`Your preferred language is now ${results.response.entity}`); - } else { - // Problem loading the selected locale - session.error(err); - } - }); - } -]); -``` - -## Determine the locale by using analytics -Another way to determine the user's locale is to use a service like the [Text Analytics API](/azure/cognitive-services/cognitive-services-text-analytics-quick-start) to automatically detect the user's language based upon the text of the message they sent. - -The code snippet below illustrates how you can incorporate this service into your own bot. -``` javascript -var request = require('request'); - -bot.use({ - receive: function (event, next) { - if (event.text && !event.textLocale) { - var options = { - method: 'POST', - url: 'https://westus.api.cognitive.microsoft.com/text/analytics/v2.0/languages?numberOfLanguagesToDetect=1', - body: { documents: [{ id: 'message', text: event.text }]}, - json: true, - headers: { - 'Ocp-Apim-Subscription-Key': '' - } - }; - request(options, function (error, response, body) { - if (!error && body) { - if (body.documents && body.documents.length > 0) { - var languages = body.documents[0].detectedLanguages; - if (languages && languages.length > 0) { - event.textLocale = languages[0].iso6391Name; - } - } - } - next(); - }); - } else { - next(); - } - } -}); -``` - -Once you add the above code snippet to your bot, calling [session.preferredLocale()][preferredLocal] will automatically return the detected language. The search order for `preferredLocale()` is as follows: -1. Locale saved by calling `session.preferredLocale()`. This value is stored in `session.userData['BotBuilder.Data.PreferredLocale']`. -2. Detected locale assigned to `session.message.textLocale`. -3. The configured default locale for the bot (e.g.: English (‘en’)). - -You can configure the bot's default locale using its constructor: - -```javascript -var bot = new builder.UniversalBot(connector, { - localizerSettings: { - defaultLocale: "es" - } -}); -``` - -## Localize prompts -The default localization system for the Bot Framework SDK is file-based and allows a bot to support multiple languages using JSON files stored on disk. By default, the localization system will search for the bot's prompts in the **./locale//index.json** file where is a valid [IETF language tag][IEFT] representing the preferred locale for which to find prompts. - -The following screenshot shows the directory structure for a bot that supports three languages: English, Italian, and Spanish. - -![Directory structure for three locales](../media/locale-dir.png) - -The structure of the file is a simple JSON map of message IDs to localized text strings. If the value is an array instead of a string, one prompt from the array is chosen at random when that value is retrieved using [session.localizer.gettext()][GetText]. - -The bot automatically retrieves the localized version of a message if you pass the message ID in a call to [session.send()](http://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#send) instead of language-specific text: - -```javascript -var bot = new builder.UniversalBot(connector, [ - function (session) { - session.send("greeting"); - session.send("instructions"); - session.beginDialog('/localePicker'); - }, - function (session) { - builder.Prompts.text(session, "text_prompt"); - } -]); -``` - -Internally, the SDK calls [`session.preferredLocale()`][preferredLocale] to get the user's preferred locale and then uses that in a call to [`session.localizer.gettext()`][GetText] to map the message ID to its localized text string. There are times where you may need to manually call the localizer. For instance, the enum values passed to [`Prompts.choice()`][promptsChoice] are never automatically localized so you may need to manually retrieve a localized list prior to calling the prompt: - -```javascript -var options = session.localizer.gettext(session.preferredLocale(), "choice_options"); -builder.Prompts.choice(session, "choice_prompt", options); -``` - -The default localizer searches for a message ID across multiple files and if it can’t find an ID (or if no localization files were provided) it will simply return the text of ID, making the use of localization files transparent and optional. Files are searched in the following order: - -1. The **index.json** file under the locale returned by [`session.preferredLocale()`][preferredLocale] is searched. -2. If the locale included an optional subtag like **en-US** then the root tag of **en** is searched. -3. The bot's configured default locale is searched. - -## Use namespaces to customize and localize prompts -The default localizer supports the namespacing of prompts to avoid collisions between message IDs. Your bot can override namespaced prompts to customize or reword the prompts from another namespace. You can leverage this capability to customize the SDK’s built-in messages, letting you either add support for additional languages or to simply reword the SDK's current messages. For instance, you can change the SDK’s default error message by simply adding a file called **BotBuilder.json** to your bot's locale directory and then adding an entry for the `default_error` message ID: - -![BotBuilder.json for locale namespacing](../media/locale-namespacing.png) - - -## Additional resources - -To learn about how to localize a recognizer, see [Recognizing intent](bot-builder-nodejs-recognize-intent-messages.md). - - -[LUIS]: https://www.luis.ai/ -[IMessage]: http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.imessage -[IntentRecognizerSetOptions]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.iintentrecognizersetoptions.html -[LUISRecognizer]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.luisrecognizer -[LUISSample]: https://aka.ms/v3-js-luisSample -[DisambiguationSample]: https://aka.ms/v3-js-onDisambiguateRoute -[preferredLocal]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#preferredlocale -[preferredLocale]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#preferredlocale -[promptsChoice]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.__global.iprompts.html#choice -[GetText]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.ilocalizer.html#gettext -[IEFT]: https://en.wikipedia.org/wiki/IETF_language_tag - diff --git a/articles/nodejs/bot-builder-nodejs-message-create.md b/articles/nodejs/bot-builder-nodejs-message-create.md deleted file mode 100644 index 6c8073033..000000000 --- a/articles/nodejs/bot-builder-nodejs-message-create.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: Create messages - Bot Service -description: Learn how create messages with the Bot Framework SDK for Node.js. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 09/7/2017 -monikerRange: 'azure-bot-service-3.0' ---- -# Create messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -Communication between the bot and the user is through messages. Your bot will send message activities to communicate information to users, and likewise, will also receive message activities from users. Some messages may simply consist of plain text, while others may contain richer content such as text to be spoken, suggested actions, media attachments, rich cards, and channel-specific data. - -This article describes some of the commonly-used message methods you can use to enhance your user experience. - -## Default message handler - -The Bot Framework SDK for Node.js comes with a default message handler built into the [`session`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html) object. This message handler allows you to send and receive text messages between the bot and the user. - -### Send a text message - -Sending a text message using the default message handler is simple, just call `session.send` and pass in a **string**. - -This sample shows how you can send a text message to greet the user. -```javascript -session.send("Good morning."); -``` - -This sample shows how you can send a text message using JavaScript string template. -```javascript -var msg = `You ordered: ${order.Description} for a total of $${order.Price}.`; -session.send(msg); //msg: "You ordered: Potato Salad for a total of $5.99." -``` - -### Receive a text message - -When a user sends the bot a message, the bot receives the message through the `session.message` property. - -This sample shows how to access the user's message. -```javascript -var userMessage = session.message.text; -``` - -## Customizing a message - -To have more control over the text formatting of your messages, you can create a custom [`message`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html) object and set the properties necessary before sending it to the user. - -This sample shows how to create a custom `message` object and set the `text`, `textFormat`, and `textLocale` properties. - -```javascript -var customMessage = new builder.Message(session) - .text("Hello!") - .textFormat("plain") - .textLocale("en-us"); -session.send(customMessage); -``` - -In cases where you do not have the `session` object in scope, you can use `bot.send` method to send a formatted message to the user. - -The `textFormat` property of a message can be used to specify the format of the text. The `textFormat` property can be set to **plain**, **markdown**, or **xml**. The default value for `textFormat` is **markdown**. - -## Message property - -The [`Message`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html) object has an internal **data** property that it uses to manage the message being sent. Other properties you set are through the different methods this object expose to you. - -## Message methods - -Message properties are set and retrieved through the object's methods. The table below provide a list of the methods you can call to set/get the different **Message** properties. - -| Method | Description | -| ---- | ---- | -| [`addAttachment(attachment:AttachmentType)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#addattachment) | Adds an attachment to a message| -| [`addEntity(obj:Object)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#addentity) | Adds an entity to the message. | -| [`address(adr:IAddress)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#address) | Address routing information for the message. To send user a proactive message, save the message's address in the userData bag. | -| [`attachmentLayout(style:string)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#attachmentlayout) | Hint for how clients should layout multiple attachments. The default value is 'list'. | -| [`attachments(list:AttachmentType)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#attachments) | A list of cards or images to send to the user. | -| [`compose(prompts:string[], ...args:any[])`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#compose) | Composes a complex and randomized reply to the user. | -| [`entities(list:Object[])`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#entities) | Structured objects passed to the bot or user. | -| [`inputHint(hint:string)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#inputhint) | Hint sent to user letting them know if the bot is expecting further input or not. The built-in prompts will automatically populate this value for outgoing messages. | -| [`localTimeStamp((optional)time:string)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#localtimestamp) | Local time when message was sent (set by client or bot, Ex: 2016-09-23T13:07:49.4714686-07:00.) | -| [`originalEvent(event:any)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#originalevent) | Message in original/native format of the channel for incoming messages. | -| [`sourceEvent(map:ISourceEventMap)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#sourceevent) | For outgoing messages can be used to pass source specific event data like custom attachments. | -| [`speak(ssml:TextType, ...args:any[])`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#speak) | Sets the speak field of the message as *Speech Synthesis Markup Language (SSML)*. This will be spoken to the user on supported devices. | -| [`suggestedActions(suggestions:ISuggestedActions `|` IIsSuggestedActions)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#suggestedactions) | Optional suggested actions to send to the user. Suggested actions will be displayed only on the channels that support suggested actions. | -| [`summary(text:TextType, ...argus:any[])`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#summary) | Text to be displayed as fall-back and as short description of the message content in (e.g.: List of recent conversations.) | -| [`text(text:TextType, ...args:any[])`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#text) | Sets the message text. | -| [`textFormat(style:string)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#textformat) | Set the text format. Default format is **markdown**. | -| [`textLocale(locale:string)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#textlocale) | Set the target language of the message. | -| [`toMessage()`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#tomessage) | Gets the JSON for the message. | -| [`composePrompt(session:Session, prompts:string[], args?:any[])`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#composeprompt-1) | Combines an array of prompts into a single localized prompt and then optionally fills the prompts template slots with the passed in arguments. | -| [`randomPrompt(prompts:TextType)`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message.html#randomprompt) | Gets a random prompt from the array of **prompts* that is passed in. | - -## Next step - -> [!div class="nextstepaction"] -> [Send and receive attachments](bot-builder-nodejs-send-receive-attachments.md) - diff --git a/articles/nodejs/bot-builder-nodejs-overview.md b/articles/nodejs/bot-builder-nodejs-overview.md deleted file mode 100644 index 95d7a6e65..000000000 --- a/articles/nodejs/bot-builder-nodejs-overview.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: Bot Framework SDK for Node.js - Bot Service -description: Explore the Bot Framework SDK for Node.js, a powerful, easy-to-use bot building framework. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Bot Framework SDK for Node.js - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-overview.md) -> - [Node.js](../nodejs/bot-builder-nodejs-overview.md) -> - [REST](../rest-api/bot-framework-rest-overview.md) - -Bot Framework SDK for Node.js is a powerful, easy-to-use framework that provides a familiar way for Node.js developers to write bots. -You can use it to build a wide variety of conversational user interfaces, from simple prompts to free-form conversations. - -The conversational logic for your bot is hosted as a web service. The Bot Framework SDK uses restify, a popular framework for building web services, to create the bot's web server. -The SDK is also compatible with Express and the use of other web app frameworks is possible with some adaption. - -Using the SDK, you can take advantage of the following SDK features: - -- Powerful system for building dialogs to encapsulate conversational logic. -- Built-in prompts for simple things such as Yes/No, strings, numbers, and enumerations, as well as support for messages containing images and attachments, and rich cards containing buttons. -- Built-in support for powerful AI frameworks such as LUIS. -- Built-in recognizers and event handlers that guide the user through the conversation, providing help, navigation, clarification, and confirmation as needed. - -## Get started - -If you are new to writing bots, [create your first bot with Node.js](bot-builder-nodejs-quickstart.md) with step-by-step instructions to help you set up your project, install the SDK, and run your first bot. - -If you are new to the Bot Framework SDK for Node.js, you can start with key concepts that help you understand the major components of the Bot Framework SDK, see [Key concepts](bot-builder-nodejs-concepts.md). - -To ensure your bot addresses the top user scenarios, review the [design principles](../bot-service-design-principles.md) and [explore patterns](../bot-service-design-pattern-task-automation.md) for guidance. - -## Get samples - -The [Bot Framework SDK for Node.js samples](bot-builder-nodejs-samples.md) demonstrate task-focused bots that show how to take advantage of features in the Bot Framework SDK for Node.js. You can use the samples to help you quickly get started with building great bots with rich capabilities. - -## Next steps -> [!div class="nextstepaction"] -> [Key concepts](bot-builder-nodejs-concepts.md) - -## Additional resources - -The following task-focused how-to guides demonstrate various features of the Bot Framework SDK for Node.js. - -* [Respond to messages](bot-builder-nodejs-use-default-message-handler.md) -* [Handle user actions](bot-builder-nodejs-dialog-actions.md) -* [Recognize user intent](bot-builder-nodejs-recognize-intent-messages.md) -* [Send a rich card](bot-builder-nodejs-send-rich-cards.md) -* [Send attachments](bot-builder-nodejs-send-receive-attachments.md) -* [Saving user data](bot-builder-nodejs-save-user-data.md) - - -If you encounter problems or have suggestions regarding the Bot Framework SDK for Node.js, -see [Support](../bot-service-resources-links-help.md) for a list of available resources. - - -[DesignGuide]: ../bot-service-design-principles.md -[DesignPatterns]: ../bot-service-design-pattern-task-automation.md -[HowTo]: bot-builder-nodejs-use-default-message-handler.md diff --git a/articles/nodejs/bot-builder-nodejs-proactive-messages.md b/articles/nodejs/bot-builder-nodejs-proactive-messages.md deleted file mode 100644 index a8366a92f..000000000 --- a/articles/nodejs/bot-builder-nodejs-proactive-messages.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: Send proactive messages (v3 JS) - Bot Service -description: Learn how to interrupt the current conversation flow with a proactive message using the Bot Framework SDK for Node.js -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- -# Send proactive messages -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-proactive-messages.md) -> - [Node.js](../nodejs/bot-builder-nodejs-proactive-messages.md) - -[!INCLUDE [Introduction to proactive messages - part 1](../includes/snippet-proactive-messages-intro-1.md)] - -## Types of proactive messages - -[!INCLUDE [Introduction to proactive messages - part 2](../includes/snippet-proactive-messages-intro-2.md)] - -## Send an ad hoc proactive message - -The following code samples show how to send an ad hoc proactive message by using the Bot Framework SDK for Node.js. - -To be able to send an ad hoc message to a user, the bot must first collect and save information about the user from the current conversation. -The **address** property of the message includes all of the information that the bot will need to send an ad hoc message to the user later. - -```javascript -bot.dialog('adhocDialog', function(session, args) { - var savedAddress = session.message.address; - - // (Save this information somewhere that it can be accessed later, such as in a database, or session.userData) - session.userData.savedAddress = savedAddress; - - var message = 'Hello user, good to meet you! I now know your address and can send you notifications in the future.'; - session.send(message); -}) -``` - -> [!NOTE] -> The bot can store the user data in any manner as long as the bot can access it later. - -After the bot has collected information about the user, it can send an ad hoc proactive message to the user at any time. -To do so, it simply retrieves the user data that it stored previously, constructs the message, and sends it. - -```javascript -var inMemoryStorage = new builder.MemoryBotStorage(); - -var bot = new builder.UniversalBot(connector) - .set('storage', inMemoryStorage); // Register in-memory storage - -function sendProactiveMessage(address) { - var msg = new builder.Message().address(address); - msg.text('Hello, this is a notification'); - msg.textLocale('en-US'); - bot.send(msg); -} -``` - -> [!TIP] -> An ad hoc proactive message can be initiated like from -> asynchronous triggers such as http requests, timers, queues or from anywhere else that the developer chooses. - -## Send a dialog-based proactive message - -The following code samples show how to send a dialog-based proactive message by using the Bot Framework SDK for Node.js. You can find the complete working example in the [startNewDialog](https://aka.ms/js-startnewdialog-sample-v3) folder. - -To be able to send a dialog-based message to a user, the bot must first collect (and save) information from the current conversation. -The `session.message.address` object includes all of the information that the bot will need to send a dialog-based proactive message to the user. - -```javascript -// proactiveDialog dialog -bot.dialog('proactiveDialog', function (session, args) { - - savedAddress = session.message.address; - - var message = 'Hey there, I\'m going to interrupt our conversation and start a survey in five seconds...'; - session.send(message); - - message = `You can also make me send a message by accessing: http://localhost:${server.address().port}/api/CustomWebApi`; - session.send(message); - - setTimeout(() => { - startProactiveDialog(savedAddress); - }, 5000); -}); -``` - -When it is time to send the message, the bot creates a new dialog and adds it to the top of the dialog stack. The new dialog takes control of the conversation, delivers the proactive message, closes, and then returns control to the previous dialog in the stack. - -```javascript -// initiate a dialog proactively -function startProactiveDialog(address) { - bot.beginDialog(address, "*:survey"); -} -``` - -> [!NOTE] -> The code sample above requires a custom file, **botadapter.js**, which you can [download from GitHub](https://aka.ms/js-botadaptor-file-v3). - -The survey dialog controls the conversation until it finishes. -Then, it closes (by calling `session.endDialog()`), thereby returning control back to the previous dialog. - - -```javascript -// handle the proactive initiated dialog -bot.dialog('survey', function (session, args, next) { - if (session.message.text === "done") { - session.send("Great, back to the original conversation"); - session.endDialog(); - } else { - session.send('Hello, I\'m the survey dialog. I\'m interrupting your conversation to ask you a question. Type "done" to resume'); - } -}); -``` - -## Sample code - -For a complete sample that shows how to send proactive messages using the Bot Framework SDK for Node.js, see the Proactive Messages sample in GitHub. -Within the Proactive Messages sample, simpleSendMessage shows how to send an ad-hoc proactive message and startNewDialog shows how to send a dialog-based proactive message. - -## Additional resources - -- [Designing conversation flow](../bot-service-design-conversation-flow.md) diff --git a/articles/nodejs/bot-builder-nodejs-recognize-intent-luis.md b/articles/nodejs/bot-builder-nodejs-recognize-intent-luis.md deleted file mode 100644 index a9e3c7cc3..000000000 --- a/articles/nodejs/bot-builder-nodejs-recognize-intent-luis.md +++ /dev/null @@ -1,606 +0,0 @@ ---- -title: Recognize intents and entities with LUIS (v3 JS) - Bot Service -description: Integrate a bot with LUIS to detect the user's intent and respond appropriately by triggering dialogs using the Bot Framework SDK for Node.js. -author: DeniseMak -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 03/28/2018 -monikerRange: 'azure-bot-service-3.0' - ---- - -# Recognize intents and entities with LUIS - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -This article uses the example of a bot for taking notes, to demonstrate how Language Understanding ([LUIS][LUIS]) helps your bot respond appropriately to natural language input. A bot detects what a user wants to do by identifying their **intent**. This intent is determined from spoken or textual input, or **utterances**. The intent maps utterances to actions that the bot takes, such as invoking a dialog. A bot may also need to extract **entities**, which are important words in utterances. Sometimes entities are required to fulfill an intent. In the example of a note-taking bot, the `Notes.Title` entity identifies the title of each note. - -## Create a Language Understanding bot with Bot Service - -1. In the [Azure portal](https://portal.azure.com), select **Create new resource** in the menu blade and click **See all**. - - ![Create new resource](../media/bot-builder-nodejs-use-luis/bot-service-creation.png) - -2. In the search box, search for **Web App Bot**. - - ![Create new resource](../media/bot-builder-nodejs-use-luis/bot-service-selection.png) - -3. In the **Bot Service** blade, provide the required information, and click **Create**. This creates and deploys the bot service and LUIS app to Azure. - * Set **App name** to your bot’s name. The name is used as the subdomain when your bot is deployed to the cloud (for example, mynotesbot.azurewebsites.net). This name is also used as the name of the LUIS app associated with your bot. Copy it to use later, to find the LUIS app associated with the bot. - * Select the subscription, [resource group](/azure/azure-resource-manager/resource-group-overview), App service plan, and [location](https://azure.microsoft.com/regions/). - * Select the **Language understanding (Node.js)** template for the **Bot template** field. - - ![Bot Service blade](../media/bot-builder-nodejs-use-luis/bot-service-setting-callout-template.png) - - * Check the box to confirm to the terms of service. - -4. Confirm that the bot service has been deployed. - * Click Notifications (the bell icon that is located along the top edge of the Azure portal). The notification will change from **Deployment started** to **Deployment succeeded**. - * After the notification changes to **Deployment succeeded**, click **Go to resource** on that notification. - -## Try the bot - -Confirm that the bot has been deployed by checking the **Notifications**. The notifications will change from **Deployment in progress...** to **Deployment succeeded**. Click **Go to resource** button to open the bot's resources blade. - -Once the bot is registered, click **Test in Web Chat** to open the Web Chat pane. Type "hello" in Web Chat. - - ![Test the bot in Web Chat](../media/bot-builder-nodejs-use-luis/bot-service-web-chat.png) - -The bot responds by saying "You have reached Greeting. You said: hello". This confirms that the bot has received your message and passed it to a default LUIS app that it created. This default LUIS app detected a Greeting intent. - -## Modify the LUIS app - -Log in to [https://www.luis.ai](https://www.luis.ai) using the same account you use to log in to Azure. Click on **My apps**. In the list of apps, find the app that begins with the name specified in **App name** in the **Bot Service** blade when you created the Bot Service. - -The LUIS app starts with 4 intents: Cancel: Greeting, Help, and None. - -The following steps add the Note.Create, Note.ReadAloud, and Note.Delete intents: - -1. Click on **Prebuit Domains** in the lower left of the page. Find the **Note** domain and click **Add domain**. - -2. This tutorial doesn't use all of the intents included in the **Note** prebuilt domain. In the **Intents** page, click on each of the following intent names and then click the **Delete Intent** button. - * Note.ShowNext - * Note.DeleteNoteItem - * Note.Confirm - * Note.Clear - * Note.CheckOffItem - * Note.AddToNote - - The only intents that should remain in the LUIS app are the following: - * Note.ReadAloud - * Note.Create - * Note.Delete - * None - * Help - * Greeting - * Cancel - - ![intents shown in LUIS app](../media/bot-builder-nodejs-use-luis/luis-intent-list.png) - - -3. Click the **Train** button in the upper right to train your app. -4. Click **PUBLISH** in the top navigation bar to open the **Publish** page. Click the **Publish to production slot** button. After successful publish, a LUIS app is deployed to the URL displayed in the **Endpoint** column in the **Publish App** page, in the row that starts with the Resource Name Starter_Key. The URL has a format similar to this example: `https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx?subscription-key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&timezoneOffset=0&verbose=true&q=`. The app ID and subscription key in this URL are the same as LuisAppId and LuisAPIKey in **App Service Settings > ApplicationSettings > App settings** - - -## Modify the bot code - -Click **Build** and then click **Open online code editor**. - - ![Open online code editor](../media/bot-builder-nodejs-use-luis/bot-service-build.png) - -In the code editor, open `app.js`. It contains the following code: - -```javascript -var restify = require('restify'); -var builder = require('botbuilder'); -var botbuilder_azure = require("botbuilder-azure"); - -// Setup Restify Server -var server = restify.createServer(); -server.listen(process.env.port || process.env.PORT || 3978, function () { - console.log('%s listening to %s', server.name, server.url); -}); - -// Create chat connector for communicating with the Bot Framework Service -var connector = new builder.ChatConnector({ - appId: process.env.MicrosoftAppId, - appPassword: process.env.MicrosoftAppPassword, - openIdMetadata: process.env.BotOpenIdMetadata -}); - -// Listen for messages from users -server.post('/api/messages', connector.listen()); - -/*---------------------------------------------------------------------------------------- -* Bot Storage: This is a great spot to register the private state storage for your bot. -* We provide adapters for Azure Table, CosmosDb, SQL Azure, or you can implement your own! -* For samples and documentation, see: https://github.com/Microsoft/BotBuilder-Azure -* ---------------------------------------------------------------------------------------- */ - -var tableName = 'botdata'; -var azureTableClient = new botbuilder_azure.AzureTableClient(tableName, process.env['AzureWebJobsStorage']); -var tableStorage = new botbuilder_azure.AzureBotStorage({ gzipData: false }, azureTableClient); - -// Create your bot with a function to receive messages from the user -// This default message handler is invoked if the user's utterance doesn't -// match any intents handled by other dialogs. -var bot = new builder.UniversalBot(connector, function (session, args) { - session.send('You reached the default message handler. You said \'%s\'.', session.message.text); -}); - -bot.set('storage', tableStorage); - -// Make sure you add code to validate these fields -var luisAppId = process.env.LuisAppId; -var luisAPIKey = process.env.LuisAPIKey; -var luisAPIHostName = process.env.LuisAPIHostName || 'westus.api.cognitive.microsoft.com'; - -const LuisModelUrl = 'https://' + luisAPIHostName + '/luis/v2.0/apps/' + luisAppId + '?subscription-key=' + luisAPIKey; - -// Create a recognizer that gets intents from LUIS, and add it to the bot -var recognizer = new builder.LuisRecognizer(LuisModelUrl); -bot.recognizer(recognizer); - -// Add a dialog for each intent that the LUIS app recognizes. -// See https://docs.microsoft.com/bot-framework/nodejs/bot-builder-nodejs-recognize-intent-luis -bot.dialog('GreetingDialog', - (session) => { - session.send('You reached the Greeting intent. You said \'%s\'.', session.message.text); - session.endDialog(); - } -).triggerAction({ - matches: 'Greeting' -}) - -bot.dialog('HelpDialog', - (session) => { - session.send('You reached the Help intent. You said \'%s\'.', session.message.text); - session.endDialog(); - } -).triggerAction({ - matches: 'Help' -}) - -bot.dialog('CancelDialog', - (session) => { - session.send('You reached the Cancel intent. You said \'%s\'.', session.message.text); - session.endDialog(); - } -).triggerAction({ - matches: 'Cancel' -}) - -``` - - -> [!TIP] -> You can also find the sample code described in this article in the [Notes bot sample][NotesSample]. - - - -## Edit the default message handler -The bot has a default message handler. Edit it to match the following: -```javascript -// Create your bot with a function to receive messages from the user. -// This default message handler is invoked if the user's utterance doesn't -// match any intents handled by other dialogs. -var bot = new builder.UniversalBot(connector, function (session, args) { - session.send("Hi... I'm the note bot sample. I can create new notes, read saved notes to you and delete notes."); - - // If the object for storing notes in session.userData doesn't exist yet, initialize it - if (!session.userData.notes) { - session.userData.notes = {}; - console.log("initializing userData.notes in default message handler"); - } -}); -``` - -## Handle the Note.Create intent - -Copy the following code and paste it at the end of app.js: - -```javascript -// CreateNote dialog -bot.dialog('CreateNote', [ - function (session, args, next) { - // Resolve and store any Note.Title entity passed from LUIS. - var intent = args.intent; - var title = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title'); - - var note = session.dialogData.note = { - title: title ? title.entity : null, - }; - - // Prompt for title - if (!note.title) { - builder.Prompts.text(session, 'What would you like to call your note?'); - } else { - next(); - } - }, - function (session, results, next) { - var note = session.dialogData.note; - if (results.response) { - note.title = results.response; - } - - // Prompt for the text of the note - if (!note.text) { - builder.Prompts.text(session, 'What would you like to say in your note?'); - } else { - next(); - } - }, - function (session, results) { - var note = session.dialogData.note; - if (results.response) { - note.text = results.response; - } - - // If the object for storing notes in session.userData doesn't exist yet, initialize it - if (!session.userData.notes) { - session.userData.notes = {}; - console.log("initializing session.userData.notes in CreateNote dialog"); - } - // Save notes in the notes object - session.userData.notes[note.title] = note; - - // Send confirmation to user - session.endDialog('Creating note named "%s" with text "%s"', - note.title, note.text); - } -]).triggerAction({ - matches: 'Note.Create', - confirmPrompt: "This will cancel the creation of the note you started. Are you sure?" -}).cancelAction('cancelCreateNote', "Note canceled.", { - matches: /^(cancel|nevermind)/i, - confirmPrompt: "Are you sure?" -}); -``` - -Any entities in the utterance are passed to the dialog using the `args` parameter. The first step of the [waterfall][waterfall] calls [EntityRecognizer.findEntity][EntityRecognizer_findEntity] to get the title of the note from any `Note.Title` entities in the LUIS response. If the LUIS app didn't detect a `Note.Title` entity, the bot prompts the user for the name of the note. The second step of the waterfall prompts for the text to include in the note. Once the bot has the text of the note, the third step uses [session.userData][session_userData] to save the note in a `notes` object, using the title as the key. For more information on `session.UserData` see [Manage state data](./bot-builder-nodejs-state.md). - - - -## Handle the Note.Delete intent -Just as for the `Note.Create` intent, the bot examines the `args` parameter for a title. If no title is detected, the bot prompts the user. The title is used to look up the note to delete from `session.userData.notes`. - - - -Copy the following code and paste it at the end of app.js: -```javascript -// Delete note dialog -bot.dialog('DeleteNote', [ - function (session, args, next) { - if (noteCount(session.userData.notes) > 0) { - // Resolve and store any Note.Title entity passed from LUIS. - var title; - var intent = args.intent; - var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title'); - if (entity) { - // Verify that the title is in our set of notes. - title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity); - } - - // Prompt for note name - if (!title) { - builder.Prompts.choice(session, 'Which note would you like to delete?', session.userData.notes); - } else { - next({ response: title }); - } - } else { - session.endDialog("No notes to delete."); - } - }, - function (session, results) { - delete session.userData.notes[results.response.entity]; - session.endDialog("Deleted the '%s' note.", results.response.entity); - } -]).triggerAction({ - matches: 'Note.Delete' -}).cancelAction('cancelDeleteNote', "Ok - canceled note deletion.", { - matches: /^(cancel|nevermind)/i -}); -``` - -The code that handles `Note.Delete` uses the `noteCount` function to determine whether the `notes` object contains notes. - -Paste the `noteCount` helper function at the end of `app.js`. - -[!code-js[Add a helper function that returns the number of notes (JavaScript)](../includes/code/node-basicNote.js#CountNotesHelper)] - -## Handle the Note.ReadAloud intent - -Copy the following code and paste it in `app.js` after the handler for `Note.Delete`: - -```javascript -// Read note dialog -bot.dialog('ReadNote', [ - function (session, args, next) { - if (noteCount(session.userData.notes) > 0) { - - // Resolve and store any Note.Title entity passed from LUIS. - var title; - var intent = args.intent; - var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title'); - if (entity) { - // Verify it's in our set of notes. - title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity); - } - - // Prompt for note name - if (!title) { - builder.Prompts.choice(session, 'Which note would you like to read?', session.userData.notes); - } else { - next({ response: title }); - } - } else { - session.endDialog("No notes to read."); - } - }, - function (session, results) { - session.endDialog("Here's the '%s' note: '%s'.", results.response.entity, session.userData.notes[results.response.entity].text); - } -]).triggerAction({ - matches: 'Note.ReadAloud' -}).cancelAction('cancelReadNote', "Ok.", { - matches: /^(cancel|nevermind)/i -}); - -``` - -The `session.userData.notes` object is passed as the third argument to `builder.Prompts.choice`, so that the prompt displays a list of notes to the user. - -Now that you've added handlers for the new intents, the full code for `app.js` contains the following: - -```javascript -var restify = require('restify'); -var builder = require('botbuilder'); -var botbuilder_azure = require("botbuilder-azure"); - -// Setup Restify Server -var server = restify.createServer(); -server.listen(process.env.port || process.env.PORT || 3978, function () { - console.log('%s listening to %s', server.name, server.url); -}); - -// Create chat connector for communicating with the Bot Framework Service -var connector = new builder.ChatConnector({ - appId: process.env.MicrosoftAppId, - appPassword: process.env.MicrosoftAppPassword, - openIdMetadata: process.env.BotOpenIdMetadata -}); - -// Listen for messages from users -server.post('/api/messages', connector.listen()); - -/*---------------------------------------------------------------------------------------- -* Bot Storage: This is a great spot to register the private state storage for your bot. -* We provide adapters for Azure Table, CosmosDb, SQL Azure, or you can implement your own! -* For samples and documentation, see: https://github.com/Microsoft/BotBuilder-Azure -* ---------------------------------------------------------------------------------------- */ - -var tableName = 'botdata'; -var azureTableClient = new botbuilder_azure.AzureTableClient(tableName, process.env['AzureWebJobsStorage']); -var tableStorage = new botbuilder_azure.AzureBotStorage({ gzipData: false }, azureTableClient); - -// Create your bot with a function to receive messages from the user. -// This default message handler is invoked if the user's utterance doesn't -// match any intents handled by other dialogs. -var bot = new builder.UniversalBot(connector, function (session, args) { - session.send("Hi... I'm the note bot sample. I can create new notes, read saved notes to you and delete notes."); - - // If the object for storing notes in session.userData doesn't exist yet, initialize it - if (!session.userData.notes) { - session.userData.notes = {}; - console.log("initializing userData.notes in default message handler"); - } -}); - -bot.set('storage', tableStorage); - -// Make sure you add code to validate these fields -var luisAppId = process.env.LuisAppId; -var luisAPIKey = process.env.LuisAPIKey; -var luisAPIHostName = process.env.LuisAPIHostName || 'westus.api.cognitive.microsoft.com'; - -const LuisModelUrl = 'https://' + luisAPIHostName + '/luis/v2.0/apps/' + luisAppId + '?subscription-key=' + luisAPIKey; - -// Create a recognizer that gets intents from LUIS, and add it to the bot -var recognizer = new builder.LuisRecognizer(LuisModelUrl); -bot.recognizer(recognizer); - -// CreateNote dialog -bot.dialog('CreateNote', [ - function (session, args, next) { - // Resolve and store any Note.Title entity passed from LUIS. - var intent = args.intent; - var title = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title'); - - var note = session.dialogData.note = { - title: title ? title.entity : null, - }; - - // Prompt for title - if (!note.title) { - builder.Prompts.text(session, 'What would you like to call your note?'); - } else { - next(); - } - }, - function (session, results, next) { - var note = session.dialogData.note; - if (results.response) { - note.title = results.response; - } - - // Prompt for the text of the note - if (!note.text) { - builder.Prompts.text(session, 'What would you like to say in your note?'); - } else { - next(); - } - }, - function (session, results) { - var note = session.dialogData.note; - if (results.response) { - note.text = results.response; - } - - // If the object for storing notes in session.userData doesn't exist yet, initialize it - if (!session.userData.notes) { - session.userData.notes = {}; - console.log("initializing session.userData.notes in CreateNote dialog"); - } - // Save notes in the notes object - session.userData.notes[note.title] = note; - - // Send confirmation to user - session.endDialog('Creating note named "%s" with text "%s"', - note.title, note.text); - } -]).triggerAction({ - matches: 'Note.Create', - confirmPrompt: "This will cancel the creation of the note you started. Are you sure?" -}).cancelAction('cancelCreateNote', "Note canceled.", { - matches: /^(cancel|nevermind)/i, - confirmPrompt: "Are you sure?" -}); - -// Delete note dialog -bot.dialog('DeleteNote', [ - function (session, args, next) { - if (noteCount(session.userData.notes) > 0) { - // Resolve and store any Note.Title entity passed from LUIS. - var title; - var intent = args.intent; - var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title'); - if (entity) { - // Verify that the title is in our set of notes. - title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity); - } - - // Prompt for note name - if (!title) { - builder.Prompts.choice(session, 'Which note would you like to delete?', session.userData.notes); - } else { - next({ response: title }); - } - } else { - session.endDialog("No notes to delete."); - } - }, - function (session, results) { - delete session.userData.notes[results.response.entity]; - session.endDialog("Deleted the '%s' note.", results.response.entity); - } -]).triggerAction({ - matches: 'Note.Delete' -}).cancelAction('cancelDeleteNote', "Ok - canceled note deletion.", { - matches: /^(cancel|nevermind)/i -}); - - -// Read note dialog -bot.dialog('ReadNote', [ - function (session, args, next) { - if (noteCount(session.userData.notes) > 0) { - - // Resolve and store any Note.Title entity passed from LUIS. - var title; - var intent = args.intent; - var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title'); - if (entity) { - // Verify it's in our set of notes. - title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity); - } - - // Prompt for note name - if (!title) { - builder.Prompts.choice(session, 'Which note would you like to read?', session.userData.notes); - } else { - next({ response: title }); - } - } else { - session.endDialog("No notes to read."); - } - }, - function (session, results) { - session.endDialog("Here's the '%s' note: '%s'.", results.response.entity, session.userData.notes[results.response.entity].text); - } -]).triggerAction({ - matches: 'Note.ReadAloud' -}).cancelAction('cancelReadNote', "Ok.", { - matches: /^(cancel|nevermind)/i -}); - - -// Helper function to count the number of notes stored in session.userData.notes -function noteCount(notes) { - - var i = 0; - for (var name in notes) { - i++; - } - return i; -} -``` - -## Test the bot - -In the Azure Portal, click on **Test in Web Chat** to test the bot. Try type messages like "Create a note", "read my notes", and "delete notes" to invoke the intents that you added to it. - ![Test notes bot in Web Chat](../media/bot-builder-nodejs-use-luis/bot-service-test-notebot.png) - -> [!TIP] -> If you find that your bot doesn't always recognize the correct intent or entities, improve your LUIS app's performance by giving it more example utterances to train it. You can retrain your LUIS app without any modification to your bot's code. See [Add example utterances](/azure/cognitive-services/LUIS/add-example-utterances) and [train and test your LUIS app](/azure/cognitive-services/LUIS/train-test). - - -## Next steps - -From trying the bot, you can see that the recognizer can trigger interruption of the currently active dialog. Allowing and handling interruptions is a flexible design that accounts for what users really do. Learn more about the various actions you can associate with a recognized intent. - -> [!div class="nextstepaction"] -> [Handle user actions](bot-builder-nodejs-dialog-actions.md) - - -[LUIS]: https://www.luis.ai/ - -[intentDialog]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.intentdialog.html - -[intentDialog_matches]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.intentdialog.html#matches - -[NotesSample]: https://github.com/Microsoft/BotFramework-Samples/tree/master/docs-samples/Node/basics-naturalLanguage - -[triggerAction]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html#triggeraction - -[confirmPrompt]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.itriggeractionoptions.html#confirmprompt - -[waterfall]: bot-builder-nodejs-dialog-manage-conversation-flow.md#manage-conversation-flow-with-a-waterfall - -[session_userData]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#userdata - -[EntityRecognizer_findEntity]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.entityrecognizer.html#findentity - -[matches]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.itriggeractionoptions.html#matches - -[LUISAzureDocs]: /azure/cognitive-services/LUIS/Home - -[Dialog]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html - -[IntentRecognizerSetOptions]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.iintentrecognizersetoptions.html - -[LuisRecognizer]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.luisrecognizer - -[LUISConcepts]: https://docs.botframework.com/node/builder/guides/understanding-natural-language/ - -[DisambiguationSample]: https://aka.ms/v3-js-onDisambiguateRoute - -[IDisambiguateRouteHandler]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.idisambiguateroutehandler.html - -[RegExpRecognizer]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.regexprecognizer.html - -[AlarmBot]: https://aka.ms/v3-js-luisSample - -[UniversalBot]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.universalbot.html diff --git a/articles/nodejs/bot-builder-nodejs-recognize-intent-messages.md b/articles/nodejs/bot-builder-nodejs-recognize-intent-messages.md deleted file mode 100644 index c6e1270d9..000000000 --- a/articles/nodejs/bot-builder-nodejs-recognize-intent-messages.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: Recognize intent from message content - Bot Service -description: Learn how to recognize the user's intent by using regular expressions or checking the message content. -author: DeniseMak -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Recognize user intent from message content - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -When your bot receives a message from a user, your bot can use a **recognizer** to examine the message and determine intent. The intent provides a mapping from messages to dialogs to invoke. This article explains how to recognize intent using regular expressions or by inspecting the content of a message. For example, a bot can use regular expressions to check if a message contains the word "help" and invoke a help dialog. A bot can also check the properties of the user message, for example, to see if the user sent an image instead of text and invoke an image processing dialog. - -> [!NOTE] -> For information on recognizing intent using LUIS, see [Recognize intents and entities with LUIS](bot-builder-nodejs-recognize-intent-luis.md) - -## Use the built-in regular expression recognizer - -Use [RegExpRecognizer][RegExpRecognizer] to detect the user's intent using a regular expression. You can pass multiple expressions to the recognizer to support multiple languages. - -> [!TIP] -> See [Support localization](bot-builder-nodejs-localization.md) for more information on localizing your bot. - -The following code creates a regular expression recognizer named `CancelIntent` and adds it to your bot. The recognizer in this example provides regular expressions for both the `en_us` and `ja_jp` locales. - -[!code-js[Add a regular expression recognizer (JavaScript)](../includes/code/node-regex-recognizer.js#addRegexRecognizer)] - -Once the recognizer is added to your bot, attach a [triggerAction][triggerAction] to the dialog that you want the bot to invoke when the recognizer detects the intent. Use the `matches` option to specify the intent name, as shown in the following code: - -[!code-js[Map the CancelIntent recognizer to a cancel dialog (JavaScript)](../includes/code/node-regex-recognizer.js#bindCancelDialogToRegexRecognizer)] - -Intent recognizers are global, which means that the recognizer will run for every message received from the user. If a recognizer detects an intent that is bound to a dialog using a `triggerAction`, it can trigger interruption of the currently active dialog. Allowing and handling interruptions is a flexible design that accounts for what users really do. - -> [!TIP] -> To learn how a `triggerAction` works with dialogs, see [Managing conversation flow](bot-builder-nodejs-manage-conversation-flow.md). To learn more about the various actions you can associate with a recognized intent, [Handle user actions](bot-builder-nodejs-dialog-actions.md). - -## Register a custom intent recognizer - -You can also implement a custom recognizer. This example adds a simple recognizer that looks for the user to say 'help' or 'goodbye' but you could easily add a recognizer that does more complex processing, such as one that recognizes when the user sends an image. - -[!code-js[Add a custom recognizer (JavaScript)](../includes/code/node-howto-recognize-intent.js#addCustomRecognizer)] - -Once you've registered a recognizer, you can associate the recognizer with an action using a `matches` clause. - -[!code-js[Bind intents to actions (JavaScript)](../includes/code/node-howto-recognize-intent.js#bindIntentsToActions)] - -## Disambiguate between multiple intents - -Your bot can register more than one recognizer. Notice that the custom recognizer example involves assigning a numerical score to each intent. This is done since your bot may have more than one recognizer, and the Bot Framework SDK provides built-in logic to disambiguate between intents returned by multiple recognizers. The score assigned to an intent is typically between 0.0 and 1.0, but a custom recognizer may define an intent greater than 1.1 to ensure that that intent will always be chosen by the Bot Framework SDK disambiguation logic. - -By default, recognizers run in parallel, but you can set recognizeOrder in [IIntentRecognizerSetOptions][IIntentRecognizerSetOptions] so the process quits as soon as your bot finds one that gives a score of 1.0. - -The Bot Framework SDK includes a [sample][DisambiguationSample] that demonstrates how to provide custom disambiguation logic in your bot by implementing [IDisambiguateRouteHandler][IDisambiguateRouteHandler]. - -## Next steps - -The logic for using regular expressions and inspecting message contents can become complex, especially if your bot's conversational flow is open-ended. To help your bot handle a wider variety of textual and spoken input from users, you can use an intent recognition service like [LUIS][LUIS] to add natural language understanding to your bot. - -> [!div class="nextstepaction"] -> [Recognize intents and entities with LUIS](bot-builder-nodejs-recognize-intent-luis.md) - -[LUIS]: https://www.luis.ai/ - -[IDisambiguateRouteHandler]: https://docs.microsoft.com/javascript/api/botbuilder/idisambiguateroutehandler?view=botbuilder-ts-3.0 -[IIntentRecognizerSetOptions]: https://docs.microsoft.com/javascript/api/botbuilder/iintentrecognizersetoptions?view=botbuilder-ts-3.0 -[RegExpRecognizer]: https://docs.microsoft.com/javascript/api/botbuilder/regexprecognizer?view=botbuilder-ts-3.0 -[triggerAction]: https://docs.microsoft.com/javascript/api/botbuilder/dialog?view=botbuilder-ts-3.0#triggeraction-itriggeractionoptions- - -[DisambiguationSample]: https://aka.ms/v3-js-onDisambiguateRoute diff --git a/articles/nodejs/bot-builder-nodejs-request-payment.md b/articles/nodejs/bot-builder-nodejs-request-payment.md deleted file mode 100644 index beb376c95..000000000 --- a/articles/nodejs/bot-builder-nodejs-request-payment.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -title: Request payment (v3 JS) - Bot Service -description: Learn how to send a payment request using the Bot Framework SDK for Node.js. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Request payment - -> [!NOTE] -> The Payment service referred to in this article will be deprecated on December 1, 2019. - - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-request-payment.md) -> - [Node.js](../nodejs/bot-builder-nodejs-request-payment.md) - -If your bot enables users to purchase items, it can request payment by including -a special type of button within a [rich card](bot-builder-nodejs-send-rich-cards.md). -This article describes how to send a payment request using the Bot Framework SDK for Node.js. - -## Prerequisites - -Before you can send a payment request using the Bot Framework SDK for Node.js, you must complete these prerequisite tasks. - -### Register and configure your bot - -Update your bot's environment variables for `MicrosoftAppId` and `MicrosoftAppPassword` to the app ID and password values that were generated for your bot during the [registration](~/bot-service-quickstart-registration.md) process. - -> [!NOTE] -> To find your bot's **AppID** and **AppPassword**, see [MicrosoftAppID and MicrosoftAppPassword](~/bot-service-manage-overview.md#microsoftappid-and-microsoftapppassword). - -### Create and configure merchant account - -1. Create and activate a Stripe account if you don't have one already. - -2. Sign in to Seller Center with your Microsoft account. - -3. Within Seller Center, connect your account with Stripe. - -4. Within Seller Center, navigate to the Dashboard and copy the value of **MerchantID**. - -5. Update the `PAYMENTS_MERCHANT_ID` environment variable to the value that you copied from the Seller Center Dashboard. - -[!INCLUDE [Payment process overview](../includes/snippet-payment-process-overview.md)] - -## Payment Bot sample - -The Payment Bot sample provides an example of a bot that sends a payment request -by using Node.js. -To see this sample bot in action, you can -try it out in web chat, -add it as a Skype -contact, or download the payment bot sample and run it locally using the Bot Framework Emulator. - -> [!NOTE] -> To complete the end-to-end payment process using the **Payment Bot** sample in web chat or Skype, -> you must specify a valid credit card or debit card within your Microsoft account -> (i.e., a valid card from a U.S. card issuer). -> Your card will not be charged and the card's CVV will not be verified, -> because the **Payment Bot** sample runs in test mode (i.e., `PAYMENTS_LIVEMODE` is set to `false` in **.env**). - -The next few sections of this article describe the three parts of the payment process, -in the context of the **Payment Bot** sample. - -## Requesting payment - -Your bot can request payment from a user by sending a message that contains a -[rich card](bot-builder-nodejs-send-rich-cards.md) with a button that specifies -`type` of "payment". -This code snippet from the **Payment Bot** sample creates a message that contains a Hero card with a **Buy** button that the user can click (or tap) to initiate the payment process. - -[!code-javascript[Request payment](../includes/code/node-request-payment.js#requestPayment)] - -In this example, the button's type is specified as `payments.PaymentActionType`, which -the app defines as "payment". -The button's value is populated by the `createPaymentRequest` function, which returns -a `PaymentRequest` object that contains information about supported payment methods, details, -and options. -For more information about implementation details, see **app.js** within the -Payment Bot sample. - -This screenshot shows the Hero card (with **Buy** button) that's generated by the code snippet above. - -![Payments sample bot](../media/payments-bot-buy.png) - -> [!IMPORTANT] -> Any user that has access to the **Buy** button may use it to initiate the payment process. -> Within the context of a group conversation, it is not possible to designate a button for use by only -> a specific user. - -## User experience - -When a user clicks the **Buy** button, he or she is directed to the payment web experience to provide all required payment, shipping, and contact information via their Microsoft account. - -![Microsoft payment](../media/microsoft-payment.png) - -### HTTP callbacks - -HTTP callbacks will be sent to your bot to indicate that it should perform certain operations. -Each callback will be an event that contains these property values: - -| Property | Value | -|----|----| -| `type` | invoke | -| `name` | Indicates the type of operation that the bot should perform (e.g., shipping address update, shipping option update, payment complete). | -| `value` | The request payload in JSON format. | -| `relatesTo` | Describes the channel and user that are associated with the payment request. | - -> [!NOTE] -> `invoke` is a special event type that is reserved for use by the Microsoft Bot Framework. -> The sender of an `invoke` event will expect your bot to acknowledge the callback by sending an HTTP response. - -## Processing callbacks - -[!INCLUDE [Process callbacks overview](../includes/snippet-payment-process-callbacks-overview.md)] - -### Shipping Address Update and Shipping Option Update callbacks - -When receiving a Shipping Address Update or a Shipping Option Update callback, -your bot will be provided with the current state of the payment details from the client in the event's `value` property. -As a merchant, you should treat these callbacks as static, given input payment details you will calculate some output payment details and -fail if the input state provided by the client is invalid for any reason.  -If the bot determines the given information is valid as-is, simply send HTTP status code `200 OK` along with the unmodified payment -details. Alternatively, the bot may send HTTP status code `200 OK` along with an updated payment details that should be applied before the order can be processed. -In some cases, your bot may determine that the updated information is invalid and the -order cannot be processed as-is. For example, the user's shipping address may specify a country to which the -product supplier does not ship. In that case, the bot may send HTTP status code `200 OK` and a message populating the error property of the payment details object. -Sending any HTTP status code in the `400` or `500` range to will result in a generic error for the customer. - -### Payment Complete callbacks - -When receiving a Payment Complete callback, your bot will be provided with a copy of the initial, unmodified payment request as -well as the payment response objects in the event's `value` property. The payment response object will contain the final selections -made by the customer along with a payment token. Your bot should take the opportunity to recalculate the final payment request based on -the initial payment request and the customer's final selections. Assuming the customer's selections are determined to be valid, the bot -should verify the amount and currency in the payment token header to ensure that they match the final payment request. If the bot -decides to charge the customer it should only charge the amount in the payment token header as this is the price the customer confirmed. -If there is a mismatch between the values that the bot expects and the values that it received in the Payment Complete callback, it can -fail the payment request by sending HTTP status code `200 OK` along with setting the result field to `failure`. - -In addition to verifying payment details, the bot should also verify that the order can be fulfilled, before it initiates payment -processing. For example, it may want to verify that the item(s) being purchased are still available in stock. -If the values are correct and your payment processor has successfully charged the payment token, then the bot should respond with HTTP -status code `200 OK` along with setting the result field to `success` in order for the payment web experience to display the payment -confirmation. The payment token that the bot receives can only be used once, by the merchant that requested it, and must be submitted to -Stripe (the only payment processor that the Bot Framework currently supports). Sending any HTTP status code in the `400` or `500` range -to will result in a generic error for the customer. - -This code snippet from the **Payment Bot** sample processes the callbacks that the bot receives. - -[!code-javascript[Request payment](../includes/code/node-request-payment.js#processCallback)] - -In this example, the bot examines the `name` property of the incoming event to identify the type of -operation it needs to perform, and then calls the appropriate method(s) to process the callback. -For more information about implementation details, see **app.js** -within the Payment Bot sample. - -## Testing a payment bot - -[!INCLUDE [Test a payment bot](../includes/snippet-payment-test-bot.md)] - -In the Payment Bot sample, the `PAYMENTS_LIVEMODE` environment variable in **.env** determines whether Payment Complete callbacks will contain emulated payment tokens or real payment tokens. If `PAYMENTS_LIVEMODE` is set to `false`, a header is added to the bot's outbound payment request to indicate that the bot is in test mode, and -the Payment Complete callback will contain an emulated payment token that cannot be charged. If `PAYMENTS_LIVEMODE` is set to `true`, the header which indicates that the bot is in test mode is omitted from the bot's outbound payment request, and the Payment Complete callback will contain a real payment token that the bot will submit to Stripe -for payment processing. This will be a real transaction that results in charges to the specified payment instrument. - -## Additional resources - -- Payment Bot sample -- [Add rich card attachments to messages](bot-builder-nodejs-send-rich-cards.md) -- Web Payments at W3C diff --git a/articles/nodejs/bot-builder-nodejs-search-azure.md b/articles/nodejs/bot-builder-nodejs-search-azure.md deleted file mode 100644 index cf488be82..000000000 --- a/articles/nodejs/bot-builder-nodejs-search-azure.md +++ /dev/null @@ -1,159 +0,0 @@ ---- -title: Create data-driven experiences with Azure Search (v3 JS) - Bot Service -description: Learn how to create data-driven experiences with Azure Search and help users navigate large amounts of content in a bot with the Bot Framework SDK for Node.js and Azure Search. -author: matthewshim-ms -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Create data-driven experiences with Azure Search - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-search-azure.md) -> - [Node.js](../nodejs/bot-builder-nodejs-search-azure.md) - -You can add [Azure Search][search] to your bot to help the user navigate large amounts of content and create a data-driven exploration experience for users of your bot. - -Azure Search is an Azure service that offers keyword search, built-in linguistics, custom scoring, faceted navigation and more. Azure Search can also index content from various sources, including Azure SQL DB, DocumentDB, Blob Storage, and Table Storage. It supports "push" indexing for other sources of data, and it can open PDFs, Office documents, and other formats containing unstructured data. Once collected, the content goes into an Azure Search index, which the bot can then query. - -## Install dependencies - -From a command prompt, navigate to your bot's project directory and install the following modules with the Node Package Manager (NPM): - -* [bluebird](https://www.npmjs.com/package/bluebird) -* [lodash](https://www.npmjs.com/package/lodash) -* [request](https://www.npmjs.com/package/request) - -## Prerequisites - -The following are **required**: -- Have an Azure subscription and an Azure Search Primary Key. You can find this in the Azure portal. -- Copy the [SearchDialogLibrary](https://github.com/Microsoft/botBuilder-Samples/tree/master/Node/demo-Search/SearchDialogLibrary) library to your bot's project directory. This library contains general dialogs for the user to search, but can be customized as needed to suit your bot. - -- Copy the [SearchProviders](https://github.com/Microsoft/botBuilder-Samples/tree/master/Node/demo-Search/SearchProviders) library to your bot's project directory. This library contains all of the components required to create a request and submit it to Azure Search. - -## Connect to the Azure Service - -In your bot's main program file (e.g.: app.js), create the reference paths to the two libraries you installed previously. - -```javascript -var SearchLibrary = require('./SearchDialogLibrary'); -var AzureSearch = require('./SearchProviders/azure-search'); -``` - -Add the following sample code to your bot. In the `AzureSearch` object, pass in your own Azure Search settings into the `.create` method. At run time, this will bind your bot to the Azure Search service and wait for a completed user query in the form of a `Promise`. - -```javascript -// Azure Search -var azureSearchClient = AzureSearch.create('Your-Azure-Search-Service-Name', 'Your-Azure-Search-Primary-Key', 'Your-Azure-Search-Service-Index'); -var ResultsMapper = SearchLibrary.defaultResultsMapper(ToSearchHit); -``` - - The `azureSearchClient` reference creates the Azure Search model, which passes the Azure Service's authorization settings from the bot's `.env` settings. - `ResultsMapper` parses the Azure response object and maps the data as we define in `ToSearchHit` method. For an implementation example of this method, see [After Azure Search responds](#after-azure-search-responds). - -## Register the search library -You can customize your search dialogs directly in the `SearchLibrary` module itself. The `SearchLibrary` performs most of the heavy lifting, including making the call to Azure Search. - -Add the following code in your bot's main program file to register the Search Dialogs library with your bot. - -```javascript -bot.library(SearchLibrary.create({ - multipleSelection: true, - search: function (query) { return azureSearchClient.search(query).then(ResultsMapper); }, - refiners: ['refiner1', 'refiner2', 'refiner3'], // customize your own refiners - refineFormatter: function (refiners) { - return _.zipObject( - refiners.map(function (r) { return 'By ' + _.capitalize(r); }), - refiners); - } -})); -``` -The `SearchLibrary` not only stores all of your search related dialogs, but also takes the user query to submit to Azure Search. You will need to define your own refiners in the `refiners` array to specify entities you wish to allow your user to narrow or filter their search results. - -## Create a search dialog - -You may choose to structure your dialogs however you want. The only requirement to setting up an Azure Search dialog is to invoke the `.begin` method -from the `SearchLibrary` object, passing in the `session` object generated by the Bot Framework SDK. - -```javascript -function (session) { - // Trigger Azure Search dialogs - SearchLibrary.begin(session); - }, - function (session, args) { - // Process selected search results - session.send( - 'Search Completed!', - args.selection.map( ); // format your response - } -``` -For more information about dialogs, see [Manage a conversation with dialogs](bot-builder-nodejs-dialog-manage-conversation.md). - -## After Azure Search responds - -Once a successful Azure Search resolves, you now need to store the data you want from the response object, and display it in a meaningful way to the user. - -> [!TIP] -> Consider including the [util module][NodeUtil]. It will help you format and map the response from Azure Search. - -In your bot's main program file, create a `ToSearchHit` method. This method returns an object which formats the relevant data you need from the Azure Response. The following code shows how you can define your own parameters in the `ToSearchHit` method. - - ```javascript - function ToSearchHit(azureResponse) { - return { - // define your own parameters - key: azureResponse.id, - title: azureResponse.title, - description: azureResponse.description, - imageUrl: azureResponse.thumbnail - }; - } -``` -After this is done, all you need to do is display the data to the user. - - In the **index.js** file of the **SearchDialogLibrary** project, the `searchHitAsCard` method parses each response from the Azure Search and creates a new card object to display to the user. The fields you defined in the `ToSearchHit` method from your bot's main program file needs to synced with the properties in the `searchHitAsCard` method. - -The following shows how and where your defined parameters from the `ToSearchHit` method are used to build a card attachment UI to render to the user. - -```javascript -function searchHitAsCard(showSave, searchHit) { - var buttons = showSave - ? [new builder.CardAction().type('imBack').title('Save').value(searchHit.key)] - : []; - - var card = new builder.HeroCard() - .title(searchHit.title) - .buttons(buttons); - - if (searchHit.description) { - card.subtitle(searchHit.description); - } - - if (searchHit.imageUrl) { - card.images([new builder.CardImage().url(searchHit.imageUrl)]); - } - - return card; -} -``` - -## Sample code - -For two complete samples that show how to support Azure Search with bots using the Bot Framework SDK for Node.js, see the -[Real Estate Bot sample](https://github.com/Microsoft/BotBuilder-Samples/tree/v3-sdk-samples/Node/demo-Search/RealEstateBot) or [Job Listing Bot sample](https://github.com/Microsoft/BotBuilder-Samples/tree/v3-sdk-samples/Node/demo-Search/JobListingBot) in GitHub. - -## Additional resources - -* [Azure Search][search] -* [Node Util][NodeUtil] -* [Dialogs](bot-builder-nodejs-dialog-manage-conversation.md) - -[NodeUtil]: https://nodejs.org/api/util.html -[search]: /azure/search/search-what-is-azure-search diff --git a/articles/nodejs/bot-builder-nodejs-send-input-hints.md b/articles/nodejs/bot-builder-nodejs-send-input-hints.md deleted file mode 100644 index 66d84e2b9..000000000 --- a/articles/nodejs/bot-builder-nodejs-send-input-hints.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Add input hints to messages (v3 JS) - Bot Service -description: Learn how to add input hints to messages using the Bot Framework SDK for .NET. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Add input hints to messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-add-input-hints.md) -> - [Node.js](../nodejs/bot-builder-nodejs-send-input-hints.md) -> - [REST](../rest-api/bot-framework-rest-connector-add-input-hints.md) - -By specifying an input hint for a message, you can indicate whether your bot is accepting, expecting, or ignoring user input after the message is delivered to the client. For many channels, this enables clients to set the state of user input controls accordingly. For example, if a message's input hint indicates that the bot is ignoring user input, the client may close the microphone and disable the input box to prevent the user from providing input. - -## Accepting input - -To indicate that your bot is passively ready for input but is not awaiting a response from the user, set the message's input hint to `builder.InputHint.acceptingInput`. On many channels, this will cause the client's input box to be enabled and microphone to be closed, but still accessible to the user. For example, Cortana will open the microphone to accept input from the user if the user holds down the microphone button. The following code example creates a message that indicates the bot is accepting user input. - -[!code-javascript[IMessage.speak](../includes/code/node-input-hints.js#InputHintAcceptingInput)] - -## Expecting input - -To indicate that your bot is awaiting a response from the user, set the message's input hint to `builder.InputHint.expectingInput`. On many channels, this will cause the client's input box to be enabled and microphone to be open. The following code example creates a prompt that indicates the bot is expecting user input. - -[!code-javascript[Prompt](../includes/code/node-input-hints.js#InputHintExpectingInput)] - -## Ignoring input - -To indicate that your bot is not ready to receive input from the user, set the message's input hint to `builder.InputHint.ignoringInput`. -On many channels, this will cause the client's input box to be disabled and microphone to be closed. The following code example uses the `session.say()` method to send a message that indicates the bot is ignoring user input. - -[!code-javascript[Session.say()](../includes/code/node-input-hints.js#InputHintIgnoringInput)] - -## Default values for input hint - -If you do not set the input hint for a message, the Bot Framework SDK will automatically set it for you by using this logic: - -- If your bot sends a prompt, the input hint for the message will specify that your bot is **expecting input**. -- If your bot sends single message, the input hint for the message will specify that your bot is **accepting input**. -- If your bot sends a series of consecutive messages, the input hint for all but the final message in the series will specify that your bot is **ignoring input**, and the input hint for the final message in the series will specify that your bot is **accepting input**. - -## Additional resources - -- [Add speech to messages](bot-builder-nodejs-text-to-speech.md) diff --git a/articles/nodejs/bot-builder-nodejs-send-receive-attachments.md b/articles/nodejs/bot-builder-nodejs-send-receive-attachments.md deleted file mode 100644 index 1827796c6..000000000 --- a/articles/nodejs/bot-builder-nodejs-send-receive-attachments.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: Send and receive attachments - Bot Service -description: Learn how to send and receive messages containing attachments using the Bot Framework SDK for Node.js. -author: DeniseMak -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Send and receive attachments - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-add-media-attachments.md) -> - [Node.js](../nodejs/bot-builder-nodejs-send-receive-attachments.md) -> - [REST](../rest-api/bot-framework-rest-connector-add-media-attachments.md) - -A message exchange between user and bot can contain media attachments, such as images, video, audio, and files. The types of attachments that can be sent varies by channel, but these are the basic types: - -* **Media and Files**: You can send files like images, audio and video by setting **contentType** to the MIME type of the [IAttachment object][IAttachment] and then passing a link to the file in **contentUrl**. -* **Cards**: You can send a rich set of visual cards by setting the **contentType** to the desired card's type and then pass the JSON for the card. If you use one of the rich card builder classes like **HeroCard**, the attachment is automatically filled in for you. See [send a rich card](bot-builder-nodejs-send-rich-cards.md) for an example of this. - -## Add a media attachment -The message object is expected to be an instance of an [IMessage][IMessage] and it's most useful to send the user a message as an object when you’d like to include an attachment like an image. Use the [session.send()][SessionSend] method to send messages in the form of a JSON object. - -## Example - -The following example checks to see if the user has sent an attachment, and if they have, it will echo back any image contained in the attachment. You can test this with the Bot Framework Emulator by sending your bot an image. - -```javascript -// Create your bot with a function to receive messages from the user -var bot = new builder.UniversalBot(connector, function (session) { - var msg = session.message; - if (msg.attachments && msg.attachments.length > 0) { - // Echo back attachment - var attachment = msg.attachments[0]; - session.send({ - text: "You sent:", - attachments: [ - { - contentType: attachment.contentType, - contentUrl: attachment.contentUrl, - name: attachment.name - } - ] - }); - } else { - // Echo back users text - session.send("You said: %s", session.message.text); - } -}); -``` -## Additional resources - -* [Channels reference][inspector] -* [IMessage][IMessage] -* [Send a rich card][SendRichCard] -* [session.send][SessionSend] - -[IMessage]: http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.imessage -[SendRichCard]: bot-builder-nodejs-send-rich-cards.md -[SessionSend]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#send -[IAttachment]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.iattachment.html -[inspector]: ../bot-service-channels-reference.md diff --git a/articles/nodejs/bot-builder-nodejs-send-rich-cards.md b/articles/nodejs/bot-builder-nodejs-send-rich-cards.md deleted file mode 100644 index 26b9409d1..000000000 --- a/articles/nodejs/bot-builder-nodejs-send-rich-cards.md +++ /dev/null @@ -1,196 +0,0 @@ ---- -title: Add rich card attachments to messages (v3 JS) - Bot Service -description: Learn how to send interactive, engaging rich cards using the Bot Framework SDK for Node.js. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Add rich card attachments to messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-add-rich-card-attachments.md) -> - [Node.js](../nodejs/bot-builder-nodejs-send-rich-cards.md) -> - [REST](../rest-api/bot-framework-rest-connector-add-rich-cards.md) - -Several channels, like Skype & Facebook, support sending rich graphical cards to users with interactive buttons that the user clicks to initiate an action. -The SDK provides several message and card builder classes which can be used to create and send cards. The Bot Framework Connector Service will render these cards using schema native to the channel, supporting cross-platform communication. If the channel does not support cards, such as SMS, the Bot Framework will do its best to render a reasonable experience to users. - -## Types of rich cards - -The Bot Framework currently supports eight types of rich cards: - -| Card type | Description | -|------|------| -| [Adaptive Card](/adaptive-cards/get-started/bots) | A customizable card that can contain any combination of text, speech, images, buttons, and input fields. See [per-channel support](/adaptive-cards/get-started/bots#channel-status). | -| [Animation Card][animationCard] | A card that can play animated GIFs or short videos. | -| [Audio Card][audioCard] | A card that can play an audio file. | -| [Hero Card][heroCard] | A card that typically contains a single large image, one or more buttons, and text. | -| [Thumbnail Card][thumbnailCard] | A card that typically contains a single thumbnail image, one or more buttons, and text.| -| [Receipt Card][receiptCard] | A card that enables a bot to provide a receipt to the user. It typically contains the list of items to include on the receipt, tax and total information, and other text. | -| [Signin Card][signinCard] | A card that enables a bot to request that a user sign-in. It typically contains text and one or more buttons that the user can click to initiate the sign-in process. | -| [Video Card][videoCard] | A card that can play videos. | - -## Send a carousel of Hero cards - -The following example shows a bot for a fictional t-shirt company and shows how to send a carousel of cards in response to the user saying "show shirts". - -```javascript -// Create your bot with a function to receive messages from the user -// Create bot and default message handler -var bot = new builder.UniversalBot(connector, function (session) { - session.send("Hi... We sell shirts. Say 'show shirts' to see our products."); -}); - -// Add dialog to return list of shirts available -bot.dialog('showShirts', function (session) { - var msg = new builder.Message(session); - msg.attachmentLayout(builder.AttachmentLayout.carousel) - msg.attachments([ - new builder.HeroCard(session) - .title("Classic White T-Shirt") - .subtitle("100% Soft and Luxurious Cotton") - .text("Price is $25 and carried in sizes (S, M, L, and XL)") - .images([builder.CardImage.create(session, 'http://petersapparel.parseapp.com/img/whiteshirt.png')]) - .buttons([ - builder.CardAction.imBack(session, "buy classic white t-shirt", "Buy") - ]), - new builder.HeroCard(session) - .title("Classic Gray T-Shirt") - .subtitle("100% Soft and Luxurious Cotton") - .text("Price is $25 and carried in sizes (S, M, L, and XL)") - .images([builder.CardImage.create(session, 'http://petersapparel.parseapp.com/img/grayshirt.png')]) - .buttons([ - builder.CardAction.imBack(session, "buy classic gray t-shirt", "Buy") - ]) - ]); - session.send(msg).endDialog(); -}).triggerAction({ matches: /^(show|list)/i }); -``` - -This example uses the [Message][Message] class to build a carousel. -The carousel is comprised of a list of [HeroCard][heroCard] classes that contain an image, text, and a single button that triggers buying the item. -Clicking the **Buy** button triggers sending a message so we need to add a second dialog to catch the button click. - -## Handle button input - -The `buyButtonClick` dialog will be triggered any time a message is received that starts with "buy" or "add" and is followed by something containing the word "shirt". -The dialog starts by using a couple of regular expressions to look for the color and optional size shirt that the user asked for. -This added flexibility lets you support both button clicks and natural language messages from the user like "please add a large gray shirt to my cart". -If the color is valid but the size is unknown, the bot prompts the user to pick a size from a list before adding the item to the cart. -Once the bot has all the information it needs, it puts the item onto a cart that’s persisted using **session.userData** and then sends the user a confirmation message. - -```javascript -// Add dialog to handle 'Buy' button click -bot.dialog('buyButtonClick', [ - function (session, args, next) { - // Get color and optional size from users utterance - var utterance = args.intent.matched[0]; - var color = /(white|gray)/i.exec(utterance); - var size = /\b(Extra Large|Large|Medium|Small)\b/i.exec(utterance); - if (color) { - // Initialize cart item - var item = session.dialogData.item = { - product: "classic " + color[0].toLowerCase() + " t-shirt", - size: size ? size[0].toLowerCase() : null, - price: 25.0, - qty: 1 - }; - if (!item.size) { - // Prompt for size - builder.Prompts.choice(session, "What size would you like?", "Small|Medium|Large|Extra Large"); - } else { - //Skip to next waterfall step - next(); - } - } else { - // Invalid product - session.send("I'm sorry... That product wasn't found.").endDialog(); - } - }, - function (session, results) { - // Save size if prompted - var item = session.dialogData.item; - if (results.response) { - item.size = results.response.entity.toLowerCase(); - } - - // Add to cart - if (!session.userData.cart) { - session.userData.cart = []; - } - session.userData.cart.push(item); - - // Send confirmation to users - session.send("A '%(size)s %(product)s' has been added to your cart.", item).endDialog(); - } -]).triggerAction({ matches: /(buy|add)\s.*shirt/i }); -``` - - - -## Add a message delay for image downloads - -Some channels tend to download images before displaying a message to the user so that if you send a message containing an image followed immediately by a message without images you’ll sometimes see the messages flipped in the user's feed. To minimize the chance of this you can try to insure that your images are coming from content deliver networks (CDNs) and avoid the use of overly large images. In extreme cases you may even need to insert a 1-2 second delay between the message with the image and the one that follows it. You can make this delay feel a bit more natural to the user by calling **session.sendTyping()** to send a typing indicator before starting your delay. - - - -The Bot Framework implements a batching to try to prevent multiple messages from the bot from being displayed out of order. When your bot sends multiple replies to the user, the individual messages will be automatically grouped into a batch and delivered to the user as a set in an effort to preserve the original order of the messages. This automatic batching waits a default of 250ms after every call to **session.send()** before initiating the next call to **send()**. - -The message batching delay is configurable. To disable the SDK’s auto-batching logic, set the default delay to a large number and then manually call **sendBatch()** with a callback to invoke after the batch is delivered. - -## Send an Adaptive card - -The Adaptive Card can contain any combination of text, speech, images, buttons, and input fields. -Adaptive Cards are created using the JSON format specified in [Adaptive Cards](http://adaptivecards.io), which gives you full control over card content and format. - -To create an Adaptive Card using Node.js, leverage the information within the [Adaptive Cards](http://adaptivecards.io) site to understand Adaptive Card schema, explore Adaptive Card elements, and see JSON samples that can be used to create cards of varying composition and complexity. Additionally, you can use the Interactive Visualizer to design Adaptive Card payloads and preview card output. - -This code example shows how to create a message that contains an Adaptive Card for a calendar reminder: - -[!code-javascript[Add Adaptive Card attachment](../includes/code/node-send-card-buttons.js#addAdaptiveCardAttachment)] - -The resulting card contains three blocks of text, an input field (choice list), and three buttons: - -![Adaptive Card calendar reminder](../media/adaptive-card-reminder.png) - -## Additional resources - -- [Channels reference][inspector] -- [Adaptive Cards](http://adaptivecards.io) -- [AnimationCard][animationCard] -- [AudioCard][audioCard] -- [HeroCard][heroCard] -- [ThumbnailCard][thumbnailCard] -- [ReceiptCard][receiptCard] -- [SigninCard][signinCard] -- [VideoCard][videoCard] -- [Message][Message] -- [How to send attachments](bot-builder-nodejs-send-receive-attachments.md) - -[MessageOrder]: bot-builder-nodejs-manage-conversation-flow.md#message-ordering -[Message]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.message -[IMessage]: http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.imessage - -[animationCard]: https://docs.microsoft.com/javascript/api/botbuilder/animationcard?view=botbuilder-ts-3.0 -[audioCard]: https://docs.microsoft.com/javascript/api/botbuilder/audiocard?view=botbuilder-ts-3.0 -[heroCard]: https://docs.microsoft.com/javascript/api/botbuilder/herocard?view=botbuilder-ts-3.0 -[thumbnailCard]: https://docs.microsoft.com/javascript/api/botbuilder/thumbnailcard?view=botbuilder-ts-3.0 -[receiptCard]: https://docs.microsoft.com/javascript/api/botbuilder/receiptcard?view=botbuilder-ts-3.0 -[signinCard]: https://docs.microsoft.com/javascript/api/botbuilder/signincard?view=botbuilder-ts-3.0 -[videoCard]: https://docs.microsoft.com/javascript/api/botbuilder/videocard?view=botbuilder-ts-3.0 - -[inspector]: ../bot-service-channels-reference.md diff --git a/articles/nodejs/bot-builder-nodejs-send-suggested-actions.md b/articles/nodejs/bot-builder-nodejs-send-suggested-actions.md deleted file mode 100644 index 8ca26e8d5..000000000 --- a/articles/nodejs/bot-builder-nodejs-send-suggested-actions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Add suggested actions to messages (v3 JS) - Bot Service -description: Learn how to send suggested actions within messages using the Bot Framework SDK for Node.js. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 02/19/2019 -monikerRange: 'azure-bot-service-3.0' ---- - -# Add suggested actions to messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-add-suggested-actions.md) -> - [Node.js](../nodejs/bot-builder-nodejs-send-suggested-actions.md) -> - [REST](../rest-api/bot-framework-rest-connector-add-suggested-actions.md) - -[!INCLUDE [Introduction to suggested actions](../includes/snippet-suggested-actions-intro.md)] - -## Suggested actions example - -To add suggested actions to a message, set the `suggestedActions` property of the message to a list of [card actions][ICardAction] that represent the buttons to be presented to the user. - -This code example shows how to send a message that presents three suggested actions to the user: - -[!code-javascript[Send suggested actions](../includes/code/node-send-suggested-actions.js#sendSuggestedActions)] - -When the user taps one of the suggested actions, the bot will receive a message from the user that contains the `value` of the corresponding action. - -Be aware that the `imBack` method will post the `value` to the chat window of the channel you are using. If this is not the desired effect, you can use the `postBack` method, which will still post the selection back to your bot, but will not display the selection in the chat window. Some channels do not support `postBack`, however, and in those instances the method will behave like `imBack`. - -## Additional resources - -- [Samples][samples] -- [IMessage][IMessage] -- [ICardAction][ICardAction] -- [session.send][SessionSend] - -[IMessage]: http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.imessage - -[SessionSend]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#send - -[ICardAction]: https://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.icardaction.html - - -[samples]: https://github.com/Microsoft/BotBuilder-Samples/tree/v3-sdk-samples diff --git a/articles/nodejs/bot-builder-nodejs-send-typing-indicator.md b/articles/nodejs/bot-builder-nodejs-send-typing-indicator.md deleted file mode 100644 index 8f3f85c6c..000000000 --- a/articles/nodejs/bot-builder-nodejs-send-typing-indicator.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: Send a typing indicator - Bot Service -description: Learn how to add a "please wait" indicator to tell a user a bot is processing a request using the Bot Framework SDK for Node.js -author: DeniseMak -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Send a typing indicator - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -Users expect a timely response to their messages. If your bot performs some long-running task like calling a server or executing a query without giving the user some indication that the bot heard them, the user could get impatient and send additional messages or just assume the bot is broken. -Many channels support the sending of a typing indication to show the user that the message was received and is being processed. - - -## Typing indicator example - -The following example demonstrates how to send a typing indication using [session.sendTyping()][SendTyping]. You can test this with the Bot Framework Emulator. - - -```javascript - -// Create bot and default message handler -var bot = new builder.UniversalBot(connector, function (session) { - session.sendTyping(); - setTimeout(function () { - session.send("Hello there..."); - }, 3000); -}); -``` - -Typing indicators are also useful when inserting a message delay to prevent messages that contain images from being sent out of order. - -To learn more, see [How to send a rich card](bot-builder-nodejs-send-rich-cards.md). - - -## Additional resources - -* [sendTyping][SendTyping] - - -[SendTyping]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session#sendtyping -[IMessage]: http://docs.botframework.com/node/builder/chat-reference/interfaces/_botbuilder_d_.imessage diff --git a/articles/nodejs/bot-builder-nodejs-state-azure-cosmosdb.md b/articles/nodejs/bot-builder-nodejs-state-azure-cosmosdb.md deleted file mode 100644 index 5ef577690..000000000 --- a/articles/nodejs/bot-builder-nodejs-state-azure-cosmosdb.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -title: Manage custom state data with Azure Cosmos DB (v3 JS) - Bot Service -description: Learn how to save and retrieve state data using Azure Cosmos DB with the Bot Framework SDK for Node.js. -author: DucVo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Manage custom state data with Azure Cosmos DB for Node.js - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -In this article, you’ll implement Cosmos DB storage to store and manage your bot’s state data. The default Connector State Service used by bots is not intended for the production environment. You should either use [Azure Extensions](https://www.npmjs.com/package/botbuilder-azure) available on GitHub or implement a custom state client using data storage platform of your choice. Here are some of the reasons to use custom state storage: - -- higher state API throughput (more control over performance) -- lower-latency for geo-distribution -- control over where the data is stored (e.g.: West US vs East US) -- access to the actual state data -- state data db not shared with other bots -- store more than 32kb - -## Prerequisites - -- [Node.js](https://nodejs.org/en/). -- [Bot Framework Emulator](~/bot-service-debug-emulator.md) -- Must have a Node.js bot. If you do not have one, go [create a bot](bot-builder-nodejs-quickstart.md). - -## Create Azure account -If you don't have an Azure account, click [here](https://azure.microsoft.com/free/) to sign up for a free account. - -## Set up the Azure Cosmos DB database -1. After you’ve logged into the Azure portal, create a new *Azure Cosmos DB* database by clicking **New**. -2. Click **Databases**. -3. Find **Azure Cosmos DB** and click **Create**. -4. Fill in the fields. For the **API** field, select **SQL (DocumentDB)**. When done filling in all the fields, click the **Create** button at the bottom of the screen to deploy the new database. -5. After the new database is deployed, navigate to your new database. Click **Access keys** to find keys and connection strings. Your bot will use this information to call the storage service to save state data. - -## Install botbuilder-azure module - -To install the `botbuilder-azure` module from a command prompt, navigate to the bot's directory and run the following npm command: - -```nodejs -npm install --save botbuilder-azure -``` - -## Modify your bot code - -To use your **Azure Cosmos DB** database, add the following lines of code to your bot's **app.js** file. - -1. Require the newly installed module. - - ```javascript - var azure = require('botbuilder-azure'); - ``` - -2. Configure the connection settings to connect to Azure. - ```javascript - var documentDbOptions = { - host: 'Your-Azure-DocumentDB-URI', - masterKey: 'Your-Azure-DocumentDB-Key', - database: 'botdocs', - collection: 'botdata' - }; - ``` - The `host` and `masterKey` values can be found in the **Keys** menu of your database. If the `database` and `collection` entries do not exist in the Azure database, they will be created for you. - -3. Using the `botbuilder-azure` module, create two new objects to connect to the Azure database. First, create an instance of `DocumentDBClient` passing in the connection configuration settings (defined as `documentDbOptions` from above). Next, create an instance of `AzureBotStorage` passing in the `DocumentDBClient` object. For example: - ```javascript - var docDbClient = new azure.DocumentDbClient(documentDbOptions); - - var cosmosStorage = new azure.AzureBotStorage({ gzipData: false }, docDbClient); - ``` - -4. Specify that you want to use your custom database instead of the in-memory storage. For example: - - ```javascript - var bot = new builder.UniversalBot(connector, function (session) { - // ... Bot code ... - }) - .set('storage', cosmosStorage); - ``` - -Now you are ready to test the bot with the emulator. - -## Run your bot app - -From a command prompt, navigate to your bot's directory and run your bot with the following command: - -```nodejs -node app.js -``` - -## Connect your bot to the emulator - -At this point, your bot is running locally. Start the emulator and then connect to your bot from the emulator: - -1. Type http://localhost:port-number/api/messages into the emulator's address bar, where port-number matches the port number shown in the browser where your application is running. You can leave Microsoft App ID and Microsoft App Password fields blank for now. You'll get this information later when you [register your bot](~/bot-service-quickstart-registration.md). -2. Click **Connect**. -3. Test your bot by sending your bot a message. Interact with your bot as you normally would. When you are done, go to **Storage Explorer** and view your saved state data. - -## View state data on Azure Portal - -To view the state data, sign into your Azure portal and navigate to your database. Click **Data Explorer (preview)** to verify that the state information from your bot is being saved. - -## Next step - -Now that you have full control over your bot's state data, let's take a look at how you can use it to better manage conversation flow. - -> [!div class="nextstepaction"] -> [Manage conversation flow](bot-builder-nodejs-dialog-manage-conversation-flow.md) diff --git a/articles/nodejs/bot-builder-nodejs-state-azure-table-storage.md b/articles/nodejs/bot-builder-nodejs-state-azure-table-storage.md deleted file mode 100644 index acdf7557a..000000000 --- a/articles/nodejs/bot-builder-nodejs-state-azure-table-storage.md +++ /dev/null @@ -1,134 +0,0 @@ ---- -title: Manage custom state data with Azure Table storage (v3 JS) - Bot Service -description: Learn how to save and retrieve state data using Azure Table storage with the Bot Framework SDK for Node.js. -author: DucVo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Manage custom state data with Azure Table storage for Node.js - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -In this article, you’ll implement Azure Table storage to store and manage your bot’s state data. The default Connector State Service used by bots is not intended for the production environment. You should either use [Azure Extensions](https://www.npmjs.com/package/botbuilder-azure) available on GitHub or implement a custom state client using data storage platform of your choice. Here are some of the reasons to use custom state storage: - -- higher state API throughput (more control over performance) -- lower-latency for geo-distribution -- control over where the data is stored (e.g.: West US vs East US) -- access to the actual state data -- state data db not shared with other bots -- store more than 32kb - -## Prerequisites - -- [Node.js](https://nodejs.org/en/). -- [Bot Framework Emulator](~/bot-service-debug-emulator.md). -- Must have a Node.js bot. If you do not have one, go [create a bot](bot-builder-nodejs-quickstart.md). -- [Storage Explorer](http://storageexplorer.com/). - -## Create Azure account -If you don't have an Azure account, click [here](https://azure.microsoft.com/free/) to sign up for a free account. - -## Set up the Azure Table storage service -1. After you’ve logged into the Azure portal, create a new Azure Table storage service by clicking on **New**. -2. Search for **Storage account** that implements the Azure Table. Click **Create** to start creating the storage account. -3. Fill in the fields, click the **Create** button at the bottom of the screen to deploy the new storage service. -4. After the new storage service is deployed, navigate to the storage account you just created. You can find it listed in the **Storage Accounts** blade. -4. Select **Access keys**, and copy the key for later use. Your bot will use **Storage account name** and **Key** to call the storage service to save state data. - -## Install botbuilder-azure module - -To install the `botbuilder-azure` module from a command prompt, navigate to the bot's directory and run the following npm command: - -```nodejs -npm install --save botbuilder-azure -``` - -## Modify your bot code - -To use your **Azure Table** storage, add the following lines of code to your bot's **app.js** file. - -1. Require the newly installed module. - - ```javascript - var azure = require('botbuilder-azure'); - ``` - -2. Configure the connection settings to connect to Azure. - ```javascript - // Table storage - var tableName = "Table-Name"; // You define - var storageName = "Table-Storage-Name"; // Obtain from Azure Portal - var storageKey = "Azure-Table-Key"; // Obtain from Azure Portal - ``` - The `storageName` and `storageKay` values can be found in the **Access keys** menu of your Azure Table. If the `tableName` does not exist in the Azure Table, it will be created for you. - -3. Using the `botbuilder-azure` module, create two new objects to connect to the Azure Table. First, create an instance of `AzureTableClient` passing in the connection configuration settings. Next, create an instance of `AzureBotStorage` passing in the `AzureTableClient` object. For example: - - ```javascript - var azureTableClient = new azure.AzureTableClient(tableName, storageName, storageKey); - - var tableStorage = new azure.AzureBotStorage({gzipData: false}, azureTableClient); - ``` - -4. Specify that you want to use your custom database instead of the in-memory storage and add session information to database. For example: - - ```javascript - var bot = new builder.UniversalBot(connector, function (session) { - // ... Bot code ... - - // capture session user information - session.userData = {"userId": session.message.user.id, "jobTitle": "Senior Developer"}; - - // capture conversation information - session.conversationData[timestamp.toISOString().replace(/:/g,"-")] = session.message.text; - - // save data - session.save(); - }) - .set('storage', tableStorage); - ``` -Now you are ready to test the bot with the emulator. - -## Run your bot app - -From a command prompt, navigate to your bot's directory and run your bot with the following command: - -```nodejs -node app.js -``` - -## Connect your bot to the emulator - -At this point, your bot is running locally. Start the emulator and then connect to your bot from the emulator: - -1. Type http://localhost:port-number/api/messages into the emulator's address bar, where port-number matches the port number shown in the browser where your application is running. You can leave Microsoft App ID and Microsoft App Password fields blank for now. You'll get this information later when you [register your bot](~/bot-service-quickstart-registration.md). -2. Click **Connect**. -3. Test your bot by sending your bot a message. Interact with your bot as you normally would. When you are done, go to **Storage Explorer** and view your saved state data. - -## View data in Storage Explorer - -To view the state data, open **Storage Explorer** and connect to Azure using your Azure Portal credential or connect directly to the Table using the `storageName` and `storageKey` and navigate to your `tableName`. - -![Screenshot of Storage Explorer with botdata table rows](~/media/bot-builder-nodejs-state-azure-table-storage/bot-builder-nodejs-state-azure-table-storage-query.png) - -One record of the conversation in the **data** column looks like: - -```JSON -{ - "2018-05-15T18-23-48.780Z": "I'm the second user", - "2018-05-15T18-23-55.120Z": "Do you know what time it is?", - "2018-05-15T18-24-12.214Z": "I'm looking for information about the new process." -} -``` - -## Next step - -Now that you have full control over your bot's state data, let's take a look at how you can use it to better manage conversation flow. - -> [!div class="nextstepaction"] -> [Manage conversation flow](bot-builder-nodejs-dialog-manage-conversation-flow.md) diff --git a/articles/nodejs/bot-builder-nodejs-state.md b/articles/nodejs/bot-builder-nodejs-state.md deleted file mode 100644 index 785f6581a..000000000 --- a/articles/nodejs/bot-builder-nodejs-state.md +++ /dev/null @@ -1,205 +0,0 @@ ---- -title: Manage state data (v3 JS) - Bot Service -description: Learn how to save and retrieve state data with the Bot Framework SDK for Node.js. -author: DucVo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Manage state data - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-state.md) -> - [Node.js](../nodejs/bot-builder-nodejs-state.md) - -[!INCLUDE [State concept overview](../includes/snippet-dotnet-concept-state.md)] - -## In-memory data storage - -In-memory data storage is intended for testing only. This storage is volatile and temporary. The data is cleared each time the bot is restarted. To use the in-memory storage for testing purposes, you will need to do two things. First create a new instance of the in-memory storage: - -```javascript -var inMemoryStorage = new builder.MemoryBotStorage(); -``` - -Then, set it to the bot when you create the **UniversalBot**: - -```javascript -var inMemoryStorage = new builder.MemoryBotStorage(); -var bot = new builder.UniversalBot(connector, [..waterfall steps..]) - .set('storage', inMemoryStorage); // Register in-memory storage -``` - -You can use this method to set your own custom data storage or use any of the *Azure Extensions*. - -## Manage custom data storage - -For performance and security reasons in the production environment, you may implement your own data storage or consider implementing one of the following data storage options: - -1. [Manage state data with Cosmos DB](bot-builder-nodejs-state-azure-cosmosdb.md) - -2. [Manage state data with Table storage](bot-builder-nodejs-state-azure-table-storage.md) - -With either of these [Azure Extensions](https://www.npmjs.com/package/botbuilder-azure) options, the mechanism for setting and persisting data via the Bot Framework SDK for Node.js remains the same as the in-memory data storage. - -## Storage containers - -In the Bot Framework SDK for Node.js, the `session` object exposes the following properties for storing state data. - -| Property | Scoped to | Description | -| ---- | ---- | ---- | -| [`userData`][userDataURL] | User | Contains data that is saved for the user on the specified channel. This data will persist across multiple conversations. | -| [`privateConversationData`][privateConversationDataURL] | Conversation | Contains data that is saved for the user within the context of a particular conversation on the specified channel. This data is private to the current user and will persist for the current conversation only. The property is cleared when the conversation ends or when `endConversation` is called explicitly. | -| [`conversationData`][conversationDataURL] | Conversation | Contains data that is saved in the context of a particular conversation on the specified channel. This data is shared with all users participating in the conversation and will persist for the current conversation only. The property is cleared when the conversation ends or when `endConversation` is called explicitly. | -| [`dialogData`][dialogDataURL] | Dialog | Contains data that is saved for the current dialog only. Each dialog maintains its own copy of this property. The property is cleared when the dialog is removed from the dialog stack. | - -These four properties correspond to the four data storage containers that can be used to store data. Which properties you use to store data will depend upon the appropriate scope for the data you are storing, the nature of the data that you are storing, and how long you want the data to persist. For example, if you need to store user data that will be available across multiple conversations, consider using the `userData` property. If you need to temporarily store local variable values within the scope of a dialog, consider using the `dialogData` property. If you need to temporarily store data that must be accessible across multiple dialogs, consider using the `conversationData` property. - -## Data Persistence - -By default, data that is stored using the `userData`, `privateConversationData`, and `conversationData` properties is set to persist after the conversation ends. If you do not want the data to persist in the `userData` container, set the `persistUserData` flag to **false**. If you do not want the data to persist in the `conversationData` container, set the `persistConversationData` flag to **false**. - -```javascript -// Do not persist userData -bot.set(`persistUserData`, false); - -// Do not persist conversationData -bot.set(`persistConversationData`, false); -``` - -> [!NOTE] -> You cannot disable data persistence for the `privateConversationData` container; it is always persisted. - -## Set data - -You can store simple JavaScript objects by saving them directly to a storage container. For a complex object like `Date`, consider converting it to `string`. This is because state data is serialized and stored as JSON. The following code samples show how to store primitive data, an array, an object map, and a complex `Date` object. - -**Store primitive data** - -```javascript -session.userData.userName = "Kumar Sarma"; -session.userData.userAge = 37; -session.userData.hasChildren = true; -``` - -**Store an array** - -```javascript -session.userData.profile = ["Kumar Sarma", "37", "true"]; -``` - -**Store an object map** - -```javascript -session.userData.about = { - "Profile": { - "Name": "Kumar Sarma", - "Age": 37, - "hasChildren": true - }, - "Job": { - "Company": "Contoso", - "StartDate": "June 8th, 2010", - "Title": "Developer" - } -} -``` -**Store Date and Time** - -For a complex JavaScript object, convert it to a string before saving to storage container. - -```javascript -var startDate = builder.EntityRecognizer.resolveTime([results.response]); - -// Date as string: "2017-08-23T05:00:00.000Z" -session.userdata.start = startDate.toISOString(); -``` - -### Saving data - -Data that is created in each storage container will remain in memory until the container is saved. The Bot Framework SDK for Node.js sends data to the `ChatConnector` service in batches to be saved when there are messages to be sent. To save the data that exists in the storage containers without sending any messages, you can manually call the [`save`](https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#save) method. If you do not call the `save` method, the data that exists in the storage containers will be persisted as part of the batch processing. - -```javascript -session.userData.favoriteColor = "Red"; -session.userData.about.job.Title = "Senior Developer"; -session.save(); -``` - -## Get data - -To access the data that is saved in a particular storage container, simply reference the corresponding property. The following code samples show how to access data that was previously stored as primitive data, an array, an object map, and a complex Date object. - -**Access primitive data** - -```javascript -var userName = session.userData.userName; -var userAge = session.userData.userAge; -var hasChildren = session.userData.hasChildren; -``` - -**Access an array** - -```javascript -var userProfile = session.userData.userProfile; - -session.send("User Profile:"); -for(int i = 0; i < userProfile.length, i++){ - session.send(userProfile[i]); -} -``` - -**Access an object map** - -```javascript -var about = session.userData.about; - -session.send("User %s works at %s.", about.Profile.Name, about.Job.Company); -``` - -**Access a Date object** - -Retrieve date data as string then convert it into a JavaScript's Date object. - -```javascript -// startDate as a JavaScript Date object. -var startDate = new Date(session.userdata.start); -``` - -## Delete data - -By default, data that is stored in the `dialogData` container is cleared when a dialog is removed from the dialog stack. Likewise, data that is stored in the `conversationData` container and `privateConversationData` container is cleared when the `endConversation` method is called. However, to delete data stored in the `userData` container, you have to explicitly clear it. - -To explicitly clear the data that is stored in any of the storage containers, simply reset the container as shown in the following code sample. - -```javascript -// Clears data stored in container. -session.userData = {}; -session.privateConversationData = {}; -session.conversationData = {}; -session.dialogData = {}; -``` - -Never set a data container `null` or remove it from the `session` object, as doing so will cause errors the next time you try to access the container. Also, you may want to manually call `session.save();` after you manually clear a container in memory, to clear any corresponding data that has previously been persisted. - -## Next steps - -Now that you understand how to manage user state data, let's take a look at how you can use it to better manage conversation flow. - -> [!div class="nextstepaction"] -> [Manage conversation flow](bot-builder-nodejs-dialog-manage-conversation-flow.md) - -## Additional resources -- [Prompt user for input](bot-builder-nodejs-dialog-prompt.md) - -[userDataURL]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#userdata -[conversationDataURL]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#conversationdata -[privateConversationDataURL]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#privateconversationdata -[dialogDataURL]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.session.html#dialogdata - -[ChatConnector]: https://docs.botframework.com/node/builder/chat-reference/classes/_botbuilder_d_.chatconnector.html diff --git a/articles/nodejs/bot-builder-nodejs-text-to-speech.md b/articles/nodejs/bot-builder-nodejs-text-to-speech.md deleted file mode 100644 index f13ceec09..000000000 --- a/articles/nodejs/bot-builder-nodejs-text-to-speech.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: Add speech to messages (v3 JS) - Bot Service -description: Learn how to add speech to messages using the Bot Framework SDK for Node.js. -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 -monikerRange: 'azure-bot-service-3.0' ---- - -# Add speech to messages - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-text-to-speech.md) -> - [Node.js](../nodejs/bot-builder-nodejs-text-to-speech.md) -> - [REST](../rest-api/bot-framework-rest-connector-text-to-speech.md) - -If you are building a bot for a speech-enabled channel such as Cortana, you can construct messages that specify the text to be spoken by your bot. You can also attempt to influence the state of the client's microphone by specifying an [input hint](bot-builder-nodejs-send-input-hints.md) to indicate whether your bot is accepting, expecting, or ignoring user input. - -## Specify text to be spoken by your bot - -Using the Bot Framework SDK for Node.js, there are multiple ways to specify the text to be spoken by your bot on a speech-enabled channel. You can set the `IMessage.speak` property and send the message using the `session.send()` method, send the message using the `session.say()` method (passing parameters that specify display text, speech text, and options), or send the message using a built-in prompt (specifying options `speak` and `retrySpeak`). - -### IMessage.speak - -If you are creating a message that will be sent using the `session.send()` method, set the `speak` property to specify the text to be spoken by your bot. The following code example creates a message that specifies text to be spoken and indicates that the bot is [accepting user input](bot-builder-nodejs-send-input-hints.md). - -[!code-javascript[IMessage.speak](../includes/code/node-text-to-speech.js#IMessageSpeak)] - -### session.say() - -As an alternative to using `session.send()`, you can call the `session.say()` method to create and send a message that specifies the text to be spoken, in addition to the text to be displayed and other options. The method is defined as follows: - -`session.say(displayText: string, speechText: string, options?: object)` - -| Parameter | Description | -|----|----| -| `displayText` | The text to be displayed. | -| `speechText` | The text (in plain text or SSML format) to be spoken. | -| `options` | An `IMessage` object that can contain an attachment or [input hint](bot-builder-nodejs-send-input-hints.md). | - -The following code example sends a message that specifies text to be displayed and text to be spoken and indicates that the bot is [ignoring user input](bot-builder-nodejs-send-input-hints.md). - -[!code-javascript[Session.say()](../includes/code/node-text-to-speech.js#SessionSay)] - -### Prompt options - -Using any of the built-in prompts, you can set the options `speak` and `retrySpeak` to specify the text to be spoken by your bot. The following code example creates a prompt that specifies text to be displayed, text to be spoken initially, and text to be spoken after waiting a while for user input. It indicates that the bot is [expecting user input](bot-builder-nodejs-send-input-hints.md) and uses [SSML](#ssml) formatting to specify that the word "sure" should be spoken with a moderate amount of emphasis. - -[!code-javascript[Prompt](../includes/code/node-text-to-speech.js#Prompt)] - -## Speech Synthesis Markup Language (SSML) - -To specify text to be spoken by your bot, you can use either a plain text string or a string that is formatted as Speech Synthesis Markup Language (SSML), an XML-based markup language that enables you to control various characteristics of your bot's speech such as voice, rate, volume, pronunciation, pitch, and more. For details about SSML, see Speech Synthesis Markup Language Reference. - -> [!TIP] -> Use an SSML library to create well-formatted SSML. - -## Input hints - -When you send a message on a speech-enabled channel, you can attempt to influence the state of the client's microphone by also including an input hint to indicate whether your bot is accepting, expecting, or ignoring user input. For more information, see [Add input hints to messages](bot-builder-nodejs-send-input-hints.md). - -## Sample code - -For a complete sample that shows how to create a speech-enabled bot using the Bot Framework SDK for Node.js, see the Roller sample in GitHub. - -## Additional resources - -- Speech Synthesis Markup Language (SSML) -- Roller sample (GitHub) diff --git a/articles/nodejs/cortana-skill-concepts.md b/articles/nodejs/cortana-skill-concepts.md deleted file mode 100644 index a76d47b5e..000000000 --- a/articles/nodejs/cortana-skill-concepts.md +++ /dev/null @@ -1,162 +0,0 @@ ---- -title: Building a Cortana skill using Node.js - Bot Service -description: Learn core concepts for building a Cortana skill in the Bot Framework SDK for Node.js. -keywords: Bot Framework, Cortana skill, speech, Node.js, Bot Builder, SDK, key concepts, core concepts -author: DeniseMak -manager: kamrani -ms.author: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 02/10/2019 -monikerRange: 'azure-bot-service-3.0' -#ROBOTS: Index ---- - -# Key concepts for building a bot for Cortana skills using Node.js - -[!INCLUDE [pre-release-label](../includes/pre-release-label-v3.md)] - -> [!NOTE] -> This article is preliminary content and will be updated. - -This article introduces key concepts for building a Cortana skill in the Bot Framework SDK for Node.js. - -## What is a Cortana skill? -A Cortana skill is a bot you can invoke by using a Cortana client, like the one built in to Windows 10. The user launches the bot by saying some keywords or phrases associated with the bot. You use the Bot Framework Portal to configure which keywords are used to launch your bot. - -Cortana can be thought of as speech-enabled channel that can send and receive voice messages in addition to textual conversation. A bot that is published as a Cortana skill should be designed for speech as well as text. The Bot Framework provides methods for specifying Speech Synthesis Markup Language (SSML) to define spoken messages that your bot sends. - -## Acknowledge user utterances - - - - - -When you create a speech-enabled bot, you should try to establish common ground and mutual understanding in the conversation. -The bot should "ground" the user's utterances by indicating that the user was heard and understood. - -Users get confused if a system fails to ground their utterances. For example, the following conversation can be a bit confusing when the bot asks "What's next?": - -> **Cortana**: Did you want to review some more of your profile? -> **User**: No. -> **Cortana**: What's next? - -If the bot adds an "Okay" as acknowledgment, it's friendlier for the user: - -> **Cortana**: Did you want to review some more of your profile? -> **User**: No. -> **Cortana**: **Okay**, what's next? - -Degrees of grounding, from weakest to strongest: - -1. Continued attention -2. Next relevant contribution -3. Acknowledgment: Minimal response or continuer: "yeah", "uh-huh", "okay", "great" -4. Demonstrate: Indicate understanding by reformulation, completion. -5. Display: Repeat all or part. - -### Acknowledgement and next relevant contribution - -> **User**: I need to travel in May. -> **Cortana**: **Okay**. What day in May did you want to travel? -> **User**: Well, I need to be there from the 12th to the 15th? -> **Cortana**: **Okay**. What city are you flying into ? - -### Grounding by demonstration - -> **User**: I need to travel in May. -> **Cortana**: And, **what day** in May did you want to travel? -> **User**: Okay, I need to be there from the 12th to the 15th? -> **Cortana**: **And** you're flying into what city? - -### Closure - -The bot performing an action should present evidence of successful performance. It's also important to indicate failure or understanding. - -* Non-speech closure: If you push an elevator button, its light turns on. -This is two step process: - * Presentation (when you press the button) - * Acceptance (when the button lights up) - -## Differences in content presentation -Keep in mind that Cortana is supported on a variety of devices, only some of which have screens. One of the things you need to consider when designing your speech-enabled bot is that the spoken dialogue often will not be the same as the text messages your bot displays. - -```javascript - var choices = [ - { - value: 'flipCoinDialog', - action: { title: "Flip A Coin" }, - synonyms: 'toss coin|flip quarter|toss quarter' - }, - { - value: 'rollDiceDialog', - action: { title: "Roll Dice" }, - synonyms: 'roll die|shoot dice|shoot die' - }, - { - value: 'magicBallDialog', - action: { title: "Magic 8-Ball" }, - synonyms: 'shake ball' - }, - { - value: 'quit', - action: { title: "Quit" }, - synonyms: 'exit|stop|end' - } - ]; - builder.Prompts.choice(session, "Decision Options", choices, { - listStyle: builder.ListStyle.button, - speak: ssml.speak("How would you like me to decide?") - }); -``` - -## Configuring your bot - -## Prompts - -## Additional resources - -Cortana documentation: [Cortana Skills Documentation](/cortana/skills/) - -Cortana SSML reference: [Speech Synthesis Markup Language (SSML) reference](/cortana/skills/speech-synthesis-markup-language) diff --git a/articles/python/bot-builder-python-quickstart.md b/articles/python/bot-builder-python-quickstart.md deleted file mode 100644 index 60db6e56e..000000000 --- a/articles/python/bot-builder-python-quickstart.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -title: Create a bot using Bot Framework SDK for Python | Microsoft Docs -description: Quickly create a bot using the Bot Framework SDK for Python. -keywords: quickstart, bot framework sdk, getting started -author: emgrol -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/10/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Create a bot with the Bot Framework SDK for Python - -[!INCLUDE [applies-to-v4](../includes/applies-to.md)] - -This quickstart walks you through building a bot by using the Python Echo Bot template, and then testing it with the Bot Framework Emulator. - -## Prerequisites -- Python [3.6](https://www.python.org/downloads/release/python-369/) or [3.7](https://www.python.org/downloads/release/python-375/) -- [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme) -- [git](https://git-scm.com/) -- knowledge of asynchronous programming in Python - -## Create a bot -1. Open a terminal and navigate to the folder where you're saving your bot locally. Install the necessary packages by running the following commands: -- `pip install botbuilder-core` -- `pip install asyncio` -- `pip install cookiecutter` - -The last package, cookiecutter, will be used to generate your bot. Verify that cookiecutter was installed correctly by running `cookiecutter --help`. - -2. To create your bot run: - -```cmd -cookiecutter https://github.com/microsoft/botbuilder-python/releases/download/Templates/echo.zip -``` - -This command creates an Echo Bot based on the Python [echo template](https://github.com/microsoft/botbuilder-python/tree/master/generators/app/templates/echo). - -3. You will then be prompted for the *name* of the bot and a *description*. Name your bot `echo-bot` and set the description to `A bot that echoes back user response.` as shown below: - -![set name and description](../media/python/quickstart/set-name-description.png) - -Copy the last four digits in the address on the last line (usually 3978) since you will be using them in the next step. You are now ready to start your bot. - -## Start you bot -1. From a terminal navigate to the `echo-bot` folder where you saved your bot. Run `pip install -r requirements.txt` to install any required packages to run your bot. - -2. Once the packages are installed run `python app.py` to start your bot. You will know your bot is ready to test when you see the last line shown in the screenshot below: - -![bot running locally](../media/python/quickstart/bot-running-locally.png) - -## Start the Emulator and connect your bot -1. Start the Emulator and click the **Open Bot** button. - -2. After clicking the button a box window will open where you set the necessary values to run the bot. Use the number you saved earlier and set the **Bot URL** to `http://localhost:/api/messages` as seen below: - -![open a bot screen](../media/python/quickstart/open-bot.png) - -3. Click the **Connect** button and your bot should start. Try testing the bot by typing anything and clicking *Enter* as seen below: - -![connect and test](../media/python/quickstart/connect-and-start.png) - -## Additional resources -See [tunneling (ngrok)](https://github.com/Microsoft/BotFramework-Emulator/wiki/Tunneling-(ngrok)) for how to connect to a bot hosted remotely. - -## Next steps - -> [!div class="nextstepaction"] -> [Deploy your bot to Azure](../bot-builder-deploy-az-cli.md) - diff --git a/articles/python/bot-builder-python-samples.md b/articles/python/bot-builder-python-samples.md deleted file mode 100644 index 3de86f38c..000000000 --- a/articles/python/bot-builder-python-samples.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: Sample bots for Bot Framework SDK for Python - Bot Service -description: Explore sample bots that can help kickstart your bot development with the Bot Framework SDK for Python. -author: jonathanfingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Python samples for Bot Framework SDK -[!INCLUDE [pre-release-label](../includes/pre-release-label.md)] - -These samples demonstrate task-focused bots that show how to take advantage of features in the Bot Framework SDK for Python. The SDK v4 is in preview, visit Python [GitHub repo](https://github.com/Microsoft/botbuilder-python) for more information. - -To get the samples, clone the [botbuilder-python](https://github.com/Microsoft/botbuilder-python) GitHub repository using Git. - -```cmd -git clone https://github.com/Microsoft/botbuilder-python.git -cd samples -``` -The sample bots built with the Bot Framework SDK for Python are organized in the **samples** directory. diff --git a/articles/resources/TOC.md b/articles/resources/TOC.md deleted file mode 100644 index 61b9362b4..000000000 --- a/articles/resources/TOC.md +++ /dev/null @@ -1,24 +0,0 @@ -# Virtual Assistant -## [Overview](../v4sdk/bot-builder-virtual-assistant-introduction.md) -## [Template Introduction](../v4sdk/bot-builder-virtual-assistant-template.md) -# Skills -## [Overview](../v4sdk/bot-builder-skills-overview.md) -# WebChat -## [Overview](../v4sdk/bot-builder-webchat-overview.md) -## [Customization](../v4sdk/bot-builder-webchat-customization.md) -# [FAQ](../bot-service-resources-bot-framework-faq.md) -# [Get support](../bot-service-resources-links-help.md) -# [Channel reference](../bot-service-channels-reference.md) -# [Guide to identifiers](../bot-service-resources-identifiers-guide.md) -# [App Insights keys](../bot-service-resources-app-insights-keys.md) -# [User-agent requests](../bot-service-resources-user-agent.md) -# [Bot review guidelines](../bot-service-review-guidelines.md) -# [Bot Framework Activity schema](https://aka.ms/botSpecs-activitySchema) -# [Bot Framework Card schema](https://aka.ms/botSpecs-cardSchema) -# [Bot Framework Transcript schema](https://aka.ms/botSpecs-transcripts) -# [Bot Service Compliance](../v4sdk/bot-service-compliance.md) -# Troubleshoot -## [Troubleshoot general problems](../bot-service-troubleshoot-general-problems.md) -## [Troubleshoot bot configuration issues](../bot-service-troubleshoot-bot-configuration.md) -## [Troubleshoot HTTP 500 errors](../bot-service-troubleshoot-500-errors.md) -## [Troubleshoot authentication](../bot-service-troubleshoot-authentication-problems.md) diff --git a/articles/rest-api/TOC.md b/articles/rest-api/TOC.md deleted file mode 100644 index 62ad6f5a7..000000000 --- a/articles/rest-api/TOC.md +++ /dev/null @@ -1,35 +0,0 @@ -# Bot Framework REST API -## [Overview](bot-framework-rest-overview.md) -## [Key concepts](bot-framework-rest-connector-concepts.md) -## [Create a bot with REST](~/rest-api/bot-framework-rest-connector-quickstart.md) -## [API reference](bot-framework-rest-connector-api-reference.md) -# Connector -## [Authentication](bot-framework-rest-connector-authentication.md) -## [Activities overview](https://aka.ms/botSpecs-activitySchema) -## [Create messages](bot-framework-rest-connector-create-messages.md) -## [Send and receive messages](bot-framework-rest-connector-send-and-receive-messages.md) -## [Add media attachments to messages](bot-framework-rest-connector-add-media-attachments.md) -## [Add rich cards to messages](bot-framework-rest-connector-add-rich-cards.md) -## [Add speech to messages](bot-framework-rest-connector-text-to-speech.md) -## [Add input hints to messages](bot-framework-rest-connector-add-input-hints.md) -## [Add suggested actions to messages](bot-framework-rest-connector-add-suggested-actions.md) -## [Implement channel-specific functionality](bot-framework-rest-connector-channeldata.md) -## [Manage state data](bot-framework-rest-state.md) -# Direct Line API 3.0 -## [Key concepts](bot-framework-rest-direct-line-3-0-concepts.md) -## [Authentication](bot-framework-rest-direct-line-3-0-authentication.md) -## [Start a conversation](bot-framework-rest-direct-line-3-0-start-conversation.md) -## [Reconnect to a conversation](bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md) -## [Send an activity to the bot](bot-framework-rest-direct-line-3-0-send-activity.md) -## [Receive activities from the bot](bot-framework-rest-direct-line-3-0-receive-activities.md) -## [End a conversation](bot-framework-rest-direct-line-3-0-end-conversation.md) -## [API reference](bot-framework-rest-direct-line-3-0-api-reference.md) -## [Swagger file](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-protocol/directline-3.0.json) -# Direct Line API 1.1 -## [Key concepts](bot-framework-rest-direct-line-1-1-concepts.md) -## [Authentication](bot-framework-rest-direct-line-1-1-authentication.md) -## [Start a conversation](bot-framework-rest-direct-line-1-1-start-conversation.md) -## [Send a message to the bot](bot-framework-rest-direct-line-1-1-send-message.md) -## [Receive messages from the bot](bot-framework-rest-direct-line-1-1-receive-messages.md) -## [API reference](bot-framework-rest-direct-line-1-1-api-reference.md) -## [Swagger file](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-protocol/directline-1.1.json) diff --git a/articles/rest-api/bot-framework-rest-connector-add-input-hints.md b/articles/rest-api/bot-framework-rest-connector-add-input-hints.md deleted file mode 100644 index e52418c44..000000000 --- a/articles/rest-api/bot-framework-rest-connector-add-input-hints.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -title: Add input hints to messages - Bot Service -description: Learn how to add input hints to messages using the Bot Connector service. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Add input hints to messages -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-add-input-hints.md) -> - [Node.js](../nodejs/bot-builder-nodejs-send-input-hints.md) -> - [REST](../rest-api/bot-framework-rest-connector-add-input-hints.md) - -By specifying an input hint for a message, you can indicate whether your bot is accepting, expecting, or ignoring user input after the message is delivered to the client. For many channels, this enables clients to set the state of user input controls accordingly. For example, if a message's input hint indicates that the bot is ignoring user input, the client may close the microphone and disable the input box to prevent the user from providing input. - -## Accepting input - -To indicate that your bot is passively ready for input but is not awaiting a response from the user, set the `inputHint` property to **acceptingInput** within the [Activity][] object that represents your message. On many channels, this will cause the client's input box to be enabled and microphone to be closed, but still accessible to the user. For example, Cortana will open the microphone to accept input from the user if the user holds down the microphone button. - -The following example shows a request that sends a message and specifies that the bot is accepting input. In this example request, `https://smba.trafficmanager.net/apis` represents the base URI; the base URI for requests that your bot issues may be different. For details about setting the base URI, see [API Reference](bot-framework-rest-connector-api-reference.md#base-uri). - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations/abcd1234/activities/5d5cdc723 -Authorization: Bearer ACCESS_TOKEN -Content-Type: application/json -``` - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "sender's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "1234abcd", - "name": "recipient's name" - }, - "text": "Here's a picture of the house I was telling you about.", - "inputHint": "acceptingInput", - "replyToId": "5d5cdc723" -} -``` - -## Expecting input - -To indicate that your bot is awaiting a response from the user, set the `inputHint` property to **expectingInput** within the [Activity][] object that represents your message. On many channels, this will cause the client's input box to be enabled and microphone to be open. - -The following example shows a request that sends a message and specifies that the bot is expecting input. In this example request, `https://smba.trafficmanager.net/apis` represents the base URI; the base URI for requests that your bot issues may be different. For details about setting the base URI, see [API Reference](bot-framework-rest-connector-api-reference.md#base-uri). - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations/abcd1234/activities/5d5cdc723 -Authorization: Bearer ACCESS_TOKEN -Content-Type: application/json -``` - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "sender's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "1234abcd", - "name": "recipient's name" - }, - "text": "What is your favorite color?", - "inputHint": "expectingInput", - "replyToId": "5d5cdc723" -} -``` - -## Ignoring input - -To indicate that your bot is not ready to receive input from the user, set the `inputHint` property to **ignoringInput** within the [Activity][] object that represents your message. On many channels, this will cause the client's input box to be disabled and microphone to be closed. - -The following example shows a request that sends a message and specifies that the bot is ignoring input. In this example request, `https://smba.trafficmanager.net/apis` represents the base URI; the base URI for requests that your bot issues may be different. For details about setting the base URI, see [API Reference](bot-framework-rest-connector-api-reference.md#base-uri). - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations/abcd1234/activities/5d5cdc723 -Authorization: Bearer ACCESS_TOKEN -Content-Type: application/json -``` - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "sender's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "1234abcd", - "name": "recipient's name" - }, - "text": "Please hold while I perform the calculation.", - "inputHint": "ignoringInput", - "replyToId": "5d5cdc723" -} -``` - -## Additional resources - -- [Create messages](bot-framework-rest-connector-create-messages.md) -- [Send and receive messages](bot-framework-rest-connector-send-and-receive-messages.md) - -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object diff --git a/articles/rest-api/bot-framework-rest-connector-add-media-attachments.md b/articles/rest-api/bot-framework-rest-connector-add-media-attachments.md deleted file mode 100644 index bd681b5b5..000000000 --- a/articles/rest-api/bot-framework-rest-connector-add-media-attachments.md +++ /dev/null @@ -1,179 +0,0 @@ ---- -title: Add media attachments to messages - Bot Service -description: Learn how to add media attachments to messages using the Bot Connector service. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 10/25/2018 ---- - -# Add media attachments to messages -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-add-media-attachments.md) -> - [Node.js](../nodejs/bot-builder-nodejs-send-receive-attachments.md) -> - [REST](../rest-api/bot-framework-rest-connector-add-media-attachments.md) - -Bots and channels typically exchange text strings but some channels also support exchanging attachments, which lets your bot send richer messages to users. For example, your bot can send media attachments (e.g., images, videos, audio, files) and [rich cards](bot-framework-rest-connector-add-rich-cards.md). This article describes how to add media attachments to messages using the Bot Connector service. - -[!INCLUDE [Channel Inspector intro](~/includes/snippet-channel-inspector.md)] - -## Add a media attachment - -To add a media attachment to a message, create an [Attachment][] object, set the `name` property, set the `contentUrl` property to the URL of the media file, and set the `contentType` property to the appropriate media type (e.g., **image/png**, **audio/wav**, **video/mp4**). Then within the [Activity][] object that represents your message, specify your `Attachment` object within the `attachments` array. - -The following example shows a request that sends a message containing text and a single image attachment. In this example request, `https://smba.trafficmanager.net/apis` represents the base URI; the base URI for requests that your bot issues may be different. For details about setting the base URI, see [API Reference](bot-framework-rest-connector-api-reference.md#base-uri). - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations/abcd1234/activities/5d5cdc723 -Authorization: Bearer ACCESS_TOKEN -Content-Type: application/json -``` - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "sender's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "1234abcd", - "name": "recipient's name" - }, - "text": "Here's a picture of the duck I was telling you about.", - "attachments": [ - { - "contentType": "image/png", - "contentUrl": "https://aka.ms/DuckOnARock", - "name": "duck-on-a-rock.jpg" - } - ], - "replyToId": "5d5cdc723" -} -``` - -For channels that support inline binaries of an image, you can set the `contentUrl` property of the `Attachment` to a base64 binary of the image (for example, **data:image/png;base64,iVBORw0KGgo…**). The channel will display the image or the image's URL next to the message's text string. - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "sender's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "1234abcd", - "name": "recipient's name" - }, - "text": "Here's a picture of the duck I was telling you about.", - "attachments": [ - { - "contentType": "image/png", - "contentUrl": "data:image/png;base64,iVBORw0KGgo…", - "name": "duck-on-a-rock.jpg" - } - ], - "replyToId": "5d5cdc723" -} -``` - -You can attach a video file or audio file to a message by using the same process as described above for an image file. Depending on the channel, the video and audio may be played inline or it may be displayed as a link. - -> [!NOTE] -> Your bot may also receive messages that contain media attachments. -> For example, a message that your bot receives may contain an attachment -> if the channel enables the user to upload a photo to be analyzed or a document to be stored. - -## Add an AudioCard attachment - -Adding an [AudioCard][] or [VideoCard][] attachment is the same as adding a media attachment. For example, the following JSON shows how to add an audio card in the media attachment. - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "sender's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "1234abcd", - "name": "recipient's name" - }, - "attachments": [ - { - "contentType": "application/vnd.microsoft.card.audio", - "content": { - "title": "Allegro in C Major", - "subtitle": "Allegro Duet", - "text": "No Image, No Buttons, Autoloop, Autostart, Sharable", - "duration": "PT2M55S", - "media": [ - { - "url": "https://contoso.com/media/AllegrofromDuetinCMajor.mp3" - } - ], - "shareable": true, - "autoloop": true, - "autostart": true, - "value": { - // Supplementary parameter for this card - } - } - }], - "replyToId": "5d5cdc723" -} -``` - -Once the channel receives this attachment, it will start playing the audio file. If a user interacts with audio by clicking the **Pause** button, for example, the channel will send a callback to the bot with a JSON that look something like this: - -```json -{ - ... - "type": "event", - "name": "media/pause", - "value": { - "url": // URL for media - "cardValue": { - // Supplementary parameter for this card - } - } -} -``` - -The media event name **media/pause** will appear in the `activity.name` field. Reference the below table for a list of all media event names. - -| Event | Description | -| ---- | ---- | -| **media/next** | The client skipped to the next media | -| **media/pause** | The client paused playing media | -| **media/play** | The client began playing media | -| **media/previous** | The client skipped to the previous media | -| **media/resume** | The client resumed playing media | -| **media/stop** | The client stopped playing media | - -## Additional resources - -- [Create messages](bot-framework-rest-connector-create-messages.md) -- [Send and receive messages](bot-framework-rest-connector-send-and-receive-messages.md) -- [Add rich cards to messages](bot-framework-rest-connector-add-rich-cards.md) -- [Bot Framework Activity schema](https://aka.ms/botSpecs-activitySchema) -- [Bot Framework card schema](https://aka.ms/botSpecs-cardSchema) - -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object -[Attachment]: bot-framework-rest-connector-api-reference.md#attachment-object -[AudioCard]: bot-framework-rest-connector-api-reference.md#audiocard-object -[VideoCard]: bot-framework-rest-connector-api-reference.md#videocard-object diff --git a/articles/rest-api/bot-framework-rest-connector-add-rich-cards.md b/articles/rest-api/bot-framework-rest-connector-add-rich-cards.md deleted file mode 100644 index 9114cf043..000000000 --- a/articles/rest-api/bot-framework-rest-connector-add-rich-cards.md +++ /dev/null @@ -1,298 +0,0 @@ ---- -title: Add rich card attachments to messages - Bot Service -description: Learn how to add rich cards to messages using the Bot Connector service. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Add rich card attachments to messages - -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-add-rich-card-attachments.md) -> - [Node.js](../nodejs/bot-builder-nodejs-send-rich-cards.md) -> - [REST](../rest-api/bot-framework-rest-connector-add-rich-cards.md) - -Bots and channels typically exchange text strings but some channels also support exchanging attachments, which lets your bot send richer messages to users. For example, your bot can send rich cards and media attachments (e.g., images, videos, audio, files). This article describes how to add rich card attachments to messages using the Bot Connector service. - -> [!NOTE] -> For information about how to add media attachments to messages, see -> [Add media attachments to messages](bot-framework-rest-connector-add-media-attachments.md). - -## Types of rich cards - -A rich card comprises a title, description, link, and images. -A message can contain multiple rich cards, displayed in either list format or carousel format. -The Bot Framework currently supports eight types of rich cards: - -| Card type | Description | -|----|----| -| [AdaptiveCard](/adaptive-cards/get-started/bots) | A customizable card that can contain any combination of text, speech, images, buttons, and input fields. See [per-channel support](/adaptive-cards/get-started/bots#channel-status). | -| [AnimationCard][] | A card that can play animated GIFs or short videos. | -| [AudioCard][] | A card that can play an audio file. | -| [HeroCard][] | A card that typically contains a single large image, one or more buttons, and text. | -| [ThumbnailCard][] | A card that typically contains a single thumbnail image, one or more buttons, and text. | -| [ReceiptCard][] | A card that enables a bot to provide a receipt to the user. It typically contains the list of items to include on the receipt, tax and total information, and other text. | -| [SignInCard][] | A card that enables a bot to request that a user sign-in. It typically contains text and one or more buttons that the user can click to initiate the sign-in process. | -| [VideoCard][] | A card that can play videos. | - -[!INCLUDE [Channel Inspector intro](~/includes/snippet-channel-inspector.md)] - -## Process events within rich cards - -To process events within rich cards, use [CardAction][] objects to specify what should happen when the user clicks a button or taps a section of the card. Each `CardAction` object contains these properties: - -| Property | Type | Description | -|----|----|----| -| channelData | string | channel-specific data associated with this action | -| displayText | string | test to display in the chat feed if the button is clicked | -| text | string | text for the action | -| type | string | type of action (one of the values specified in the table below) | -| title | string | title of the button | -| image | string | image URL for the button | -| value | string | value needed to perform the specified type of action | - -> [!NOTE] -> Buttons within Adaptive Cards are not created using `CardAction` objects, -> but instead using the schema that is defined by Adaptive Cards. -> See [Add an Adaptive Card to a message](#add-an-adaptive-card-to-a-message) for an example that shows how to -> add buttons to an Adaptive Card. - -This table lists the valid values for the `type` property of a `CardAction` object and describes the expected contents of the `value` property for each type: - -| type | value | -|----|----| -| openUrl | URL to be opened in the built-in browser | -| imBack | Text of the message to send to the bot (from the user who clicked the button or tapped the card). This message (from user to bot) will be visible to all conversation participants via the client application that is hosting the conversation. | -| postBack | Text of the message to send to the bot (from the user who clicked the button or tapped the card). Some client applications may display this text in the message feed, where it will be visible to all conversation participants. | -| call | Destination for a phone call in this format: **tel:123123123123** | -| playAudio | URL of audio to be played | -| playVideo | URL of video to be played | -| showImage | URL of image to be displayed | -| downloadFile | URL of file to be downloaded | -| signin | URL of OAuth flow to be initiated | - -## Add a Hero card to a message - -To add a rich card attachment to a message, first create an object that corresponds to the [type of card](#types-of-rich-cards) that you want to add to the message. Then create an [Attachment][] object, set its `contentType` property to the card's media type and its `content` property to the object you created to represent the card. Specify your `Attachment` object within the `attachments` array of the message. - -> [!TIP] -> Messages that contain rich card attachments typically do not specify `text`. - -Some channels allow you to add multiple rich cards to the `attachments` array within a message. This capability can be useful in scenarios where you want to provide the user with multiple options. For example, if your bot lets users book hotel rooms, it could present the user with a list of rich cards that shows the types of available rooms. Each card could contain a picture and list of amenities corresponding to the room type and the user could select a room type by tapping a card or clicking a button. - -> [!TIP] -> To display multiple rich cards in list format, set the [Activity][] object's `attachmentLayout` property to "list". -> To display multiple rich cards in carousel format, set the `Activity` object's `attachmentLayout` property to "carousel". -> If the channel does not support carousel format, it will display the rich cards in list format, even if the `attachmentLayout` property specifies "carousel". - -The following example shows a request that sends a message containing a single Hero card attachment. In this example request, `https://smba.trafficmanager.net/apis` represents the base URI; the base URI for requests that your bot issues may be different. For details about setting the base URI, see [API Reference](bot-framework-rest-connector-api-reference.md#base-uri). - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations/abcd1234/activities/5d5cdc723 -Authorization: Bearer ACCESS_TOKEN -Content-Type: application/json -``` - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "sender's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "1234abcd", - "name": "recipient's name" - }, - "attachments": [ - { - "contentType": "application/vnd.microsoft.card.hero", - "content": { - "title": "title goes here", - "subtitle": "subtitle goes here", - "text": "descriptive text goes here", - "images": [ - { - "url": "https://aka.ms/DuckOnARock", - "alt": "picture of a duck", - "tap": { - "type": "playAudio", - "value": "url to an audio track of a duck call goes here" - } - } - ], - "buttons": [ - { - "type": "playAudio", - "title": "Duck Call", - "value": "url to an audio track of a duck call goes here" - }, - { - "type": "openUrl", - "title": "Watch Video", - "image": "https://aka.ms/DuckOnARock", - "value": "url goes here of the duck in flight" - } - ] - } - } - ], - "replyToId": "5d5cdc723" -} -``` - -## Add an Adaptive card to a message - -The Adaptive Card can contain any combination of text, speech, images, buttons, and input fields. -Adaptive Cards are created using the JSON format specified in [Adaptive Cards](http://adaptivecards.io), which gives you full control over card content and format. - -Leverage the information within the [Adaptive Cards](http://adaptivecards.io) site to understand Adaptive Card schema, explore Adaptive Card elements, and see JSON samples that can be used to create cards of varying composition and complexity. Additionally, you can use the Interactive Visualizer to design Adaptive Card payloads and preview card output. The following example is a single Adaptive Card for a work assignment. - -```json -{ - "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", - "type": "AdaptiveCard", - "version": "1.0", - "body": [ - { - "type": "Container", - "items": [ - { - "type": "TextBlock", - "text": "Publish Adaptive Card schema", - "weight": "bolder", - "size": "medium" - }, - { - "type": "ColumnSet", - "columns": [ - { - "type": "Column", - "width": "auto", - "items": [ - { - "type": "Image", - "url": "https://pbs.twimg.com/profile_images/3647943215/d7f12830b3c17a5a9e4afcc370e3a37e_400x400.jpeg", - "size": "small", - "style": "person" - } - ] - }, - { - "type": "Column", - "width": "stretch", - "items": [ - { - "type": "TextBlock", - "text": "Matt Hidinger", - "weight": "bolder", - "wrap": true - }, - { - "type": "TextBlock", - "spacing": "none", - "text": "Created {{DATE(2017-02-14T06:08:39Z, SHORT)}}", - "isSubtle": true, - "wrap": true - } - ] - } - ] - } - ] - }, - { - "type": "Container", - "items": [ - { - "type": "TextBlock", - "text": "Now that we have defined the main rules and features of the format, we need to produce a schema and publish it to GitHub. The schema will be the starting point of our reference documentation.", - "wrap": true - }, - { - "type": "FactSet", - "facts": [ - { - "title": "Board:", - "value": "Adaptive Card" - }, - { - "title": "List:", - "value": "Backlog" - }, - { - "title": "Assigned to:", - "value": "Matt Hidinger" - }, - { - "title": "Due date:", - "value": "Not set" - } - ] - } - ] - } - ], - "actions": [ - { - "type": "Action.ShowCard", - "title": "Comment", - "card": { - "type": "AdaptiveCard", - "body": [ - { - "type": "Input.Text", - "id": "comment", - "isMultiline": true, - "placeholder": "Enter your comment" - } - ], - "actions": [ - { - "type": "Action.Submit", - "title": "OK" - } - ] - } - }, - { - "type": "Action.OpenUrl", - "title": "View", - "url": "https://adaptivecards.io" - } - ] -} - -``` - -The resulting card contains a title, information about who created the card (their name and avatar), when the card was created, a description of the work assignments, and information related to the assignment. There are also buttons which can be clicked to either comment on the work assignment or view it: - -![Adaptive Card calendar reminder](../media/adaptive-card-reminder.png) - -## Additional resources - -- [Create messages](bot-framework-rest-connector-create-messages.md) -- [Send and receive messages](bot-framework-rest-connector-send-and-receive-messages.md) -- [Add media attachments to messages](bot-framework-rest-connector-add-media-attachments.md) -- [Bot Framework Activity schema](https://aka.ms/botSpecs-activitySchema) -- [Channel Inspector][ChannelInspector] - -[ChannelInspector]: ../bot-service-channels-reference.md -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object -[Attachment]: bot-framework-rest-connector-api-reference.md#attachment-object -[CardAction]: bot-framework-rest-connector-api-reference.md#cardaction-object -[AnimationCard]: bot-framework-rest-connector-api-reference.md#animationcard-object -[AudioCard]: bot-framework-rest-connector-api-reference.md#audiocard-object -[HeroCard]: bot-framework-rest-connector-api-reference.md#herocard-object -[ThumbnailCard]: bot-framework-rest-connector-api-reference.md#thumbnailcard-object -[ReceiptCard]: bot-framework-rest-connector-api-reference.md#receiptcard-object -[SigninCard]: bot-framework-rest-connector-api-reference.md#signincard-object -[VideoCard]: bot-framework-rest-connector-api-reference.md#videocard-object diff --git a/articles/rest-api/bot-framework-rest-connector-add-suggested-actions.md b/articles/rest-api/bot-framework-rest-connector-add-suggested-actions.md deleted file mode 100644 index d411d53aa..000000000 --- a/articles/rest-api/bot-framework-rest-connector-add-suggested-actions.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: Add suggested actions to messages - Bot Service -description: Learn how to add suggested actions to messages using the Bot Connector service. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Add suggested actions to messages -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-add-suggested-actions.md) -> - [Node.js](../nodejs/bot-builder-nodejs-send-suggested-actions.md) -> - [REST](../rest-api/bot-framework-rest-connector-add-suggested-actions.md) - -[!INCLUDE [Introduction to suggested actions](../includes/snippet-suggested-actions-intro.md)] - -## Send suggested actions - -To add suggested actions to a message, set the `suggestedActions` property of the [Activity][] object to specify the list of [CardAction][] objects that represent the buttons to be presented to the user. - -The following request sends a message that presents three suggested actions to the user. In this example request, `https://smba.trafficmanager.net/apis` represents the base URI; the base URI for requests that your bot issues may be different. For details about setting the base URI, see [API Reference](bot-framework-rest-connector-api-reference.md#base-uri). - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations/abcd1234/activities/5d5cdc723 -Authorization: Bearer ACCESS_TOKEN -Content-Type: application/json -``` - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "sender's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "1234abcd", - "name": "recipient's name" - }, - "text": "I have colors in mind, but need your help to choose the best one.", - "inputHint": "expectingInput", - "suggestedActions": { - "actions": [ - { - "type": "imBack", - "title": "Blue", - "value": "Blue" - }, - { - "type": "imBack", - "title": "Red", - "value": "Red" - }, - { - "type": "imBack", - "title": "Green", - "value": "Green" - } - ] - }, - "replyToId": "5d5cdc723" -} -``` - -When the user taps one of the suggested actions, the bot will receive a message from the user that contains the `value` of the corresponding action. - -## Additional resources - -- [Create messages](bot-framework-rest-connector-create-messages.md) -- [Send and receive messages](bot-framework-rest-connector-send-and-receive-messages.md) - -[channelInspector]: ../bot-service-channel-inspector.md - -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object -[CardAction]: bot-framework-rest-connector-api-reference.md#cardaction-object diff --git a/articles/rest-api/bot-framework-rest-connector-api-reference.md b/articles/rest-api/bot-framework-rest-connector-api-reference.md deleted file mode 100644 index d8f48feaf..000000000 --- a/articles/rest-api/bot-framework-rest-connector-api-reference.md +++ /dev/null @@ -1,946 +0,0 @@ ---- -title: API reference - Bot Service -description: Learn about headers, operations, objects, and errors in the Bot Connector service and Bot State service. -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 08/02/2019 - ---- - -# API reference - -> [!NOTE] -> The REST API is not equivalent to the SDK. The REST API is provided to allow standard REST communication, however the preferred method of interacting with the Bot Framework is the SDK. - -Within the Bot Framework, the Bot Connector service enables your bot to exchange messages with users on channels that are configured in the Bot Framework Portal. The service uses industry-standard REST and JSON over HTTPS. - -## Base URI - -When a user sends a message to your bot, the incoming request contains an [Activity](#activity-object) object with a `serviceUrl` property that specifies the endpoint to which your bot should send its response. To access the Bot Connector service, use the `serviceUrl` value as the base URI for API requests. - -For example, assume that your bot receives the following activity when the user sends a message to the bot. - -```json -{ - "type": "message", - "id": "bf3cc9a2f5de...", - "timestamp": "2016-10-19T20:17:52.2891902Z", - "serviceUrl": "https://smba.trafficmanager.net/apis", - "channelId": "channel's name/id", - "from": { - "id": "1234abcd", - "name": "user's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "12345678", - "name": "bot's name" - }, - "text": "Haircut on Saturday" -} -``` - -The `serviceUrl` property within the user's message indicates that the bot should send its response to the endpoint `https://smba.trafficmanager.net/apis`; this will be the base URI for any subsequent requests that the bot issues in the context of this conversation. If your bot will need to send a proactive message to the user, be sure to save the value of `serviceUrl`. - -The following example shows the request that the bot issues to respond to the user's message. - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations/abcd1234/activities/bf3cc9a2f5de... -Authorization: Bearer eyJhbGciOiJIUzI1Ni... -Content-Type: application/json -``` - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "bot's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "1234abcd", - "name": "user's name" - }, - "text": "I have several times available on Saturday!", - "replyToId": "bf3cc9a2f5de..." -} -``` - -## Headers - -### Request headers - -In addition to the standard HTTP request headers, every API request that you issue must include an `Authorization` header that specifies an access token to authenticate your bot. Specify the `Authorization` header using this format: - -```http -Authorization: Bearer ACCESS_TOKEN -``` - -For details about how to obtain an access token for your bot, see [Authenticate requests from your bot to the Bot Connector service](bot-framework-rest-connector-authentication.md#bot-to-connector). - -### Response headers - -In addition to the standard HTTP response headers, every response will contain an `X-Correlating-OperationId` header. The value of this header is an ID that corresponds to the Bot Framework log entry which contains details about the request. Any time that you receive an error response, you should capture the value of this header. If you are not able to independently resolve the issue, include this value in the information that you provide to the Support team when you report the issue. - -## HTTP status codes - -The HTTP status code that is returned with each response indicates the outcome of the corresponding request. - -| HTTP status code | Meaning | -|----|----| -| 200 | The request succeeded. | -| 201 | The request succeeded. | -| 202 | The request has been accepted for processing. | -| 204 | The request succeeded but no content was returned. | -| 400 | The request was malformed or otherwise incorrect. | -| 401 | The bot is not authorized to make the request. | -| 403 | The bot is not allowed to perform the requested operation. | -| 404 | The requested resource was not found. | -| 500 | An internal server error occurred. | -| 503 | The service is unavailable. | - -### Errors - -Any response that specifies an HTTP status code in the 4xx range or 5xx range will include an [ErrorResponse](#errorresponse-object) object in the body of the response that provides information about the error. If you receive an error response in the 4xx range, inspect the **ErrorResponse** object to identify the cause of the error and resolve your issue prior to resubmitting the request. - -## Conversation operations - -Use these operations to create conversations, send messages (activities), and manage the contents of conversations. - -| Operation | Description | -|----|----| -| [Create Conversation](#create-conversation) | Creates a new conversation. | -| [Send to Conversation](#send-to-conversation) | Sends an activity (message) to the end of the specified conversation. | -| [Reply to Activity](#reply-to-activity) | Sends an activity (message) to the specified conversation, as a reply to the specified activity. | -| [Get Conversations](#get-conversations) | Gets a list of conversations the bot has participated in. | -| [Get Conversation Members](#get-conversation-members) | Gets the members of the specified conversation. | -| [Get Conversation Paged Members](#get-conversation-paged-members) | Gets the members of the specified conversation one page at a time. | -| [Get Activity Members](#get-activity-members) | Gets the members of the specified activity within the specified conversation. | -| [Update Activity](#update-activity) | Updates an existing activity. | -| [Delete Activity](#delete-activity) | Deletes an existing activity. | -| [Delete Conversation Member](#delete-conversation-member) | Removes a member from a conversation. | -| [Send Conversation History](#send-conversation-history) | Uploads a transcript of past activities to the conversation. | -| [Upload Attachment to Channel](#upload-attachment-to-channel) | Uploads an attachment directly into a channel's blob storage. | - -### Create Conversation - -Creates a new conversation. - -```http -POST /v3/conversations -``` - -| | | -|----|----| -| **Request body** | A [ConversationParameters](#conversationparameters-object) object | -| **Returns** | A [ConversationResourceResponse](#conversationresourceresponse-object) object | - -### Send to Conversation - -Sends an activity (message) to the specified conversation. The activity will be appended to the end of the conversation according to the timestamp or semantics of the channel. To reply to a specific message within the conversation, use [Reply to Activity](#reply-to-activity) instead. - -```http -POST /v3/conversations/{conversationId}/activities -``` - -| | | -|----|----| -| **Request body** | An [Activity](#activity-object) object | -| **Returns** | A [ResourceResponse](#resourceresponse-object) object | - -### Reply to Activity - -Sends an activity (message) to the specified conversation, as a reply to the specified activity. The activity will be added as a reply to another activity, if the channel supports it. If the channel does not support nested replies, then this operation behaves like [Send to Conversation](#send-to-conversation). - -```http -POST /v3/conversations/{conversationId}/activities/{activityId} -``` - -| | | -|----|----| -| **Request body** | An [Activity](#activity-object) object | -| **Returns** | A [ResourceResponse](#resourceresponse-object) object | - -### Get Conversations - -Gets a list of conversations the bot has participated in. - -```http -GET /v3/conversations?continuationToken={continuationToken} -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | A [ConversationsResult](#conversationsresult-object) object | - -### Get Conversation Members - -Gets the members of the specified conversation. - -```http -GET /v3/conversations/{conversationId}/members -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | An array of [ChannelAccount](#channelaccount-object) objects | - -### Get Conversation Paged Members - -Gets the members of the specified conversation one page at a time. - -```http -GET /v3/conversations/{conversationId}/pagedmembers?pageSize={pageSize}&continuationToken={continuationToken} -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | A [PagedMembersResult](#pagedmembersresult-object) object | - -### Get Activity Members - -Gets the members of the specified activity within the specified conversation. - -```http -GET /v3/conversations/{conversationId}/activities/{activityId}/members -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | An array of [ChannelAccount](#channelaccount-object) objects | - -### Update Activity - -Some channels allow you to edit an existing activity to reflect the new state of a bot conversation. For example, you might remove buttons from a message in the conversation after the user has clicked one of the buttons. If successful, this operation updates the specified activity within the specified conversation. - -```http -PUT /v3/conversations/{conversationId}/activities/{activityId} -``` - -| | | -|----|----| -| **Request body** | An [Activity](#activity-object) object | -| **Returns** | A [ResourceResponse](#resourceresponse-object) object | - -### Delete Activity - -Some channels allow you to delete an existing activity. If successful, this operation removes the specified activity from the specified conversation. - -```http -DELETE /v3/conversations/{conversationId}/activities/{activityId} -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | An HTTP Status code that indicates the outcome of the operation. Nothing is specified in the body of the response. | - -### Delete Conversation Member - -Removes a member from a conversation. If that member was the last member of the conversation, the conversation will also be deleted. - -```http -DELETE /v3/conversations/{conversationId}/members/{memberId} -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | An HTTP Status code that indicates the outcome of the operation. Nothing is specified in the body of the response. | - -### Send Conversation History - -Uploads a transcript of past activities to the conversation so that the client can render them. - -```http -POST /v3/conversations/{conversationId}/activities/history -``` - -| | | -|----|----| -| **Request body** | A [Transcript](#transcript-object) object. | -| **Returns** | A [ResourceResponse](#resourceresponse-object) object. | - -### Upload Attachment to Channel - -Uploads an attachment for the specified conversation directly into a channel's blob storage. This enables you to store data in a compliant store. - -```http -POST /v3/conversations/{conversationId}/attachments -``` - -| | | -|----|----| -| **Request body** | An [AttachmentData](#attachmentdata-object) object. | -| **Returns** | A [ResourceResponse](#resourceresponse-object) object. The **id** property specifies the attachment ID that can be used with the [Get Attachment Info](#get-attachment-info) operation and the [Get Attachment](#get-attachment) operation. | - -## Attachment operations - -Use these operations to retrieve information about an attachment as well the binary data for the file itself. - -| Operation | Description | -|----|----| -| [Get Attachment Info](#get-attachment-info) | Gets information about the specified attachment, including file name, file type, and the available views (e.g. original or thumbnail). | -| [Get Attachment](#get-attachment) | Gets the specified view of the specified attachment as binary content. | - -### Get Attachment Info - -Gets information about the specified attachment, including file name, type, and the available views (e.g. original or thumbnail). - -```http -GET /v3/attachments/{attachmentId} -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | An [AttachmentInfo](#attachmentinfo-object) object | - -### Get Attachment - -Gets the specified view of the specified attachment as binary content. - -```http -GET /v3/attachments/{attachmentId}/views/{viewId} -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | Binary content that represents the specified view of the specified attachment | - -## State operations (deprecated) - -The Microsoft Bot Framework State service is retired as of March 30, 2018. Previously, bots built on the Azure Bot Service or the Bot Builder SDK had a default connection to this service hosted by Microsoft to store bot state data. Bots will need to be updated to use their own state storage. - -| Operation | Description | -|----|----| -| `Set User Data` | Stores state data for a specific user on a channel. | -| `Set Conversation Data` | Stores state data for a specific conversation on a channel. | -| `Set Private Conversation Data` | Stores state data for a specific user within the context of a specific conversation on a channel. | -| `Get User Data` | Retrieves state data that has previously been stored for a specific user across all conversations on a channel. | -| `Get Conversation Data` | Retrieves state data that has previously been stored for a specific conversation on a channel. | -| `Get Private Conversation Data` | Retrieves state data that has previously been stored for a specific user within the context of a specific conversation on a channel. | -| `Delete State For User` | Deletes state data that has previously been stored for a user. | - -## Schema - -The Bot Framework schema defines the objects and their properties that your bot can use to communicate with a user. - -| Object | Description | -| ---- | ---- | -| [Activity object](#activity-object) | Defines a message that is exchanged between bot and user. | -| [AnimationCard object](#animationcard-object) | Defines a card that can play animated GIFs or short videos. | -| [Attachment object](#attachment-object) | Defines additional information to include in the message. An attachment may be a media file (e.g. audio, video, image, file) or a rich card. | -| [AttachmentData object](#attachmentdata-object) | Describes an attachment data. | -| [AttachmentInfo object](#attachmentinfo-object) | Describes an attachment. | -| [AttachmentView object](#attachmentview-object) | Defines a attachment view. | -| [AudioCard object](#audiocard-object) | Defines a card that can play an audio file. | -| [CardAction object](#cardaction-object) | Defines an action to perform. | -| [CardImage object](#cardimage-object) | Defines an image to display on a card. | -| [ChannelAccount object](#channelaccount-object) | Defines a bot or user account on the channel. | -| [ConversationAccount object](#conversationaccount-object) | Defines a conversation in a channel. | -| [ConversationMembers object](#conversationmembers-object) | Defines the members of a conversation. | -| [ConversationParameters object](#conversationparameters-object) | Define parameters for creating a new conversation | -| [ConversationReference object](#conversationreference-object) | Defines a particular point in a conversation. | -| [ConversationResourceResponse object](#conversationresourceresponse-object) | Defines a response to [Create Conversation](#create-conversation). | -| [ConversationsResult object](#conversationsresult-object) | Defines the result of a call to [Get Conversations](#get-conversations). | -| [Entity object](#entity-object) | Defines an entity object. | -| [Error object](#error-object) | Defines an error. | -| [ErrorResponse object](#errorresponse-object) | Defines an HTTP API response. | -| [Fact object](#fact-object) | Defines a key-value pair that contains a fact. | -| [GeoCoordinates object](#geocoordinates-object) | Defines a geographical location using World Geodetic System (WSG84) coordinates. | -| [HeroCard object](#herocard-object) | Defines a card with a large image, title, text, and action buttons. | -| [InnerHttpError object](#innerhttperror-object) | Object representing an inner HTTP error. | -| [MediaEventValue object](#mediaeventvalue-object) | Supplementary parameter for media events. | -| [MediaUrl object](#mediaurl-object) | Defines the URL to a media file's source. | -| [Mention object](#mention-object) | Defines a user or bot that was mentioned in the conversation. | -| [MessageReaction object](#messagereaction-object) | Defines a reaction to a message. | -| [PagedMembersResult object](#pagedmembersresult-object) | Page of members returned by [Get Conversation Paged Members](#get-conversation-paged-members). | -| [Place object](#place-object) | Defines a place that was mentioned in the conversation. | -| [ReceiptCard object](#receiptcard-object) | Defines a card that contains a receipt for a purchase. | -| [ReceiptItem object](#receiptitem-object) | Defines a line item within a receipt. | -| [ResourceResponse object](#resourceresponse-object) | Defines a resource. | -| [SemanticAction object](#semanticaction-object) | Defines a reference to a programmatic action. | -| [SignInCard object](#signincard-object) | Defines a card that lets a user sign in to a service. | -| [SuggestedActions object](#suggestedactions-object) | Defines the options from which a user can choose. | -| [TextHighlight object](#texthighlight-object) | Refers to a substring of content within another field. | -| [ThumbnailCard object](#thumbnailcard-object) | Defines a card with a thumbnail image, title, text, and action buttons. | -| [ThumbnailUrl object](#thumbnailurl-object) | Defines the URL to an image's source. | -| [Transcript object](#transcript-object) | A collection of activities to be uploaded using [Send Conversation History](#send-conversation-history). | -| [VideoCard object](#videocard-object) | Defines a card that can play videos. | - -### Activity object - -Defines a message that is exchanged between bot and user. - -| Property | Type | Description | -|----|----|----| -| **action** | string | The action to apply or that was applied. Use the **type** property to determine context for the action. For example, if **type** is **contactRelationUpdate**, the value of the **action** property would be **add** if the user added your bot to their contacts list, or **remove** if they removed your bot from their contacts list. | -| **attachmentLayout** | string | Layout of the rich card **attachments** that the message includes. One of these values: **carousel**, **list**. For more information about rich card attachments, see [Add rich card attachments to messages](bot-framework-rest-connector-add-rich-cards.md). | -| **attachments** | [Attachment](#attachment-object)[] | Array of **Attachment** objects that defines additional information to include in the message. Each attachment may be either a file (e.g. audio, video, image) or a rich card. | -| **callerId** | string | A string containing an IRI identifying the caller of a bot. This field is not intended to be transmitted over the wire, but is instead populated by bots and clients based on cryptographically verifiable data that asserts the identity of the callers (e.g. tokens). | -| **channelData** | object | An object that contains channel-specific content. Some channels provide features that require additional information that cannot be represented using the attachment schema. For those cases, set this property to the channel-specific content as defined in the channel's documentation. For more information, see [Implement channel-specific functionality](bot-framework-rest-connector-channeldata.md). | -| **channelId** | string | An ID that uniquely identifies the channel. Set by the channel. | -| **code** | string | Code indicating why the conversation has ended. | -| **conversation** | [ConversationAccount](#conversationaccount-object) | A **ConversationAccount** object that defines the conversation to which the activity belongs. | -| **deliveryMode** | string | A delivery hint to signal to the recipient alternate delivery paths for the activity. One of these values: **normal**, **notification**. | -| **entities** | object[] | Array of objects that represents the entities that were mentioned in the message. Objects in this array may be any [Schema.org](http://schema.org/) object. For example, the array may include [Mention](#mention-object) objects that identify someone who was mentioned in the conversation and [Place](#place-object) objects that identify a place that was mentioned in the conversation. | -| **expiration** | string | The time at which the activity should be considered to be "expired" and should not be presented to the recipient. | -| **from** | [ChannelAccount](#channelaccount-object) | A **ChannelAccount** object that specifies the sender of the message. | -| **historyDisclosed** | boolean | Flag that indicates whether or not history is disclosed. Default value is **false**. | -| **id** | string | ID that uniquely identifies the activity on the channel. | -| **importance** | string | Defines the importance of an Activity. One of these values: **low**, **normal**, **high**. | -| **inputHint** | string | Value that indicates whether your bot is accepting, expecting, or ignoring user input after the message is delivered to the client. One of these values: **acceptingInput**, **expectingInput**, **ignoringInput**. | -| **label** | string | A descriptive label for the activity. | -| **listenFor** | string[] | List of phrases and references that speech and language priming systems should listen for. | -| **locale** | string | Locale of the language that should be used to display text within the message, in the format `-`. The channel uses this property to indicate the user's language, so that your bot may specify display strings in that language. Default value is **en-US**. | -| **localTimestamp** | string | Date and time that the message was sent in the local time zone, expressed in [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601) format. | -| **localTimezone** | string | Contains the name of the local timezone of the message, expressed in IANA Time Zone database format. For example, America/Los_Angeles. | -| **membersAdded** | [ChannelAccount](#channelaccount-object)[] | Array of **ChannelAccount** objects that represents the list of users that joined the conversation. Present only if activity **type** is "conversationUpdate" and users joined the conversation. | -| **membersRemoved** | [ChannelAccount](#channelaccount-object)[] | Array of **ChannelAccount** objects that represents the list of users that left the conversation. Present only if activity **type** is "conversationUpdate" and users left the conversation. | -| **name** | string | Name of the operation to invoke or the name of the event. | -| **reactionsAdded** | [MessageReaction](#messagereaction-object)[] | The collection of reactions added to the conversation. | -| **reactionsRemoved** | [MessageReaction](#messagereaction-object)[] | The collection of reactions removed from the conversation. | -| **recipient** | [ChannelAccount](#channelaccount-object) | A **ChannelAccount** object that specifies the recipient of the message. | -| **relatesTo** | [ConversationReference](#conversationreference-object) | A **ConversationReference** object that defines a particular point in a conversation. | -| **replyToId** | string | The ID of the message to which this message replies. To reply to a message that the user sent, set this property to the ID of the user's message. Not all channels support threaded replies. In these cases, the channel will ignore this property and use time ordered semantics (timestamp) to append the message to the conversation. | -| **semanticAction** |[SemanticAction](#semanticaction-object) | A **SemanticAction** object that represents a reference to a programmatic action. | -| **serviceUrl** | string | URL that specifies the channel's service endpoint. Set by the channel. | -| **speak** | string | Text to be spoken by your bot on a speech-enabled channel. To control various characteristics of your bot's speech such as voice, rate, volume, pronunciation, and pitch, specify this property in [Speech Synthesis Markup Language (SSML)](https://msdn.microsoft.com/library/hh378377(v=office.14).aspx) format. | -| **suggestedActions** | [SuggestedActions](#suggestedactions-object) | A **SuggestedActions** object that defines the options from which the user can choose. | -| **summary** | string | Summary of the information that the message contains. For example, for a message that is sent on an email channel, this property may specify the first 50 characters of the email message. | -| **text** | string | Text of the message that is sent from user to bot or bot to user. See the channel's documentation for limits imposed upon the contents of this property. | -| **textFormat** | string | Format of the message's **text**. One of these values: **markdown**, **plain**, **xml**. For details about text format, see [Create messages](bot-framework-rest-connector-create-messages.md). | -| **textHighlights** | [TextHighlight](#texthighlight-object)[] | The collection of text fragments to highlight when the activity contains a **replyToId** value. | -| **timestamp** | string | Date and time that the message was sent in the UTC time zone, expressed in [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601) format. | -| **topicName** | string | Topic of the conversation to which the activity belongs. | -| **type** | string | Type of activity. One of these values: **message**, **contactRelationUpdate**, **conversationUpdate**, **typing**, **endOfConversation**, **event**, **invoke**, **deleteUserData**, **messageUpdate**, **messageDelete**, **installationUpdate**, **messageReaction**, **suggestion**, **trace**, **handoff**. For details about activity types, see [Activities overview](https://aka.ms/botSpecs-activitySchema). | -| **value** | object | Open-ended value. | -| **valueType** | string | The type of the activity's value object. | - -[Back to Schema table](#schema) - -### AnimationCard object - -Defines a card that can play animated GIFs or short videos. - -| Property | Type | Description | -|----|----|----| -| **aspect** | boolean | Aspect ratio of thumbnail/media placeholder. Allowed values are "16:9" and "4:3". | -| **autoloop** | boolean | Flag that indicates whether to replay the list of animated GIFs when the last one ends. Set this property to **true** to automatically replay the animation; otherwise, **false**. The default value is **true**. | -| **autostart** | boolean | Flag that indicates whether to automatically play the animation when the card is displayed. Set this property to **true** to automatically play the animation; otherwise, **false**. The default value is **true**. | -| **buttons** | [CardAction](#cardaction-object)[] | Array of **CardAction** objects that enable the user to perform one or more actions. The channel determines the number of buttons that you may specify. | -| **duration** | string | The length of the media content, in [ISO 8601 duration format](https://www.iso.org/iso-8601-date-and-time-format.html). | -| **image** | [ThumbnailUrl](#thumbnailurl-object) | A **ThumbnailUrl** object that specifies the image to display on the card. | -| **media** | [MediaUrl](#mediaurl-object)[] | Array of **MediaUrl** objects. When this field contains more than one URL, each URL is an alternative format of the same content.| -| **shareable** | boolean | Flag that indicates whether the animation may be shared with others. Set this property to **true** if the animation may be shared; otherwise, **false**. The default value is **true**. | -| **subtitle** | string | Subtitle to display under the card's title. | -| **text** | string | Description or prompt to display under the card's title or subtitle. | -| **title** | string | Title of the card. | -| **value** | object | Supplementary parameter for this card. | - -[Back to Schema table](#schema) - -### Attachment object - -Defines additional information to include in the message. An attachment may be a file (such as an image, audio, or video) or a rich card. - -| Property | Type | Description | -|----|----|----| -| **content** | object | The content of the attachment. If the attachment is a rich card, set this property to the rich card object. This property and the **contentUrl** property are mutually exclusive. | -| **contentType** | string | The media type of the content in the attachment. For media files, set this property to known media types such as **image/png**, **audio/wav**, and **video/mp4**. For rich cards, set this property to one of these vendor-specific types:
  • **application/vnd.microsoft.card.adaptive**: A rich card that can contain any combination of text, speech, images, buttons, and input fields. Set the **content** property to an [AdaptiveCard](https://adaptivecards.io/explorer/AdaptiveCard.html) object.
  • **application/vnd.microsoft.card.animation**: A rich card that plays animation. Set the **content** property to an [AnimationCard](#animationcard-object) object.
  • **application/vnd.microsoft.card.audio**: A rich card that plays audio files. Set the **content** property to an [AudioCard](#audiocard-object) object.
  • **application/vnd.microsoft.card.hero**: A Hero card. Set the **content** property to a [HeroCard](#herocard-object) object.
  • **application/vnd.microsoft.card.receipt**: A Receipt card. Set the **content** property to a [ReceiptCard](#receiptcard-object) object.
  • **application/vnd.microsoft.card.signin**: A user Sign In card. Set the **content** property to a [SignInCard](#signincard-object) object.
  • **application/vnd.microsoft.card.thumbnail**: A Thumbnail card. Set the **content** property to a [ThumbnailCard](#thumbnailcard-object) object.
  • **application/vnd.microsoft.card.video**: A rich card that plays videos. Set the **content** property to a [VideoCard](#videocard-object) object.
| -| **contentUrl** | string | URL for the content of the attachment. For example, if the attachment is an image, you can set **contentUrl** to the URL that represents the location of the image. Supported protocols are: HTTP, HTTPS, File, and Data. | -| **name** | string | Name of the attachment. | -| **thumbnailUrl** | string | URL to a thumbnail image that the channel can use if it supports using an alternative, smaller form of **content** or **contentUrl**. For example, if you set **contentType** to **application/word** and set **contentUrl** to the location of the Word document, you might include a thumbnail image that represents the document. The channel could display the thumbnail image instead of the document. When the user clicks the image, the channel would open the document. | - -[Back to Schema table](#schema) - -### AttachmentData object - -Describes an attachment's data. - -| Property | Type | Description | -|----|----|----| -| **name** | string | Name of the attachment. | -| **originalBase64** | string | Attachment content. | -| **thumbnailBase64** | string | Attachment thumbnail content. | -| **type** | string | Content type of the attachment. | - -[Back to Schema table](#schema) - -### AttachmentInfo object - -Metadata for an attachment. - -| Property | Type | Description | -|----|----|----| -| **name** | string | Name of the attachment. | -| **type** | string | Content type of the attachment. | -| **views** | [AttachmentView](#attachmentview-object)[] | Array of **AttachmentView** objects that represent the available views for the attachment. | - -[Back to Schema table](#schema) - -### AttachmentView object - -Defines a attachment view. - -| Property | Type | Description | -|----|----|----| -| **size** | number | Size of the file. | -| **viewId** | string | View ID. | - -[Back to Schema table](#schema) - -### AudioCard object - -Defines a card that can play an audio file. - -| Property | Type | Description | -|----|----|----| -| **aspect** | string | Aspect ratio of the thumbnail that is specified in the **image** property. Valid values are **16:9** and **4:3**. | -| **autoloop** | boolean | Flag that indicates whether to replay the list of audio files when the last one ends. Set this property to **true** to automatically replay the audio files; otherwise, **false**. The default value is **true**. | -| **autostart** | boolean | Flag that indicates whether to automatically play the audio when the card is displayed. Set this property to **true** to automatically play the audio; otherwise, **false**. The default value is **true**. | -| **buttons** | [CardAction](#cardaction-object)[] | Array of **CardAction** objects that enable the user to perform one or more actions. The channel determines the number of buttons that you may specify. | -| **duration** | string | The length of the media content, in [ISO 8601 duration format](https://www.iso.org/iso-8601-date-and-time-format.html). | -| **image** | [ThumbnailUrl](#thumbnailurl-object) | A **ThumbnailUrl** object that specifies the image to display on the card. | -| **media** | [MediaUrl](#mediaurl-object)[] | Array of **MediaUrl** objects. When this field contains more than one URL, each URL is an alternative format of the same content. | -| **shareable** | boolean | Flag that indicates whether the audio files may be shared with others. Set this property to **true** if the audio may be shared; otherwise, **false**. The default value is **true**. | -| **subtitle** | string | Subtitle to display under the card's title. | -| **text** | string | Description or prompt to display under the card's title or subtitle. | -| **title** | string | Title of the card. | -| **value** | object | Supplementary parameter for this card. | - -[Back to Schema table](#schema) - -### CardAction object - -Defines a clickable action with a button. - -| Property | Type | Description | -|----|----|----| -| **channelData** | string | Channel-specific data associated with this action. | -| **displayText** | string | Text to display in the chat feed if the button is clicked. | -| **image** | string | Image URL which will appear on the button, next to the text label. | -| **text** | string | Text for the action. | -| **title** | string | Text description which appears on the button. | -| **type** | string | Type of action to perform. For a list of valid values, see [Add rich card attachments to messages](bot-framework-rest-connector-add-rich-cards.md). | -| **value** | object | Supplementary parameter for the action. The behavior of this property will vary according to the action **type**. For more information, see [Add rich card attachments to messages](bot-framework-rest-connector-add-rich-cards.md). | - -[Back to Schema table](#schema) - -### CardImage object - -Defines an image to display on a card. - -| Property | Type | Description | -|----|----|----| -| **alt** | string | Description of the image. You should include the description to support accessibility. | -| **tap** | [CardAction](#cardaction-object) | A **CardAction** object that specifies the action to perform if the user taps or clicks the image. | -| **url** | string | URL to the source of the image or the base64 binary of the image (for example, `data:image/png;base64,iVBORw0KGgo...`). | - -[Back to Schema table](#schema) - -### ChannelAccount object - -Defines a bot or user account on the channel. - -| Property | Type | Description | -|----|----|----| -| **aadObjectId** | string | This account's object ID within Azure Active Directory. | -| **id** | string | Unique ID for the user or bot on this channel. | -| **name** | string | Display-friendly name of the bot or user. | -| **role** | string | Role of the entity behind the account. Either **user** or **bot**. | - -[Back to Schema table](#schema) - -### ConversationAccount object - -Defines a conversation in a channel. - -| Property | Type | Description | -|----|----|----| -| **aadObjectId** | string | This account's object ID within Azure Active Directory (AAD). | -| **conversationType** | string | Indicates the type of the conversation in channels that distinguish between conversation types (e.g. group, personal). | -| **id** | string | The ID that identifies the conversation. The ID is unique per channel. If the channel starts the conversation, it sets this ID; otherwise, the bot sets this property to the ID that it gets back in the response when it starts the conversation (see [Create Conversation](#create-conversation)). | -| **isGroup** | boolean | Flag to indicate whether the conversation contains more than two participants at the time the activity was generated. Set to **true** if this is a group conversation; otherwise, **false**. The default is **false**. | -| **name** | string | A display name that can be used to identify the conversation. | -| **role** | string | Role of the entity behind the account. Either **user** or **bot**. | -| **tenantId** | string | This conversation's tenant ID. | - -[Back to Schema table](#schema) - -### ConversationMembers object - -Defines the members of a conversation. - -| Property | Type | Description | -|----|----|----| -| **id** | string | The conversation ID. | -| **members** | [ChannelAccount](#channelaccount-object)[] | List of members in this conversation. | - -[Back to Schema table](#schema) - -### ConversationParameters object - -Defines parameters for creating a new conversation. - -| Property | Type | Description | -|----|----|----| -| **activity** | [Activity](#activity-object) | The initial message to send to the conversation when it is created. | -| **bot** | [ChannelAccount](#channelaccount-object) | Channel account information needed to route a message to the bot. | -| **channelData** | object | Channel-specific payload for creating the conversation. | -| **isGroup** | boolean | Indicates whether this is a group conversation. | -| **members** | [ChannelAccount](#channelaccount-object)[] | Channel account information needed to route a message to each user. | -| **tenantId** | string | The tenant ID in which the conversation should be created. | -| **topicName** | string | Topic of the conversation. This property is only used if a channel supports it. | - -[Back to Schema table](#schema) - -### ConversationReference object - -Defines a particular point in a conversation. - -| Property | Type | Description | -|----|----|----| -| **activityId** | string | ID that uniquely identifies the activity that this object references. | -| **bot** | [ChannelAccount](#channelaccount-object) | A **ChannelAccount** object that identifies the bot in the conversation that this object references. | -| **channelId** | string | An ID that uniquely identifies the channel in the conversation that this object references. | -| **conversation** | [ConversationAccount](#conversationaccount-object) | A **ConversationAccount** object that defines the conversation that this object references. | -| **serviceUrl** | string | URL that specifies the channel's service endpoint in the conversation that this object references. | -| **user** | [ChannelAccount](#channelaccount-object) | A **ChannelAccount** object that identifies the user in the conversation that this object references. | - -[Back to Schema table](#schema) - -### ConversationResourceResponse object - -Defines a response to [Create Conversation](#create-conversation). - -| Property | Type | Description | -|----|----|----| -| **activityId** | string | ID of the activity, if sent. | -| **id** | string | ID of the resource. | -| **serviceUrl** | string | Service endpoint where operations concerning the conversation may be performed. | - -[Back to Schema table](#schema) - -### ConversationsResult object - -Defines the result of [Get Conversations](#get-conversations). - -| Property | Type | Description | -|----|----|----| -| **conversations** | [ConversationMembers](#conversationmembers-object)[] | The members in each of the conversations. | -| **continuationToken** | string | The continuation token that can be used in subsequent calls to [Get Conversations](#get-conversations). | - -[Back to Schema table](#schema) - -### Entity object - -Metadata object pertaining to an activity. - -| Property | Type | Description | -|----|----|----| -| **type** | string | Type of this entity (RFC 3987 IRI). | - -[Back to Schema table](#schema) - -### Error object - -Object representing error information. - -| Property | Type | Description | -|----|----|----| -| **code** | string | Error code. | -| **innerHttpError** | [InnerHttpError](#innerhttperror-object) | Object representing the inner HTTP error. | -| **message** | string | A description of the error. | - -[Back to Schema table](#schema) - -### ErrorResponse object - -Defines an HTTP API response. - -| Property | Type | Description | -|----|----|----| -| **error** | [Error](#error-object) | An **Error** object that contains information about the error. | - -[Back to Schema table](#schema) - -### Fact object - -Defines a key-value pair that contains a fact. - -| Property | Type | Description | -|----|----|----| -| **key** | string | Name of the fact. For example, **Check-in**. The key is used as a label when displaying the fact's value. | -| **value** | string | Value of the fact. For example, **10 October 2016**. | - -[Back to Schema table](#schema) - -### GeoCoordinates object - -Defines a geographical location using World Geodetic System (WSG84) coordinates. - -| Property | Type | Description | -|----|----|----| -| **elevation** | number | Elevation of the location. | -| **latitude** | number | Latitude of the location. | -| **longitude** | number | Longitude of the location. | -| **name** | string | Name of the location. | -| **type** | string | The type of this object. Always set to **GeoCoordinates**. | - -[Back to Schema table](#schema) - -### HeroCard object - -Defines a card with a large image, title, text, and action buttons. - -| Property | Type | Description | -|----|----|----| -| **buttons** | [CardAction](#cardaction-object)[] | Array of **CardAction** objects that enable the user to perform one or more actions. The channel determines the number of buttons that you may specify. | -| **images** | [CardImage](#cardimage-object)[] | Array of **CardImage** objects that specifies the image to display on the card. A Hero card contains only one image. | -| **subtitle** | string | Subtitle to display under the card's title. | -| **tap** | [CardAction](#cardaction-object) | A **CardAction** object that specifies the action to perform if the user taps or clicks the card. This can be the same action as one of the buttons or a different action. | -| **text** | string | Description or prompt to display under the card's title or subtitle. | -| **title** | string | Title of the card. | - -[Back to Schema table](#schema) - -### InnerHttpError object - -Object representing an inner HTTP error. - -| Property | Type | Description | -|----|----|----| -| **statusCode** | number | HTTP status code from the failed request. | -| **body** | object | Body from the failed request. | - -[Back to Schema table](#schema) - -### MediaEventValue object - -Supplementary parameter for media events. - -| Property | Type | Description | -|----|----|----| -| **cardValue** | object | Callback parameter specified in the **value** field of the media card that originated this event. | - -[Back to Schema table](#schema) - -### MediaUrl object - -Defines the URL to a media file's source. - -| Property | Type | Description | -|----|----|----| -| **profile** | string | Hint that describes the media's content. | -| **url** | string | URL to the source of the media file. | - -[Back to Schema table](#schema) - -### Mention object - -Defines a user or bot that was mentioned in the conversation. - -| Property | Type | Description | -|----|----|----| -| **mentioned** | [ChannelAccount](#channelaccount-object) | A **ChannelAccount** object that specifies the user or the bot that was mentioned. Note that some channels such as Slack assign names per conversation, so it is possible that your bot's mentioned name (in the message's **recipient** property) may be different from the handle that you specified when you [registered](../bot-service-quickstart-registration.md) your bot. However, the account IDs for both would be the same. | -| **text** | string | The user or bot as mentioned in the conversation. For example, if the message is "@ColorBot pick me a new color," this property would be set to **@ColorBot**. Not all channels set this property. | -| **type** | string | This object's type. Always set to **Mention**. | - -[Back to Schema table](#schema) - -### MessageReaction object - -Defines a reaction to a message. - -| Property | Type | Description | -|----|----|----| -| **type** | string | Type of reaction. Either **like** or **plusOne**. | - -[Back to Schema table](#schema) - -### PagedMembersResult object - -Page of members returned by [Get Conversation Paged Members](#get-conversation-paged-members). - -| Property | Type | Description | -|----|----|----| -| **continuationToken** | string | The continuation token that can be used in subsequent calls to [Get Conversation Paged Members](#get-conversation-paged-members). | -| **members** | [ChannelAccount](#channelaccount-object)[] | An array of conversation members. | - -[Back to Schema table](#schema) - -### Place object - -Defines a place that was mentioned in the conversation. - -| Property | Type | Description | -|----|----|----| -| **address** | object | Address of a place. This property can be a **string** or a complex object of type **PostalAddress**. | -| **geo** | [GeoCoordinates](#geocoordinates-object) | A **GeoCoordinates** object that specifies the geographical coordinates of the place. | -| **hasMap** | object | Map to the place. This property can be a **string** (URL) or a complex object of type **Map**. | -| **name** | string | Name of the place. | -| **type** | string | This object's type. Always set to **Place**. | - -[Back to Schema table](#schema) - -### ReceiptCard object - -Defines a card that contains a receipt for a purchase. - -| Property | Type | Description | -|----|----|----| -| **buttons** | [CardAction](#cardaction-object)[] | Array of **CardAction** objects that enable the user to perform one or more actions. The channel determines the number of buttons that you may specify. | -| **facts** | [Fact](#fact-object)[] | Array of **Fact** objects that specify information about the purchase. For example, the list of facts for a hotel stay receipt might include the check-in date and check-out date. The channel determines the number of facts that you may specify. | -| **items** | [ReceiptItem](#receiptitem-object)[] | Array of **ReceiptItem** objects that specify the purchased items | -| **tap** | [CardAction](#cardaction-object) | A **CardAction** object that specifies the action to perform if the user taps or clicks the card. This can be the same action as one of the buttons or a different action. | -| **tax** | string | A currency-formatted string that specifies the amount of tax applied to the purchase. | -| **title** | string | Title displayed at the top of the receipt. | -| **total** | string | A currency-formatted string that specifies the total purchase price, including all applicable taxes. | -| **vat** | string | A currency-formatted string that specifies the amount of value-added tax (VAT) applied to the purchase price. | - -[Back to Schema table](#schema) - -### ReceiptItem object - -Defines a line item within a receipt. - -| Property | Type | Description | -|----|----|----| -| **image** | [CardImage](#cardimage-object) | A **CardImage** object that specifies thumbnail image to display next to the line item. | -| **price** | string | A currency-formatted string that specifies the total price of all units purchased. | -| **quantity** | string | A numeric string that specifies the number of units purchased. | -| **subtitle** | string | Subtitle to be displayed under the line item’s title. | -| **tap** | [CardAction](#cardaction-object) | A **CardAction** object that specifies the action to perform if the user taps or clicks the line item. | -| **text** | string | Description of the line item. | -| **title** | string | Title of the line item. | - -[Back to Schema table](#schema) - -### ResourceResponse object - -Defines a response that contains a resource ID. - -| Property | Type | Description | -|----|----|----| -| **id** | string | ID that uniquely identifies the resource. | - -[Back to Schema table](#schema) - -### SemanticAction object - -Defines a reference to a programmatic action. - -| Property | Type | Description | -|----|----|----| -| **entities** | object | An object where the value of each property is an [Entity](#entity-object) object. | -| **id** | string | ID of this action. | -| **state** | string | State of this action. Allowed values: **start**, **continue**, **done**. | - -[Back to Schema table](#schema) - -### SignInCard object - -Defines a card that lets a user sign in to a service. - -| Property | Type | Description | -|----|----|----| -| **buttons** | [CardAction](#cardaction-object)[] | Array of **CardAction** objects that enable the user to sign in to a service. The channel determines the number of buttons that you may specify. | -| **text** | string | Description or prompt to include on the sign in card. | - -[Back to Schema table](#schema) - -### SuggestedActions object - -Defines the options from which a user can choose. - -| Property | Type | Description | -|----|----|----| -| **actions** | [CardAction](#cardaction-object)[] | Array of **CardAction** objects that define the suggested actions. | -| **to** | string[] | Array of strings that contains the IDs of the recipients to whom the suggested actions should be displayed. | - -[Back to Schema table](#schema) - -### TextHighlight object - -Refers to a substring of content within another field. - -| Property | Type | Description | -|----|----|----| -| **occurrence** | number | Occurrence of the text field within the referenced text, if multiple exist. | -| **text** | string | Defines the snippet of text to highlight. | - -[Back to Schema table](#schema) - -### ThumbnailCard object - -Defines a card with a thumbnail image, title, text, and action buttons. - -| Property | Type | Description | -|----|----|----| -| **buttons** | [CardAction](#cardaction-object)[] | Array of **CardAction** objects that enable the user to perform one or more actions. The channel determines the number of buttons that you may specify. | -| **images** | [CardImage](#cardimage-object)[] | Array of **CardImage** objects that specify thumbnail images to display on the card. The channel determines the number of thumbnail images that you may specify. | -| **subtitle** | string | Subtitle to display under the card's title. | -| **tap** | [CardAction](#cardaction-object) | A **CardAction** object that specifies the action to perform if the user taps or clicks the card. This can be the same action as one of the buttons or a different action. | -| **text** | string | Description or prompt to display under the card's title or subtitle. | -| **title** | string | Title of the card. | - -[Back to Schema table](#schema) - -### ThumbnailUrl object - -Defines the URL to an image's source. - -| Property | Type | Description | -|----|----|----| -| **alt** | string | Description of the image. You should include the description to support accessibility. | -| **url** | string | URL to the source of the image or the base64 binary of the image (for example, `data:image/png;base64,iVBORw0KGgo...`). | - -[Back to Schema table](#schema) - -### Transcript object - -A collection of activities to be uploaded using [Send Conversation History](#send-conversation-history). - -| Property | Type | Description | -|----|----|----| -| **activities** | array | An array of [Activity](#activity-object) objects. They should each have a unique ID and timestamp. | - -[Back to Schema table](#schema) - -### VideoCard object - -Defines a card that can play videos. - -| Property | Type | Description | -|----|----|----| -| **aspect** | string | Aspect ratio of the video. Either **16:9** or **4:3**. | -| **autoloop** | boolean | Flag that indicates whether to replay the list of videos when the last one ends. Set this property to **true** to automatically replay the videos; otherwise, **false**. The default value is **true**. | -| **autostart** | boolean | Flag that indicates whether to automatically play the videos when the card is displayed. Set this property to **true** to automatically play the videos; otherwise, **false**. The default value is **true**. | -| **buttons** | [CardAction](#cardaction-object)[] | Array of **CardAction** objects that enable the user to perform one or more actions. The channel determines the number of buttons that you may specify. | -| **duration** | string | The length of the media content, in [ISO 8601 duration format](https://www.iso.org/iso-8601-date-and-time-format.html). | -| **image** | [ThumbnailUrl](#thumbnailurl-object) | A **ThumbnailUrl** object that specifies the image to display on the card. | -| **media** | [MediaUrl](#mediaurl-object)[] | Array of **MediaUrl**. When this field contains more than one URL, each URL is an alternative format of the same content. | -| **shareable** | boolean | Flag that indicates whether the videos may be shared with others. Set this property to **true** if the videos may be shared; otherwise, **false**. The default value is **true**. | -| **subtitle** | string | Subtitle to display under the card's title. | -| **text** | string | Description or prompt to display under the card's title or subtitle. | -| **title** | string | Title of the card. | -| **value** | object | Supplementary parameter for this card | - -[Back to Schema table](#schema) diff --git a/articles/rest-api/bot-framework-rest-connector-authentication.md b/articles/rest-api/bot-framework-rest-connector-authentication.md deleted file mode 100644 index 38fc0920b..000000000 --- a/articles/rest-api/bot-framework-rest-connector-authentication.md +++ /dev/null @@ -1,412 +0,0 @@ ---- -title: Authenticate requests - Bot Service -description: Learn how to authenticate API requests in the Bot Connector API and Bot State API. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Authentication - -Your bot communicates with the Bot Connector service using HTTP over a secured channel (SSL/TLS). -When your bot sends a request to the Connector service, it must include information that the Connector service can use to verify its identity. -Likewise, when the Connector service sends a request to your bot, it must include information that the bot can use to verify its identity. -This article describes the authentication technologies and requirements for the service-level authentication that takes place between a bot and the Bot Connector service. If you are writing your own authentication code, you must implement the security procedures described in this article to enable your bot to exchange messages with the Bot Connector service. - -> [!IMPORTANT] -> If you are writing your own authentication code, it is critical that you implement all security procedures correctly. -> By implementing all steps in this article, you can mitigate the risk of an attacker being able to read messages that -> are sent to your bot, send messages that impersonate your bot, and steal secret keys. - -If you are using the [Bot Framework SDK for .NET](../dotnet/bot-builder-dotnet-overview.md) or the [Bot Framework SDK for Node.js](../nodejs/index.md), you do not need to implement the security procedures described in this article, because the SDK automatically does it for you. Simply configure your project with the App ID and password that you obtained for your bot during [registration](../bot-service-quickstart-registration.md) and the SDK will handle the rest. - -> [!WARNING] -> In December 2016, v3.1 of the Bot Framework security protocol introduced changes to several values that are -> used during token generation and validation. In late fall of 2017, v3.2 of the Bot Framework security protocol was introduced -> which included changes to values that are used during token generation and validation. -> For more information, see [Security protocol changes](#security-protocol-changes). - -## Authentication technologies - -Four authentication technologies are used to establish trust between a bot and the Bot Connector: - -| Technology | Description | -|----|----| -| **SSL/TLS** | SSL/TLS is used for all service-to-service connections. `X.509v3` certificates are used to establish the identity of all HTTPS services. **Clients should always inspect service certificates to ensure they are trusted and valid.** (Client certificates are NOT used as part of this scheme.) | -| **OAuth 2.0** | OAuth 2.0 uses the Azure Active Directory (Azure AD) v2 account login service to generate a secure token that a bot can use to send messages. This token is a service-to-service token; no user login is required. | -| **JSON Web Token (JWT)** | JSON Web Tokens are used to encode tokens that are sent to and from the bot. **Clients should fully verify all JWT tokens that they receive**, according to the requirements outlined in this article. | -| **OpenID metadata** | The Bot Connector service publishes a list of valid tokens that it uses to sign its own JWT tokens to OpenID metadata at a well-known, static endpoint. | - -This article describes how to use these technologies via standard HTTPS and JSON. No special SDKs are required, although you may find that helpers for OpenID etc. are useful. - -## Authenticate requests from your bot to the Bot Connector service - -To communicate with the Bot Connector service, you must specify an access token in the `Authorization` header of each API request, using this format: - -```http -Authorization: Bearer ACCESS_TOKEN -``` - -This diagram shows the steps for bot-to-connector authentication: - -![Authenticate to the MSA login service and then to the bot](../media/connector/auth_bot_to_bot_connector.png) - -### Step 1: Request an access token from the Azure AD v2 account login service - -> [!IMPORTANT] -> If you have not already done so, you must [register your bot](../bot-service-quickstart-registration.md) with the Bot Framework to obtain its AppID and password. You need the bot's App ID and password to request an access token. - -To request an access token from the login service, issue the following request, replacing **MICROSOFT-APP-ID** and **MICROSOFT-APP-PASSWORD** with the bot's AppID and password that you obtained when you [registered](../bot-service-quickstart-registration.md) your bot with the Bot Framework. - -```http -POST https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token -Host: login.microsoftonline.com -Content-Type: application/x-www-form-urlencoded - -grant_type=client_credentials&client_id=MICROSOFT-APP-ID&client_secret=MICROSOFT-APP-PASSWORD&scope=https%3A%2F%2Fapi.botframework.com%2F.default -``` - -### Step 2: Obtain the JWT token from the the Azure AD v2 account login service response - -If your application is authorized by the login service, the JSON response body will specify your access token, its type, and its expiration (in seconds). - -When adding the token to the `Authorization` header of a request, you must use the exact value that is specified in this response (i.e., do not escape or encode the token value). The access token is valid until its expiration. To prevent token expiration from impacting your bot's performance, you may choose to cache and proactively refresh the token. - -This example shows a response from the the Azure AD v2 account login service: - -```http -HTTP/1.1 200 OK -... (other headers) -``` - -```json -{ - "token_type":"Bearer", - "expires_in":3600, - "ext_expires_in":3600, - "access_token":"eyJhbGciOiJIUzI1Ni..." -} -``` - -### Step 3: Specify the JWT token in the Authorization header of requests - -When you send an API request to the Bot Connector service, specify the access token in the `Authorization` header of the request using this format: - -```http -Authorization: Bearer ACCESS_TOKEN -``` - -All requests that you send to the Bot Connector service must include the access token in the `Authorization` header. -If the token is correctly formed, is not expired, and was generated by the the Azure AD v2 account login service, the Bot Connector service will authorize the request. Additional checks are performed to ensure that the token belongs to the bot that sent the request. - -The following example shows how to specify the access token in the `Authorization` header of the request. - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations/12345/activities -Authorization: Bearer eyJhbGciOiJIUzI1Ni... - -(JSON-serialized Activity message goes here) -``` - -> [!IMPORTANT] -> Only specify the JWT token in the `Authorization` header of requests you send to the Bot Connector service. -> Do NOT send the token over unsecured channels and do NOT include it in HTTP requests that you send to other services. -> The JWT token that you obtain from the the Azure AD v2 account login service is like a password and should be handled with -> great care. Anyone that possesses the token may use it to perform operations on behalf of your bot. - -#### Bot to Connector: example JWT components - -```json -header: -{ - typ: "JWT", - alg: "RS256", - x5t: "", - kid: "" -}, -payload: -{ - aud: "https://api.botframework.com", - iss: "https://sts.windows.net/d6d49420-f39b-4df7-a1dc-d59a935871db/", - nbf: 1481049243, - exp: 1481053143, - appid: "", - ... other fields follow -} -``` - -> [!NOTE] -> Actual fields may vary in practice. Create and validate all JWT tokens as specified above. - -## Authenticate requests from the Bot Connector service to your bot - -When the Bot Connector service sends a request to your bot, it specifies a signed JWT token in the `Authorization` header of the request. Your bot can authenticate calls from the Bot Connector service by verifying the authenticity of the signed JWT token. - -This diagram shows the steps for connector-to-bot authentication: - -![Authenticate calls from the Bot Connector to your bot](../media/connector/auth_bot_connector_to_bot.png) - -### Step 2: Get the OpenID metadata document - -The OpenID metadata document specifies the location of a second document that lists the Bot Connector service's valid signing keys. To get the OpenID metadata document, issue this request via HTTPS: - -```http -GET https://login.botframework.com/v1/.well-known/openidconfiguration -``` - -> [!TIP] -> This is a static URL that you can hardcode into your application. - -The following example shows an OpenID metadata document that is returned in response to the `GET` request. The `jwks_uri` property specifies the location of the document that contains the Bot Connector service's valid signing keys. - -```json -{ - "issuer": "https://api.botframework.com", - "authorization_endpoint": "https://invalid.botframework.com", - "jwks_uri": "https://login.botframework.com/v1/.well-known/keys", - "id_token_signing_alg_values_supported": [ - "RS256" - ], - "token_endpoint_auth_methods_supported": [ - "private_key_jwt" - ] -} -``` - -### Step 3: Get the list of valid signing keys - -To get the list of valid signing keys, issue a `GET` request via HTTPS to the URL specified by the `jwks_uri` property in the OpenID metadata document. For example: - -```http -GET https://login.botframework.com/v1/.well-known/keys -``` - -The response body specifies the document in the [JWK format](https://tools.ietf.org/html/rfc7517) but also includes an additional property for each key: `endorsements`. The list of keys is relatively stable and may be cached for long periods of time (by default, 5 days within the Bot Framework SDK). - -The `endorsements` property within each key contains one or more endorsement strings which you can use to verify that the channel ID specified in the `channelId` property within the [Activity][] object of the incoming request is authentic. The list of channel IDs that require endorsements is configurable within each bot. By default, it will be the list of all published channel IDs, although bot developers may override selected channel ID values either way. - -### Step 4: Verify the JWT token - -To verify the authenticity of the token that was sent by the Bot Connector service, you must extract the token from the `Authorization` header of the request, parse the token, verify its contents, and verify its signature. - -JWT parsing libraries are available for many platforms and most implement secure and reliable parsing for JWT tokens, although you must typically configure these libraries to require that certain characteristics of the token (its issuer, audience, etc.) contain correct values. -When parsing the token, you must configure the parsing library or write your own validation to ensure the token meets these requirements: - -1. The token was sent in the HTTP `Authorization` header with "Bearer" scheme. -2. The token is valid JSON that conforms to the [JWT standard](http://openid.net/specs/draft-jones-json-web-token-07.html). -3. The token contains an "issuer" claim with value of `https://api.botframework.com`. -4. The token contains an "audience" claim with a value equal to the bot's Microsoft App ID. -5. The token is within its validity period. Industry-standard clock-skew is 5 minutes. -6. The token has a valid cryptographic signature, with a key listed in the OpenID keys document that was retrieved in [Step 3](#connector-to-bot-step-3), using the signing algorithm that is specified in the `id_token_signing_alg_values_supported` property of the Open ID Metadata document that was retrieved in [Step 2](#openid-metadata-document). -7. The token contains a "serviceUrl" claim with value that matches the `servieUrl` property at the root of the [Activity][] object of the incoming request. - -If endorsement for a channel ID is required: - -- You should require that any `Activity` object sent to your bot with that channel ID is accompanied by a JWT token that is signed with an endorsement for that channel. -- If the endorsement is not present, your bot should reject the request by returning an **HTTP 403 (Forbidden)** status code. - -> [!IMPORTANT] -> All of these requirements are important, particularly requirements 4 and 6. -> Failure to implement ALL of these verification requirements will leave the bot open to attacks -> which could cause the bot to divulge its JWT token. - -Implementers should not expose a way to disable validation of the JWT token that is sent to the bot. - -#### Connector to Bot: example JWT components - -```json -header: -{ - typ: "JWT", - alg: "RS256", - x5t: "", - kid: "" -}, -payload: -{ - aud: "", - iss: "https://api.botframework.com", - nbf: 1481049243, - exp: 1481053143, - ... other fields follow -} -``` - -> [!NOTE] -> Actual fields may vary in practice. Create and validate all JWT tokens as specified above. - -## Authenticate requests from the Bot Framework Emulator to your bot - -> [!WARNING] -> In late fall of 2017, v3.2 of the Bot Framework security protocol was introduced. This new version includes a new "issuer" value within tokens that are exchanged between the Bot Framework Eumaltor and your bot. To prepare for this change, the below steps outline how to check for both the v3.1 and v3.2 issuer values. - -The [Bot Framework Emulator](../bot-service-debug-emulator.md) is a desktop tool that you can use to test the functionality of your bot. Although the Bot Framework Emulator uses the same [authentication technologies](#authentication-technologies) as described above, it is unable to impersonate the real Bot Connector service. -Instead, it uses the Microsoft App ID and Microsoft App Password that you specify when you connect the emulator to your bot to create tokens that are identical to those that the bot creates. -When the emulator sends a request to your bot, it specifies the JWT token in the `Authorization` header of the request -- in essence, using the bot's own credentials to authenticate the request. - -If you are implementing an authentication library and want to accept requests from the Bot Framework Emulator, you must add this additional verification path. The path is structurally similar to the [Connector -> Bot](#connector-to-bot) verification path, but it uses MSA’s OpenID document instead of the Bot Connector’s OpenID document. - -This diagram shows the steps for emulator-to-bot authentication: - -![Authenticate calls from the Bot Framework Emulator to your bot](../media/connector/auth_bot_framework_emulator_to_bot.png) - ---- -### Step 2: Get the MSA OpenID metadata document - -The OpenID metadata document specifies the location of a second document that lists the valid signing keys. To get the MSA OpenID metadata document, issue this request via HTTPS: - -```http -GET https://login.microsoftonline.com/botframework.com/v2.0/.well-known/openid-configuration -``` - -The following example shows an OpenID metadata document that is returned in response to the `GET` request. The `jwks_uri` property specifies the location of the document that contains the valid signing keys. - -```json -{ - "authorization_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/authorize", - "token_endpoint":"https://login.microsoftonline.com/common/oauth2/v2.0/token", - "token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt"], - "jwks_uri":"https://login.microsoftonline.com/common/discovery/v2.0/keys", - ... -} -``` - -### Step 3: Get the list of valid signing keys - -To get the list of valid signing keys, issue a `GET` request via HTTPS to the URL specified by the `jwks_uri` property in the OpenID metadata document. For example: - -```http -GET https://login.microsoftonline.com/common/discovery/v2.0/keys -Host: login.microsoftonline.com -``` - -The response body specifies the document in the [JWK format](https://tools.ietf.org/html/rfc7517). - -### Step 4: Verify the JWT token - -To verify the authenticity of the token that was sent by the emulator, you must extract the token from the `Authorization` header of the request, parse the token, verify its contents, and verify its signature. - -JWT parsing libraries are available for many platforms and most implement secure and reliable parsing for JWT tokens, although you must typically configure these libraries to require that certain characteristics of the token (its issuer, audience, etc.) contain correct values. -When parsing the token, you must configure the parsing library or write your own validation to ensure the token meets these requirements: - -1. The token was sent in the HTTP `Authorization` header with "Bearer" scheme. -2. The token is valid JSON that conforms to the [JWT standard](http://openid.net/specs/draft-jones-json-web-token-07.html). -3. The token contains an "issuer" claim with value of `https://sts.windows.net/d6d49420-f39b-4df7-a1dc-d59a935871db/` or `https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/`. (Checking for both issuer values will ensure you are checking for both the security protocol v3.1 and v3.2 issuer values) -4. The token contains an "audience" claim with a value equal to the bot's Microsoft App ID. -5. The token contains an "appid" claim with the value equal to the bot's Microsoft App ID. -6. The token is within its validity period. Industry-standard clock-skew is 5 minutes. -7. The token has a valid cryptographic signature with a key listed in the OpenID keys document that was retrieved in [Step 3](#emulator-to-bot-step-3). - -> [!NOTE] -> Requirement 5 is a specific to the emulator verification path. - -If the token does not meet all of these requirements, your bot should terminate the request by returning an **HTTP 403 (Forbidden)** status code. - -> [!IMPORTANT] -> All of these requirements are important, particularly requirements 4 and 7. -> Failure to implement ALL of these verification requirements will leave the bot open to attacks -> which could cause the bot to divulge its JWT token. - -#### Emulator to Bot: example JWT components - -```json -header: -{ - typ: "JWT", - alg: "RS256", - x5t: "", - kid: "" -}, -payload: -{ - aud: "", - iss: "https://sts.windows.net/d6d49420-f39b-4df7-a1dc-d59a935871db/", - nbf: 1481049243, - exp: 1481053143, - ... other fields follow -} -``` - -> [!NOTE] -> Actual fields may vary in practice. Create and validate all JWT tokens as specified above. - -## Security protocol changes - -> [!WARNING] -> Support for v3.0 of the security protocol was discontinued on **July 31, 2017**. -> If you have written your own authentication code (i.e., did not use the Bot Framework SDK to create your bot), -> you must upgrade to v3.1 of the security protocol by updating your application to use the v3.1 values that are listed below. - -### [Bot to Connector authentication](#bot-to-connector) - -#### OAuth login URL - -| Protocol version | Valid value | -|----|----| -| v3.1 & v3.2 | `https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token` | - -#### OAuth scope - -| Protocol version | Valid value | -|----|----| -| v3.1 & v3.2 | `https://api.botframework.com/.default` | - -### [Connector to Bot authentication](#connector-to-bot) - -#### OpenID metadata document - -| Protocol version | Valid value | -|----|----| -| v3.1 & v3.2 | `https://login.botframework.com/v1/.well-known/openidconfiguration` | - -#### JWT Issuer - -| Protocol version | Valid value | -|----|----| -| v3.1 & v3.2 | `https://api.botframework.com` | - -### [Emulator to Bot authentication](#emulator-to-bot) - -#### OAuth login URL - -| Protocol version | Valid value | -|----|----| -| v3.1 & v3.2 | `https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token` | - -#### OAuth scope - -| Protocol version | Valid value | -|----|----| -| v3.1 & v3.2 | Your bot’s Microsoft App ID + `/.default` | - -#### JWT Audience - -| Protocol version | Valid value | -|----|----| -| v3.1 & v3.2 | Your bot’s Microsoft App ID | - -#### JWT Issuer - -| Protocol version | Valid value | -|----|----| -| v3.1 | `https://sts.windows.net/d6d49420-f39b-4df7-a1dc-d59a935871db/` | -| v3.2 | `https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/` | - -#### OpenID metadata document - -| Protocol version | Valid value | -|----|----| -| v3.1 & v3.2 | `https://login.microsoftonline.com/botframework.com/v2.0/.well-known/openid-configuration` | - -## Additional resources - -- [Troubleshooting Bot Framework authentication](../bot-service-troubleshoot-authentication-problems.md) -- [Bot Framework Activity schema](https://aka.ms/botSpecs-activitySchema) -- [JSON Web Token (JWT) draft-jones-json-web-token-07](http://openid.net/specs/draft-jones-json-web-token-07.html) -- [JSON Web Signature (JWS) draft-jones-json-web-signature-04](https://tools.ietf.org/html/draft-jones-json-web-signature-04) -- [JSON Web Key (JWK) RFC 7517](https://tools.ietf.org/html/rfc7517) - -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object diff --git a/articles/rest-api/bot-framework-rest-connector-channeldata.md b/articles/rest-api/bot-framework-rest-connector-channeldata.md deleted file mode 100644 index 7014db0ce..000000000 --- a/articles/rest-api/bot-framework-rest-connector-channeldata.md +++ /dev/null @@ -1,282 +0,0 @@ ---- -title: Implement channel-specific functionality using REST API - Bot Service -description: Learn how to implement channel-specific functionality using the Bot Connector API. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Implement channel-specific functionality - -Some channels provide features that cannot be implemented by using only [message text and attachments](bot-framework-rest-connector-create-messages.md). To implement channel-specific functionality, you can pass native metadata to a channel in the [Activity[]] object's `channelData` property. For example, your bot can use the `channelData` property to instruct Telegram to send a sticker or to instruct Office365 to send an email. - -This article describes how to use a message activity's `channelData` property to implement this channel-specific functionality: - -| Channel | Functionality | -|----|----| -| Email | Send and receive an email that contains body, subject, and importance metadata | -| Slack | Send full fidelity Slack messages | -| Facebook | Send Facebook notifications natively | -| Telegram | Perform Telegram-specific actions, such as sharing a voice memo or a sticker | -| Kik | Send and receive native Kik messages | - -> [!NOTE] -> The value of an `Activity` object's `channelData` property is a JSON object. -> The structure of the JSON object will vary according to the channel and the functionality being implemented, as described below. - -## Create a custom Email message - -To create an email message, set the `Activity` object's `channelData` property to a JSON object that contains these properties: - -[!INCLUDE [Email channelData table](~/includes/snippet-channelData-email.md)] - -This snippet shows an example of the `channelData` property for a custom email message. - -```json -"channelData": -{ - "htmlBody": "This is more than awesome.", - "subject": "Super awesome message subject", - "importance": "high", - "ccRecipients": "Yasemin@adatum.com;Temel@adventure-works.com" -} -``` - -## Create a full-fidelity Slack message - -To create a full-fidelity Slack message, set the `Activity` object's `channelData` property to a JSON object that specifies -Slack messages, Slack attachments, and/or Slack buttons. - -> [!NOTE] -> To support buttons in Slack messages, you must enable **Interactive Messages** when you -> [connect your bot](../bot-service-manage-channels.md) to the Slack channel. - -This snippet shows an example of the `channelData` property for a custom Slack message. - -```json -"channelData": { - "text": "Now back in stock! :tada:", - "attachments": [ - { - "title": "The Further Adventures of Slackbot", - "author_name": "Stanford S. Strickland", - "author_icon": "https://api.slack.com/img/api/homepage_custom_integrations-2x.png", - "image_url": "http://i.imgur.com/OJkaVOI.jpg?1" - }, - { - "fields": [ - { - "title": "Volume", - "value": "1", - "short": true - }, - { - "title": "Issue", - "value": "3", - "short": true - } - ] - }, - { - "title": "Synopsis", - "text": "After @episod pushed exciting changes to a devious new branch back in Issue 1, Slackbot notifies @don about an unexpected deploy..." - }, - { - "fallback": "Would you recommend it to customers?", - "title": "Would you recommend it to customers?", - "callback_id": "comic_1234_xyz", - "color": "#3AA3E3", - "attachment_type": "default", - "actions": [ - { - "name": "recommend", - "text": "Recommend", - "type": "button", - "value": "recommend" - }, - { - "name": "no", - "text": "No", - "type": "button", - "value": "bad" - } - ] - } - ] -} -``` - -When a user clicks a button within a Slack message, your bot will receive a response message in which the `channelData` property is populated with a `payload` JSON object. The `payload` object specifies contents of the original message, -identifies the button that was clicked, and identifies the user who clicked the button. - -This snippet shows an example of the `channelData` property in the message that a bot receives when a user clicks a button in the Slack message. - -```json -"channelData": { - "payload": { - "actions": [ - { - "name": "recommend", - "value": "yes" - } - ], - . . . - "original_message": "{…}", - "response_url": "https://hooks.slack.com/actions/..." - } -} -``` - -Your bot can reply to this message in the [normal manner](bot-framework-rest-connector-send-and-receive-messages.md#create-reply), or it can post its response directly to the endpoint that is specified by the `payload` object's `response_url` property. For information about when and how to post a response to the `response_url`, see Slack Buttons. - -## Create a Facebook notification - -To create a Facebook notification, set the `Activity` object's `channelData` property to a JSON object that specifies these properties: - -| Property | Description | -|----|----| -| notification_type | The type of notification (e.g., **REGULAR**, **SILENT_PUSH**, **NO_PUSH**). -| attachment | An attachment that specifies an image, video, or other multimedia type, or a templated attachment such as a receipt. | - -> [!NOTE] -> For details about format and contents of the `notification_type` property and `attachment` property, see the -> Facebook API documentation. - -This snippet shows an example of the `channelData` property for a Facebook receipt attachment. - -```json -"channelData": { - "notification_type": "NO_PUSH", - "attachment": { - "type": "template" - "payload": { - "template_type": "receipt", - . . . - } - } -} -``` - -## Create a Telegram message - -To create a message that implements Telegram-specific actions, -such as sharing a voice memo or a sticker, -set the `Activity` object's `channelData` property to a JSON object that specifies these properties: - -| Property | Description | -|----|----| -| method | The Telegram Bot API method to call. | -| parameters | The parameters of the specified method. | - -These Telegram methods are supported: - -- answerInlineQuery -- editMessageCaption -- editMessageReplyMarkup -- editMessageText -- forwardMessage -- kickChatMember -- sendAudio -- sendChatAction -- sendContact -- sendDocument -- sendLocation -- sendMessage -- sendPhoto -- sendSticker -- sendVenue -- sendVideo -- sendVoice -- unbanChateMember - -For details about these Telegram methods and their parameters, see the -Telegram Bot API documentation. - -> [!NOTE] ->
  • The chat_id parameter is common to all Telegram methods. If you do not specify chat_id as a parameter, the framework will provide the ID for you.
  • ->
  • Instead of passing file contents inline, specify the file using a URL and media type as shown in the example below.
  • ->
  • Within each message that your bot receives from the Telegram channel, the channelData property will include the message that your bot sent previously.
- -This snippet shows an example of a `channelData` property that specifies a single Telegram method. - -```json -"channelData": { - "method": "sendSticker", - "parameters": { - "sticker": { - "url": "https://domain.com/path/gif", - "mediaType": "image/gif", - } - } -} -``` - -This snippet shows an example of a `channelData` property that specifies an array of Telegram methods. - -```json -"channelData": [ - { - "method": "sendSticker", - "parameters": { - "sticker": { - "url": "https://domain.com/path/gif", - "mediaType": "image/gif", - } - } - }, - { - "method": "sendMessage", - "parameters": { - "text": "This message is HTML formatted.", - "parse_mode": "HTML" - } - } -] -``` - -## Create a native Kik message - -To create a native Kik message, -set the `Activity` object's `channelData` property to a JSON object that specifies this property: - -| Property | Description | -|----|----| -| messages | An array of Kik messages. For details about Kik message format, see Kik Message Formats. | - -This snippet shows an example of the `channelData` property for a native Kik message. - -```json -"channelData": { - "messages": [ - { - "chatId": "c6dd8165…", - "type": "link", - "to": "kikhandle", - "title": "My Webpage", - "text": "Some text to display", - "url": "http://botframework.com", - "picUrl": "http://lorempixel.com/400/200/", - "attribution": { - "name": "My App", - "iconUrl": "http://lorempixel.com/50/50/" - }, - "noForward": true, - "kikJsData": { - "key": "value" - } - } - ] -} -``` - -## Additional resources - -- [Create messages](bot-framework-rest-connector-create-messages.md) -- [Send and receive messages](bot-framework-rest-connector-send-and-receive-messages.md) -- [Bot Framework Activity schema](https://aka.ms/botSpecs-activitySchema) -- [Channels reference](../bot-service-channels-reference.md) - -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object diff --git a/articles/rest-api/bot-framework-rest-connector-concepts.md b/articles/rest-api/bot-framework-rest-connector-concepts.md deleted file mode 100644 index b982406c4..000000000 --- a/articles/rest-api/bot-framework-rest-connector-concepts.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: Key concepts in the Bot Connector and Bot State services - Bot Service -description: Understand key concepts in the Bot Framework's Bot Connector service and Bot State service. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/16/2019 ---- - -# Key concepts - -You can use the Bot Connector service to communicate with users across multiple channels such as Skype, Email, Slack, and more. This article introduces key concepts in the Bot Connector service. - -## Bot Connector service - -The Bot Connector service enables your bot to exchange messages with channels configured in the [Azure Portal](https://portal.azure.com). It uses industry-standard REST and JSON over HTTPS and enables authentication with JWT Bearer tokens. For detailed information about how to use the Bot Connector service, see [Authentication](bot-framework-rest-connector-authentication.md) and the remaining articles in this section. - -### Activity - -The Bot Connector service exchanges information between between bot and channel (user) by passing an [Activity][Activity] object. The most common type of activity is **message**, but there are other activity types that can be used to communicate various types of information to a bot or channel. For details about Activities in the Bot Connector service, see [Activities overview](https://aka.ms/botSpecs-activitySchema). - -## Bot State service - -The Microsoft Bot Framework State service is retired as of March 30, 2018. Previously, bots built on the Azure Bot Service or the Bot Builder SDK had a default connection to this service hosted by Microsoft to store bot state data. Bots will need to be updated to use their own state storage. - -## Authentication - -Both the Bot Connector service enables authentication with JWT Bearer tokens. For detailed information about how to authenticate outbound requests that your bot sends to the Bot Framework, how to authenticate inbound requests that your bot receives from the Bot Framework, and more, see [Authentication](bot-framework-rest-connector-authentication.md). - -## Client libraries - -The Bot Framework provides client libraries that can be used to build bots in either C# or Node.js. - -- To build a bot using C#, use the [Bot Framework SDK for C#](../dotnet/bot-builder-dotnet-overview.md). -- To build a bot using Node.js, use the [Bot Framework SDK for Node.js](../nodejs/index.md). - -In addition to modeling the Bot Connector service, each Bot Framework SDK also provides a powerful system for building dialogs that encapsulate conversational logic, built-in prompts for simple things such as Yes/No, strings, numbers, and enumerations, built-in support for powerful AI frameworks such as LUIS, and more. - -> [!NOTE] -> As an alternative to using the C# SDK or Node.js SDK, you can generate your own client library in the language of your choice by using the Bot Connector Swagger file. - -## Additional resources - -Learn more about building bots using the Bot Connector service by reviewing articles throughout this section, beginning with [Authentication](bot-framework-rest-connector-authentication.md). If you encounter problems or have suggestions regarding the Bot Connector service, see [Support](../bot-service-resources-links-help.md) for a list of available resources. - -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object diff --git a/articles/rest-api/bot-framework-rest-connector-create-messages.md b/articles/rest-api/bot-framework-rest-connector-create-messages.md deleted file mode 100644 index df1d343b9..000000000 --- a/articles/rest-api/bot-framework-rest-connector-create-messages.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Create messages with the Bot Connector API - Bot Service -description: Learn about commonly-used message properties within the Bot Connector API. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Create messages - -Your bot will send [Activity][] objects of type **message** to communicate information to users, and likewise, will also receive **message** activities from users. Some messages may simply consist of plain text, while others may contain richer content such as [text to be spoken](bot-framework-rest-connector-text-to-speech.md), [suggested actions](bot-framework-rest-connector-add-suggested-actions.md), [media attachments](bot-framework-rest-connector-add-media-attachments.md), [rich cards](bot-framework-rest-connector-add-rich-cards.md), and [channel-specific data](bot-framework-rest-connector-channeldata.md). This article describes some of the commonly-used message properties. - -## Message text and formatting - -Message text can be formatted using **plain**, **markdown**, or **xml**. The default format for the `textFormat` property is **markdown** and interprets text using Markdown formatting standards. The level of text format support varies across channels. - -[!INCLUDE [Channel Inspector intro](~/includes/snippet-channel-inspector.md)] - -The `textFormat` property of the [Activity][] object can be used to specify the format of the text. For example, to create a basic message that contains only plain text, set the `textFormat` property of the `Activity` object to **plain**, set the `text` property to the contents of the message and set the `locale` property to the locale of the sender. - -## Attachments - -The `attachments` property of the [Activity][] object can be used to send simple media attachments -(image, audio, video, file) and rich cards. For details, see [Add media attachments to messages](bot-framework-rest-connector-add-media-attachments.md) and [Add rich cards to messages](bot-framework-rest-connector-add-rich-cards.md). - -## Entities - -The `entities` property of the [Activity][] object is an array of open-ended schema.org objects that allows the exchange of common contextual metadata between the channel and bot. - -### Mention entities - -Many channels support the ability for a bot or user to "mention" someone within the context of a conversation. -To mention a user in a message, populate the message's `entities` property with a [Mention][] object. - -### Place entities - -To convey location-related information within a message, populate the message's `entities` property with [Place][] object. - -## Channel data - -The `channelData` property of the [Activity][] object can be used to implement channel-specific functionality. -For details, see [Implement channel-specific functionality](bot-framework-rest-connector-channeldata.md). - -## Text to speech - -The `speak` property of the [Activity][] object can be used to specify the text to be spoken by your bot on a speech-enabled channel and the `inputHint` property of the `Activity` object can be used to influence the state of the client's microphone. For details, see [Add speech to messages](bot-framework-rest-connector-text-to-speech.md) and [Add input hints to messages](bot-framework-rest-connector-add-input-hints.md). - -## Suggested actions - -The `suggestedActions` property of the [Activity][] object can be used to present buttons that the user can tap to provide input. Unlike buttons that appear within rich cards (which remain visible and accessible to the user even after being tapped), buttons that appear within the suggested actions pane will disappear after the user makes a selection. For details, see [Add suggested actions to messages](bot-framework-rest-connector-add-suggested-actions.md). - -## Additional resources - -- [Channels reference][ChannelInspector] -- [Activities overview](https://aka.ms/botSpecs-activitySchema) -- [Send and receive messages](bot-framework-rest-connector-send-and-receive-messages.md) -- [Add media attachments to messages](bot-framework-rest-connector-add-media-attachments.md) -- [Add rich cards to messages](bot-framework-rest-connector-add-rich-cards.md) -- [Add speech to messages](bot-framework-rest-connector-text-to-speech.md) -- [Add input hints to messages](bot-framework-rest-connector-add-input-hints.md) -- [Add suggested actions to messages](bot-framework-rest-connector-add-suggested-actions.md) -- [Implement channel-specific functionality](bot-framework-rest-connector-channeldata.md) - -[ChannelInspector]: ../bot-service-channels-reference.md -[textFormating]: ../bot-service-channel-inspector.md#text-formatting - -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object -[Mention]: bot-framework-rest-connector-api-reference.md#mention-object -[Place]: bot-framework-rest-connector-api-reference.md#place-object diff --git a/articles/rest-api/bot-framework-rest-connector-quickstart.md b/articles/rest-api/bot-framework-rest-connector-quickstart.md deleted file mode 100644 index c419a05a7..000000000 --- a/articles/rest-api/bot-framework-rest-connector-quickstart.md +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: Create a bot with the Bot Connector service - Bot Service -description: Create a bot with the Bot Connector service. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Create a bot with the Bot Connector service -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-quickstart.md) -> - [Node.js](../nodejs/bot-builder-nodejs-quickstart.md) -> - [Bot Service](../bot-service-quickstart.md) -> - [REST](../rest-api/bot-framework-rest-connector-quickstart.md) - -The Bot Connector service enables your bot to exchange messages with channels that are configured in the [Azure Portal](https://portal.azure.com), by using industry-standard REST and JSON over HTTPS. This tutorial walks you through the process of obtaining an access token from the Bot Framework and using the Bot Connector service to exchange messages with the user. - -## Get an access token - -> [!IMPORTANT] -> If you have not already done so, you must [register your bot](../bot-service-quickstart-registration.md) with the Bot Framework to obtain its App ID and password. You will need the bot's AppID and password to get an access token. - -To communicate with the Bot Connector service, you must specify an access token in the `Authorization` header of each API request, using this format: - -```http -Authorization: Bearer ACCESS_TOKEN -``` - -You can obtain the access token for your bot by issuing an API request. - -### Request - -To request an access token that can be used to authenticate requests to the Bot Connector service, issue the following request, replacing **MICROSOFT-APP-ID** and **MICROSOFT-APP-PASSWORD** with the App ID and password that you obtained when you [registered](../bot-service-quickstart-registration.md) your bot with the Bot Framework. - -```http -POST https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token -Host: login.microsoftonline.com -Content-Type: application/x-www-form-urlencoded - -grant_type=client_credentials&client_id=MICROSOFT-APP-ID&client_secret=MICROSOFT-APP-PASSWORD&scope=https%3A%2F%2Fapi.botframework.com%2F.default -``` - -### Response - -If the request succeeds, you will receive an HTTP 200 response that specifies the access token and information about its expiration. - -```json -{ - "token_type":"Bearer", - "expires_in":3600, - "ext_expires_in":3600, - "access_token":"eyJhbGciOiJIUzI1Ni..." -} -``` - -> [!TIP] -> For more details about authentication in the Bot Connector service, see [Authentication](bot-framework-rest-connector-authentication.md). - -## Exchange messages with the user - -A conversation is a series of messages exchanged between a user and your bot. - -### Receive a message from the user - -When the user sends a message, the Bot Framework Connector POSTs a request to the endpoint that you specified when you [registered](../bot-service-quickstart-registration.md) your bot. The body of the request is an [Activity][] object. The following example shows the request body that a bot receives when the user sends a simple message to the bot. - -```json -{ - "type": "message", - "id": "bf3cc9a2f5de...", - "timestamp": "2016-10-19T20:17:52.2891902Z", - "serviceUrl": "https://smba.trafficmanager.net/apis", - "channelId": "channel's name/id", - "from": { - "id": "1234abcd", - "name": "user's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "12345678", - "name": "bot's name" - }, - "text": "Haircut on Saturday" -} -``` - -### Reply to the user's message - -When your bot's endpoint receives a `POST` request that represents a message from the user (i.e., `type` = **message**), use the information in that request to create the [Activity][] object for your response. - -1. Set the **conversation** property to the contents of the **conversation** property in the user's message. -2. Set the **from** property to the contents of the **recipient** property in the user's message. -3. Set the **recipient** property to the contents of the **from** property in the user's message. -4. Set the **text** and **attachments** properties as appropriate. - -Use the `serviceUrl` property in the incoming request to [identify the base URI](bot-framework-rest-connector-api-reference.md#base-uri) that your bot should use to issue its response. - -To send the response, `POST` your `Activity` object to `/v3/conversations/{conversationId}/activities/{activityId}`, as shown in the following example. The body of this request is an `Activity` object that prompts the user to select an available appointment time. - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations/abcd1234/activities/bf3cc9a2f5de... -Authorization: Bearer eyJhbGciOiJIUzI1Ni... -Content-Type: application/json -``` - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "bot's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "1234abcd", - "name": "user's name" - }, - "text": "I have these times available:", - "replyToId": "bf3cc9a2f5de..." -} -``` - -In this example request, `https://smba.trafficmanager.net/apis` represents the base URI; the base URI for requests that your bot issues may be different. For details about setting the base URI, see [API Reference](bot-framework-rest-connector-api-reference.md#base-uri). - -> [!IMPORTANT] -> As shown in this example, the `Authorization` header of each API request that you send must contain the word **Bearer** followed by the access token that you [obtained from the Bot Framework](#get-token). - -To send another message that enables a user to select an available appointment time by clicking a button, `POST` another request to the same endpoint: - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations/abcd1234/activities/bf3cc9a2f5de... -Authorization: Bearer eyJhbGciOiJIUzI1Ni... -Content-Type: application/json -``` - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "bot's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "1234abcd", - "name": "user's name" - }, - "attachmentLayout": "list", - "attachments": [ - { - "contentType": "application/vnd.microsoft.card.thumbnail", - "content": { - "buttons": [ - { - "type": "imBack", - "title": "10:30", - "value": "10:30" - }, - { - "type": "imBack", - "title": "11:30", - "value": "11:30" - }, - { - "type": "openUrl", - "title": "See more", - "value": "http://www.contososalon.com/scheduling" - } - ] - } - } - ], - "replyToId": "bf3cc9a2f5de..." -} -``` - -## Next steps - -In this tutorial, you obtained an access token from the Bot Framework and used the Bot Connector service to exchange messages with the user. -You can use the [Bot Framework Emulator](../bot-service-debug-emulator.md) to test and debug your bot. -If you'd like to share your bot with others, you'll need to [configure](../bot-service-manage-channels.md) it to run on one or more channels. - -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object diff --git a/articles/rest-api/bot-framework-rest-connector-send-and-receive-messages.md b/articles/rest-api/bot-framework-rest-connector-send-and-receive-messages.md deleted file mode 100644 index b8cc08663..000000000 --- a/articles/rest-api/bot-framework-rest-connector-send-and-receive-messages.md +++ /dev/null @@ -1,152 +0,0 @@ ---- -title: Send and receive messages - Bot Service -description: Learn how to send and receive messages using the Bot Connector service. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Send and receive messages - -The Bot Connector service enables a bot to communicate across multiple channels such as Skype, Email, Slack, and more. It facilitates communication between bot and user, by relaying [activities](https://aka.ms/botSpecs-activitySchema) from bot to channel and from channel to bot. Every activity contains information used for routing the message to the appropriate destination along with information about who created the message, the context of the message, and the recipient of the message. This article describes how to use the Bot Connector service to exchange **message** activities between bot and user on a channel. - -## Reply to a message - -### Create a reply - -When the user sends a message to your bot, your bot will receive the message as an [Activity][] object of type **message**. To create a reply to a user's message, create a new `Activity` object and start by setting these properties: - -| Property | Value | -|----|----| -| conversation | Set this property to the contents of the `conversation` property in the user's message. | -| from | Set this property to the contents of the `recipient` property in the user's message. | -| locale | Set this property to the contents of the `locale` property in the user's message, if specified. | -| recipient | Set this property to the contents of the `from` property in the user's message. | -| replyToId | Set this property to the contents of the `id` property in the user's message. | -| type | Set this property to **message**. | - -Next, set the properties that specify the information that you want to communicate to the user. For example, you can set the `text` property to specify the text to be displayed in the message, set the `speak` property to specify text to be spoken by your bot, and set the `attachments` property to specify media attachments or rich cards to include in the message. For detailed information about commonly-used message properties, see [Create messages](bot-framework-rest-connector-create-messages.md). - -### Send the reply - -Use the `serviceUrl` property in the incoming activity to [identify the base URI](bot-framework-rest-connector-api-reference.md#base-uri) that your bot should use to issue its response. - -To send the reply, issue this request: - -```http -POST /v3/conversations/{conversationId}/activities/{activityId} -``` - -In this request URI, replace **{conversationId}** with the value of the `conversation` object's `id` property within your (reply) Activity and replace **{activityId}** with the value of the `replyToId` property within your (reply) Activity. Set the body of the request to the [Activity][] object that you created to represent your reply. - -The following example shows a request that sends a simple text-only reply to a user's message. In this example request, `https://smba.trafficmanager.net/apis` represents the base URI; the base URI for requests that your bot issues may be different. For details about setting the base URI, see [API Reference](bot-framework-rest-connector-api-reference.md#base-uri). - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations/abcd1234/activities/5d5cdc723 -Authorization: Bearer ACCESS_TOKEN -Content-Type: application/json -``` - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "Pepper's News Feed" - }, - "conversation": { - "id": "abcd1234", - "name": "Convo1" - }, - "recipient": { - "id": "1234abcd", - "name": "SteveW" - }, - "text": "My bot's reply", - "replyToId": "5d5cdc723" -} -``` - -## Send a (non-reply) message - -A majority of the messages that your bot sends will be in reply to messages that it receives from the user. However, there may be times when your bot needs to send a message to the conversation that is not a direct reply to any message from the user. For example, your bot may need to start a new topic of conversation or send a goodbye message at the end of the conversation. - -To send a message to a conversation that is not a direct reply to any message from the user, issue this request: - -```http -POST /v3/conversations/{conversationId}/activities -``` - -In this request URI, replace **{conversationId}** with the ID of the conversation. - -Set the body of the request to an [Activity][] object that you create to represent your reply. - -> [!NOTE] -> The Bot Framework does not impose any restrictions on the number of messages that a bot may send. -> However, most channels enforce throttling limits to restrict bots from sending a large number of messages in a short period of time. -> Additionally, if the bot sends multiple messages in quick succession, the channel may not always render the messages in the proper sequence. - -## Start a conversation - -There may be times when your bot needs to initiate a conversation with one or more users. -To start a conversation with a user on a channel, your bot must know its account information and the user's account information on that channel. - -> [!TIP] -> If your bot may need to start conversations with its users in the future, cache user account information, other relevant information such as user preferences and locale, and the service URL (to use as the base URI in the Start Conversation request). - -To start a conversation, issue this request: - -```http -POST /v3/conversations -``` - -Set the body of the request to a [ConversationParameters][] object that specifies your bot's account information and the account information of the user(s) that you want to include in the conversation. - -> [!NOTE] -> Not all channels support group conversations. Consult the channel's documentation to determine whether a channel supports group conversations and to identify the maximum number of participants that a channel allows in a conversation. - -The following example shows a request that starts a conversation. In this example request, `https://smba.trafficmanager.net/apis` represents the base URI; the base URI for requests that your bot issues may be different. For details about setting the base URI, see [API Reference](bot-framework-rest-connector-api-reference.md#base-uri). - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations -Authorization: Bearer ACCESS_TOKEN -Content-Type: application/json -``` - -```json -{ - "bot": { - "id": "12345678", - "name": "bot's name" - }, - "isGroup": false, - "members": [ - { - "id": "1234abcd", - "name": "recipient's name" - } - ], - "topicName": "News Alert" -} -``` - -If the conversation is established with the specified users, the response will contain an ID that identifies the conversation. - -```json -{ - "id": "abcd1234" -} -``` - -Your bot can then use this conversation ID to [send a message](#send-message) to the user(s) within the conversation. - -## Additional resources - -- [Create messages](bot-framework-rest-connector-create-messages.md) -- [Bot Framework Activity schema](https://aka.ms/botSpecs-activitySchema) - -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object -[ConversationParameters]: bot-framework-rest-connector-api-reference.md#conversationparameters-object diff --git a/articles/rest-api/bot-framework-rest-connector-text-to-speech.md b/articles/rest-api/bot-framework-rest-connector-text-to-speech.md deleted file mode 100644 index a09539745..000000000 --- a/articles/rest-api/bot-framework-rest-connector-text-to-speech.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Add speech to messages - Bot Service -description: Learn how to add speech to messages using the Bot Connector service. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Add speech to messages -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-text-to-speech.md) -> - [Node.js](../nodejs/bot-builder-nodejs-text-to-speech.md) -> - [REST](../rest-api/bot-framework-rest-connector-text-to-speech.md) - -If you are building a bot for a speech-enabled channel such as Cortana, you can construct messages that specify the text to be spoken by your bot. You can also attempt to influence the state of the client's microphone by specifying an [input hint](bot-framework-rest-connector-add-input-hints.md) to indicate whether your bot is accepting, expecting, or ignoring user input. - -## Specify text to be spoken by your bot - -To specify text to be spoken by your bot on a speech-enabled channel, set the `speak` property within the [Activity][Activity] object that represents your message. You can set the `speak` property to either a plain text string or a string that is formatted as Speech Synthesis Markup Language (SSML), an XML-based markup language that enables you to control various characteristics of your bot's speech such as voice, rate, volume, pronunciation, pitch, and more. - - -The following request sends a message that specifies text to be displayed and text to be spoken and indicates that the bot is [expecting user input](bot-framework-rest-connector-add-input-hints.md). It specifies the `speak` property using SSML format to indicate that the word "sure" should be spoken with a moderate amount of emphasis. In this example request, `https://smba.trafficmanager.net/apis` represents the base URI; the base URI for requests that your bot issues may be different. For details about setting the base URI, see [API Reference](bot-framework-rest-connector-api-reference.md#base-uri). - -```http -POST https://smba.trafficmanager.net/apis/v3/conversations/abcd1234/activities/5d5cdc723 -Authorization: Bearer ACCESS_TOKEN -Content-Type: application/json -``` - -```json -{ - "type": "message", - "from": { - "id": "12345678", - "name": "sender's name" - }, - "conversation": { - "id": "abcd1234", - "name": "conversation's name" - }, - "recipient": { - "id": "1234abcd", - "name": "recipient's name" - }, - "text": "Are you sure that you want to cancel this transaction?", - "speak": "Are you sure that you want to cancel this transaction?", - "inputHint": "expectingInput", - "replyToId": "5d5cdc723" -} -``` - -## Input hints - -When you send a message on a speech-enabled channel, you can attempt to influence the state of the client's microphone by also including an input hint to indicate whether your bot is accepting, expecting, or ignoring user input. For more information, see [Add input hints to messages](bot-framework-rest-connector-add-input-hints.md). - -## Additional resources - -- [Create messages](bot-framework-rest-connector-create-messages.md) -- [Send and receive messages](bot-framework-rest-connector-send-and-receive-messages.md) -- [Add input hints to messages](bot-framework-rest-connector-add-input-hints.md) -- Speech Synthesis Markup Language (SSML) - -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object \ No newline at end of file diff --git a/articles/rest-api/bot-framework-rest-direct-line-1-1-api-reference.md b/articles/rest-api/bot-framework-rest-direct-line-1-1-api-reference.md deleted file mode 100644 index 5ec60dbf8..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-1-1-api-reference.md +++ /dev/null @@ -1,232 +0,0 @@ ---- -title: API reference - Direct Line API 1.1 - Bot Service -description: Learn about headers, HTTP status codes, schema, operations, and objects in Direct Line API 1.1. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# API reference - Direct Line API 1.1 - -> [!IMPORTANT] -> This article contains reference information for Direct Line API 1.1. If you are creating a new connection between your client application and bot, use [Direct Line API 3.0](bot-framework-rest-direct-line-3-0-api-reference.md) instead. - -You can enable your client application to communicate with your bot by using Direct Line API 1.1. Direct Line API 1.1 uses industry-standard REST and JSON over HTTPS. - -## Base URI - -To access Direct Line API 1.1, use this base URI for all API requests: - -`https://directline.botframework.com` - -## Headers - -In addition to the standard HTTP request headers, a Direct Line API request must include an `Authorization` header that specifies a secret or token to authenticate the client that is issuing the request. You can specify the `Authorization` header using either the "Bearer" scheme or the "BotConnector" scheme. - -**Bearer scheme**: -```http -Authorization: Bearer SECRET_OR_TOKEN -``` - -**BotConnector scheme**: -```http -Authorization: BotConnector SECRET_OR_TOKEN -``` - -For details about how to obtain a secret or token that your client can use to authenticate its Direct Line API requests, see [Authentication](bot-framework-rest-direct-line-1-1-authentication.md). - -## HTTP status codes - -The HTTP status code that is returned with each response indicates the outcome of the corresponding request. - -| HTTP status code | Meaning | -|----|----| -| 200 | The request succeeded. | -| 204 | The request succeeded but no content was returned. | -| 400 | The request was malformed or otherwise incorrect. | -| 401 | The client is not authorized to make the request. Often this status code occurs because the `Authorization` header is missing or malformed. | -| 403 | The client is not allowed to perform the requested operation. Often this status code occurs because the `Authorization` header specifies an invalid token or secret. | -| 404 | The requested resource was not found. Typically this status code indicates an invalid request URI. | -| 500 | An internal server error occurred within the Direct Line service | -| 502 | A failure occurred within the bot; the bot is unavailable or returned an error. **This is a common error code.** | - -## Token operations -Use these operations to create or refresh a token that a client can use to access a single conversation. - -| Operation | Description | -|----|----| -| [Generate Token](#generate-token) | Generate a token for a new conversation. | -| [Refresh Token](#refresh-token) | Refresh a token. | - -### Generate Token -Generates a token that is valid for one conversation. -```http -POST /api/tokens/conversation -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | A string that represents the token | - -### Refresh Token -Refreshes the token. -```http -GET /api/tokens/{conversationId}/renew -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | A string that represents the new token | - -## Conversation operations -Use these operations to open a conversation with your bot and exchange messages between client and bot. - -| Operation | Description | -|----|----| -| [Start Conversation](#start-conversation) | Opens a new conversation with the bot. | -| [Get Messages](#get-messages) | Retrieves messages from the bot. | -| [Send a Message](#send-a-message) | Sends a message to the bot. | -| [Upload and Send File(s)](#upload-send-files) | Uploads and sends file(s) as attachment(s). | - -### Start Conversation -Opens a new conversation with the bot. -```http -POST /api/conversations -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | A [Conversation](#conversation-object) object | - -### Get Messages -Retrieves messages from the bot for the specified conversation. Set the `watermark` parameter in the request URI to indicate the most recent message seen by the client. - -```http -GET /api/conversations/{conversationId}/messages?watermark={watermark_value} -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | A [MessageSet](#messageset-object) object. The response contains `watermark` as a property of the `MessageSet` object. Clients should page through the available messages by advancing the `watermark` value until no messages are returned. | - -### Send a Message -Sends a message to the bot. -```http -POST /api/conversations/{conversationId}/messages -``` - -| | | -|----|----| -| **Request body** | A [Message](#message-object) object | -| **Returns** | No data is returned in body of the response. The service responds with an HTTP 204 status code if the message was sent successfully. The client may obtain its sent message (along with any messages that the bot has sent to the client) by using the [Get Messages](#get-messages) operation. | - -### Upload and Send File(s) -Uploads and sends file(s) as attachment(s). Set the `userId` parameter in the request URI to specify the ID of the user that is sending the attachments. -```http -POST /api/conversations/{conversationId}/upload?userId={userId} -``` - -| | | -|----|----| -| **Request body** | For a single attachment, populate the request body with the file contents. For multiple attachments, create a multipart request body that contains one part for each attachment, and also (optionally) one part for the [Message](#message-object) object that should serve as the container for the specified attachment(s). For more information, see [Send a message to the bot](bot-framework-rest-direct-line-1-1-send-message.md). | -| **Returns** | No data is returned in body of the response. The service responds with an HTTP 204 status code if the message was sent successfully. The client may obtain its sent message (along with any messages that the bot has sent to the client) by using the [Get Messages](#get-messages) operation. | - -> [!NOTE] -> Uploaded files are deleted after 24 hours. - -## Schema - -Direct Line 1.1 schema is a simplified copy of the Bot Framework v1 schema that includes the following objects. - -### Message object - -Defines a message that a client sends to a bot or receives from a bot. - -| Property | Type | Description | -|----|----|----| -| **id** | string | ID that uniquely identifies the message (assigned by Direct Line). | -| **conversationId** | string | ID that identifies the conversation. | -| **created** | string | Date and time that the message was created, expressed in ISO-8601 format. | -| **from** | string | ID that identifies the user that is the sender of the message. When creating a message, clients should set this property to a stable user ID. Although Direct Line will assign a user ID if none is supplied, this typically results in unexpected behavior. | -| **text** | string | Text of the message that is sent from user to bot or bot to user. | -| **channelData** | object | An object that contains channel-specific content. Some channels provide features that require additional information that cannot be represented using the attachment schema. For those cases, set this property to the channel-specific content as defined in the channel's documentation. This data is sent unmodified between client and bot. This property must either be set to a complex object or left empty. Do not set it to a string, number, or other simple type. | -| **images** | string[] | Array of strings that contains the URL(s) for the image(s) that the message contains. In some cases, strings in this array may be relative URLs. If any string in this array does not begin with either "http" or "https", prepend `https://directline.botframework.com` to the string to form the complete URL. | -| **attachments** | [Attachment](#attachment-object)[] | Array of **Attachment** objects that represent the non-image attachments that the message contains. Each object in the array contains a `url` property and a `contentType` property. In messages that a client receives from a bot, the `url` property may sometimes specify a relative URL. For any `url` property value that does not begin with either "http" or "https", prepend `https://directline.botframework.com` to the string to form the complete URL. | - -The following example shows a Message object that contains all possible properties. In most cases when creating a message, the client only needs to supply the `from` property and at least one content property (e.g., `text`, `images`, `attachments`, or `channelData`). - -```json -{ - "id": "CuvLPID4kDb|000000000000000004", - "conversationId": "CuvLPID4kDb", - "created": "2016-10-28T21:19:51.0357965Z", - "from": "examplebot", - "text": "Hello!", - "channelData": { - "examplefield": "abc123" - }, - "images": [ - "/attachments/CuvLPID4kDb/0.jpg?..." - ], - "attachments": [ - { - "url": "https://example.com/example.docx", - "contentType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document" - }, - { - "url": "https://example.com/example.doc", - "contentType": "application/msword" - } - ] -} -``` - -### MessageSet object -Defines a set of messages.

- -| Property | Type | Description | -|----|----|----| -| **messages** | [Message](#message-object)[] | Array of **Message** objects. | -| **watermark** | string | Maximum watermark of messages within the set. A client may use the `watermark` value to indicate the most recent message it has seen when [retrieving messages from the bot](bot-framework-rest-direct-line-1-1-receive-messages.md). | - -### Attachment object -Defines a non-image attachment.

- -| Property | Type | Description | -|----|----|----| -| **contentType** | string | The media type of the content in the attachment. | -| **url** | string | URL for the content of the attachment. | - -### Conversation object -Defines a Direct Line conversation.

- -| Property | Type | Description | -|----|----|----| -| **conversationId** | string | ID that uniquely identifies the conversation for which the specified token is valid. | -| **token** | string | Token that is valid for the specified conversation. | -| **expires_in** | number | Number of seconds until the token expires. | - -### Error object -Defines an error.

- -| Property | Type | Description | -|----|----|----| -| **code** | string | Error code. One of these values: **MissingProperty**, **MalformedData**, **NotFound**, **ServiceError**, **Internal**, **InvalidRange**, **NotSupported**, **NotAllowed**, **BadCertificate**. | -| **message** | string | A description of the error. | -| **statusCode** | number | Status code. | - -### ErrorMessage object -A standardized message error payload.

- - -| Property | Type | Description | -|------------------------|------------------------|-----------------------------------------------------------------------------| -| error | [Error](#error-object) | An Error object that contains information about the error. | - diff --git a/articles/rest-api/bot-framework-rest-direct-line-1-1-authentication.md b/articles/rest-api/bot-framework-rest-direct-line-1-1-authentication.md deleted file mode 100644 index d84789e9d..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-1-1-authentication.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: Direct Line API 1.1 Authentication - Bot Service -description: Learn how to authenticate API requests in Direct Line API v1.1. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Authentication - -> [!IMPORTANT] -> This article describes authentication in Direct Line API 1.1. If you are creating a new connection between your client application and bot, use [Direct Line API 3.0](bot-framework-rest-direct-line-3-0-authentication.md) instead. - -A client can authenticate requests to Direct Line API 1.1 either by using a **secret** that you [obtain from the Direct Line channel configuration page](../bot-service-channel-connect-directline.md) in the Bot Framework Portal or by using a **token** that you obtain at runtime. - -The secret or token should be specified in the `Authorization` header of each request, using either the "Bearer" scheme or the "BotConnector" scheme. - -**Bearer scheme**: -```http -Authorization: Bearer SECRET_OR_TOKEN -``` - -**BotConnector scheme**: -```http -Authorization: BotConnector SECRET_OR_TOKEN -``` - -## Secrets and tokens - -A Direct Line **secret** is a master key that can be used to access any conversation that belongs to the associated bot. A **secret** can also be used to obtain a **token**. Secrets do not expire. - -A Direct Line **token** is a key that can be used to access a single conversation. A token expires but can be refreshed. - -If you're creating a service-to-service application, specifying the **secret** in the `Authorization` header of Direct Line API requests may be simplest approach. If you're writing an application where the client runs in a web browser or mobile app, you may want to exchange your secret for a token (which only works for a single conversation and will expire unless refreshed) and specify the **token** in the `Authorization` header of Direct Line API requests. Choose the security model that works best for you. - -> [!NOTE] -> Your Direct Line client credentials are different from your bot's credentials. This enables you to revise your keys independently and lets you share client tokens without disclosing your bot's password. - -## Get a Direct Line secret - -You can [obtain a Direct Line secret](../bot-service-channel-connect-directline.md) via the Direct Line channel configuration page for your bot in the [Azure Portal](https://portal.azure.com): - -![Direct Line configuration](../media/direct-line-configure.png) - -## Generate a Direct Line token - -To generate a Direct Line token that can be used to access a single conversation, first obtain the Direct Line secret from the Direct Line channel configuration page in the [Azure Portal](https://portal.azure.com). Then issue this request to exchange your Direct Line secret for a Direct Line token: - -```http -POST https://directline.botframework.com/api/tokens/conversation -Authorization: Bearer SECRET -``` - -In the `Authorization` header of this request, replace **SECRET** with the value of your Direct Line secret. - -The following snippets provide an example of the Generate Token request and response. - -### Request - -```http -POST https://directline.botframework.com/api/tokens/conversation -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0 -``` - -### Response - -If the request is successful, the response contains a token that is valid for one conversation. The token will expire in 30 minutes. For the token to remain useful, you must [refresh the token](#refresh-token) before it expires. - -```http -HTTP/1.1 200 OK -[other headers] - -"RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xn" -``` - -### Generate Token versus Start Conversation - -The Generate Token operation (`POST /api/tokens/conversation`) is similar to the [Start Conversation](bot-framework-rest-direct-line-1-1-start-conversation.md) operation (`POST /api/conversations`) in that both operations return a `token` that can be used to access a single conversation. However, unlike the Start Conversation operation, the Generate Token operation does not start the conversation or contact the bot. - -If you plan to distribute the token to clients and want them to initiate the conversation, use the Generate Token operation. If you intend to start the conversation immediately, use the [Start Conversation](bot-framework-rest-direct-line-1-1-start-conversation.md) operation instead. - -## Refresh a Direct Line token - -A Direct Line token is valid for 30 minutes from the time it is generated and can be refreshed an unlimited amount of times, as long as it has not expired. An expired token cannot be refreshed. To refresh a Direct Line token, issue this request: - -```http -POST https://directline.botframework.com/api/tokens/{conversationId}/renew -Authorization: Bearer TOKEN_TO_BE_REFRESHED -``` - -In the URI of this request, replace **{conversationId}** with the ID of the conversation for which the token is valid and in the `Authorization` header of this request, replace **TOKEN_TO_BE_REFRESHED** with the Direct Line token that you want to refresh. - -The following snippets provide an example of the Refresh Token request and response. - -### Request - -```http -POST https://directline.botframework.com/api/tokens/abc123/renew -Authorization: Bearer CurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xn -``` - -### Response - -If the request is successful, the response contains a new token that is valid for the same conversation as the previous token. The new token will expire in 30 minutes. For the new token to remain useful, you must [refresh the token](#refresh-token) before it expires. - -```http -HTTP/1.1 200 OK -[other headers] - -"RCurR_XV9ZA.cwA.BKA.y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xniaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0" -``` - -## Additional resources - -- [Key concepts](bot-framework-rest-direct-line-1-1-concepts.md) -- [Connect a bot to Direct Line](../bot-service-channel-connect-directline.md) \ No newline at end of file diff --git a/articles/rest-api/bot-framework-rest-direct-line-1-1-concepts.md b/articles/rest-api/bot-framework-rest-direct-line-1-1-concepts.md deleted file mode 100644 index e8315aa69..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-1-1-concepts.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Key concepts in the Bot Framework Direct Line API 1.1 - Bot Service -description: Understand key concepts in the Bot Framework Direct Line API 1.1. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Key concepts in Direct Line API 1.1 - -You can enable communication between your bot and your own client application by using the Direct Line API. - -> [!IMPORTANT] -> This article introduces key concepts in Direct Line API 1.1 and provides information about relevant developer resources. If you are creating a new connection between your client application and bot, use [Direct Line API 3.0](bot-framework-rest-direct-line-3-0-concepts.md) instead. - -## Authentication - -Direct Line API 1.1 requests can be authenticated either by using a **secret** that you obtain from the Direct Line channel configuration page in the [Azure Portal](https://portal.azure.com) or by using a **token** that you obtain at runtime. For more information, see [Authentication](bot-framework-rest-direct-line-1-1-authentication.md). - -## Starting a conversation - -Direct Line conversations are explicitly opened by clients and may run as long as the bot and client participate and have valid credentials. For more information, see [Start a conversation](bot-framework-rest-direct-line-1-1-start-conversation.md). - -## Sending messages - -Using Direct Line API 1.1, a client can send messages to your bot by issuing `HTTP POST` requests. A client may send a single message per request. For more information, see [Send a message to the bot](bot-framework-rest-direct-line-1-1-send-message.md). - -## Receiving messages - -Using Direct Line API 1.1, a client can receive messages by polling with `HTTP GET` requests. In response to each request, a client may receive multiple messages from the bot as part of a `MessageSet`. For more information, see [Receive messages from the bot](bot-framework-rest-direct-line-1-1-receive-messages.md). - -## Developer resources - -### Client library - -The Bot Framework provides a client library that facilitates access to Direct Line API 1.1 via C#. To use the client library within a Visual Studio project, install the `Microsoft.Bot.Connector.DirectLine` v1.x NuGet package. - -As an alternative to using the C# client library, you can generate your own client library in the language of your choice by using the Direct Line API 1.1 Swagger file. - -### Web chat control - -The Bot Framework provides a control that enables you to embed a Direct-Line-powered bot into your client application. For more information, see the Microsoft Bot Framework WebChat control. diff --git a/articles/rest-api/bot-framework-rest-direct-line-1-1-receive-messages.md b/articles/rest-api/bot-framework-rest-direct-line-1-1-receive-messages.md deleted file mode 100644 index 517dc6a8c..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-1-1-receive-messages.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: Receive messages from the bot - Bot Service -description: Learn how to receive messages from the bot using Direct Line API v1.1. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Receive messages from the bot - -> [!IMPORTANT] -> This article describes how to receive messages from the bot using Direct Line API 1.1. If you are creating a new connection between your client application and bot, use [Direct Line API 3.0](bot-framework-rest-direct-line-3-0-receive-activities.md) instead. - -Using the Direct Line 1.1 protocol, clients must poll an `HTTP GET` interface to receive messages. - -## Retrieve messages with HTTP GET - -To retrieve messages for a specific conversation, issue a `GET` request to the `api/conversations/{conversationId}/messages` endpoint, optionally specifying the `watermark` parameter to indicate the most recent message seen by the client. An updated `watermark` value will be returned in the JSON response, even if no messages are included. - -The following snippets provide an example of the Get Messages request and response. The Get Messages response contains `watermark` as a property of the [MessageSet](bot-framework-rest-direct-line-1-1-api-reference.md#messageset-object). Clients should page through the available messages by advancing the `watermark` value until no messages are returned. - -### Request - -```http -GET https://directline.botframework.com/api/conversations/abc123/messages?watermark=0001a-94 -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0 -``` - -### Response - -```http -HTTP/1.1 200 OK -[other headers] -``` - -```json -{ - "messages": [ - { - "conversation": "abc123", - "id": "abc123|0000", - "text": "hello", - "from": "user1" - }, - { - "conversation": "abc123", - "id": "abc123|0001", - "text": "Nice to see you, user1!", - "from": "bot1" - } - ], - "watermark": "0001a-95" -} -``` - -## Timing considerations - -Even though Direct Line is a multi-part protocol with potential timing gaps, the protocol and service is designed to make it easy to build a reliable client. The `watermark` property that is sent in the Get Messages response is reliable. A client will not miss any messages as long as it replays the watermark verbatim. - -Clients should choose a polling interval that matches their intended use. - -- Service-to-service applications often use a polling interval of 5s or 10s. - -- Client-facing applications often use a polling interval of 1s, and issue an additional request ~300ms after every message that the client sends (to rapidly retrieve a bot's response). This 300ms delay should be adjusted based on the bot's speed and transit time. - -## Additional resources - -- [Key concepts](bot-framework-rest-direct-line-1-1-concepts.md) -- [Authentication](bot-framework-rest-direct-line-1-1-authentication.md) -- [Start a conversation](bot-framework-rest-direct-line-1-1-start-conversation.md) -- [Send a message to the bot](bot-framework-rest-direct-line-1-1-send-message.md) \ No newline at end of file diff --git a/articles/rest-api/bot-framework-rest-direct-line-1-1-send-message.md b/articles/rest-api/bot-framework-rest-direct-line-1-1-send-message.md deleted file mode 100644 index 5f0bc26b7..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-1-1-send-message.md +++ /dev/null @@ -1,159 +0,0 @@ ---- -title: Send a message the bot - Bot Service -description: Learn how to send a message to the bot using Direct Line API v1.1. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Send a message to the bot - -> [!IMPORTANT] -> This article describes how to send a message to the bot using Direct Line API 1.1. If you are creating a new connection between your client application and bot, use [Direct Line API 3.0](bot-framework-rest-direct-line-3-0-send-activity.md) instead. - -Using the Direct Line 1.1 protocol, clients can exchange messages with bots. These messages are converted to the schema that the bot supports (Bot Framework v1 or Bot Framework v3). A client may send a single message per request. - -## Send a message - -To send a message to the bot, the client must create a [Message](bot-framework-rest-direct-line-1-1-api-reference.md#message-object) object to define the message and then issue a `POST` request to `https://directline.botframework.com/api/conversations/{conversationId}/messages`, specifying the Message object in the body of the request. - -The following snippets provide an example of the Send Message request and response. - -### Request - -```http -POST https://directline.botframework.com/api/conversations/abc123/messages -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0 -[other headers] -``` - -```json -{ - "text": "hello", - "from": "user1" -} -``` - -### Response - -When the message is delivered to the bot, the service responds with an HTTP status code that reflects the bot's status code. If the bot generates an error, an HTTP 500 response ("Internal Server Error") is returned to the client in response to its Send Message request. If the POST is successful, the service returns an HTTP 204 status code. No data is returned in body of the response. The client's message and any messages from the bot can be obtained via [polling](bot-framework-rest-direct-line-1-1-receive-messages.md). - -```http -HTTP/1.1 204 No Content -[other headers] -``` - -### Total time for the Send Message request/response - -The total time to POST a message to a Direct Line conversation is the sum of the following: - -- Transit time for the HTTP request to travel from the client to the Direct Line service -- Internal processing time within Direct Line (typically less than 120ms) -- Transit time from the Direct Line service to the bot -- Processing time within the bot -- Transit time for the HTTP response to travel back to the client - -## Send attachment(s) to the bot - -In some situations, a client may need to send attachments to the bot such as images or documents. A client may send attachments to the bot either by [specifying the URL(s)](#send-by-url) of the attachment(s) within the [Message](bot-framework-rest-direct-line-1-1-api-reference.md#message-object) object that it sends using `POST /api/conversations/{conversationId}/messages` or by [uploading attachment(s)](#upload-attachments) using `POST /api/conversations/{conversationId}/upload`. - -## Send attachment(s) by URL - -To send one or more attachments as part of the [Message](bot-framework-rest-direct-line-1-1-api-reference.md#message-object) object using `POST /api/conversations/{conversationId}/messages`, specify the attachment URL(s) within the message's `images` array and/or `attachments` array. - -## Send attachment(s) by upload - -Often, a client may have image(s) or document(s) on a device that it wants to send to the bot, but no URLs corresponding to those files. In this situation, a client can can issue a `POST /api/conversations/{conversationId}/upload` request to send attachments to the bot by upload. The format and contents of the request will depend upon whether the client is [sending a single attachment](#upload-one-attachment) or [sending multiple attachments](#upload-multiple-attachments). - -### Send a single attachment by upload - -To send a single attachment by upload, issue this request: - -```http -POST https://directline.botframework.com/api/conversations/{conversationId}/upload?userId={userId} -Authorization: Bearer SECRET_OR_TOKEN -Content-Type: TYPE_OF_ATTACHMENT -Content-Disposition: ATTACHMENT_INFO -[other headers] - -[file content] -``` - -In this request URI, replace **{conversationId}** with the ID of the conversation and **{userId}** with the ID of the user that is sending the message. In the request headers, set `Content-Type` to specify the attachment's type and set `Content-Disposition` to specify the attachment's filename. - -The following snippets provide an example of the Send (single) Attachment request and response. - -#### Request - -```http -POST https://directline.botframework.com/api/conversations/abc123/upload?userId=user1 -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0 -Content-Type: image/jpeg -Content-Disposition: name="file"; filename="badjokeeel.jpg" -[other headers] - -[JPEG content] -``` - -#### Response - -If the request is successful, a message is sent to the bot when the upload completes and the service returns an HTTP 204 status code. - -```http -HTTP/1.1 204 No Content -[other headers] -``` - -### Send multiple attachments by upload - -To send multiple attachments by upload, `POST` a multipart request to the `/api/conversations/{conversationId}/upload` endpoint. Set the `Content-Type` header of the request to `multipart/form-data` and include the `Content-Type` header and `Content-Disposition` header for each part to specify each attachment's type and filename. In the request URI, set the `userId` parameter to the ID of the user that is sending the message. - -You may include a [Message](bot-framework-rest-direct-line-1-1-api-reference.md#message-object) object within the request by adding a part that specifies the `Content-Type` header value `application/vnd.microsoft.bot.message`. This allows the client to customize the message that contains the attachment(s). If the request includes a Message, the attachments that are specified by other parts of the payload are added as attachments to that Message before it is sent. - -The following snippets provide an example of the Send (multiple) Attachments request and response. In this example, the request sends a message that contains some text and a single image attachment. Additional parts could be added to the request to include multiple attachments in this message. - -#### Request - -```http -POST https://directline.botframework.com/api/conversations/abc123/upload?userId=user1 -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0 -Content-Type: multipart/form-data; boundary=----DD4E5147-E865-4652-B662-F223701A8A89 -[other headers] - -----DD4E5147-E865-4652-B662-F223701A8A89 -Content-Type: image/jpeg -Content-Disposition: form-data; name="file"; filename="badjokeeel.jpg" -[other headers] - -[JPEG content] - -----DD4E5147-E865-4652-B662-F223701A8A89 -Content-Type: application/vnd.microsoft.bot.message -[other headers] - -{ - "text": "Hey I just IM'd you\n\nand this is crazy\n\nbut here's my webhook\n\nso POST me maybe", - "from": "user1" -} - -----DD4E5147-E865-4652-B662-F223701A8A89 -``` - -#### Response - -If the request is successful, a message is sent to the bot when the upload completes and the service returns an HTTP 204 status code. - -```http -HTTP/1.1 204 No Content -[other headers] -``` - -## Additional resources - -- [Key concepts](bot-framework-rest-direct-line-1-1-concepts.md) -- [Authentication](bot-framework-rest-direct-line-1-1-authentication.md) -- [Start a conversation](bot-framework-rest-direct-line-1-1-start-conversation.md) -- [Receive messages from the bot](bot-framework-rest-direct-line-1-1-receive-messages.md) \ No newline at end of file diff --git a/articles/rest-api/bot-framework-rest-direct-line-1-1-start-conversation.md b/articles/rest-api/bot-framework-rest-direct-line-1-1-start-conversation.md deleted file mode 100644 index 7ae924e2a..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-1-1-start-conversation.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Start a conversation using Direct Line API 1.1 - Bot Service -description: Learn how to start a conversation using Direct Line API v1.1. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Start a conversation - -> [!IMPORTANT] -> This article describes how to start a conversation using Direct Line API 1.1. If you are creating a new connection between your client application and bot, use [Direct Line API 3.0](bot-framework-rest-direct-line-3-0-start-conversation.md) instead. - -Direct Line conversations are explicitly opened by clients and may run as long as the bot and client participate and have valid credentials. While the conversation is open, both the bot and client may send messages. More than one client may connect to a given conversation and each client may participate on behalf of multiple users. - -## Open a new conversation - -To open a new conversation with a bot, issue this request: - -```http -POST https://directline.botframework.com/api/conversations -Authorization: Bearer SECRET_OR_TOKEN -``` - -The following snippets provide an example of the Start Conversation request and response. - -### Request - -```http -POST https://directline.botframework.com/api/conversations -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xn -``` - -### Response - -If the request is successful, the response will contain an ID for the conversation, a token, and a value that indicates the number of seconds until the token expires. - -```http -HTTP/1.1 200 OK -[other headers] -``` - -```json -{ - "conversationId": "abc123", - "token": "RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xn", - "expires_in": 1800 -} -``` - -## Start Conversation versus Generate Token - -The Start Conversation operation (`POST /api/conversations`) is similar to the [Generate Token](bot-framework-rest-direct-line-1-1-authentication.md#generate-token) operation (`POST /api/tokens/conversation`) in that both operations return a `token` that can be used to access a single conversation. However, the Start Conversation operation also starts the conversation and contacts the bot, whereas the Generate Token operation does neither of these things. - -If you intend to start the conversation immediately, use the Start Conversation operation. If you plan to distribute the token to clients and want them to initiate the conversation, use the [Generate Token](bot-framework-rest-direct-line-1-1-authentication.md#generate-token) operation instead. - -## Additional resources - -- [Key concepts](bot-framework-rest-direct-line-1-1-concepts.md) -- [Authentication](bot-framework-rest-direct-line-1-1-authentication.md) \ No newline at end of file diff --git a/articles/rest-api/bot-framework-rest-direct-line-3-0-api-reference.md b/articles/rest-api/bot-framework-rest-direct-line-3-0-api-reference.md deleted file mode 100644 index a8b1ae539..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-3-0-api-reference.md +++ /dev/null @@ -1,263 +0,0 @@ ---- -title: API reference - Direct Line API 3.0 - Bot Service -description: Learn about headers, HTTP status codes, schema, operations, and objects in Direct Line API 3.0. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# API reference - Direct Line API 3.0 - -You can enable your client application to communicate with your bot by using Direct Line API 3.0. Direct Line API 3.0 uses industry-standard REST and JSON over HTTPS. - -## Base URI - -To access Direct Line API 3.0, use this base URI for all API requests: - -`https://directline.botframework.com` - -## Headers - -In addition to the standard HTTP request headers, a Direct Line API request must include an `Authorization` header that specifies a secret or token to authenticate the client that is issuing the request. Specify the `Authorization` header using this format: - -```http -Authorization: Bearer SECRET_OR_TOKEN -``` - -For details about how to obtain a secret or token that your client can use to authenticate its Direct Line API requests, see [Authentication](bot-framework-rest-direct-line-3-0-authentication.md). - -## HTTP status codes - -The HTTP status code that is returned with each response indicates the outcome of the corresponding request. - -| HTTP status code | Meaning | -|----|----| -| 200 | The request succeeded. | -| 201 | The request succeeded. | -| 202 | The request has been accepted for processing. | -| 204 | The request succeeded but no content was returned. | -| 400 | The request was malformed or otherwise incorrect. | -| 401 | The client is not authorized to make the request. Often this status code occurs because the `Authorization` header is missing or malformed. | -| 403 | The client is not allowed to perform the requested operation. If the request specified a token that was previously valid but has expired, the `code` property of the [Error][] that is returned within the [ErrorResponse][] object is set to `TokenExpired`. | -| 404 | The requested resource was not found. Typically this status code indicates an invalid request URI. | -| 500 | An internal server error occurred within the Direct Line service. | -| 502 | The bot is unavailable or returned an error. **This is a common error code.** | - -> [!NOTE] -> HTTP status code 101 is used in the WebSocket connection path, although this is likely handled by your WebSocket client. - -### Errors - -Any response that specifies an HTTP status code in the 4xx range or 5xx range will include an [ErrorResponse][] object in the body of the response that provides information about the error. If you receive an error response in the 4xx range, inspect the **ErrorResponse** object to identify the cause of the error and resolve your issue prior to resubmitting the request. - -> [!NOTE] -> HTTP status codes and values specified in the `code` property inside the **ErrorResponse** object are stable. Values specified in the `message` property inside the **ErrorResponse** object may change over time. - -The following snippets show an example request and the resulting error response. - -#### Request - -```http -POST https://directline.botframework.com/v3/directline/conversations/abc123/activities -[detail omitted] -``` - -#### Response - -```http -HTTP/1.1 502 Bad Gateway -[other headers] -``` - -```json -{ - "error": { - "code": "BotRejectedActivity", - "message": "Failed to send activity: bot returned an error" - } -} -``` - -## Token operations - -Use these operations to create or refresh a token that a client can use to access a single conversation. - -| Operation | Description | -|----|----| -| [Generate Token](#generate-token) | Generate a token for a new conversation. | -| [Refresh Token](#refresh-token) | Refresh a token. | - -### Generate Token - -Generates a token that is valid for one conversation. - -```http -POST /v3/directline/tokens/generate -``` - -| | | -|----|----| -| **Request body** | A [TokenParameters](#tokenparameters-object) object | -| **Returns** | A [Conversation](#conversation-object) object | - -### Refresh Token - -Refreshes the token. - -```http -POST /v3/directline/tokens/refresh -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | A [Conversation](#conversation-object) object | - -## Conversation operations - -Use these operations to open a conversation with your bot and exchange activities between client and bot. - -| Operation | Description | -|----|----| -| [Start Conversation](#start-conversation) | Opens a new conversation with the bot. | -| [Get Conversation Information](#get-conversation-information) | Gets information about an existing conversation. This operation generates a new WebSocket stream URL that a client may use to [reconnect](bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md) to a conversation. | -| [Get Activities](#get-activities) | Retrieves activities from the bot. | -| [Send an Activity](#send-an-activity) | Sends an activity to the bot. | -| [Upload and Send File(s)](#upload-and-send-files) | Uploads and sends file(s) as attachment(s). | - -### Start Conversation - -Opens a new conversation with the bot. - -```http -POST /v3/directline/conversations -``` - -| | | -|----|----| -| **Request body** | A [TokenParameters](#tokenparameters-object) object | -| **Returns** | A [Conversation](#conversation-object) object | - -### Get Conversation Information - -Gets information about an existing conversation and also generates a new WebSocket stream URL that a client may use to [reconnect](bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md) to a conversation. You may optionally supply the `watermark` parameter in the request URI to indicate the most recent message seen by the client. - -```http -GET /v3/directline/conversations/{conversationId}?watermark={watermark_value} -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | A [Conversation](#conversation-object) object | - -### Get Activities - -Retrieves activities from the bot for the specified conversation. You may optionally supply the `watermark` parameter in the request URI to indicate the most recent message seen by the client. - -```http -GET /v3/directline/conversations/{conversationId}/activities?watermark={watermark_value} -``` - -| | | -|----|----| -| **Request body** | n/a | -| **Returns** | An [ActivitySet](#activityset-object) object. The response contains `watermark` as a property of the `ActivitySet` object. Clients should page through the available activities by advancing the `watermark` value until no activities are returned. | - -### Send an Activity - -Sends an activity to the bot. - -```http -POST /v3/directline/conversations/{conversationId}/activities -``` - -| | | -|----|----| -| **Request body** | An [Activity][] object | -| **Returns** | A [ResourceResponse][] that contains an `id` property which specifies the ID of the Activity that was sent to the bot. | - -### Upload and Send File(s) - -Uploads and sends file(s) as attachment(s). Set the `userId` parameter in the request URI to specify the ID of the user that is sending the attachment(s). - -```http -POST /v3/directline/conversations/{conversationId}/upload?userId={userId} -``` - -| | | -|----|----| -| **Request body** | For a single attachment, populate the request body with the file contents. For multiple attachments, create a multipart request body that contains one part for each attachment, and also (optionally) one part for the [Activity][] object that should serve as the container for the specified attachment(s). For more information, see [Send an activity to the bot](bot-framework-rest-direct-line-3-0-send-activity.md). | -| **Returns** | A [ResourceResponse][] that contains an `id` property which specifies the ID of the Activity that was sent to the bot. | - -> [!NOTE] -> Uploaded files are deleted after 24 hours. - -## Schema - -The Direct Line 3.0 schema includes all of the objects that are defined by the [Bot Framework schema](bot-framework-rest-connector-api-reference.md#schema) as well as some objects that are specific to Direct Line. - -### ActivitySet object - -Defines a set of activities. - -| Property | Type | Description | -|----|----|----| -| **activities** | [Activity][][] | Array of **Activity** objects. | -| **watermark** | string | Maximum watermark of activities within the set. A client may use the `watermark` value to indicate the most recent message it has seen either when [retrieving activities from the bot](bot-framework-rest-direct-line-3-0-receive-activities.md#http-get) or when [generating a new WebSocket stream URL](bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md). | - -### Conversation object - -Defines a Direct Line conversation. - -| Property | Type | Description | -|----|----|----| -| **conversationId** | string | ID that uniquely identifies the conversation for which the specified token is valid. | -| **eTag** | string | An HTTP ETag (entity tag). | -| **expires_in** | number | Number of seconds until the token expires. | -| **referenceGrammarId** | string | ID for the reference grammar for this bot. | -| **streamUrl** | string | URL for the conversation's message stream. | -| **token** | string | Token that is valid for the specified conversation. | - -### TokenParameters object - -Parameters for creating a token. - -| Property | Type | Description | -|----|----|----| -| **eTag** | string | An HTTP ETag (entity tag). | -| **trustedOrigins** | string[] | Trusted origins to embed within the token. | -| **user** | [ChannelAccount][] | User account to embed within the token. | - -## Activities - -For each [Activity][] that a client receives from a bot via Direct Line: - -- Attachment cards are preserved. -- URLs for uploaded attachments are hidden with a private link. -- The `channelData` property is preserved without modification. - -Clients may [receive](bot-framework-rest-direct-line-3-0-receive-activities.md) multiple activities from the bot as part of an [ActivitySet](#activityset-object). - -When a client sends an `Activity` to a bot via Direct Line: - -- The `type` property specifies the type activity it is sending (typically **message**). -- The `from` property must be populated with a user ID, chosen by the client. -- Attachments may contain URLs to existing resources or URLs uploaded through the Direct Line attachment endpoint. -- The `channelData` property is preserved without modification. -- The total size of the activity, when serialized to JSON and encrypted, must not exceed 256K characters. Therefore it is recommended that activities are kept under 150K. If more data is needed consider breaking the activity into multiple and/or consider using attachments. - -Clients may [send](bot-framework-rest-direct-line-3-0-send-activity.md) a single activity per request. - -## Additional resources - -- [Bot Framework Activity spec](https://aka.ms/botSpecs-activitySchema) - -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object -[ChannelAccount]: bot-framework-rest-connector-api-reference.md#channelaccount-object -[Error]: bot-framework-rest-connector-api-reference.md#error-object -[ErrorResponse]: bot-framework-rest-connector-api-reference.md#errorresponse-object -[ResourceResponse]: bot-framework-rest-connector-api-reference.md#resourceresponse-object diff --git a/articles/rest-api/bot-framework-rest-direct-line-3-0-authentication.md b/articles/rest-api/bot-framework-rest-direct-line-3-0-authentication.md deleted file mode 100644 index 68eea67c6..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-3-0-authentication.md +++ /dev/null @@ -1,279 +0,0 @@ ---- -title: Authentication - Bot Service -description: Learn how to authenticate API requests in Direct Line API v3.0. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 08/22/2019 ---- - -# Authentication - -A client can authenticate requests to Direct Line API 3.0 either by using a **secret** that you [obtain from the Direct Line channel configuration page](../bot-service-channel-connect-directline.md) in the Bot Framework Portal or by using a **token** that you obtain at runtime. The secret or token should be specified in the `Authorization` header of each request, using this format: - -```http -Authorization: Bearer SECRET_OR_TOKEN -``` - -## Secrets and tokens - -A Direct Line **secret** is a master key that can be used to access any conversation that belongs to the associated bot. A **secret** can also be used to obtain a **token**. Secrets do not expire. - -A Direct Line **token** is a key that can be used to access a single conversation. A token expires but can be refreshed. - -Deciding when or if to use the **secret** key or a **token** must be based on security considerations. -Exposing the secret key could be acceptable if done intentionally and with care. As matter of a fact, this is the default behavior because allows Direct Line to figure out if the client is legitimate. -Generally speaking though, security is a concern if you're trying to persist user data. -For more information, see section [Security considerations](#security-considerations). - -If you're creating a service-to-service application, specifying the **secret** in the `Authorization` header of Direct Line API requests may be simplest approach. If you're writing an application where the client runs in a web browser or mobile app, you may want to exchange your secret for a token (which only works for a single conversation and will expire unless refreshed) and specify the **token** in the `Authorization` header of Direct Line API requests. Choose the security model that works best for you. - -> [!NOTE] -> Your Direct Line client credentials are different from your bot's credentials. This enables you to revise your keys independently and lets you share client tokens without disclosing your bot's password. - -## Get a Direct Line secret - -You can [obtain a Direct Line secret](../bot-service-channel-connect-directline.md) via the Direct Line channel configuration page for your bot in the [Azure Portal](https://portal.azure.com): - -![Direct Line configuration](../media/direct-line-configure.png) - -## Generate a Direct Line token - -To generate a Direct Line token that can be used to access a single conversation, first obtain the Direct Line secret from the Direct Line channel configuration page in the [Azure Portal](https://portal.azure.com). Then issue this request to exchange your Direct Line secret for a Direct Line token: - -```http -POST https://directline.botframework.com/v3/directline/tokens/generate -Authorization: Bearer SECRET -``` - -In the `Authorization` header of this request, replace **SECRET** with the value of your Direct Line secret. - -The following snippets provide an example of the Generate Token request and response. - -### Request - -```http -POST https://directline.botframework.com/v3/directline/tokens/generate -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0 -``` - -The request payload, which contains the token parameters, is optional but recommended. When generating a token that can be sent back to the Direct Line service, provide the following payload to make the connection more secure. By including these values, Direct Line can perform additional security validation of the user ID and name, inhibiting tampering of these values by malicious clients. Including these values also improves Direct Line's ability to send the _conversation update_ activity, allowing it to generate the conversation update immediately upon the user joining the conversation. When this information is not provided, the user must send content before Direct Line can send the conversation update. - -```json -{ - "user": { - "id": "string", - "name": "string" - }, - "trustedOrigins": [ - "string" - ] -} -``` - -| Parameter | Type | Description | -| :--- | :--- | :--- | -| `user.id` | string | Optional. Channel-specific ID of the user to encode within the token. For a Direct Line user, this must begin with `dl_`. You can create a unique user ID for each conversation, and for better security, you should make this ID unguessable. | -| `user.name` | string | Optional. The display-friendly name of the user to encode within the token. | -| `trustedOrigins` | string array | Optional. A list of trusted domains to embed within the token. These are the domains that can host the bot's Web Chat client. This should match the list in the Direct Line configuration page for your bot. | - -### Response - -If the request is successful, the response contains a `token` that is valid for one conversation and an `expires_in` value that indicates the number of seconds until the token expires. For the token to remain useful, you must [refresh the token](#refresh-token) before it expires. - -```http -HTTP/1.1 200 OK -[other headers] -``` - -```json -{ - "conversationId": "abc123", - "token": "RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xn", - "expires_in": 1800 -} -``` - -### Generate Token versus Start Conversation - -The Generate Token operation (`POST /v3/directline/tokens/generate`) is similar to the [Start Conversation](bot-framework-rest-direct-line-3-0-start-conversation.md) operation (`POST /v3/directline/conversations`) in that both operations return a `token` that can be used to access a single conversation. However, unlike the Start Conversation operation, the Generate Token operation does not start the conversation, does not contact the bot, and does not create a streaming WebSocket URL. - -If you plan to distribute the token to clients and want them to initiate the conversation, use the Generate Token operation. If you intend to start the conversation immediately, use the [Start Conversation](bot-framework-rest-direct-line-3-0-start-conversation.md) operation instead. - -## Refresh a Direct Line token - -A Direct Line token can be refreshed an unlimited amount of times, as long as it has not expired. An expired token cannot be refreshed. To refresh a Direct Line token, issue this request: - -```http -POST https://directline.botframework.com/v3/directline/tokens/refresh -Authorization: Bearer TOKEN_TO_BE_REFRESHED -``` - -In the `Authorization` header of this request, replace **TOKEN_TO_BE_REFRESHED** with the Direct Line token that you want to refresh. - -The following snippets provide an example of the Refresh Token request and response. - -### Request - -```http -POST https://directline.botframework.com/v3/directline/tokens/refresh -Authorization: Bearer CurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xn -``` - -### Response - -If the request is successful, the response contains a new `token` that is valid for the same conversation as the previous token and an `expires_in` value that indicates the number of seconds until the new token expires. For the new token to remain useful, you must [refresh the token](#refresh-token) before it expires. - -```http -HTTP/1.1 200 OK -[other headers] -``` - -```json -{ - "conversationId": "abc123", - "token": "RCurR_XV9ZA.cwA.BKA.y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xniaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0", - "expires_in": 1800 -} -``` - -## Azure Bot Service authentication - -The information presented in this section is based on the [Add authentication to your bot via Azure Bot Service](../v4sdk/bot-builder-authentication.md) article. - -**Azure Bot Service authentication** enables you to authenticate users to and get **access tokens** from a variety of identity providers such as *Azure Active Directory*, *GitHub*, *Uber* and so on. You can also configure authentication for a custom **OAuth2** identity provider. All this enables you to write **one piece of authentication code** that works across all supported identity providers and channels. To utilize these capabilities you need to perform the following steps: - -1. Statically configure `settings` on your bot that contains the details of your application registration with an identity provider. -2. Use an `OAuthCard`, backed by the application information you supplied in the previous step, to sign-in a user. -3. Retrieve access tokens through **Azure Bot Service API**. - -### Security considerations - - - -When you use *Azure Bot Service authentication* with [Web Chat](../bot-service-channel-connect-webchat.md) there are some important security considerations you must keep in mind. - -1. **Impersonation**. Impersonation here means an attacker makes the bot thinks he is someone else. In Web Chat, an attacker can impersonate someone else by **changing the user ID** of his Web Chat instance. To prevent this, it is recommend to bot developers to make the **user ID unguessable**. - - If you enable **enhanced authentication** options, Azure Bot Service can further detect and reject any user ID change. This means the user ID (`Activity.From.Id`) on messages from Direct Line to your bot will always be the same as the one you initialized the Web Chat with. Note that this feature requires the user ID starts with `dl_`. - - > [!NOTE] - > When a *User.Id* is provided while exchanging a secret for a token, that *User.Id* is embedded in the token. DirectLine males sure the messages sent to the bot have that id as the activity's *From.Id*. If a client sends a message to DirectLine having a different *From.Id*, it will be changed to the **Id in the token** before forwarding the message to the bot. So you cannot use another user id after a channel secret is initialized with a user id - -1. **User identities**. You must be aware that your are dealing with two user identities: - - 1. The user’s identity in a channel. - 1. The user’s identity in an identity provider that the bot is interested in. - - When a bot asks user A in a channel to sign-in to an identity provider P, the sign-in process must assure that user A is the one that signs into P. - If another user B is allowed to sign-in, then user A would have access to user B’s resource through the bot. In Web Chat we have 2 mechanisms for ensuring the right user signed in as described next. - - 1. At the end of sign-in, in the past, the user was presented with a randomly generated 6-digit code (aka magic code). The user must type this code in the conversation that initiated the sign-in to complete the sign-in process. This mechanism tends to result in a bad user experience. Additionally, it is still susceptible to phishing attacks. A malicious user can trick another user to sign-in and obtain the magic code through phishing. - - 2. Because of the issues with the previous approach, Azure Bot Service removed the need for the magic code. Azure Bot Service guarantees that the sign-in process can only be completed in the **same browser session** as the Web Chat itself. - To enable this protection, as a bot developer, you must start Web Chat with a **Direct Line token** that contains a **list of trusted domains that can host the bot’s Web Chat client**. Before, you could only obtain this token by passing an undocumented optional parameter to the Direct Line token API. Now, with enhanced authentication options, you can statically specify the trusted domain (origin) list in the Direct Line configuration page. - - See also [Add authentication to your bot via Azure Bot Service](../v4sdk/bot-builder-authentication.md). - -### Code examples - -The following .NET controller works with enhanced authentication options enabled and returns a Direct Line Token and user ID. - -```csharp -public class HomeController : Controller -{ - public async Task Index() - { - var secret = GetSecret(); - - HttpClient client = new HttpClient(); - - HttpRequestMessage request = new HttpRequestMessage( - HttpMethod.Post, - $"https://directline.botframework.com/v3/directline/tokens/generate"); - - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", secret); - - var userId = $"dl_{Guid.NewGuid()}"; - - request.Content = new StringContent( - JsonConvert.SerializeObject( - new { User = new { Id = userId } }), - Encoding.UTF8, - "application/json"); - - var response = await client.SendAsync(request); - string token = String.Empty; - - if (response.IsSuccessStatusCode) - { - var body = await response.Content.ReadAsStringAsync(); - token = JsonConvert.DeserializeObject(body).token; - } - - var config = new ChatConfig() - { - Token = token, - UserId = userId - }; - - return View(config); - } -} - -public class DirectLineToken -{ - public string conversationId { get; set; } - public string token { get; set; } - public int expires_in { get; set; } -} -public class ChatConfig -{ - public string Token { get; set; } - public string UserId { get; set; } -} - -``` - -The following JavaScript controller works with enhanced authentication options enabled and returns a Direct Line Token and user ID. - -```javascript -var router = express.Router(); // get an instance of the express Router - -// Get a directline configuration (accessed at GET /api/config) -const userId = "dl_" + createUniqueId(); - -router.get('/config', function(req, res) { - const options = { - method: 'POST', - uri: 'https://directline.botframework.com/v3/directline/tokens/generate', - headers: { - 'Authorization': 'Bearer ' + secret - }, - json: { - User: { Id: userId } - } - }; - - request.post(options, (error, response, body) => { - if (!error && response.statusCode < 300) { - res.json({ - token: body.token, - userId: userId - }); - } - else { - res.status(500).send('Call to retrieve token from Direct Line failed'); - } - }); -}); - -``` - -## Additional resources - -- [Key concepts](bot-framework-rest-direct-line-3-0-concepts.md) -- [Connect a bot to Direct Line](../bot-service-channel-connect-directline.md) -- [Add authentication to your bot via Azure Bot Service](../bot-builder-tutorial-authentication.md) diff --git a/articles/rest-api/bot-framework-rest-direct-line-3-0-concepts.md b/articles/rest-api/bot-framework-rest-direct-line-3-0-concepts.md deleted file mode 100644 index fdb10b574..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-3-0-concepts.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: Key concepts in the Bot Framework Direct Line API 3.0 - Bot Service -description: Understand key concepts in the Bot Framework Direct Line API 3.0. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/06/2019 ---- - -# Key concepts in Direct Line API 3.0 - -You can enable communication between your bot and your own client application by using the Direct Line API. This article introduces key concepts in Direct Line API 3.0 and provides information about relevant developer resources. - -## Authentication - -Direct Line API 3.0 requests can be authenticated either by using a **secret** that you obtain from the Direct Line channel configuration page in the [Azure Portal](https://portal.azure.com) or by using a **token** that you obtain at runtime. For more information, see [Authentication](bot-framework-rest-direct-line-3-0-authentication.md). - -## Starting a conversation - -Direct Line conversations are explicitly opened by clients and may run as long as the bot and client participate and have valid credentials. For more information, see [Start a conversation](bot-framework-rest-direct-line-3-0-start-conversation.md). - -## Sending messages - -Using Direct Line API 3.0, a client can send messages to your bot by issuing `HTTP POST` requests. A client may send a single message per request. For more information, see [Send an activity to the bot](bot-framework-rest-direct-line-3-0-send-activity.md). - -## Receiving messages - -Using Direct Line API 3.0, a client can receive messages from your bot either via `WebSocket` stream or by issuing `HTTP GET` requests. Using either of these techniques, a client may receive multiple messages from the bot at a time as part of an `ActivitySet`. For more information, see [Receive activities from the bot](bot-framework-rest-direct-line-3-0-receive-activities.md). - -## Developer resources - -### Client libraries - -The Bot Framework provides client libraries that facilitate access to Direct Line API 3.0 via C# and Node.js. - -- To use the .NET client library within a Visual Studio project, install the `Microsoft.Bot.Connector.DirectLine` NuGet package. - -- To use the Node.js client library, install the `botframework-directlinejs` library using NPM (or download the source). - -::: moniker range="azure-bot-service-3.0" - -### Sample code - -The BotBuilder-Samples GitHub repo contains multiple samples that show how to use Direct Line API 3.0 with C# and Node.js. - -| Sample | Language | Description | -|----|----|----| -| Direct Line Bot Sample | C# | A sample bot and a custom client communicating to each other using the Direct Line API. | -| Direct Line Bot Sample (using client WebSockets) | C# | A sample bot and a custom client communicating to each other using the Direct Line API and WebSockets. | -| Direct Line Bot Sample | JavaScript | A sample bot and a custom client communicating to each other using the Direct Line API. | -| Direct Line Bot Sample (using client WebSockets) | JavaScript | A sample bot and a custom client communicating to each other using the Direct Line API and WebSockets. | - -::: moniker-end - -### Web chat control - -The Bot Framework provides a control that enables you to embed a Direct-Line-powered bot into your client application. For more information, see the Microsoft Bot Framework WebChat control. diff --git a/articles/rest-api/bot-framework-rest-direct-line-3-0-end-conversation.md b/articles/rest-api/bot-framework-rest-direct-line-3-0-end-conversation.md deleted file mode 100644 index 5b81add46..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-3-0-end-conversation.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: End a conversation - Bot Service -description: Learn how to end a conversation using Direct Line API v3.0. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# End a conversation - -The **endOfConversation** [activity](https://aka.ms/botSpecs-activitySchema) means the channel or bot has ended the conversation. - -> [!NOTE] -> While the **endOfConversation** event is only sent by very few channels, the Cortana channel is the only one that accepts it. Other channels, including Direct Line, do not implement this functionality and instead drop or forward the activity on; each channel determines how to react to an endOfConversation activity. If you are designing a DirectLine client, you would update the client to behave appropriately, such as generating an error if the bot sent an activity to a conversation that has already ended. - -## Send an endOfConversation activity - -An **endOfConversation** activity ends communication between bot and client. After an **endOfConversation** activity has been sent, the client may still [retrieve messages](bot-framework-rest-direct-line-3-0-receive-activities.md#http-get) using `HTTP GET`, but neither the client nor the bot can send any additional messages to the conversation. - -To end a conversation, simply issue a POST request to send an **endOfConversation** activity. - -### Request - -```http -POST https://directline.botframework.com/v3/directline/conversations/abc123/activities -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0 -[other headers] -``` - -```json -{ - "type": "endOfConversation", - "from": { - "id": "user1" - } -} -``` - -### Response - -If the request is successful, the response will contain an ID for the activity that was sent. - -```http -HTTP/1.1 200 OK -[other headers] -``` - -```json -{ - "id": "0004" -} -``` - -## Additional resources - -- [Key concepts](bot-framework-rest-direct-line-3-0-concepts.md) -- [Authentication](bot-framework-rest-direct-line-3-0-authentication.md) -- [Send an activity to the bot](bot-framework-rest-direct-line-3-0-send-activity.md) diff --git a/articles/rest-api/bot-framework-rest-direct-line-3-0-receive-activities.md b/articles/rest-api/bot-framework-rest-direct-line-3-0-receive-activities.md deleted file mode 100644 index 0bc0f48d4..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-3-0-receive-activities.md +++ /dev/null @@ -1,173 +0,0 @@ ---- -title: Receive activities from the bot - Bot Service -description: Learn how to receive activities from the bot using Direct Line API v3.0. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 06/13/2019 ---- - -# Receive activities from the bot - -Using the Direct Line 3.0 protocol, clients can receive activities via `WebSocket` stream or retrieve activities by issuing `HTTP GET` requests. - -## WebSocket vs HTTP GET - -A streaming WebSocket efficiently pushes messages to clients, whereas the GET interface enables clients to explicitly request messages. Although the WebSocket mechanism is often preferred due to its efficiency, the GET mechanism can be useful for clients that are unable to use WebSockets. - -The service allows only 1 WebSocket connection per conversation. Direct Line may close additional WebSocket connections with a reason value of `collision`. - -Not all [activity types](https://aka.ms/botSpecs-activitySchema) are available both via WebSocket and via HTTP GET. The following table describes the availability of the various activity types for clients that use the Direct Line protocol. - -| Activity type | Availability | -|----|----| -| message | HTTP GET and WebSocket | -| typing | WebSocket only | -| conversationUpdate | Not sent/received via client | -| contactRelationUpdate | Not supported in Direct Line | -| endOfConversation | HTTP GET and WebSocket | -| all other activity types | HTTP GET and WebSocket | - -## Receive activities via WebSocket stream - -When a client sends a [Start Conversation](bot-framework-rest-direct-line-3-0-start-conversation.md) request to open a conversation with a bot, the service's response includes a `streamUrl` property that the client can subsequently use to connect via WebSocket. The stream URL is preauthorized and therefore the client's request to connect via WebSocket does NOT require an `Authorization` header. - -The following example shows a request that uses a `streamUrl` to connect via WebSocket. - -```http --- connect to wss://directline.botframework.com -- -GET /v3/directline/conversations/abc123/stream?t=RCurR_XV9ZA.cwA..." -Upgrade: websocket -Connection: upgrade -[other headers] -``` - -The service responds with status code HTTP 101 ("Switching Protocols"). - -```http -HTTP/1.1 101 Switching Protocols -[other headers] -``` - -### Receive messages - -After it connects via WebSocket, a client may receive these types of messages from the Direct Line service: - -- A message that contains an [ActivitySet](bot-framework-rest-direct-line-3-0-api-reference.md#activityset-object) that includes one or more activities and a watermark (described below). -- An empty message, which the Direct Line service uses to ensure the connection is still valid. -- Additional types, to be defined later. These types are identified by the properties in the JSON root. - -An `ActivitySet` contains messages sent by the bot and by all users in the conversation. The following example shows an `ActivitySet` that contains a single message. - -```json -{ - "activities": [ - { - "type": "message", - "channelId": "directline", - "conversation": { - "id": "abc123" - }, - "id": "abc123|0000", - "from": { - "id": "user1" - }, - "text": "hello" - } - ], - "watermark": "0000a-42" -} -``` - -### Process messages - -A client should keep track of the `watermark` value that it receives in each [ActivitySet](bot-framework-rest-direct-line-3-0-api-reference.md#activityset-object), so that it may use the watermark to guarantee that no messages are lost if it loses its connection and needs to [reconnect to the conversation](bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md). If the client receives an `ActivitySet` wherein the `watermark` property is `null` or missing, it should ignore that value and not overwrite the prior watermark that it received. - -A client should ignore empty messages that it receives from the Direct Line service. - -A client may send empty messages to the Direct Line service to verify connectivity. The Direct Line service will ignore empty messages that it receives from the client. - -The Direct Line service may forcibly close the WebSocket connection under certain conditions. If the client has not received an `endOfConversation` activity, it may [generate a new WebSocket stream URL](bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md) that it can use to reconnect to the conversation. - -The WebSocket stream contains live updates and very recent messages (since the call to connect via WebSocket was issued) but it does not include messages that were sent prior to the most recent `POST` to `/v3/directline/conversations/{id}`. To retrieve messages that were sent earlier in the conversation, use `HTTP GET` as described below. - -## Retrieve activities with HTTP GET - -Clients that are unable to use WebSockets can retrieve activities by using `HTTP GET`. - -To retrieve messages for a specific conversation, issue a `GET` request to the `/v3/directline/conversations/{conversationId}/activities` endpoint, optionally specifying the `watermark` parameter to indicate the most recent message seen by the client. - -The following snippets provide an example of the Get Conversation Activities request and response. The Get Conversation Activities response contains `watermark` as a property of the [ActivitySet](bot-framework-rest-direct-line-3-0-api-reference.md#activityset-object). Clients should page through the available activities by advancing the `watermark` value until no activities are returned. - -### Request - -```http -GET https://directline.botframework.com/v3/directline/conversations/abc123/activities?watermark=0001a-94 -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0 -``` - -### Response - -```http -HTTP/1.1 200 OK -[other headers] -``` - -```json -{ - "activities": [ - { - "type": "message", - "channelId": "directline", - "conversation": { - "id": "abc123" - }, - "id": "abc123|0000", - "from": { - "id": "user1" - }, - "text": "hello" - }, - { - "type": "message", - "channelId": "directline", - "conversation": { - "id": "abc123" - }, - "id": "abc123|0001", - "from": { - "id": "bot1" - }, - "text": "Nice to see you, user1!" - } - ], - "watermark": "0001a-95" -} -``` - -## Timing considerations - -Most clients wish to retain a complete message history. Even though Direct Line is a multi-part protocol with potential timing gaps, the protocol and service is designed to make it easy to build a reliable client. - -- The `watermark` property that is sent in the WebSocket stream and Get Conversation Activities response is reliable. A client will not miss any messages as long as it replays the watermark verbatim. - -- When a client starts a conversation and connects to the WebSocket stream, any activities that are sent after the POST but before the socket is opened are replayed before new activities. - -- When a client issues a Get Conversation Activities request (to refresh history) while it is connected to the WebSocket stream, activities may be duplicated across both channels. Clients should keep track of all known activity IDs so that they are able to reject duplicate activities, should they occur. - -Clients that poll using `HTTP GET` should choose a polling interval that matches their intended use. - -- Service-to-service applications often use a polling interval of 5s or 10s. - -- Client-facing applications often use a polling interval of 1s, and issue a single additional request shortly after every message that the client sends (to rapidly retrieve a bot's response). This delay can be as short at 300ms but should be tuned based on the bot's speed and transit time. Polling should not be more frequent than once per second for any extended period of time. - -## Additional resources - -- [Key concepts](bot-framework-rest-direct-line-3-0-concepts.md) -- [Authentication](bot-framework-rest-direct-line-3-0-authentication.md) -- [Start a conversation](bot-framework-rest-direct-line-3-0-start-conversation.md) -- [Reconnect to a conversation](bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md) -- [Send an activity to the bot](bot-framework-rest-direct-line-3-0-send-activity.md) -- [End a conversation](bot-framework-rest-direct-line-3-0-end-conversation.md) diff --git a/articles/rest-api/bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md b/articles/rest-api/bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md deleted file mode 100644 index c6acf1e48..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Reconnect to a conversation - Bot Service -description: Learn how to reconnect to a conversation using Direct Line API v3.0. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 2/09/2019 ---- - -# Reconnect to a conversation - -If a client is using the [WebSocket interface](bot-framework-rest-direct-line-3-0-receive-activities.md#connect-via-websocket) to receive messages but loses its connection, it may need to reconnect. In this scenario, the client must generate a new WebSocket stream URL that it can use to reconnect to the conversation. - -## Generate a new WebSocket stream URL - -To generate a new WebSocket stream URL that can be used to reconnect to an existing conversation, issue this request: - -```http -GET https://directline.botframework.com/v3/directline/conversations/{conversationId}?watermark={watermark_value} -Authorization: Bearer SECRET_OR_TOKEN -``` - -In this request URI, replace **{conversationId}** with the conversation ID and replace **{watermark_value}** with the watermark value (if the `watermark` parameter is supplied). The `watermark` parameter is optional. If the `watermark` parameter is specified in the request URI, the conversation replays from the watermark, guaranteeing that no messages are lost. If the `watermark` parameter is omitted from the request URI, only messages received after the reconnection request are replayed. - -The following snippets provide an example of the Reconnect request and response. - -### Request - -```http -GET https://directline.botframework.com/v3/directline/conversations/abc123?watermark=0000a-42 -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xn -``` - -### Response - -If the request is successful, the response will contain an ID for the conversation, a token, and a new WebSocket stream URL. - -```http -HTTP/1.1 200 OK -[other headers] -``` - -```json -{ - "conversationId": "abc123", - "token": "RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xn", - "streamUrl": "https://directline.botframework.com/v3/directline/conversations/abc123/stream?watermark=000a-4&t=RCurR_XV9ZA.cwA..." -} -``` - -## Reconnect to the conversation - -The client must use the new WebSocket stream URL to [reconnect to the conversation](bot-framework-rest-direct-line-3-0-receive-activities.md#connect-via-websocket) within 60 seconds. If the connection cannot be established during this time, the client must issue another Reconnect request to generate a new stream URL. - -If you have "Enhanced authentication option" enabled in the Direct Line settings, you might get a 400 "MissingProperty" error saying no user ID specified. - -## Additional resources - -- [Key concepts](bot-framework-rest-direct-line-3-0-concepts.md) -- [Authentication](bot-framework-rest-direct-line-3-0-authentication.md) -- [Receive activities via WebSocket stream](bot-framework-rest-direct-line-3-0-receive-activities.md#connect-via-websocket) diff --git a/articles/rest-api/bot-framework-rest-direct-line-3-0-send-activity.md b/articles/rest-api/bot-framework-rest-direct-line-3-0-send-activity.md deleted file mode 100644 index 560da5a46..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-3-0-send-activity.md +++ /dev/null @@ -1,192 +0,0 @@ ---- -title: Send an activity the bot - Bot Service -description: Learn how to send an activity to the bot using Direct Line API v3.0. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Send an activity to the bot - -Using the Direct Line 3.0 protocol, clients and bots may exchange several different types of [activities](https://aka.ms/botSpecs-activitySchema), including **message** activities, **typing** activities, and custom activities that the bot supports. A client may send a single activity per request. - -## Send an activity - -To send an activity to the bot, the client must create an [Activity][] object to define the activity and then issue a `POST` request to `https://directline.botframework.com/v3/directline/conversations/{conversationId}/activities`, specifying the Activity object in the body of the request. - -The following snippets provide an example of the Send Activity request and response. - -### Request - -```http -POST https://directline.botframework.com/v3/directline/conversations/abc123/activities -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0 -Content-Type: application/json -[other headers] -``` - -```json -{ - "type": "message", - "from": { - "id": "user1" - }, - "text": "hello" -} -``` - -### Response - -When the activity is delivered to the bot, the service responds with an HTTP status code that reflects the bot's status code. If the bot generates an error, an HTTP 502 response ("Bad Gateway") is returned to the client in response to its Send Activity request. - -> [!NOTE] -> This can be caused by the fact that a correct token was not used. Only the token which was received against *start conversation* can be used to send an activity. - -If the POST is successful, the response contains a JSON payload that specifies the ID of the Activity that was sent to the bot. - -```http -HTTP/1.1 200 OK -[other headers] -``` - -```json -{ - "id": "0001" -} -``` - -### Total time for the Send Activity request/response - -The total time to POST a message to a Direct Line conversation is the sum of the following: - -- Transit time for the HTTP request to travel from the client to the Direct Line service -- Internal processing time within Direct Line (typically less than 120ms) -- Transit time from the Direct Line service to the bot -- Processing time within the bot -- Transit time for the HTTP response to travel back to the client - -## Send attachment(s) to the bot - -In some situations, a client may need to send attachments to the bot such as images or documents. A client may send attachments to the bot either by [specifying the URL(s)](#send-by-url) of the attachment(s) within the [Activity][] object that it sends using `POST /v3/directline/conversations/{conversationId}/activities` or by [uploading attachment(s)](#upload-attachments) using `POST /v3/directline/conversations/{conversationId}/upload`. - -## Send attachment(s) by URL - -To send one or more attachments as part of the [Activity][] object using `POST /v3/directline/conversations/{conversationId}/activities`, simply include one or more [Attachment][] objects within the Activity object and set the `contentUrl` property of each Attachment object to specify the HTTP, HTTPS, or `data` URI of the attachment. - -## Send attachment(s) by upload - -Often, a client may have image(s) or document(s) on a device that it wants to send to the bot, but no URLs corresponding to those files. In this situation, a client can can issue a `POST /v3/directline/conversations/{conversationId}/upload` request to send attachments to the bot by upload. The format and contents of the request will depend upon whether the client is [sending a single attachment](#upload-one-attachment) or [sending multiple attachments](#upload-multiple-attachments). - -### Send a single attachment by upload - -To send a single attachment by upload, issue this request: - -```http -POST https://directline.botframework.com/v3/directline/conversations/{conversationId}/upload?userId={userId} -Authorization: Bearer SECRET_OR_TOKEN -Content-Type: TYPE_OF_ATTACHMENT -Content-Disposition: ATTACHMENT_INFO -[other headers] - -[file content] -``` - -In this request URI, replace **{conversationId}** with the ID of the conversation and **{userId}** with the ID of the user that is sending the message. The `userId` parameter is required. In the request headers, set `Content-Type` to specify the attachment's type and set `Content-Disposition` to specify the attachment's filename. - -The following snippets provide an example of the Send (single) Attachment request and response. - -#### Request - -```http -POST https://directline.botframework.com/v3/directline/conversations/abc123/upload?userId=user1 -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0 -Content-Type: image/jpeg -Content-Disposition: name="file"; filename="badjokeeel.jpg" -[other headers] - -[JPEG content] -``` - -#### Response - -If the request is successful, a **message** Activity is sent to the bot when the upload completes and the response that the client receives will contain the ID of the Activity that was sent. - -```http -HTTP/1.1 200 OK -[other headers] -``` - -```json -{ - "id": "0003" -} -``` - -### Send multiple attachments by upload - -To send multiple attachments by upload, `POST` a multipart request to the `/v3/directline/conversations/{conversationId}/upload` endpoint. Set the `Content-Type` header of the request to `multipart/form-data` and include the `Content-Type` header and `Content-Disposition` header for each part to specify each attachment's type and filename. In the request URI, set the `userId` parameter to the ID of the user that is sending the message. - -You may include an `Activity` object within the request by adding a part that specifies the `Content-Type` header value `application/vnd.microsoft.activity`. If the request includes an Activity, the attachments that are specified by other parts of the payload are added as attachments to that Activity before it is sent. If the request does not include an Activity, an empty Activity is created to serve as the container in which the specified attachments are sent. - -The following snippets provide an example of the Send (multiple) Attachments request and response. In this example, the request sends a message that contains some text and a single image attachment. Additional parts could be added to the request to include multiple attachments in this message. - -#### Request - -```http -POST https://directline.botframework.com/v3/directline/conversations/abc123/upload?userId=user1 -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0 -Content-Type: multipart/form-data; boundary=----DD4E5147-E865-4652-B662-F223701A8A89 -[other headers] - -----DD4E5147-E865-4652-B662-F223701A8A89 -Content-Type: image/jpeg -Content-Disposition: form-data; name="file"; filename="badjokeeel.jpg" -[other headers] - -[JPEG content] - -----DD4E5147-E865-4652-B662-F223701A8A89 -Content-Type: application/vnd.microsoft.activity -[other headers] - -{ - "type": "message", - "from": { - "id": "user1" - }, - "text": "Hey I just IM'd you\n\nand this is crazy\n\nbut here's my webhook\n\nso POST me maybe" -} - -----DD4E5147-E865-4652-B662-F223701A8A89 -``` - -#### Response - -If the request is successful, a message Activity is sent to the bot when the upload completes and the response that the client receives will contain the ID of the Activity that was sent. - -```http -HTTP/1.1 200 OK -[other headers] -``` - -```json -{ - "id": "0004" -} -``` - -## Additional resources - -- [Key concepts](bot-framework-rest-direct-line-3-0-concepts.md) -- [Authentication](bot-framework-rest-direct-line-3-0-authentication.md) -- [Start a conversation](bot-framework-rest-direct-line-3-0-start-conversation.md) -- [Reconnect to a conversation](bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md) -- [Receive activities from the bot](bot-framework-rest-direct-line-3-0-receive-activities.md) -- [End a conversation](bot-framework-rest-direct-line-3-0-end-conversation.md) -- [Bot Framework Activity schema](https://aka.ms/botSpecs-activitySchema) - -[Activity]: bot-framework-rest-connector-api-reference.md#activity-object -[Attachment]: bot-framework-rest-connector-api-reference.md#attachment-object diff --git a/articles/rest-api/bot-framework-rest-direct-line-3-0-start-conversation.md b/articles/rest-api/bot-framework-rest-direct-line-3-0-start-conversation.md deleted file mode 100644 index 1d4e1ca64..000000000 --- a/articles/rest-api/bot-framework-rest-direct-line-3-0-start-conversation.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: Start a conversation - Bot Service -description: Learn how to start a conversation using Direct Line API v3.0. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Start a conversation - -Direct Line conversations are explicitly opened by clients and may run as long as the bot and client participate and have valid credentials. While the conversation is open, both the bot and client may send messages. More than one client may connect to a given conversation and each client may participate on behalf of multiple users. - -## Open a new conversation - -To open a new conversation with a bot, issue this request: - -```http -POST https://directline.botframework.com/v3/directline/conversations -Authorization: Bearer SECRET_OR_TOKEN -``` - -The following snippets provide an example of the Start Conversation request and response. - -### Request - -```http -POST https://directline.botframework.com/v3/directline/conversations -Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xn -``` - -### Response - -If the request is successful, the response will contain an ID for the conversation, a token, a value that indicates the number of seconds until the token expires, and a stream URL that the client may use to [receive activities via WebSocket stream](bot-framework-rest-direct-line-3-0-receive-activities.md#connect-via-websocket). - -```http -HTTP/1.1 201 Created -[other headers] -``` - -```json -{ - "conversationId": "abc123", - "token": "RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xn", - "expires_in": 1800, - "streamUrl": "https://directline.botframework.com/v3/directline/conversations/abc123/stream?t=RCurR_XV9ZA.cwA..." -} -``` - -Typically, a Start Conversation request is used to open a new conversation and an **HTTP 201** status code is returned if the new conversation is successfully started. However, if a client submits a Start Conversation request with a Direct Line token in the `Authorization` header that has previously been used to start a conversation using the Start Conversation operation, an **HTTP 200** status code will be returned to indicate that the request was acceptable but no conversation was created (as it already existed). - -> [!TIP] -> You have 60 seconds to connect to the WebSocket stream URL. If the connection cannot be established during this time, you can [reconnect to the conversation](bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md) to generate a new stream URL. - -## Start Conversation versus Generate Token - -The Start Conversation operation (`POST /v3/directline/conversations`) is similar to the [Generate Token](bot-framework-rest-direct-line-3-0-authentication.md#generate-token) operation (`POST /v3/directline/tokens/generate`) in that both operations return a `token` that can be used to access a single conversation. However, the Start Conversation operation also starts the conversation, contacts the bot, and creates a WebSocket stream URL, whereas the Generate Token operation does none of these things. - -If you intend to start the conversation immediately, use the Start Conversation operation. If you plan to distribute the token to clients and want them to initiate the conversation, use the [Generate Token](bot-framework-rest-direct-line-3-0-authentication.md#generate-token) operation instead. - -## Additional resources - -- [Key concepts](bot-framework-rest-direct-line-3-0-concepts.md) -- [Authentication](bot-framework-rest-direct-line-3-0-authentication.md) -- [Receive activities via WebSocket stream](bot-framework-rest-direct-line-3-0-receive-activities.md#connect-via-websocket) -- [Reconnect to a conversation](bot-framework-rest-direct-line-3-0-reconnect-to-conversation.md) \ No newline at end of file diff --git a/articles/rest-api/bot-framework-rest-overview.md b/articles/rest-api/bot-framework-rest-overview.md deleted file mode 100644 index 90b53e0b4..000000000 --- a/articles/rest-api/bot-framework-rest-overview.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Bot Framework REST APIs - Bot Service -description: Get started with the Bot Framework REST APIs that can be used to build bots and clients that connect to bots. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Bot Framework REST APIs -> [!div class="op_single_selector"] -> - [.NET](../dotnet/bot-builder-dotnet-overview.md) -> - [Node.js](../nodejs/bot-builder-nodejs-overview.md) -> - [REST](../rest-api/bot-framework-rest-overview.md) - -The Bot Framework REST APIs enable you to build bots that exchange messages with channels configured in the [Azure Portal](https://portal.azure.com), store and retrieve state data, and connect your own client applications to your bots. All Bot Framework services use industry-standard REST and JSON over HTTPS. - -## Build a bot - -You can create a bot with any programming language by using the Bot Connector service to exchange messages with channels configured in the Bot Framework Portal. - -> [!TIP] -> The Bot Framework provides client libraries that can be used to build bots in either C# or Node.js. -> To build a bot using C#, use the [Bot Framework SDK for C#](../dotnet/bot-builder-dotnet-overview.md). -> To build a bot using Node.js, use the [Bot Framework SDK for Node.js](../nodejs/index.md). - -To learn more about building bots using the Bot Connector service, see [Key concepts](bot-framework-rest-connector-concepts.md). - -## Build a client - -You can enable your own client application to communicate with your bot by using the Direct Line API. The Direct Line API implements an authentication mechanism that uses standard secret/token patterns and provides a stable schema, even if your bot changes its protocol version. To learn more about using the Direct Line API to enable communication between a client and your bot, see [Key concepts](bot-framework-rest-direct-line-3-0-concepts.md). \ No newline at end of file diff --git a/articles/rest-api/bot-framework-rest-state.md b/articles/rest-api/bot-framework-rest-state.md deleted file mode 100644 index 3295aa146..000000000 --- a/articles/rest-api/bot-framework-rest-state.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: Manage state data - Bot Service -description: Learn how to store and retrieve state data using the Bot State service. -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/13/2017 ---- - -# Manage state data - -The Microsoft Bot Framework State service is retired as of March 30, 2018. Previously, bots built on the Azure Bot Service or the Bot Builder SDK had a default connection to this service hosted by Microsoft to store bot state data. Bots will need to be updated to use their own state storage. diff --git a/articles/v4sdk/abs-quickstart.md b/articles/v4sdk/abs-quickstart.md deleted file mode 100644 index 944c3c384..000000000 --- a/articles/v4sdk/abs-quickstart.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: Create a bot with Azure Bot Service - Bot Service -description: Learn how to create a bot with Bot Service, an integrated, dedicated bot development environment. -keywords: Quickstart, create bot, bot service, web app bot -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/09/2020 ---- - -# Create a bot with Azure Bot Service - -[!INCLUDE [applies-to-v4](../includes/applies-to.md)] - -Azure Bot Service provides the core components for creating bots, including the Bot Framework SDK for developing bots and the bot service for connecting bots to channels. In the topic, you'll be able to choose either .NET or Node.js template to create a bot using the Bot Framework SDK v4. - ->[!NOTE] -> The bot you create is automatically registered with the Azure Bot Service. If you already have a bot hosted elsewhere and you want to register it, see the article: [Register a bot with Azure Bot Service](../bot-service-quickstart-registration.md). - -[!INCLUDE [Azure vs local development](~/includes/snippet-quickstart-paths.md)] - -## Prerequisites - -- [Azure](https://portal.azure.com) account - -### Create a new bot service - -1. Log in to the [Azure portal](https://portal.azure.com/). -1. Click **Create new resource** link found on the upper left-hand corner of the Azure portal, then select **AI + Machine Learning** > **Web App bot**. - -![create bot](../media/azure-bot-quickstarts/abs-create-blade.png) - -2. A *new blade* will open with information about the **Web App Bot**. - -3. In the **Bot Service** blade, provide the requested information about your bot as specified in the table below the image.
- ![Create Web App Bot blade](../media/azure-bot-quickstarts/sdk-create-bot-service-blade.png) - - | Setting | Suggested value | Description | - | ---- | ---- | ---- | - | **Bot name** | Your bot's display name | The display name for the bot that appears in channels and directories. This name can be changed at anytime. | - | **Subscription** | Your subscription | Select the Azure subscription you want to use. | - | **Resource Group** | myResourceGroup | You can create a new [resource group](/azure/azure-resource-manager/resource-group-overview#resource-groups) or choose from an existing one. | - | **Location** | The default location | Select the geographic location for your resource group. Your location choice can be any location listed, though it's often best to choose a location closest to your customer. The location cannot be changed once the bot is created. | - | **Pricing tier** | F0 | Select a pricing tier. You may update the pricing tier at any time. For more information, see [Bot Service pricing](https://azure.microsoft.com/pricing/details/bot-service/). | - | **App name** | A unique name | The unique URL name of the bot. For example, if you name your bot *myawesomebot*, then your bot's URL will be `http://myawesomebot.azurewebsites.net`. The name must use alphanumeric and underscore characters only. There is a 35 character limit to this field. The App name cannot be changed once the bot is created. | - | **Bot template** | Echo bot | Choose **SDK v4**. Select either C# or Node.js for this quickstart, then click **Select**. - | **App service plan/Location** | Your app service plan | Select an [app service plan](https://azure.microsoft.com/pricing/details/app-service/plans/) location. Your location choice can be any location listed, though it's often best to choose the same location as the bot service. | - | **LUIS Accounts** _Only available for Basic Bot template_ | LUIS Azure Resource Name | After [migrating LUIS Resources over to an Azure Resource](https://docs.microsoft.com/azure/cognitive-services/luis/luis-migration-authoring), input the Azure Resource name to associate this LUIS Application with that Azure Resource. - | **Application Insights** | On | Decide if you want to turn [Application Insights](/bot-framework/bot-service-manage-analytics) **On** or **Off**. If you select **On**, you must also specify a regional location. Your location choice can be any location listed, though it's often best to choose the same location as the bot service. | - | **Microsoft App ID and password** | Auto create App ID and password | Use this option if you need to manually enter a Microsoft App ID and password. Otherwise, a new Microsoft App ID and password will be created for you in the bot creation process. When creating an app registration manually for the Bot Service, please ensure that the supported account types is set to ‘Accounts in any organizational directory’ or ‘Accounts in any organizational directory and personal Microsoft accounts (e.g. Skype, Outlook.com, Xbox, etc.)’ | - -4. Click **Create** to create the service and deploy the bot to the cloud. This process may take several minutes. - -Confirm that the bot has been deployed by checking the **Notifications**. The notifications will change from **Deployment in progress...** to **Deployment succeeded**. Click **Go to resource** button to open the bot's resources blade. - -Now that your bot is created, test it in Web Chat. - -## Test the bot -In the **Bot Management** section, click **Test in Web Chat**. Azure Bot Service will load the Web Chat control and connect to your bot. - -![Azure Webchat test](../media/azure-bot-quickstarts/azure-webchat-test.png) - -Enter a message and your bot should respond. - -## Manual app registration - -A manual registration is necessary for situations like: - -- You are unable to make the registrations in your organization and need another party to create the App ID for the bot you're building. -- You need to manually create your own app ID (and password). - -See [FAQ - App Registration](../bot-service-resources-bot-framework-faq.md#app-registration). - - -## Download code -You can download the code to work on it locally. -1. In the **Bot Management** section, click **Build**. -1. Click on **Download Bot source code** link in the right-pane. -1. Follow the prompts to download the code, and then unzip the folder. - 1. [!INCLUDE [download keys snippet](../includes/snippet-abs-key-download.md)] - -## Next steps -After you download the code, you can continue to develop the bot locally on your machine. Once you test your bot and are ready to upload the bot code to the Azure portal, follow the instructions listed under [set up continous deployment](../bot-service-build-continuous-deployment.md) topic to automatically update code after you make changes. diff --git a/articles/v4sdk/bf-cli-overview.md b/articles/v4sdk/bf-cli-overview.md deleted file mode 100644 index c5b489746..000000000 --- a/articles/v4sdk/bf-cli-overview.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: Azure Bot Framework Command-Line Interface (CLI) overview - Bot Service -description: Learn about the Bot Framework Command-Line Interface (CLI). -keywords: Bot Framework Command-Line Interface, Bot Framework CLI -author: JonathanFingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/01/2019 -monikerRange: 'azure-bot-service-4.0' ---- - - -# Bot Framework CLI overview - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -Bot Framework Command-Line Interface (CLI) is a cross-platform tool that allows you to manage bots and related services. It replaces a collection of older standalone CLI tools by aggregating them into a single tool. - -## Prerequisites - -* [Node.js](https://nodejs.org/), version 10.14.1 or later. - -## Installation - -Install the BF CLI from the command line. - -~~~cmd -npm i -g @microsoft/botframework-cli -~~~ - -## Available commands - -The following commands are currently available. - -| Old tool | BF command set | Description | -| :--- | :--- | :--- | -| ChatDown | [`bf chatdown`](bf-cli-reference.md#bf-chatdown) | Commands for working with chat dialog (**.chat**) files. | -| na | [`bf config`](bf-cli-reference.md#bf-config) | Configures various settings within the CLI. | -| LuDown, LuisGen | [`bf luis`](bf-cli-reference.md#bf-luis) | Commands for working with LUIS resource files and managing LUIS models. | -| QnAMaker | [`bf qnamaker`](bf-cli-reference.md#bf-qnamaker) | Commands for working with QnA Maker resource files and managing knowledge bases. | - -The following tools will be ported in upcoming releases: -- LUIS (API) -- Dispatch - -See [Porting Map](https://github.com/microsoft/botframework-cli/blob/master/PortingMap.md) for a mapping reference between the old and new tools. - -_Note: The older CLI tools will be deprecated in upcoming releases and support for them will end in the future. -All new investments, bug fixes, and new features in this area will target only the BF CLI._ - -## Overview - -The BF CLI manages bots and related services. It is part of the Microsoft Bot Framework, a comprehensive framework for building enterprise-grade conversational AI experiences. In addition to managing bot related resources, the BF CLI can be used as part of continuous integration and continuous deployment (CI/CD) pipelines. As you build your bot, you might also need to integrate AI services like LUIS for language understanding, QnAMaker for your bot to respond to simple questions in a Q&A format, and more. To integrate AI service in your bot, use: - -* [`bf luis`](bf-cli-reference.md#bf-luis) command to work with LUIS **.lu** resource files and manage LUIS models. It can also generate corresponding source (C# or JavaScript) code. -* [LUIS APIs tool](https://github.com/microsoft/botbuilder-tools/tree/master/packages/LUIS/readme.md) to deploy the local files, train, test, and publish them as Language Understanding models within the LUIS service. -* [`bf qnamaker`](bf-cli-reference.md#bf-qnamaker) command to work with QnAMaker knowledge bases. It can create and manage QnA Maker assets both locally, and on the QnA Maker service. - -* Refer to the lu library [documentation](https://github.com/microsoft/botframework-cli/tree/master/packages/lu/README.md) for how to work with **.lu** and **.qna** file formats. - -As your bot becomes more sophisticated, use the [Dispatch](https://github.com/Microsoft/botbuilder-tools/tree/master/packages/Dispatch) CLI tool to create, evaluate, and dispatch intent across multiple LUIS models and QnA Maker knowledge bases. - -To test and refine your bot, you can use the new [Bot Framework Emulator](https://github.com/Microsoft/BotFramework-Emulator/releases). The Emulator enables you to test and debug your bots on local machine or in the cloud. - -During early design stages you might want to create mock conversations between the user and the bot for the specific scenarios your bot will support. Use [`bf chatdown`](bf-cli-reference.md#bf-chatdown) command to author conversation mockup **.chat** files, convert them into rich transcripts, and view the conversations in the the Emulator. - -Lastly, with the [Azure CLI](https://github.com/microsoft/botframework-cli/blob/master/AzureCli.md) (`az bot` command), you can create, download, publish, and configure channels with the [Azure Bot Service](https://azure.microsoft.com/services/bot-service/). It is a plugin that extends the functionality of the [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest) to manage your Azure Bot Service assets. - -## Privacy and instrumentation -BF CLI contains instrumentation options that are designed to help us improve the tool based on **anonymous** usage patterns. __It is disabled, opted-out by default__. If you elect to opt-in, Microsoft gathers some usage data: - -* Command group calls -* Flags used, **excluding** specific values. For example, for the parameter `--folder:name`, only the use of `--folder` is gathered, the folder name is not gathered. - -To modify data collection behavior, use the [`bf config`](bf-cli-reference.md#bf-config) command. - -Please refer to [Microsoft Privacy Statement](https://privacy.microsoft.com/privacystatement) for more details. - -## Issues and feature requests -- You can file issues and feature requests [here](https://github.com/microsoft/botframework-cli/issues). -- You can find known issues [here](https://github.com/microsoft/botframework-cli/labels/known-issues). - -## Next steps -- [BF cli reference](bf-cli-reference.md) diff --git a/articles/v4sdk/bf-cli-reference.md b/articles/v4sdk/bf-cli-reference.md deleted file mode 100644 index cc63ad5f5..000000000 --- a/articles/v4sdk/bf-cli-reference.md +++ /dev/null @@ -1,852 +0,0 @@ ---- -title: Azure Bot Framework Command-Line Interface (CLI) reference - Bot Service -description: Learn about the Bot Framework Command-Line Interface (CLI). -keywords: Bot Framework Command-Line Interface, Bot Framework CLI -author: JonathanFingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 10/25/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Bot Framework CLI reference - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -Usage - -```sh-session -npm install -g @microsoft/botframework-cli -``` - -## Commands - -* [`bf chatdown`](#bf-chatdown) -* [`bf chatdown:convert`](#bf-chatdownconvert) -* [`bf config`](#bf-config) -* [`bf config:set:qnamaker`](#bf-configsetqnamaker) -* [`bf config:set:telemetry`](#bf-configsettelemetry) -* [`bf config:show`](#bf-configshow) -* [`bf config:show:qnamaker`](#bf-configshowqnamaker) -* [`bf config:show:telemetry`](#bf-configshowtelemetry) -* [`bf help [COMMAND]`](#bf-help-command) -* [`bf luis`](#bf-luis) -* [`bf luis:convert`](#bf-luisconvert) -* [`bf luis:generate:cs`](#bf-luisgeneratecs) -* [`bf luis:generate:ts`](#bf-luisgeneratets) -* [`bf luis:translate`](#bf-luistranslate) -* [`bf qnamaker`](#bf-qnamaker) -* [`bf qnamaker:alterations`](#bf-qnamakeralterations) -* [`bf qnamaker:alterations:list`](#bf-qnamakeralterationslist) -* [`bf qnamaker:alterations:replace`](#bf-qnamakeralterationsreplace) -* [`bf qnamaker:convert`](#bf-qnamakerconvert) -* [`bf qnamaker:endpointkeys`](#bf-qnamakerendpointkeys) -* [`bf qnamaker:endpointkeys:list`](#bf-qnamakerendpointkeyslist) -* [`bf qnamaker:endpointkeys:refresh`](#bf-qnamakerendpointkeysrefresh) -* [`bf qnamaker:endpointsettings`](#bf-qnamakerendpointsettings) -* [`bf qnamaker:endpointsettings:get`](#bf-qnamakerendpointsettingsget) -* [`bf qnamaker:endpointsettings:update`](#bf-qnamakerendpointsettingsupdate) -* [`bf qnamaker:init`](#bf-qnamakerinit) -* [`bf qnamaker:kb`](#bf-qnamakerkb) -* [`bf qnamaker:kb:create`](#bf-qnamakerkbcreate) -* [`bf qnamaker:kb:delete`](#bf-qnamakerkbdelete) -* [`bf qnamaker:kb:export`](#bf-qnamakerkbexport) -* [`bf qnamaker:kb:get`](#bf-qnamakerkbget) -* [`bf qnamaker:kb:list`](#bf-qnamakerkblist) -* [`bf qnamaker:kb:publish`](#bf-qnamakerkbpublish) -* [`bf qnamaker:kb:replace`](#bf-qnamakerkbreplace) -* [`bf qnamaker:kb:update`](#bf-qnamakerkbupdate) -* [`bf qnamaker:operationdetails`](#bf-qnamakeroperationdetails) -* [`bf qnamaker:operationdetails:get`](#bf-qnamakeroperationdetailsget) -* [`bf qnamaker:query`](#bf-qnamakerquery) -* [`bf qnamaker:train`](#bf-qnamakertrain) -* [`bf qnamaker:translate`](#bf-qnamakertranslate) - -## `bf chatdown` - -Converts chat dialog files in \.chat format into transcript files. Writes corresponding \.transcript for each .chat file. - -```text -USAGE - $ bf chatdown - -OPTIONS - -h, --help Chatdown command help -``` - -_See code: [@microsoft/bf-chatdown](https://github.com/microsoft/botframework-cli/tree/master/packages/chatdown/src/commands/chatdown/index.ts)_ - -## `bf chatdown:convert` - -Converts chat dialog files in \.chat format into transcript files. Writes corresponding \.transcript for each .chat file. - -```text -USAGE - $ bf chatdown:convert - -OPTIONS - -f, --force If --out flag is provided with the path to an existing file, overwrites that file - -h, --help Chatdown command help - - -i, --in=in The path of the chat file or directory to be parsed. A glob expression may be passed containing chat - files to be processed all at once, ex. ./**/*.chat. If flag is omitted, stdin will be used. If an - output directory is not present (-o), it will default the output to the current working directory. - - -o, --out=out Path to the directory where the output of the multiple chat file processing (-o) will be placed. - - -p, --prefix Prefix stdout with package name. - - -s, --stamp Use static timestamps when generating timestamps on activities. - -EXAMPLE - - $ bf chatdown - $ bf chatdown --in=./path/to/file/sample.chat - $ bf chatdown --in ./test/utils/*.sample.chat -o ./ - $ (echo user=Joe && [ConversationUpdate=MembersAdded=Joe]) | bf chatdown --static -``` - -_See code: [@microsoft/bf-chatdown](https://github.com/microsoft/botframework-cli/tree/master/packages/chatdown/src/commands/chatdown/convert.ts)_ - -## `bf config` - -Configures various settings within the CLI. - -```text -USAGE - $ bf config - -OPTIONS - -h, --help config help -``` - -_See code: [@microsoft/bf-cli-config](https://github.com/microsoft/botframework-cli/tree/master/packages/config/src/commands/config/index.ts)_ - -## `bf config:set:qnamaker` - -Sets the QnA Maker config data - -```text -USAGE - $ bf config:set:qnamaker - -OPTIONS - -h, --help config:set:qnamaker help - --endpointKey=endpointKey QnAMaker endpointKey to be set - --hostname=hostname QnAMaker hostname to be set - --kbId=kbId QnAMaker kbId to be set - --subscriptionKey=subscriptionKey QnAMaker subscriptionkey to be set - -EXAMPLE - - { - "qnamaker_kbId": "3bda64af-dddd-dddd-dddd-021906b093b1", - "qnamaker_subscriptionKey": "nnnnnnnnnnnnnnnnnnnnnnnnn", - "qnamaker_endpointKey": "6b5ecf9c-kkkk-kkkk-kkkk-761489817e5f", - "qnamaker_hostname": "https://{qnaservice-hostname}.azurewebsites.net" - } -``` - -_See code: [@microsoft/bf-cli-config](https://github.com/microsoft/botframework-cli/tree/master/packages/config/src/commands/config/set/qnamaker.ts)_ - -## `bf config:set:telemetry` - -Enables or disables anonymous data collection to improve the products. (Command group calls and flags usage) - -```text -USAGE - $ bf config:set:telemetry - -OPTIONS - -d, --disable Disable tlemetry - -e, --enable Enable tlemetry - -h, --help config:set:telemetry help -``` - -_See code: [@microsoft/bf-cli-config](https://github.com/microsoft/botframework-cli/tree/master/packages/config/src/commands/config/set/telemetry.ts)_ - -## `bf config:show` - -Displays the config file - -```text -USAGE - $ bf config:show - -OPTIONS - -h, --help config:show help -``` - -_See code: [@microsoft/bf-cli-config](https://github.com/microsoft/botframework-cli/tree/master/packages/config/src/commands/config/show.ts)_ - -## `bf config:show:qnamaker` - -Displays QnA Maker settings - -```text -USAGE - $ bf config:show:qnamaker - -OPTIONS - -h, --help config:show:qnamaker help -``` - -_See code: [@microsoft/bf-cli-config](https://github.com/microsoft/botframework-cli/tree/master/packages/config/src/commands/config/show/qnamaker.ts)_ - -## `bf config:show:telemetry` - -Displays telemetry settings - -```text -USAGE - $ bf config:show:telemetry - -OPTIONS - -h, --help config:show:telemetry help -``` - -_See code: [@microsoft/bf-cli-config](https://github.com/microsoft/botframework-cli/tree/master/packages/config/src/commands/config/show/telemetry.ts)_ - -## `bf help [COMMAND]` - -Displays help for the bf command - -```text -USAGE - $ bf help [COMMAND] - -ARGUMENTS - COMMAND command to show help for - -OPTIONS - --all see all commands in CLI -``` - -_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v2.1.6/src/commands/help.ts)_ - -## `bf luis` - -Converts, translates luis/lu files or generates source code. - -```text -USAGE - $ bf luis - -OPTIONS - -h, --help Display Luis available commands -``` - -_See code: [@microsoft/bf-lu](https://github.com/microsoft/botframework-cli/tree/master/packages/lu/src/commands/luis/index.ts)_ - -## `bf luis:convert` - -Converts .lu file(s) to a LUIS application JSON model or vice versa - -```text -USAGE - $ bf luis:convert - -OPTIONS - -f, --force If --out flag is provided with the path to an existing file, overwrites that file - -h, --help luis:convert help - -i, --in=in Source .lu file(s) or LUIS application JSON model - -o, --out=out Output file or folder name. If not specified stdout will be used as output - -r, --recurse Indicates if sub-folders need to be considered to file .lu file(s) - --culture=culture Lang code for the LUIS application - --description=description Text describing the LUIS application - --log Enables log messages - --name=name Name of the LUIS application - --schemaversion=schemaversion Schema version of the LUIS application - --sort When set, intent, utterances, entities are alphabetically sorted in .lu files - --versionid=versionid Version ID of the LUIS application -``` - -_See code: [@microsoft/bf-lu](https://github.com/microsoft/botframework-cli/tree/master/packages/lu/src/commands/luis/convert.ts)_ - -## `bf luis:generate:cs` - -Generates a strongly typed C# source code from an exported (JSON) LUIS model. - -```text -USAGE - $ bf luis:generate:cs - -OPTIONS - -f, --force If --out flag is provided with the path to an existing file, overwrites that file - -h, --help luis:generate:cs help - -i, --in=in Path to the file containing the LUIS application JSON model - -o, --out=out Output file or folder name. If not specified stdout will be used as output - --className=className Name of the autogenerated class (can include namespace) -``` - -_See code: [@microsoft/bf-lu](https://github.com/microsoft/botframework-cli/tree/master/packages/lu/src/commands/luis/generate/cs.ts)_ - -## `bf luis:generate:ts` - -Generates a strongly typed typescript source code from an exported (JSON) LUIS model. - -```text -USAGE - $ bf luis:generate:ts - -OPTIONS - -f, --force If --out flag is provided with the path to an existing file, overwrites that file - -h, --help luis:generate:ts help - -i, --in=in Path to the file containing the LUIS application JSON model - -o, --out=out Output file or folder name. If not specified stdout will be used as output - --className=className Name of the autogenerated class -``` - -_See code: [@microsoft/bf-lu](https://github.com/microsoft/botframework-cli/tree/master/packages/lu/src/commands/luis/generate/ts.ts)_ - -## `bf luis:translate` - -Translates given LUIS application JSON model or .lu file(s) - -```text -USAGE - $ bf luis:translate - -OPTIONS - -f, --force If --out flag is provided with the path to an existing file, overwrites that file - -h, --help luis:translate help - -i, --in=in Source .lu file(s) or LUIS application JSON model - -o, --out=out Output folder name. If not specified stdout will be used as output - -r, --recurse Indicates if sub-folders need to be considered to file .lu file(s) - --srclang=srclang Source lang code. Auto detect if missing. - --tgtlang=tgtlang (required) Comma separated list of target languages. - --translate_comments When set, machine translate comments found in .lu file - --translate_link_text When set, machine translate link description in .lu file - --translatekey=translatekey (required) Machine translation endpoint key. -``` - -_See code: [@microsoft/bf-lu](https://github.com/microsoft/botframework-cli/tree/master/packages/lu/src/commands/luis/translate.ts)_ - -## `bf qnamaker` - -QnA Maker - -```text -USAGE - $ bf qnamaker - -OPTIONS - -h, --help Display QnA Maker CLI available commands -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/index.ts)_ - -## `bf qnamaker:alterations` - -Commands for replacing and listing your alterations - -```text -USAGE - $ bf qnamaker:alterations - -OPTIONS - -h, --help display qnamaker:alterations available commands -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/alterations/index.ts)_ - -## `bf qnamaker:alterations:list` - -Downloads all word alterations (synonyms) that have been added by the user. - -```text -USAGE - $ bf qnamaker:alterations:list - -OPTIONS - -h, --help qnamaker:alterations:list command help - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/alterations/list.ts)_ - -## `bf qnamaker:alterations:replace` - -Replaces word alterations (synonyms) for the KB with the given records. - -```text -USAGE - $ bf qnamaker:alterations:replace - -OPTIONS - -h, --help qnamaker:alterations:replace command help - -i, --in=in File path to the WordAlterationsDTO object to send in the body of the request - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/alterations/replace.ts)_ - -## `bf qnamaker:convert` - -Converts .lu file(s) to QnA application JSON models or vice versa. - -```text -USAGE - $ bf qnamaker:convert - -OPTIONS - -f, --force If --out flag is provided with the path to an existing file, overwrites that file - -h, --help qnamaker:convert help - -i, --in=in Source .qna file(s) or QnA KB JSON file - -o, --out=out Output file or folder name. If not specified stdout will be used as output - -r, --recurse Indicates if sub-folders need to be considered to file .qna file(s) - --alterations Indicates if files is QnA Alterations - --log Enables log messages - --name=name Name of the QnA KB - --sort When set, questions collections are alphabetically sorted are alphabetically sorted in .qna files -``` - -_See code: [@microsoft/bf-lu](https://github.com/microsoft/botframework-cli/tree/master/packages/lu/src/commands/qnamaker/convert.ts)_ - -## `bf qnamaker:endpointkeys` - -Commands to refresh and list keys - -```text -USAGE - $ bf qnamaker:endpointkeys - -OPTIONS - -h, --help display qnamaker:endpointkeys available commands -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/endpointkeys/index.ts)_ - -## `bf qnamaker:endpointkeys:list` - -Lists all the currently valid endpointKeys for querying your private endpoint - -```text -USAGE - $ bf qnamaker:endpointkeys:list - -OPTIONS - -h, --help qnamaker:endpointkeys:list command help - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/endpointkeys/list.ts)_ - -## `bf qnamaker:endpointkeys:refresh` - -Re-generates an endpoint key, in case you suspect your keys have been compromised - -```text -USAGE - $ bf qnamaker:endpointkeys:refresh - -OPTIONS - -h, --help qnamaker:endpoints:refresh command help - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - --keyType=keyType (required) Type of Key. (PrimaryKey/SecondaryKey) - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/endpointkeys/refresh.ts)_ - -## `bf qnamaker:endpointsettings` - -Commands to get and update endpoint settings - -```text -USAGE - $ bf qnamaker:endpointsettings - -OPTIONS - -h, --help display qnamaker:update available commands -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/endpointsettings/index.ts)_ - -## `bf qnamaker:endpointsettings:get` - -Gets endpoint settings for an endpoint. - -```text -USAGE - $ bf qnamaker:endpointsettings:get - -OPTIONS - -h, --help qnamaker:endpointsettings:get command help - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - --kbId=kbId Knowledgebase id to get metadata. - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/endpointsettings/get.ts)_ - -## `bf qnamaker:endpointsettings:update` - -Updates endpoint settings for an endpoint. - -```text -USAGE - $ bf qnamaker:endpointsettings:update - -OPTIONS - -h, --help qnamaker:endpointsettings:update command help - --activelearning Enable active learning. Disables if flag not set - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/endpointsettings/update.ts)_ - -## `bf qnamaker:init` - -Initializes the config file with settings. - -```text -USAGE - $ bf qnamaker:init - -OPTIONS - -h, --help qnamaker:init command help - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/init.ts)_ - -## `bf qnamaker:kb` - -Commands for manipulating your knowledge base - -```text -USAGE - $ bf qnamaker:kb - -OPTIONS - -h, --help display qnamaker:kb available commands -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/kb/index.ts)_ - -## `bf qnamaker:kb:create` - -Creates a new knowledgebase - -```text -USAGE - $ bf qnamaker:kb:create - -OPTIONS - -h, --help qnamaker:kb:create command help - -i, --in=in File path to the CreateKbDTO object to send in the body of the request. - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - - --name=name Name of the kb you want to create. This will override the name of KB that might be - present in the CreateKb DTO - - --save Save the kbId in config. - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/kb/create.ts)_ - -## `bf qnamaker:kb:delete` - -Deletes a knowledge base by ID - -```text -USAGE - $ bf qnamaker:kb:delete - -OPTIONS - -h, --help qnamaker:kb:delete command help - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - --force Do not prompt for confirmation, force the operation - - --kbId=kbId Knowledgebase id to be deleted. Overrides the knowledge base id present in the - config - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/kb/delete.ts)_ - -## `bf qnamaker:kb:export` - -Echoes a knowledge base JSON to stdout - -```text -USAGE - $ bf qnamaker:kb:export - -OPTIONS - -h, --help qnamaker:kb:export command help - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - --environment=environment (required) Specifies whether environment is Test or Prod. - - --kbId=kbId Knowledgebase id to be exported. Overrides the knowledge base id present in the - config - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/kb/export.ts)_ - -## `bf qnamaker:kb:get` - -Gets metadata about a knowledgebase - -```text -USAGE - $ bf qnamaker:kb:get - -OPTIONS - -h, --help qnamaker:kb:get command help - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - - --kbId=kbId Knowledgebase id to get metadata. Overrides the knowledge base id present in the - config - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/kb/get.ts)_ - -## `bf qnamaker:kb:list` - -Lists all of your knowledgebases - -```text -USAGE - $ bf qnamaker:kb:list - -OPTIONS - -h, --help qnamaker:kb:list command help - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/kb/list.ts)_ - -## `bf qnamaker:kb:publish` - -Publishes all unpublished in the knowledgebase to the prod endpoint. - -```text -USAGE - $ bf qnamaker:kb:publish - -OPTIONS - -h, --help qnamaker:kb:publish command help - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - --kbId=kbId Knowledgebase id to pubish. Overrides the knowledge base id present in the config - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/kb/publish.ts)_ - -## `bf qnamaker:kb:replace` - -Replaces knowledgebase contents with new contents - -```text -USAGE - $ bf qnamaker:kb:replace - -OPTIONS - -h, --help qnamaker:kb:replace command help - -i, --in=in File path to the ReplaceKbDTO object to send in the body of the request - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - --kbId=kbId Knowledgebase id. Overrides the knowledge base id present in the config - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/kb/replace.ts)_ - -## `bf qnamaker:kb:update` - -Adds or deletes QnA Pairs and / or URLs to an existing knowledge base - -```text -USAGE - $ bf qnamaker:kb:update - -OPTIONS - -h, --help qnamaker:kb:update command help - - -i, --in=in The file path to the UpdateKbOperationDTO object to send in the body of the - request. - - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - - --kbId=kbId Knowledgebase id. Overrides the knowledge base id present in the config - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config - - --wait Wait for the operation to complete. -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/kb/update.ts)_ - -## `bf qnamaker:operationdetails` - -Command to get operation details - -```text -USAGE - $ bf qnamaker:operationdetails - -OPTIONS - -h, --help display qnamaker:operationdetails available commands -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/operationdetails/index.ts)_ - -## `bf qnamaker:operationdetails:get` - -Gets details of a specific long running operation. - -```text -USAGE - $ bf qnamaker:operationdetails:get - -OPTIONS - -h, --help qnamaker:operationdetails:get command help - --endpoint=endpoint Overrides public endpoint https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/ - --operationId=operationId (required) Operation id. - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in the config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/operationdetails/get.ts)_ - -## `bf qnamaker:query` - -Queries a knowledge base for an answer - -```text -USAGE - $ bf qnamaker:query - -OPTIONS - -h, --help qnamaker:query command help - --context=context Path to Context object json file with previous QnA - - --endpointKey=endpointKey Specifies the endpoint key for your private QnA service (From qnamaker.ai portal user - settings page). Overrides the value present in config - - --hostname=hostname Specifies the url for your private QnA service. Overrides the value present in config - - --kbId=kbId Specifies the active qnamaker knowledgebase id. Overrides the value present in the - config - - --qnaId=qnaId Exact qnaId to fetch from the knowledgebase, this field takes priority over question - - --question=question (required) Query to get a prediction for - - --scorethreshold=scorethreshold Specifies the confidence score threshold for the returned answer. - - --strictfilters=strictfilters Path to json file with MetadataDTO[] e.g {"strictfilters": MetadataDTO[]} - - --test Query against the test index - - --top=top Specifies the number of matching results -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/query.ts)_ - -## `bf qnamaker:train` - -Adds suggestions to the knowledgebase. - -```text -USAGE - $ bf qnamaker:train - -OPTIONS - -h, --help qnamaker:get:kb command help - - --endpointKey=endpointKey Specifies the endpoint key for your private QnA service.(from qnamaker.ai portal - user settings page). Overrides the value present in config. - - --hostname=hostname Specifies the url for your private QnA service. Overrides the value present in - config. - - --in=in File path to the FeedbackRecordDTO object to send in the body of the request. - - --kbId=kbId Specifies the active qnamaker knowledgebase id. Overrides the value present in the - config - - --subscriptionKey=subscriptionKey Specifies the qnamaker Ocp-Apim-Subscription Key (found in Keys under Resource - Management section for your Qna Maker cognitive service). Overrides the - subscriptionkey value present in config -``` - -_See code: [@microsoft/bf-qnamaker](https://github.com/microsoft/botframework-cli/tree/master/packages/qnamaker/src/commands/qnamaker/train.ts)_ - -## `bf qnamaker:translate` - -Translates given QnA Maker application JSON model or .qna file(s) - -```text -USAGE - $ bf qnamaker:translate - -OPTIONS - -f, --force If --out flag is provided with the path to an existing file, overwrites that file - -h, --help qnamaker:translate help - -i, --in=in Source .qna file(s) or QnA maker application JSON model - -o, --out=out Output folder name. If not specified stdout will be used as output - -r, --recurse Indicates if sub-folders need to be considered to find .qna file(s) - --srclang=srclang Source lang code. Auto detect if missing. - --tgtlang=tgtlang (required) Comma separated list of target languages. - --translate_comments When set, machine translate comments found in .qna file - --translate_link_text When set, machine translate link description in .qna file - --translatekey=translatekey (required) Machine translation endpoint key. -``` - -_See code: [@microsoft/bf-lu](https://github.com/microsoft/botframework-cli/tree/master/packages/lu/src/commands/qnamaker/translate.ts)_ - diff --git a/articles/v4sdk/bot-builder-authentication.md b/articles/v4sdk/bot-builder-authentication.md deleted file mode 100644 index 261811866..000000000 --- a/articles/v4sdk/bot-builder-authentication.md +++ /dev/null @@ -1,528 +0,0 @@ ---- -title: Add authentication to your bot via Azure Bot Service - Bot Service -description: Learn how to use the Azure Bot Service authentication features to add SSO to your bot. -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 2/7/2020 -monikerRange: 'azure-bot-service-4.0' ---- - - - - - -# Add authentication to your bot via Azure Bot Service - -[!INCLUDE [applies-to-v4](../includes/applies-to.md)] - -The Azure Bot Service and the v4 SDK include new bot authentication capabilities, providing features to make it easier to develop a bot that authenticates users to various identity providers, such as Azure AD (Azure Active Directory), GitHub, Uber, and so on. These capabilities can improve the user experience by eliminating the _magic code verification_ for some clients. - -Prior to this, your bot needed to include OAuth controllers and login links, store the target client IDs and secrets, and perform user token management. The bot would ask the user sign in on a website, which would then generate a _magic code_ the user could use to verify their identity. - -Now, bot developers no longer need to host OAuth controllers or manage the token life-cycle, as all of this can now be done by the Azure Bot Service. - -The features include: - -- Improvements to the channels to support new authentication features, such as new WebChat and DirectLineJS libraries to eliminate the need for the 6-digit magic code verification. -- Improvements to the Azure Portal to add, delete, and configure connection settings to various OAuth identity providers. -- Support for a variety of out-of-the-box identity providers including Azure AD (both v1 and v2 endpoints), GitHub, and others. -- Updates to the C# and Node.js Bot Framework SDKs to be able to retrieve tokens, create OAuthCards and handle TokenResponse events. -- Samples for how to make a bot that authenticates to Azure AD. - -For more information about how the Azure Bot Service handles authentication, see [User authentication within a conversation](bot-builder-concept-authentication.md). - -You can extrapolate from the steps in this article to add such features to an existing bot. These sample bots demonstrate the new authentication features. - -> [!NOTE] -> The authentication features also work with BotBuilder v3. However, this article covers just the v4 sample code. - -### About this sample - -You need to create an Azure bot resource, and you need: - -1. An Azure AD app registration to allow your bot to access an external resource, such as Office 365. -1. A separate bot resource. The bot resource registers your bot's credentials, and you need these credentials to test the authentication features, even when running your bot code locally. - -> [!IMPORTANT] -> Whenever you register a bot in Azure, it gets assigned an Azure AD app. However, this app secures channel-to-bot access. You need an additional AAD app for each application that you want the bot to be able to authenticate on behalf of the user. - -This article describes a sample bot that connects to the Microsoft Graph using an Azure AD v1 or v2 token. It also covers how to create and register the associated Azure AD app. As part of this process, you'll use code from the [Microsoft/BotBuilder-Samples](https://github.com/Microsoft/BotBuilder-Samples) GitHub repo. This article covers these processes. - -- **Create your bot resource** -- **Create an Azure AD application** -- **Register your Azure AD application with your bot** -- **Prepare the bot sample code** - -Once you finish, you will have a bot running locally that can respond to a few simple tasks against an Azure AD application, such as checking and sending an email, or displaying who you are and who your manager is. To do this, your bot will use a token from an Azure AD application against the Microsoft.Graph library. You do not need to publish your bot to test the OAuth sign-in features; however, your bot will need a valid Azure app ID and password. - -### Web Chat and Direct Line considerations - - - -> [!IMPORTANT] -> Please, keep in mind these important [Security considerations](../rest-api/bot-framework-rest-direct-line-3-0-authentication.md#security-considerations). - -## Prerequisites - -- Knowledge of [bot basics][concept-basics], [managing state][concept-state], the [dialogs library][concept-dialogs], how to [implement sequential conversation flow][simple-dialog], and how to [reuse dialogs][component-dialogs]. -- Knowledge of Azure and OAuth 2.0 development. -- Visual Studio 2017 or later, Node.js, npm, and git. -- One of these samples. - -| Sample | BotBuilder version | Demonstrates | -|:---|:---:|:---| -| **Bot authentication** in [**CSharp**][cs-auth-sample] or [**JavaScript**][js-auth-sample] or [**Python**][python-auth-sample] | v4 | OAuthCard support | -| **Bot authentication MSGraph** in [**CSharp**][cs-msgraph-sample] or [**JavaScript**][js-msgraph-sample] or [**Python**](https://aka.ms/bot-auth-msgraph-python-sample-code)| v4 | Microsoft Graph API support with OAuth 2 | - -## Create your bot resource on Azure - -Create a **Bot resource** using the [Azure Portal](https://portal.azure.com/). - -For more information, see [Create a bot with Azure Bot Service](./abs-quickstart.md). - -## Create and register an Azure AD application - -You need an Azure AD application that your bot can use to connect to the Microsoft Graph API. - -For this bot you can use Azure AD v1 or v2 endpoints. -For information about the differences between the v1 and v2 endpoints, see the [v1-v2 comparison](https://docs.microsoft.com/azure/active-directory/develop/active-directory-v2-compare) and the [Azure AD v2.0 endpoint overview](https://docs.microsoft.com/azure/active-directory/develop/active-directory-appmodel-v2-overview). - -### Create your Azure AD application - -Use these steps to create a new Azure AD application. You can use the v1 or v2 endpoints with the app that you create. - -> [!TIP] -> You will need to create and register the Azure AD application in a tenant -> in which you can consent to delegate permissions requested by an application. - -1. Open the [Azure Active Directory][azure-aad-blade] panel in the Azure portal. - If you are not in the correct tenant, click **Switch directory** to switch to the correct tenant. (For instruction on creating a tenant, see [Access the portal and create a tenant](https://docs.microsoft.com/azure/active-directory/fundamentals/active-directory-access-create-new-tenant).) -1. Open the **App registrations** panel. -1. In the **App registrations** panel, click **New registration**. -1. Fill in the required fields and create the app registration. - - 1. Name your application. - 1. Select the **Supported account types** for your application. (Any of these options will work with this sample.) - 1. For the **Redirect URI** - 1. Select **Web**. - 1. Set the URL to `https://token.botframework.com/.auth/web/redirect`. - 1. Click **Register**. - - - Once it is created, Azure displays the **Overview** page for the app. - - Record the **Application (client) ID** value. You will use this value later as the _Client id_ when you register your Azure AD application with your bot. - - Also record the **Directory (tenant) ID** value. You will also use this to register this application with your bot. - -1. In the navigation pane, click **Certificates & secrets** to create a secret for your application. - - 1. Under **Client secrets**, click **New client secret**. - 1. Add a description to identify this secret from others you might need to create for this app, such as `bot login`. - 1. Set **Expires** to **Never**. - 1. Click **Add**. - 1. Before leaving this page, record the secret. You will use this value later as the _Client secret_ when you register your Azure AD application with your bot. - -1. In the navigation pane, click **API permissions** to open the **API permissions** panel. It is a best practice to explicitly set the API permissions for the app. - - 1. Click **Add a permission** to show the **Request API permissions** pane. - 1. For this sample, select **Microsoft APIs** and **Microsoft Graph**. - 1. Choose **Delegated permissions** and make sure the permissions you need are selected. This sample requires theses permissions. - - > [!NOTE] - > Any permission marked as **ADMIN CONSENT REQUIRED** will require both a user and a tenant admin to login, so for your bot tend to stay away from these. - - - **openid** - - **profile** - - **Mail.Read** - - **Mail.Send** - - **User.Read** - - **User.ReadBasic.All** - - 1. Click **Add permissions**. (The first time a user accesses this app through the bot, they will need to grant consent.) - -You now have an Azure AD application configured. - -### Register your Azure AD application with your bot - -The next step is to register with your bot the Azure AD application that you just created. - -#### Azure AD v1 - -1. Navigate to your bot's resource page on the [Azure Portal](https://portal.azure.com/). -1. Click **Settings**. -1. Under **OAuth Connection Settings** near the bottom of the page, click **Add Setting**. -1. Fill in the form as follows: - - 1. For **Name**, enter a name for your connection. You'll use this name in your bot code. - 1. For **Service Provider**, select **Azure Active Directory**. Once you select this, the Azure AD-specific fields will be displayed. - 1. For **Client id**, enter the application (client) ID that you recorded for your Azure AD v1 application. - 1. For **Client secret**, enter the secret that you created to grant the bot access to the Azure AD app. - 1. For **Grant Type**, enter `authorization_code`. - 1. For **Login URL**, enter `https://login.microsoftonline.com`. - 1.For **Tenant ID**, enter the **directory (tenant) ID** that your recorded earlier for your AAD app or **common** depending on the supported account types selected when you created the ADD app. To decide which value to assign follow these criteria: - - - When creating the AAD app if you selected either *Accounts in this organizational directory only (Microsoft only - Single tenant)* or *Accounts in any organizational directory(Microsoft AAD directory - Multi tenant)* enter the **tenant ID** you recorded earlier for the AAD app. - - - However, if you selected *Accounts in any organizational directory (Any AAD directory - Multi tenant and personal Microsoft accounts e.g. Skype, Xbox, Outlook.com)* enter the word **common** instead of a tenant ID. Otherwise, the AAD app will verify through the tenant whose ID was selected and exclude personal MS accounts. - - This will be the tenant associated with the users who can be authenticated. - - 1. For **Resource URL**, enter `https://graph.microsoft.com/`. - 1. Leave **Scopes** blank. - -1. Click **Save**. - -> [!NOTE] -> These values enable your application to access Office 365 data via the Microsoft Graph API. - -#### Azure AD v2 - -1. Navigate to your bot's Bot Channels Registration page on the [Azure Portal](https://portal.azure.com/). -1. Click **Settings**. -1. Under **OAuth Connection Settings** near the bottom of the page, click **Add Setting**. -1. Fill in the form as follows: - - 1. For **Name**, enter a name for your connection. You'll use it in your bot code. - 1. For **Service Provider**, select **Azure Active Directory v2**. Once you select this, the Azure AD-specific fields will be displayed. - 1. For **Client id**, enter the application (client) ID that you recorded for your Azure AD v1 application. - 1. For **Client secret**, enter the secret that you created to grant the bot access to the Azure AD app. - 1. For **Tenant ID**, enter the **directory (tenant) ID** that your recorded earlier for your AAD app or **common** depending on the supported account types selected when you created the ADD app. To decide which value to assign follow these criteria: - - - When creating the AAD app if you selected either *Accounts in this organizational directory only (Microsoft only - Single tenant)* or *Accounts in any organizational directory(Microsoft AAD directory - Multi tenant)* enter the **tenant ID** you recorded earlier for the AAD app. - - - However, if you selected *Accounts in any organizational directory (Any AAD directory - Multi tenant and personal Microsoft accounts e.g. Skype, Xbox, Outlook.com)* enter the word **common** instead of a tenant ID. Otherwise, the AAD app will verify through the tenant whose ID was selected and exclude personal MS accounts. - - This will be the tenant associated with the users who can be authenticated. - - 1. For **Scopes**, enter the names of the permission you chose from application registration: - `Mail.Read Mail.Send openid profile User.Read User.ReadBasic.All`. - - > [!NOTE] - > For Azure AD v2, **Scopes** takes a case-sensitive, space-separated list of values. - -1. Click **Save**. - -> [!NOTE] -> These values enable your application to access Office 365 data via the Microsoft Graph API. - -### Test your connection - -1. Click on the connection entry to open the connection you just created. -1. Click **Test Connection** at the top of the **Service Provider Connection Setting** pane. -1. The first time, this should open a new browser tab listing the permissions your app is requesting and prompt you to accept. -1. Click **Accept**. -1. This should then redirect you to a **Test Connection to \ Succeeded** page. - -You can now use this connection name in your bot code to retrieve user tokens. - -## Prepare the bot code - -You will need your bot's app ID and password to complete this process. - -# [C#](#tab/csharp) - - - -1. Clone from the github repository the sample you want to work with: [**Bot authentication**][cs-auth-sample] or [**Bot authentication MSGraph**][cs-msgraph-sample]. -1. Update **appsettings.json**: - - - Set `ConnectionName` to the name of the OAuth connection setting you added to your bot. - - Set `MicrosoftAppId` and `MicrosoftAppPassword` to your bot's app ID and app secret. - - Depending on the characters in your bot secret, you may need to XML escape the password. For example, any ampersands (&) will need to be encoded as `&`. - - [!code-json[appsettings](~/../botbuilder-samples/samples/csharp_dotnetcore/18.bot-authentication/appsettings.json)] - -# [JavaScript](#tab/javascript) - -1. Clone from the github repository you want to work with: [**Bot authentication**][js-auth-sample] or [**Bot authentication MSGraph**][js-msgraph-sample]. -1. Update **.env**: - - - Set `connectionName` to the name of the OAuth connection setting you added to your bot. - - Set `MicrosoftAppId` and `MicrosoftAppPassword` values to your bot's app ID and app secret. - - Depending on the characters in your bot secret, you may need to XML escape the password. For example, any ampersands (&) will need to be encoded as `&`. - - [!code-txt[.env](~/../botbuilder-samples/samples/javascript_nodejs/18.bot-authentication/.env)] - -# [Python](#tab/python) - -1. Clone the sample [**Bot authentication**][python-auth-sample] from the github repository. -1. Update **config.py**: - - - Set `ConnectionName` to the name of the OAuth connection setting you added to your bot. - - Set `MicrosoftAppId` and `MicrosoftAppPassword` to your bot's app ID and app secret. - - Depending on the characters in your bot secret, you may need to XML escape the password. For example, any ampersands (&) will need to be encoded as `&`. - - [!code-python[config](~/../botbuilder-samples/samples/python/18.bot-authentication/config.py)] - ---- - -If you do not know how to get your **Microsoft app ID** and **Microsoft app password** values, you can create a new password [as described here](../bot-service-quickstart-registration.md#get-registration-password) - -> [!NOTE] -> You could now publish this bot code to your Azure subscription (right-click on the project and choose **Publish**), but it is not necessary for this article. You would need to set up a publishing configuration that uses the application and hosting plan that you used when configuration the bot in the Azure Portal. - -## Test the bot using the emulator - -If you have not done so already, install the [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme). See also [Debug with the emulator](../bot-service-debug-emulator.md). - - -In order for the bot sample login to work you must configure the emulator -as shown in [Configure the emulator for authentication](../bot-service-debug-emulator.md#configure-the-emulator-for-authentication). - -### Testing - -After you have configured the authentication mechanism, you can perform the actual bot sample testing. - -1. Run the bot sample locally on your machine. -1. Start the emulator. -1. You will need to provide your bot's app ID and password when you connect to the bot. - - You get the app ID and the password from the Azure app registration. These are the same values you assigned to the bot app in the `appsettings.json` or `.env` file. In the emulator, you assign these values in the configuration file or the first time you connect to the bot. - - If you needed to XML-escape the password in your bot code, you also need to do so here. -1. Type `help` to see a list of available commands for the bot, and test the authentication features. -1. Once you've signed in, you don't need to provide your credentials again until you sign out. -1. To sign out, and cancel your authentication, type `logout`. - -> [!NOTE] -> Bot authentication requires use of the Bot Connector Service. The service accesses the bot channels registration information for your bot. - -## Bot authentication example - -In the **Bot authentication** sample, the dialog is designed to retrieve the user token after the user is logged in. - -![Sample output](media/how-to-auth/auth-bot-test.png) - -## Bot authentication MSGraph example - -In the **Bot authentication MSGraph** sample, the dialog is designed to accept a limited set of commands after the user is logged in. - -![Sample output](media/how-to-auth/msgraph-bot-test.png) - ---- - -## Additional information - -When a user asks the bot to do something that requires the bot to have the user logged in, the bot can use an `OAuthPrompt` to initiate retrieving a token for a given connection. The `OAuthPrompt` creates a token retrieval flow that consists of: - -1. Checking to see if the Azure Bot Service already has a token for the current user and connection. If there is a token, the token is returned. -1. If Azure Bot Service does not have a cached token, an `OAuthCard` is created which is a sign in button the user can click on. -1. After the user clicks on the `OAuthCard` sign in button, Azure Bot Service will either send the bot the user's token directly or will present the user with a 6-digit authentication code to enter in the chat window. -1. If the user is presented with an authentication code, the bot then exchanges this authentication code for the user's token. - -The following sections describe how the sample implements some common authentication tasks. - -### Use an OAuth prompt to sign the user in and get a token - -# [C#](#tab/csharp) - -![Bot architecture](media/how-to-auth/architecture.png) - - - -**Dialogs\MainDialog.cs** - -Add an OAuth prompt to **MainDialog** in its constructor. Here, the value for the connection name was retrieved from the **appsettings.json** file. - -[!code-csharp[Add OAuthPrompt](~/../botbuilder-samples/samples/csharp_dotnetcore/18.bot-authentication/Dialogs/MainDialog.cs?range=23-31)] - -Within a dialog step, use `BeginDialogAsync` to start the OAuth prompt, which asks the user to sign in. - -- If the user is already signed in, this will generate a token response event, without prompting the user. -- Otherwise, this will prompt the user to sign in. The Azure Bot Service sends the token response event after the user attempts to sign in. - -[!code-csharp[Use the OAuthPrompt](~/../botbuilder-samples/samples/csharp_dotnetcore/18.bot-authentication/Dialogs/MainDialog.cs?range=49)] - -Within the following dialog step, check for the presence of a token in the result from the previous step. If it is not null, the user successfully signed in. - -[!code-csharp[Get the OAuthPrompt result](~/../botbuilder-samples/samples/csharp_dotnetcore/18.bot-authentication/Dialogs/MainDialog.cs?range=54-56)] - -# [JavaScript](#tab/javascript) - -![Bot architecture](media/how-to-auth/architecture-js.png) - -**dialogs/mainDialog.js** - -Add an OAuth prompt to **MainDialog** in its constructor. Here, the value for the connection name was retrieved from the **.env** file. - -[!code-javascript[Add OAuthPrompt](~/../botbuilder-samples/samples/javascript_nodejs/18.bot-authentication/dialogs/mainDialog.js?range=24-29)] - -Within a dialog step, use `beginDialog` to start the OAuth prompt, which asks the user to sign in. - -- If the user is already signed in, this will generate a token response event, without prompting the user. -- Otherwise, this will prompt the user to sign in. The Azure Bot Service sends the token response event after the user attempts to sign in. - -[!code-javascript[Use OAuthPrompt](~/../botbuilder-samples/samples/javascript_nodejs/18.bot-authentication/dialogs/mainDialog.js?range=57)] - -Within the following dialog step, check for the presence of a token in the result from the previous step. If it is not null, the user successfully signed in. - -[!code-javascript[Get OAuthPrompt result](~/../botbuilder-samples/samples/javascript_nodejs/18.bot-authentication/dialogs/mainDialog.js?range=62-63)] - -# [Python](#tab/python) - -![Bot architecture](media/how-to-auth/architecture-python.png) - -**dialogs/main_dialog.py** - -Add an OAuth prompt to **MainDialog** in its constructor. Here, the value for the connection name was retrieved from the **config.py** file. - -[!code-python[Add OAuthPrompt](~/../botbuilder-samples/samples/python/18.bot-authentication/dialogs/main_dialog.py?range=34-44)] - -Within a dialog step, use `begin_dialog` to start the OAuth prompt, which asks the user to sign in. - -- If the user is already signed in, this will generate a token response event, without prompting the user. -- Otherwise, this will prompt the user to sign in. The Azure Bot Service sends the token response event after the user attempts to sign in. - -[!code-python[Add OAuthPrompt](~/../botbuilder-samples/samples/python/18.bot-authentication/dialogs/main_dialog.py?range=49)] - -Within the following dialog step, check for the presence of a token in the result from the previous step. If it is not null, the user successfully signed in. - -[!code-python[Add OAuthPrompt](~/../botbuilder-samples/samples/python/18.bot-authentication/dialogs/main_dialog.py?range=54-65)] - ---- - -### Wait for a TokenResponseEvent - -When you start an OAuth prompt, it waits for a token response event, from which it will retrieve the user's token. - -# [C#](#tab/csharp) - -**Bots\AuthBot.cs** - -**AuthBot** derives from `ActivityHandler` and explicitly handles token response event activities. Here, we continue the active dialog, which allows the OAuth prompt to process the event and retrieve the token. - -[!code-csharp[OnTokenResponseEventAsync](~/../botbuilder-samples/samples/csharp_dotnetcore/18.bot-authentication/Bots/AuthBot.cs?range=32-38)] - -# [JavaScript](#tab/javascript) - -**bots/authBot.js** - -**AuthBot** derives from `ActivityHandler` and explicitly handles token response event activities. Here, we continue the active dialog, which allows the OAuth prompt to process the event and retrieve the token. - -[!code-javascript[onTokenResponseEvent](~/../botbuilder-samples/samples/javascript_nodejs/18.bot-authentication/bots/authBot.js?range=29-31)] - -# [Python](#tab/python) - -**bots/auth_bot.py** - -**AuthBot** explicitly handles token response event activities. Here, we continue the active dialog, which allows the OAuth prompt to process the event and retrieve the token. - -[!code-python[on_token_response_event](~/../botbuilder-samples/samples/python/18.bot-authentication/bots/auth_bot.py?range=38-44)] - ---- - -### Log the user out - -It is best practice to let users explicitly sign out or logout, instead of relying on the connection to time out. - -# [C#](#tab/csharp) - -**Dialogs\LogoutDialog.cs** -[!code-csharp[Allow logout](~/../botbuilder-samples/samples/csharp_dotnetcore/18.bot-authentication/Dialogs/LogoutDialog.cs?range=44-61&highlight=11)] - -# [JavaScript](#tab/javascript) - -**dialogs/logoutDialog.js** -[!code-javascript[Allow logout](~/../botbuilder-samples/samples/javascript_nodejs/18.bot-authentication/dialogs/logoutDialog.js?range=31-42&highlight=7)] - -# [Python](#tab/python) - -**dialogs/logout_dialog.py** -[!code-python[allow logout](~/../botbuilder-samples/samples/python/18.bot-authentication/dialogs/logout_dialog.py?range=27-34&highlight=6)] - ---- - -### Adding Teams Authentication - -Teams behaves somewhat differently than other channels in regards to OAuth and requires a few changes to properly implement authentication. We will add code from the Teams Authentication Bot sample ([C#][cs-teams-auth-sample]/[JavaScript][js-teams-auth-sample]). - -One difference between other channels and Teams is that Teams sends an *invoke* activity to the bot, rather than an *event* activity. - -# [C#](#tab/csharp) - -**Bots/TeamsBot.cs** -[!code-csharp[Invoke Activity](~/../botbuilder-samples/samples/csharp_dotnetcore/46.teams-auth/Bots/TeamsBot.cs?range=34-42&highlight=1)] - -# [JavaScript](#tab/javascript) - -**bots/teamsBot.js** -[!code-javascript[Invoke Activity](~/../botbuilder-samples/samples/javascript_nodejs/46.teams-auth/bots/teamsBot.js?range=16-25&highlight=1)] - -# [Python](#tab/python) - -Microsoft Teams currently differs slightly in the way auth is integrated with the bot. Please, refer to [Teams documentation](https://aka.ms/teams-docs) on authentication. - ---- - -If you use an *OAuth prompt*, this invoke activity must be forwarded to the dialog. We will do so in the `TeamsActivityHandler`. Add the following code to your main dialog file. - -# [C#](#tab/csharp) - -**Bots/DialogBot.cs** -[!code-csharp[Dialogs Handler](~/../botbuilder-samples/samples/csharp_dotnetcore/46.teams-auth/Bots/DialogBot.cs?range=19)] - -# [JavaScript](#tab/javascript) - -**Bots/dialogBot.js** -[!code-javascript[Dialogs Handler](~/../botbuilder-samples/samples/javascript_nodejs/46.teams-auth/bots/dialogBot.js?range=6)] - -# [Python](#tab/python) - -Microsoft Teams currently differs slightly in the way auth is integrated with the bot. Please, refer to [Teams documentation](https://aka.ms/teams-docs) on authentication. - ---- - -Finally, make sure to add an appropriate `TeamsActivityHandler` file (`TeamsActivityHandler.cs` for C# bots and `teamsActivityHandler.js` for Javascript bots) at the topmost level in your bot's folder. - -The `TeamsActivityHandler` also sends *message reaction* activities. A message reaction activity references the original activity using the *reply to ID* field. This activity should also be visible through the [Activity Feed][teams-activity-feed] in Microsoft Teams. - -> [!NOTE] -> You need to create a manifest and include `token.botframework.com` in the `validDomains` section; otherwise the OAuthCard **Sign in** button will not open the authentication window. Use the [App Studio](https://docs.microsoft.com/microsoftteams/platform/get-started/get-started-app-studio) to generate your manifest. - -### Further reading - -- [Bot Framework additional resources](https://docs.microsoft.com/azure/bot-service/bot-service-resources-links-help) includes links for additional support. -- The [Bot Framework SDK](https://github.com/microsoft/botbuilder) repo has more information about repos, samples, tools, and specs associated with the Bot Builder SDK. - - - -[Azure portal]: https://ms.portal.azure.com -[azure-aad-blade]: https://ms.portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/Overview -[aad-registration-blade]: https://ms.portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview - -[concept-basics]: bot-builder-basics.md -[concept-state]: bot-builder-concept-state.md -[concept-dialogs]: bot-builder-concept-dialog.md - -[simple-dialog]: bot-builder-dialog-manage-conversation-flow.md -[dialog-prompts]: bot-builder-prompts.md -[component-dialogs]: bot-builder-compositcontrol.md - -[cs-auth-sample]: https://aka.ms/v4cs-bot-auth-sample -[js-auth-sample]: https://aka.ms/v4js-bot-auth-sample -[python-auth-sample]: https://aka.ms/bot-auth-python-sample-code - -[cs-msgraph-sample]: https://aka.ms/v4cs-auth-msgraph-sample -[js-msgraph-sample]: https://aka.ms/v4js-auth-msgraph-sample -[cs-teams-auth-sample]:https://aka.ms/cs-teams-auth-sample -[js-teams-auth-sample]:https://aka.ms/js-teams-auth-sample -[teams-activity-feed]:[https://aka.ms/teams-activity-feed diff --git a/articles/v4sdk/bot-builder-basics-teams.md b/articles/v4sdk/bot-builder-basics-teams.md deleted file mode 100644 index 9bc0196c7..000000000 --- a/articles/v4sdk/bot-builder-basics-teams.md +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: How bots for Microsoft Teams work -description: A continuation of the article on How bots work specific to Microsoft Teams bots -author: WashingtonKayaker -ms.author: kamrani -manager: kamrani -ms.topic: overview -ms.service: bot-service -ms.date: 10/31/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# How Microsoft Teams bots work - -This is an introduction that builds on what you learned in the article [How bots work](https://docs.microsoft.com/azure/bot-service/bot-builder-basics), you should be familiar with that article before reading this. - -The primary differences in bots developed for Microsoft Teams is in how activities are handled. The Microsoft Teams activity handler derives from the Bot Framework's activity handler to route all teams activities before allowing any non-teams specific activities to be handled. - -## Teams Activity handlers - -Just like any other bot, when a bot is designed for Microsoft Teams receives an activity, it passes it on to its *activity handlers*. Under the covers, there is one base handler called the *turn handler*, that all activities are routed through. The *turn handler* calls the required activity handler to handle whatever type of activity was received. Where a bot designed for Microsoft Teams differs is that it is derived from a _Teams_ `Activity Handler` class that is derived from the Bot Framework's `Activity Handler` class. The _Teams_ `Activity Handler` class includes various Microsoft Teams specific activity handlers that will be discussed in this article. - -# [C#](#tab/csharp) - -As with any bot created using the Microsoft Bot Framework, if the bot receives a message activity, the turn handler would see that incoming activity and send it to the `OnMessageActivityAsync` activity handler. This functionality remains the same, however if the bot receives a conversation update activity, the turn handler would see that incoming activity and send it to the `OnConversationUpdateActivityAsync` _Teams_ activity handler that will first check for any Teams specific events and pass it along to the Bot Framework's activity handler if none are found. - -In the Teams activity handler class there are two primary Teams activity handlers, `OnConversationUpdateActivityAsync` that routes all conversation update activities, and `OnInvokeActivityAsync` that routes all Teams invoke activities. All of the activity handlers described in the [Bot logic](https://aka.ms/how-bots-work#bot-logic) section of the `How bots work` article will continue to work as they do with a non-Teams bot, with the exception of handling the members added and removed activities, these will be different in the context of a team, where the new member is added to the team as opposed to a message thread. See the _Teams conversation update activities_ table in the [Bot logic](#bot-logic) section for more details. - -To implement your logic for these Teams specific activity handlers, you will override these methods in your bot as shown in the [Bot logic](#bot-logic) section below. For each of these handlers, there is no base implementation, so just add the logic that you want in your override. - -# [JavaScript](#tab/javascript) - -As with any bot created using the Microsoft Bot Framework, if the bot receives a message activity, the turn handler would see that incoming activity and send it to the `onMessage` activity handler. This functionality remains the same, however if the bot receives a conversation update activity, the turn handler would see that incoming activity and send it to the `dispatchConversationUpdateActivity` _Teams_ activity handler that will first check for any Teams specific events and pass it along to the Bot Framework's activity handler if none are found. - -In the Teams activity handler class there are two primary Teams activity handlers, `dispatchConversationUpdateActivity` that routes all conversation update Activities, and `onInvokeActivity` that routes all Teams invoke activities. All of the activity handlers described in the [Bot logic](https://aka.ms/how-bots-work#bot-logic) section of the `How bots work` article will continue to work as they do with a non-Teams bot, with the exception of handling the members added and removed activities, these will be different in the context of a team, where the new member is added to the team as opposed to a message thread. See the _Teams conversation update activities_ table in the [Bot logic](#bot-logic) section for more details. - -As with any bot handler, to implement your logic for the Teams handlers, you will override the methods in your bot as seen in the [Bot logic](#bot-logic) section below. For each of these handlers, define your bot logic, then **be sure to call `next()` at the end**. By calling `next()` you ensure that the next handler is run. - ---- - -### Bot logic - -The bot logic processes incoming activities from one or more of your bots channels and generates outgoing activities in response. This is still true of bot derived from the Teams activity handler class, which first checks for Teams activities, then passes all other activities to the Bot Framework's activity handler. - -# [C#](#tab/csharp) - -#### Teams conversation update activities - -Below is a list of all of the Teams activity handlers called from the `OnConversationUpdateActivityAsync` _Teams_ activity handler. The [Conversation update events](https://aka.ms/azure-bot-subscribe-to-conversation-events) article describes how to use each of these events in a bot. - -| Event | Handler | Description | -| :-- | :-- | :-- | -| channelCreated | `OnTeamsChannelCreatedAsync` | Override this to handle a Teams channel being created. For more information see [Channel created](https://aka.ms/azure-bot-subscribe-to-conversation-events#channel-created). | -| channelDeleted | `OnTeamsChannelDeletedAsync` | Override this to handle a Teams channel being deleted. For more information see [Channel deleted](https://aka.ms/azure-bot-subscribe-to-conversation-events#channel-deleted). | -| channelRenamed | `OnTeamsChannelRenamedAsync` | Override this to handle a Teams channel being renamed. For more information see [Channel renamed](https://aka.ms/azure-bot-subscribe-to-conversation-events#channel-renamed). | -| teamRenamed | `OnTeamsTeamRenamedAsync` | `return Task.CompletedTask;` Override this to handle a Teams Team being Renamed. For more information see [Team renamed](https://aka.ms/azure-bot-subscribe-to-conversation-events#team-renamed). | -| MembersAdded | `OnTeamsMembersAddedAsync` | Calls the `OnMembersAddedAsync` method in `ActivityHandler`. Override this to handle members joining a team. For more information see [Team member added](https://aka.ms/azure-bot-subscribe-to-conversation-events#Team-Member-Added).| -| MembersRemoved | `OnTeamsMembersRemovedAsync` | Calls the `OnMembersRemovedAsync` method in `ActivityHandler`. Override this to handle members leaving a team. For more information see [Team member removed](https://aka.ms/azure-bot-subscribe-to-conversation-events#Team-Member-Removed).| - - - - -#### Teams invoke activities - -Here is a list of all of the Teams activity handlers called from the `OnInvokeActivityAsync` _Teams_ activity handler: - -| Invoke types | Handler | Description | -| :----------------------------- | :----------------------------------- | :----------------------------------------------------------- | -| CardAction.Invoke | `OnTeamsCardActionInvokeAsync` | Teams Card Action Invoke. | -| fileConsent/invoke | `OnTeamsFileConsentAcceptAsync` | Teams File Consent Accept. | -| fileConsent/invoke | `OnTeamsFileConsentAsync` | Teams File Consent. | -| fileConsent/invoke | `OnTeamsFileConsentDeclineAsync` | Teams File Consent. | -| actionableMessage/executeAction | `OnTeamsO365ConnectorCardActionAsync` | Teams O365 Connector Card Action. | -| signin/verifyState | `OnTeamsSigninVerifyStateAsync` | Teams Sign in Verify State. | -| task/fetch | `OnTeamsTaskModuleFetchAsync` | Teams Task Module Fetch. | -| task/submit | `OnTeamsTaskModuleSubmitAsync` | Teams Task Module Submit. | - -The invoke activities listed above are for conversational bots in Teams. The Bot Framework SDK also supports invokes specific to messaging extensions. For more information see [What are messaging extensions](https://aka.ms/azure-bot-what-are-messaging-extensions) - -# [JavaScript](#tab/javascript) - -#### Teams conversation update activities - -Below is a list of all of the Teams activity handlers called from the `dispatchConversationUpdateActivity` _Teams_ activity handler. The [Conversation update events](https://aka.ms/azure-bot-subscribe-to-conversation-events) article describes how to use each of these events in a bot. - -| Event | Handler | Description | -| :-- | :-- | :-- | -| channelCreated | `OnTeamsChannelCreatedEvent` | Override this to handle a Teams channel being created. For more information see [Channel created](https://aka.ms/azure-bot-subscribe-to-conversation-events#channel-created). | -| channelDeleted | `OnTeamsChannelDeletedEvent` | Override this to handle a Teams channel being deleted. For more information see [Channel deleted](https://aka.ms/azure-bot-subscribe-to-conversation-events#channel-deleted).| -| channelRenamed | `OnTeamsChannelRenamedEvent` | Override this to handle a Teams channel being renamed. For more information see [Channel renamed](https://aka.ms/azure-bot-subscribe-to-conversation-events#channel-renamed). | -| teamRenamed | `OnTeamsTeamRenamedEvent` | `return Task.CompletedTask;` Override this to handle a Teams Team being Renamed. For more information see [Team renamed](https://aka.ms/azure-bot-subscribe-to-conversation-events#team-renamed). | -| MembersAdded | `OnTeamsMembersAddedEvent` | Calls the `OnMembersAddedEvent` method in `ActivityHandler`. Override this to handle members joining a team. For more information see [Team member added](https://aka.ms/azure-bot-subscribe-to-conversation-events#Team-Member-Added). | -| MembersRemoved | `OnTeamsMembersRemovedEvent` | Calls the `OnMembersRemovedEvent` method in `ActivityHandler`. Override this to handle members leaving a team. For more information see [Team member removed](https://aka.ms/azure-bot-subscribe-to-conversation-events#Team-Member-Removed). | - - - -#### Teams invoke activities - -Here is a list of all of the Teams activity handlers called from the `onInvokeActivity` _Teams_ activity handler: - -| Invoke types | Handler | Description | -| :----------------------------- | :----------------------------------- | :----------------------------------------------------------- | -| CardAction.Invoke | `handleTeamsCardActionInvoke` | Teams Card Action Invoke. | -| fileConsent/invoke | `handleTeamsFileConsentAccept` | Teams File Consent Accept. | -| fileConsent/invoke | `handleTeamsFileConsent` | Teams File Consent. | -| fileConsent/invoke | `handleTeamsFileConsentDecline` | Teams File Consent. | -| actionableMessage/executeAction | `handleTeamsO365ConnectorCardAction` | Teams O365 Connector Card Action. | -| signin/verifyState | `handleTeamsSigninVerifyState` | Teams Sign in Verify State. | -| task/fetch | `handleTeamsTaskModuleFetch` | Teams Task Module Fetch. | -| task/submit | `handleTeamsTaskModuleSubmit` | Teams Task Module Submit. | - -The invoke activities listed above are for conversational bots in Teams. The Bot Framework SDK also supports invokes specific to messaging extensions. For more information see [What are messaging extensions](https://aka.ms/azure-bot-what-are-messaging-extensions) - ---- - -## Next steps -For building Teams bots, refer to Microsoft Teams Developer [documentation](https://aka.ms/teams-docs). \ No newline at end of file diff --git a/articles/v4sdk/bot-builder-basics.md b/articles/v4sdk/bot-builder-basics.md deleted file mode 100644 index 7f536fbef..000000000 --- a/articles/v4sdk/bot-builder-basics.md +++ /dev/null @@ -1,538 +0,0 @@ ---- -title: How bots work - Bot Service -description: Describes how activity and http work within the Bot Framework SDK. -keywords: conversation flow, turn, bot conversation, dialogs, prompts, waterfalls, dialog set -author: johnataylor -ms.author: johtaylo -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/31/2020 -monikerRange: 'azure-bot-service-4.0' ---- - -# How bots work - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -A bot is an app that users interact with in a conversational way, using text, graphics (such as cards or images), or speech. Every interaction between the user and the bot generates an *activity*. The Bot Framework Service, which is a component of the Azure Bot Service, sends information between the user's bot-connected app (such as Facebook, Skype, Slack, etc. which we call the *channel*) and the bot. Each channel may include additional information in the activities they send. Before creating bots, it is important to understand how a bot uses activity objects to communicate with its users. Let's first take a look at activities that are exchanged when we run a simple echo bot. - -![activity diagram](media/bot-builder-activity.png) - -Two activity types illustrated here are: *conversation update* and *message*. - -The Bot Framework Service may send a conversation update when a party joins the conversation. For example, on starting a conversation with the Bot Framework Emulator, you will see two conversation update activities (one for the user joining the conversation and one for the bot joining). To distinguish these conversation update activities, check whether the *members added* property includes a member other than the bot. - -The message activity carries conversation information between the parties. In an echo bot example, the message activities are carrying simple text and the channel will render this text. Alternatively, the message activity might carry text to be spoken, suggested actions or cards to be displayed. - -In this example, the bot created and sent a message activity in response to the inbound message activity it had received. However, a bot can respond in other ways to a received message activity; it’s not uncommon for a bot to respond to a conversation update activity by sending some welcome text in a message activity. More information can be found in [welcoming the user](bot-builder-welcome-user.md). - -### HTTP Details - -Activities arrive at the bot from the Bot Framework Service via an HTTP POST request. The bot responds to the inbound POST request with a 200 HTTP status code. Activities sent from the bot to the channel are sent on a separate HTTP POST to the Bot Framework Service. This, in turn, is acknowledged with a 200 HTTP status code. - -The protocol doesn’t specify the order in which these POST requests and their acknowledgments are made. However, to fit with common HTTP service frameworks, typically these requests are nested, meaning that the outbound HTTP request is made from the bot within the scope of the inbound HTTP request. This pattern is illustrated in the diagram above. Since there are two distinct HTTP connections back to back, the security model must provide for both. - -### Defining a turn - -In a conversation, people often speak one-at-a-time, taking turns speaking. With a bot, it generally reacts to user input. Within the Bot Framework SDK, a _turn_ consists of the user's incoming activity to the bot and any activity the bot sends back to the user as an immediate response. You can think of a turn as the processing associated with the arrival of a given activity. - -The *turn context* object provides information about the activity such as the sender and receiver, the channel, and other data needed to process the activity. It also allows for the addition of information during the turn across various layers of the bot. - -The turn context is one of the most important abstractions in the SDK. Not only does it carry the inbound activity to all the middleware components and the application logic but it also provides the mechanism whereby the middleware components and the application logic can send outbound activities. - -## The activity processing stack - -Let's drill into the previous diagram with a focus on the arrival of a message activity. - -![activity processing stack](media/bot-builder-activity-processing-stack.png) - -In the example above, the bot replied to the message activity with another message activity containing the same text message. Processing starts with the HTTP POST request, with the activity information carried as a JSON payload, arriving at the web server. In C# this will typically be an ASP.NET project, in a JavaScript Node.js project this is likely to be one of the popular frameworks such as Express or Restify. - -The *adapter*, an integrated component of the SDK, is the core of the SDK runtime. The activity is carried as JSON in the HTTP POST body. This JSON is deserialized to create the Activity object that is then handed to the adapter with a call to *process activity* method. On receiving the activity, the adapter creates a *turn context* and calls the middleware. - -As mentioned above, the turn context provides the mechanism for the bot to send outbound activities, most often in response to an inbound activity. To achieve this, the turn context provides _send, update, and delete activity_ response methods. Each response method runs in an asynchronous process. - -[!INCLUDE [alert-await-send-activity](../includes/alert-await-send-activity.md)] - -## Activity handlers - -When the bot receives an activity, it passes it on to its *activity handlers*. Under the covers, there is one base handler called the *turn handler*. All activities get routed through there. That turn handler then calls the individual activity handler for whatever type of activity it received. - -# [C#](#tab/csharp) - -For example, if the bot receives a message activity, the turn handler would see that incoming activity and send it to the `OnMessageActivityAsync` activity handler. - -When building your bot, your bot logic for handling and responding to messages will go in this `OnMessageActivityAsync` handler. Likewise, your logic for handling members being added to the conversation will go in your `OnMembersAddedAsync` handler, which is called whenever a member is added to the conversation. - -To implement your logic for these handlers, you will override these methods in your bot as seen in the [Bot logic](#bot-logic) section below. For each of these handlers, there is no base implementation, so just add the logic that you want in your override. - -There are certain situations where you will want to override the base turn handler, such as [saving state](bot-builder-concept-state.md) at the end of a turn. When doing so, be sure to first call `await base.OnTurnAsync(turnContext, cancellationToken);` to make sure the base implementation of `OnTurnAsync` is run before your additional code. That base implementation is, among other things, responsible for calling the rest of the activity handlers such as `OnMessageActivityAsync`. - -# [JavaScript](#tab/javascript) - -The JavaScript `ActivityHandler` uses an event emitter and listener pattern. -For example, use the `onMessage` method to register an event listener for message activities. You can register more than one listener. When the bot receives a message activity, the activity handler would see that incoming activity and send it each of the `onMessage` activity listeners, in the order in which they were registered. - -When building your bot, your bot logic for handling and responding to messages will go in the `onMessage` listeners. Likewise, your logic for handling members being added to the conversation will go in your `onMembersAdded` listeners, which are called whenever a member is added to the conversation. -To add these listeners, you will register them in your bot as seen in the [Bot logic](#bot-logic) section below. For each listener, include your bot logic, then **be sure to call `next()` at the end**. By calling `next()` you ensure that the next listener is run. - -Make sure to [save state](bot-builder-concept-state.md) before the turn ends. You can do so by overriding the activity handler `run` method and saving state after the parent's `run` method completes. - -There aren't any common situations where you will want to override the base turn handler, so be careful if you try to do so. -There is a special handler called `onDialog`. The `onDialog` handler runs at the end, after the rest of the handlers have run, and is not tied to a certain activity type. As with all the above handlers, be sure to call `next()` to ensure the rest of the process wraps up. - -# [Python](#tab/python) - -For example, if the bot receives a message activity, the turn handler would see that incoming activity and send it to the `on_message_activity` activity handler. - -When building your bot, your bot logic for handling and responding to messages will go in this `on_message_activity` handler. Likewise, your logic for handling members being added to the conversation will go in your `on_members_added` handler, which is called whenever a member is added to the conversation. - -To implement your logic for these handlers, you will override these methods in your bot as seen in the [Bot logic](#bot-logic) section below. For each of these handlers, there is no base implementation, so just add the logic that you want in your override. - -There are certain situations where you will want to override the base turn handler, such as [saving state](bot-builder-concept-state.md) at the end of a turn. When doing so, be sure to first call `await super().on_turn(turnContext);` to make sure the base implementation of `on_turn` is run before your additional code. That base implementation is, among other things, responsible for calling the rest of the activity handlers such as `on_message_activity`. - ---- - -## Middleware - -Middleware is much like any other messaging middleware, comprising a linear set of components that are each executed in order, giving each a chance to operate on the activity. The final stage of the middleware pipeline is a callback to the turn handler on the bot class the application has registered with the adapter's *process activity* method. The turn handler is generally `OnTurnAsync` in C# and `onTurn` in JavaScript. - -The turn handler takes a turn context as its argument, typically the application logic running inside the turn handler function will process the inbound activity’s content and generate one or more activities in response, sending these out using the *send activity* function on the turn context. Calling *send activity* on the turn context will cause the middleware components to be invoked on the outbound activities. Middleware components execute before and after the bot’s turn handler function. The execution is inherently nested and, as such, sometimes referred to being like a Russian Doll. For more in depth information about middleware, see the [middleware topic](~/v4sdk/bot-builder-concept-middleware.md). - -## Bot structure - -In the following sections, we examine _key pieces_ of an EchoBot that you can easily create using the templates provided for [**CSharp**](../dotnet/bot-builder-dotnet-sdk-quickstart.md) or [**JavaScript**](../javascript/bot-builder-javascript-quickstart.md). - - - -A bot is a web application, and we provide templates for each language. - -# [C#](#tab/csharp) - -The VSIX template generates a [ASP.NET MVC Core](https://dotnet.microsoft.com/apps/aspnet/mvc) web app. If you look at the [ASP.NET](https://docs.microsoft.com/aspnet/core/fundamentals/index?view=aspnetcore-2.1&tabs=aspnetcore2x) fundamentals, you'll see similar code in files such as **Program.cs** and **Startup.cs**. These files are required for all web apps and are not bot specific. - -### appsettings.json file - -The **appsettings.json** file specifies the configuration information for your bot, such as the app ID, and password among other things. If using certain technologies or using this bot in production, you will need to add your specific keys or URL to this configuration. For this Echo bot, however, you don't need to do anything here right now; the app ID and password may be left undefined at this time. - -# [JavaScript](#tab/javascript) - - - -The Yeoman generator creates a type of [restify](http://restify.com/) web application. If you look at the restify quickstart in their docs, you'll see an app similar to the generated **index.js** file. We describe some of the key files generated by the template. Code in some files won't be copied, but you will see it when you run the bot, and you can refer to the [Node.js echobot](https://aka.ms/js-echobot-sample) sample. - -### package.json - -**package.json** specifies dependencies and their associated versions for your bot. This is all set up by the template and your system. - -### .env file - -The **.env** file specifies the configuration information for your bot, such as the port number, app ID, and password among other things. If using certain technologies or using this bot in production, you will need to add your specific keys or URL to this configuration. For this Echo bot, however, you don't need to do anything here right now; the app ID and password may be left undefined at this time. - -To use the **.env** configuration file, the template needs an extra package included. First, get the `dotenv` package from npm: - -`npm install dotenv` - -# [Python](#tab/python) - -### requirements.txt - -**requirements.txt** specifies dependencies and their associated versions for your bot. This is all setup by the template and your system. - -Dependencies should be installed using `pip install -r requirements.txt` - -### config.py - -The **config.py** file specifies the configuration information for your bot, such as the port number, app ID, and password among other things. If using certain technologies or using this bot in production, you will need to add your specific keys or URL to this configuration. For this Echo bot, however, you don't need to do anything here right now; the app ID and password may be left undefined at this time. - ---- - -### Bot logic - -The bot logic processes incoming activities from one or more channels and generates outgoing activities in response. - -# [C#](#tab/csharp) - -The main bot logic is defined in the bot code, here called `Bots/EchoBot.cs`. `EchoBot` derives from `ActivityHandler`, which in turn derives from the `IBot` interface. `ActivityHandler` defines various handlers for different types of activities, such as the two defined here: `OnMessageActivityAsync`, and `OnMembersAddedAsync`. These methods are protected, but can be overwritten since we're deriving from `ActivityHandler`. - -The handlers defined in `ActivityHandler` are: - -| Event | Handler | Description | -| :-- | :-- | :-- | -| Any activity type received | `OnTurnAsync` | Calls one of the other handlers, based on the type of activity received. | -| Message activity received | `OnMessageActivityAsync` | Override this to handle a `message` activity. | -| Conversation update activity received | `OnConversationUpdateActivityAsync` | On a `conversationUpdate` activity, calls a handler if members other than the bot joined or left the conversation. | -| Non-bot members joined the conversation | `OnMembersAddedAsync` | Override this to handle members joining a conversation. | -| Non-bot members left the conversation | `OnMembersRemovedAsync` | Override this to handle members leaving a conversation. | -| Event activity received | `OnEventActivityAsync` | On an `event` activity, calls a handler specific to the event type. | -| Token-response event activity received | `OnTokenResponseEventAsync` | Override this to handle token response events. | -| Non-token-response event activity received | `OnEventAsync` | Override this to handle other types of events. | -| Message reaction activity received | `OnMessageReactionActivityAsync` | On a `messageReaction` activity, calls a handler if one or more reactions were added or removed from a message. | -| Message reactions added to a message | `OnReactionsAddedAsync` | Override this to handle reactions added to a message. | -| Message reactions removed from a message | `OnReactionsRemovedAsync` | Override this to handle reactions removed from a message. | -| Other activity type received | `OnUnrecognizedActivityTypeAsync` | Override this to handle any activity type otherwise unhandled. | - -These different handlers have a `turnContext` that provides information about the incoming activity, which corresponds to the inbound HTTP request. Activities can be of various types, so each handler provides a strongly-typed activity in its turn context parameter; in most cases, `OnMessageActivityAsync` will always be handled, and is generally the most common. - -As in previous 4.x versions of this framework, there is also the option to implement the public method `OnTurnAsync`. Currently, the base implementation of this method handles error checking and then calls each of the specific handlers (like the two we define in this sample) depending on the type of incoming activity. In most cases, you can leave that method alone and use the individual handlers, but if your situation requires a custom implementation of `OnTurnAsync`, it is still an option. - -> [!IMPORTANT] -> If you do override the `OnTurnAsync` method, you'll need to call `base.OnTurnAsync` to get the base implementation to call all the other `OnAsync` handlers or call those handlers yourself. Otherwise, those handlers won't be called and that code won't be run. - -In this sample, we welcome a new user or echo back the message the user sent using the `SendActivityAsync` call. The outbound activity corresponds to the outbound HTTP POST request. - -```cs -public class MyBot : ActivityHandler -{ - protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) - { - await turnContext.SendActivityAsync(MessageFactory.Text($"Echo: {turnContext.Activity.Text}"), cancellationToken); - } - - protected override async Task OnMembersAddedAsync(IList membersAdded, ITurnContext turnContext, CancellationToken cancellationToken) - { - foreach (var member in membersAdded) - { - await turnContext.SendActivityAsync(MessageFactory.Text($"welcome {member.Name}"), cancellationToken); - } - } -} -``` - -# [JavaScript](#tab/javascript) - -The main bot logic is defined in the bot code, here called `bots\echoBot.js`. `EchoBot` derives from `ActivityHandler`. `ActivityHandler` defines various events for different types of activities, and you can modify your bot's behavior by registering event listeners, such as with `onMessage` and `onConversationUpdate` here. - -Use these methods to register listeners for each type of event: - -| Event | Registration method | Description | -| :-- | :-- | :-- | -| Any activity type received | `onTurn` | Registers a listener for when any activity is received. | -| Message activity received | `onMessage` | Registers a listener for when a `message` activity is received. | -| Conversation update activity received | `onConversationUpdate` | Registers a listener for when any `conversationUpdate` activity is received. | -| Members joined the conversation | `onMembersAdded` | Registers a listener for when members joined the conversation, including the bot. | -| Members left the conversation | `onMembersRemoved` | Registers a listener for when members left the conversation, including the bot. | -| Message reaction activity received | `onMessageReaction` | Registers a listener for when any `messageReaction` activity is received. | -| Message reactions added to a message | `onReactionsAdded` | Registers a listener for when reactions are added to a message. | -| Message reactions removed from a message | `onReactionsRemoved` | Registers a listener for when reactions are removed from a message. | -| Event activity received | `onEvent` | Registers a listener for when any `event` activity is received. | -| Token-response event activity received | `onTokenResponseEvent` | Registers a listener for when a `tokens/response` event is received. | -| Other activity type received | `onUnrecognizedActivityType` | Registers a listener for when a handler for the specific type of activity is not defined. | -| Activity handlers have completed | `onDialog` | Called after any applicable handlers have completed. | - -Call the `next` continuation function from each handler to allow processing to continue. If `next` is not called, processing of the activity ends. - -For example, this bot registers listeners for messages and conversation updates. When it receives a message from the user, it echoes back the message they sent. - -```javascript -const { ActivityHandler } = require('botbuilder'); - -class MyBot extends ActivityHandler { - constructor() { - super(); - // See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types. - this.onMessage(async (context, next) => { - await context.sendActivity(`You said '${ context.activity.text }'`); - // By calling next() you ensure that the next BotHandler is run. - await next(); - }); - this.onConversationUpdate(async (context, next) => { - await context.sendActivity('[conversationUpdate event detected]'); - // By calling next() you ensure that the next BotHandler is run. - await next(); - }); - } -} - -module.exports.MyBot = MyBot; -``` - -# [Python](#tab/python) - -The main bot logic is defined in the bot code, here called `bots/echo_bot.py`. `EchoBot` derives from `ActivityHandler`, which in turn derives from the `Bot` interface. `ActivityHandler` defines various handlers for different types of activities, such as the two defined here: `on_message_activity`, and `on_members_added`. These methods are protected, but can be overwritten since we're deriving from `ActivityHandler`. - -The handlers defined in `ActivityHandler` are: - -| Event | Handler | Description | -| :-- | :-- | :-- | -| Any activity type received | `on_turn` | Calls one of the other handlers, based on the type of activity received. | -| Message activity received | `on_message_activity` | Override this to handle a `message` activity. | -| Conversation update activity received | `on_conversation_update_activity` | On a `conversationUpdate` activity, calls a handler if members other than the bot joined or left the conversation. | -| Non-bot members joined the conversation | `on_members_added_activity` | Override this to handle members joining a conversation. | -| Non-bot members left the conversation | `on_members_removed_activity` | Override this to handle members leaving a conversation. | -| Event activity received | `on_event_activity` | On an `event` activity, calls a handler specific to the event type. | -| Token-response event activity received | `on_token_response_event` | Override this to handle token response events. | -| Non-token-response event activity received | `on_event_activity` | Override this to handle other types of events. | -| Message reaction activity received | `on_message_reaction_activity` | On a `messageReaction` activity, calls a handler if one or more reactions were added or removed from a message. | -| Message reactions added to a message | `on_reactions_added` | Override this to handle reactions added to a message. | -| Message reactions removed from a message | `on_reactions_removed` | Override this to handle reactions removed from a message. | -| Other activity type received | `on_unrecognized_activity_type` | Override this to handle any activity type otherwise unhandled. | - -These different handlers have a `turn_context` that provides information about the incoming activity, which corresponds to the inbound HTTP request. Activities can be of various types, so each handler provides a strongly-typed activity in its turn context parameter; in most cases, `on_message_activity` will always be handled, and is generally the most common. - -As in previous 4.x versions of this framework, there is also the option to implement the public method `on_turn`. Currently, the base implementation of this method handles error checking and then calls each of the specific handlers (like the two we define in this sample) depending on the type of incoming activity. In most cases, you can leave that method alone and use the individual handlers, but if your situation requires a custom implementation of `on_turn`, it is still an option. - -> [!IMPORTANT] -> If you do override the `on_turn` method, you'll need to call `super().on_turn` to get the base implementation to call all the other `on_` handlers or call those handlers yourself. Otherwise, those handlers won't be called and that code won't be run. - -In this sample, we welcome a new user or echo back the message the user sent using the `send_activity` call. The outbound activity corresponds to the outbound HTTP POST request. - -```py -class MyBot(ActivityHandler): - async def on_members_added_activity( - self, members_added: [ChannelAccount], turn_context: TurnContext - ): - for member in members_added: - if member.id != turn_context.activity.recipient.id: - await turn_context.send_activity("Hello and welcome!") - - async def on_message_activity(self, turn_context: TurnContext): - return await turn_context.send_activity( - f"Echo: {turn_context.activity.text}" - ) -``` - ---- - -### Access the bot from your app - -# [C#](#tab/csharp) - -#### Set up services - -The `ConfigureServices` method in the `Startup.cs` file loads the connected services, as well as their keys from `appsettings.json` or Azure Key Vault (if there are any), connects state, and so on. Here, we're adding MVC and setting the compatibility version on our services, then setting up the adapter and bot to be available through dependency injection to the bot controller. - - - -```csharp -// This method gets called by the runtime. Use this method to add services to the container. -public void ConfigureServices(IServiceCollection services) -{ - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); - - // Create the credential provider to be used with the Bot Framework Adapter. - services.AddSingleton(); - - // Create the Bot Framework Adapter. - services.AddSingleton(); - - // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. - services.AddTransient(); -} -``` - -The `Configure` method finishes the configuration of your app by specifying that the app use MVC and a few other files. All bots using the Bot Framework will need that configuration call, however that will already be defined in samples or the VSIX template when you build your bot. `ConfigureServices` and `Configure` are called by the runtime when the app starts. - -#### Bot Controller - -The controller, following the standard MVC structure, lets you determine the routing of messages and HTTP POST requests. For our bot, we pass the incoming request on to the adapter's *process async activity* method as explained in the [activity processing stack](#the-activity-processing-stack) section above. In that call, we specify the bot and any other authorization information that may be required. - -The controller implements `ControllerBase`, holds the adapter and bot that we set in `Startup.cs` (that are available here through dependency injection), and passes the necessary information on to the bot when it receives an incoming HTTP POST. - -Here, you'll see the class proceeded by route and controller attributes. These assist the framework to route the messages appropriately and know which controller to use. If you change the value in the route attribute, that changes the endpoint the emulator or other channels use access your bot. - -```cs -// This ASP Controller is created to handle a request. Dependency Injection will provide the Adapter and IBot -// implementation at runtime. Multiple different IBot implementations running at different endpoints can be -// achieved by specifying a more specific type for the bot constructor argument. -[Route("api/messages")] -[ApiController] -public class BotController : ControllerBase -{ - private readonly IBotFrameworkHttpAdapter Adapter; - private readonly IBot Bot; - - public BotController(IBotFrameworkHttpAdapter adapter, IBot bot) - { - Adapter = adapter; - Bot = bot; - } - - [HttpPost] - public async Task PostAsync() - { - // Delegate the processing of the HTTP POST to the adapter. - // The adapter will invoke the bot. - await Adapter.ProcessAsync(Request, Response, Bot); - } -} -``` - -# [JavaScript](#tab/javascript) - -#### index.js - -The `index.js` sets up your bot and the hosting service that will forward activities to your bot logic. - -#### Required libraries - -At the very top of your `index.js` file you will find a series of modules or libraries that are being required. These modules will give you access to a set of functions that you may want to include in your application. - -```javascript -const dotenv = require('dotenv'); -const path = require('path'); -const restify = require('restify'); - -// Import required bot services. -// See https://aka.ms/bot-services to learn more about the different parts of a bot. -const { BotFrameworkAdapter } = require('botbuilder'); - -// This bot's main dialog. -const { MyBot } = require('./bot'); - -// Import required bot configuration. -const ENV_FILE = path.join(__dirname, '.env'); -dotenv.config({ path: ENV_FILE }); -``` - -#### Set up services - -The next parts set up the server and adapter that allow your bot to communicate with the user and send responses. The server will listen on the specified port from the configuration file, or fall back to _3978_ for connection with your emulator. The adapter will act as the conductor for your bot, directing incoming and outgoing communication, authentication, and so on. - -```javascript -// Create HTTP server -const server = restify.createServer(); -server.listen(process.env.port || process.env.PORT || 3978, () => { - console.log(`\n${ server.name } listening to ${ server.url }`); - console.log(`\nGet Bot Framework Emulator: https://aka.ms/bot-framework-www-portal-emulator`); - console.log(`\nTo talk to your bot, open the emulator select "Open Bot"`); -}); - -// Create adapter. -// See https://aka.ms/about-bot-adapter to learn more about how bots work. -const adapter = new BotFrameworkAdapter({ - appId: process.env.MicrosoftAppId, - appPassword: process.env.MicrosoftAppPassword -}); - -// Catch-all for errors. -adapter.onTurnError = async (context, error) => { - // This check writes out errors to console log .vs. app insights. - console.error(`\n [onTurnError]: ${ error }`); - // Send a message to the user - await context.sendActivity(`Oops. Something went wrong!`); -}; - -// Create the main dialog. -const myBot = new MyBot(); -``` - -#### Forwarding requests to the bot logic - -The adapter's `processActivity` sends incoming activities to the bot logic. -The third parameter within `processActivity` is a function handler that will be called to perform the bot's logic after the received [activity](#the-activity-processing-stack) has been pre-processed by the adapter and routed through any middleware. The turn context variable, passed as an argument to the function handler, can be used to provide information about the incoming activity, the sender and receiver, the channel, the conversation, etc. Activity processing is routed to the bot's `run` method. `run` is defined in `ActivityHandler`; it performs some error checking, and then calls the bot's event handlers based on the type of activity received. - -```javascript -// Listen for incoming requests. -server.post('/api/messages', (req, res) => { - adapter.processActivity(req, res, async (context) => { - // Route to main dialog. - await myBot.run(context); - }); -}); -``` - -# [Python](#tab/python) - -#### app.py - -The `app.py` sets up your bot and the hosting service that will forward activities to your bot logic. - -#### Required libraries - -At the very top of your `app.py` file you will find a series of modules or libraries that are being required. These modules will give you access to a set of functions that you may want to include in your application. - -```py -from botbuilder.core import BotFrameworkAdapterSettings, TurnContext, BotFrameworkAdapter -from botbuilder.schema import Activity, ActivityTypes - -from bots import MyBot - -# Create the loop and Flask app -LOOP = asyncio.get_event_loop() -app = Flask(__name__, instance_relative_config=True) -app.config.from_object("config.DefaultConfig") -``` - -#### Set up services - -The next parts set up the server and adapter that allow your bot to communicate with the user and send responses. The server will listen on the specified port from the configuration file, or fall back to _3978_ for connection with your emulator. The adapter will act as the conductor for your bot, directing incoming and outgoing communication, authentication, and so on. - -```py -# Create adapter. -# See https://aka.ms/about-bot-adapter to learn more about how bots work. -SETTINGS = BotFrameworkAdapterSettings(app.config["APP_ID"], app.config["APP_PASSWORD"]) -ADAPTER = BotFrameworkAdapter(SETTINGS) - -# Catch-all for errors. -async def on_error(context: TurnContext, error: Exception): - # This check writes out errors to console log .vs. app insights. - # NOTE: In production environment, you should consider logging this to Azure - # application insights. - print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr) - - # Send a message to the user - await context.send_activity("The bot encountered an error or bug.") - await context.send_activity("To continue to run this bot, please fix the bot source code.") - # Send a trace activity if we're talking to the Bot Framework Emulator - if context.activity.channel_id == 'emulator': - # Create a trace activity that contains the error object - trace_activity = Activity( - label="TurnError", - name="on_turn_error Trace", - timestamp=datetime.utcnow(), - type=ActivityTypes.trace, - value=f"{error}", - value_type="https://www.botframework.com/schemas/error" - ) - # Send a trace activity, which will be displayed in Bot Framework Emulator - await context.send_activity(trace_activity) - -ADAPTER.on_turn_error = on_error - -# Create the Bot -BOT = MyBot() -``` - -#### Forwarding requests to the bot logic - -The adapter's `process_activity` sends incoming activities to the bot logic. -The third parameter within `process_activity` is a function handler that will be called to perform the bot's logic after the received [activity](#the-activity-processing-stack) has been pre-processed by the adapter and routed through any middleware. The turn context variable, passed as an argument to the function handler, can be used to provide information about the incoming activity, the sender and receiver, the channel, the conversation, etc. Activity processing is routed to the bot's `on_turn` method. `on_turn` is defined in `ActivityHandler`; it performs some error checking, and then calls the bot's event handlers based on the type of activity received. - -```py -# Listen for incoming requests on /api/messages -@app.route("/api/messages", methods=["POST"]) -def messages(): - # Main bot message handler. - if "application/json" in request.headers["Content-Type"]: - body = request.json - else: - return Response(status=415) - - activity = Activity().deserialize(body) - auth_header = ( - request.headers["Authorization"] if "Authorization" in request.headers else "" - ) - - try: - task = LOOP.create_task( - ADAPTER.process_activity(activity, auth_header, BOT.on_turn) - ) - LOOP.run_until_complete(task) - return Response(status=201) - except Exception as exception: - raise exception -``` - ---- - -## Manage bot resources - -The bot resources, such as app ID, passwords, keys or secrets for connected services, will need to be managed appropriately. For more on how to do so, see [Manage bot resources](bot-file-basics.md). - -## Additional resources - -- To understand the role of state in bots, see [managing state](bot-builder-concept-state.md). - -- To understand key concepts of developing bots for Microsoft Teams, see [How Microsoft Teams bots work](bot-builder-basics-teams.md) diff --git a/articles/v4sdk/bot-builder-channeldata.md b/articles/v4sdk/bot-builder-channeldata.md deleted file mode 100644 index 834ee98cc..000000000 --- a/articles/v4sdk/bot-builder-channeldata.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: Implement channel-specific functionality - Bot Service -description: Learn how to implement channel-specific functionality using the Bot Framework SDK for .NET. -keywords: channel specific, email, slack, facebook, telegram, kik, custom channel -author: RobStand -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Implement channel-specific functionality - -[!INCLUDE [pre-release-label](../includes/pre-release-label.md)] - -[!INCLUDE [Channel Data Content](../includes/snippet-channeldata.md)] diff --git a/articles/v4sdk/bot-builder-compositcontrol.md b/articles/v4sdk/bot-builder-compositcontrol.md deleted file mode 100644 index 93048fe02..000000000 --- a/articles/v4sdk/bot-builder-compositcontrol.md +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: Reuse dialogs - Bot Service -description: Learn how to modularize your bot logic using component dialogs in the Bot Framework SDK. -keywords: composite control, modular bot logic -author: v-ducvo -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/30/2020 -monikerRange: 'azure-bot-service-4.0' ---- - -# Reuse dialogs - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -With component dialogs, you can create independent dialogs to handle specific scenarios, breaking a large dialog set into more manageable pieces. Each of these pieces has its own dialog set, and avoids any name collisions with the dialog sets outside of it. - -## Prerequisites - -- Knowledge of [bot basics][concept-basics], the [dialogs library][concept-dialogs], and how to [manage conversations][simple-flow]. -- A copy of the multi-turn prompt sample in [**C#**][cs-sample], [**JavaScript**][js-sample], or [**Python**][python-sample]. - -## About the sample - -In the multi-turn prompt sample, we use a waterfall dialog, a few prompts, and a component dialog to create a simple interaction that asks the user a series of questions. The code uses a dialog to cycle through these steps: - -| Steps | Prompt type | -|:-------------|:-------------| -| Ask the user for their mode of transportation | Choice prompt | -| Ask the user for their name | Text prompt | -| Ask the user if they want to provide their age | Confirm prompt | -| If they answered yes, asks for their age | Number prompt with validation to only accept ages greater than 0 and less than 150. | -| Asks if the collected information is "ok" | Reuse Confirm prompt | - -Finally, if they answered yes, display the collected information; otherwise, tell the user that their information will not be kept. - -## Implement the component dialog - -In the multi-turn prompt sample, we use a _waterfall dialog_, a few _prompts_, and a _component dialog_ to create a simple interaction that asks the user a series of questions. - -A component dialog encapsulates one or more dialogs. The component dialog has an inner dialog set, and the dialogs and prompts that you add to this inner dialog set have their own IDs, visible only from within the component dialog. - -# [C#](#tab/csharp) - -To use dialogs, install the **Microsoft.Bot.Builder.Dialogs** NuGet package. - -**Dialogs\UserProfileDialog.cs** - -Here the `UserProfileDialog` class derives from the `ComponentDialog` class. - -[!code-csharp[Class](~/../botbuilder-samples/samples/csharp_dotnetcore/05.multi-turn-prompt/Dialogs/UserProfileDialog.cs?range=17)] - -Within the constructor, the `AddDialog` method adds dialogs and prompts to the component dialog. The first item you add with this method is set as the initial dialog, but you can change this by explicitly setting the `InitialDialogId` property. When you start a component dialog, it will start its _initial dialog_. - -[!code-csharp[Constructor](~/../botbuilder-samples/samples/csharp_dotnetcore/05.multi-turn-prompt/Dialogs/UserProfileDialog.cs?range=21-48)] - -This is the implementation of the first step of the waterfall dialog. - -[!code-csharp[First step](~/../botbuilder-samples/samples/csharp_dotnetcore/05.multi-turn-prompt/Dialogs/UserProfileDialog.cs?range=50-60)] - -For more information on implementing waterfall dialogs, see how to [implement sequential conversation flow](bot-builder-dialog-manage-complex-conversation-flow.md). - -# [JavaScript](#tab/javascript) - -To use dialogs, your project needs to install the **botbuilder-dialogs** npm package. - -**dialogs/userProfileDialog.js** - -Here the `UserProfileDialog` class extends `ComponentDialog`. - -[!code-javascript[Class](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/dialogs/userProfileDialog.js?range=28)] - -Within the constructor, the `AddDialog` method adds dialogs and prompts to the component dialog. The first item you add with this method is set as the initial dialog, but you can change this by explicitly setting the `InitialDialogId` property. When you start a component dialog, it will start its _initial dialog_. - -[!code-javascript[Constructor](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/dialogs/userProfileDialog.js?range=29-51)] - -This is the implementation of the first step of the waterfall dialog. - -[!code-javascript[First step](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/dialogs/userProfileDialog.js?range=70-77)] - -For more information on implementing waterfall dialogs, see how to [implement sequential conversation flow](bot-builder-dialog-manage-complex-conversation-flow.md). - -# [Python](#tab/python) - -To use dialogs, install the **botbuilder-dialogs** and **botbuilder-ai** PyPI packages by running `pip install botbuilder-dialogs` and `pip install botbuilder-ai` from a terminal. - -**dialogs/user_profile_dialog.py** - -Here the `UserProfileDialog` class extends `ComponentDialog`. - -[!code-python[Class](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/dialogs/user_profile_dialog.py?range=25)] - -Within the constructor, the `add_dialog` method adds dialogs and prompts to the component dialog. The first item you add with this method is set as the initial dialog, but you can change this by explicitly setting the `initial_dialog_id` property. When you start a component dialog, it will start its _initial dialog_. - -[!code-python[Constructor](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/dialogs/user_profile_dialog.py?range=25-57)] - -This is the implementation of the first step of the waterfall dialog. - -[!code-python[First step](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/dialogs/user_profile_dialog.py?range=59-71)] - -For more information on implementing waterfall dialogs, see how to [implement sequential conversation flow](bot-builder-dialog-manage-complex-conversation-flow.md). - ---- - -At run-time, the component dialog maintains its own dialog stack. When the component dialog is started: - -- An instance is created and added to the outer dialog stack -- It creates an inner dialog stack that it adds to its state -- It starts its initial dialog and adds that to the inner dialog stack. - -From the parent context, it will look like the component is the active dialog. From inside the component, it will look like the initial dialog is the active dialog. - -### Implement the rest of the dialog and add it to the bot - -In the outer dialog set, the one to which you add the component dialog, the component dialog has the ID that you created it with. In the outer set, the component looks like a single dialog, much like prompts do. - -To use a component dialog, add an instance of it to the bot's dialog set - this is the outer dialog set. - -# [C#](#tab/csharp) - -**Bots\DialogBot.cs** - -In the sample, this is done using the `RunAsync` method that is called from the bot's `OnMessageActivityAsync` method. - -[!code-csharp[OnMessageActivityAsync](~/../botbuilder-samples/samples/csharp_dotnetcore/05.multi-turn-prompt/Bots/DialogBot.cs?range=42-48&highlight=6)] - -# [JavaScript](#tab/javascript) - -**dialogs/userProfileDialog.js** - -In the sample, we've added a `run` method to the user profile dialog. - -[!code-javascript[run method](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/dialogs/userProfileDialog.js?range=59-68)] - -**bots/dialogBot.js** - -The `run` method is called from the bot's `onMessage` method. - -[!code-javascript[onMessage](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/bots/dialogBot.js?range=24-31&highlight=5)] - -# [Python](#tab/python) - -**helpers/dialog_helper.py** - -In the sample, we've added a `run_dialog` method to the user profile dialog. - -[!code-python[DialogHelper.run_dialog](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/helpers/dialog_helper.py?range=8-19)] - -The `run_dialog` method that is called from the bot's `on_message_activity` method. - -**bots/dialog_bot.py** -[!code-python[om_message_activity](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/bots/dialog_bot.py?range=46-51&highlight=2-6)] - ---- - -## To test the bot - -1. If you have not done so already, install the [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme). -1. Run the sample locally on your machine. -1. Start the emulator, connect to your bot, and send messages as shown below. - -![Sample run of the multi-turn prompt dialog](../media/emulator-v4/multi-turn-prompt.png) - -## Additional information - -### How cancellation works for component dialogs - -If you call _cancel all dialogs_ from the component dialog's context, the component dialog will cancel all of the dialogs on its inner stack and then end, returning control to the next dialog on the outer stack. - -If you call _cancel all dialogs_ from the outer context, the component is cancelled, along with the rest of the dialogs on the outer context. - -Keep this in mind when managing nested component dialogs in your bot. - -## Next steps - -You can enhance bots to react to additional input, like "help" or "cancel", that can interrupt the normal flow of the conversation. - -> [!div class="nextstepaction"] -> [Handle user interruptions](bot-builder-howto-handle-user-interrupt.md) - - - -[concept-basics]: bot-builder-basics.md -[concept-state]: bot-builder-concept-state.md -[concept-dialogs]: bot-builder-concept-dialog.md - -[simple-flow]: bot-builder-dialog-manage-conversation-flow.md -[prompting]: bot-builder-prompts.md -[component-dialogs]: bot-builder-compositcontrol.md - -[cs-sample]: https://aka.ms/cs-multi-prompts-sample -[js-sample]: https://aka.ms/js-multi-prompts-sample -[python-sample]: https://aka.ms/python-multi-prompts-sample diff --git a/articles/v4sdk/bot-builder-concept-activity-processing.md b/articles/v4sdk/bot-builder-concept-activity-processing.md deleted file mode 100644 index d5a4adcf9..000000000 --- a/articles/v4sdk/bot-builder-concept-activity-processing.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: Activity processing - Bot Service -description: Understand activity processing in the bot SDK. -keywords: bot adapter, custom middleware, short circuit, fallback, event handlers -author: jonathanfingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Activity processing - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -The bot and user interact and exchange information via activities. Each activity received by your bot application is passed to a bot adapter, which passes activity information to your bot logic and ultimately sends any responses to the user. Receiving an activity, and subsequently processing it through your bot, is called a turn; this represents one complete cycle of your bot. A turn ends when all execution is done, the activity is fully processed and all the layers of the bot have completed. - -Activities, particularly those that are [sent from a bot](#generating-responses) during a bot turn, are handled asynchronously. It's a necessary part of building a bot; if you need to brush up on how that all works, check out [async for .NET](https://docs.microsoft.com/dotnet/csharp/async) or [async for JavaScript](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function) depending on your language choice. - -## The bot adapter - -The bot adapter encapsulates authentication processes and sends activities to and receives activities from the Bot Connector Service. When your bot receives an activity, the adapter wraps up everything about that activity, creates a [context object](#turn-context) for the turn, passes it to your bot's application logic, and sends responses generated by your bot back to the user's channel. - -## Authentication - -The adapter authenticates each incoming activity the application receives, using information from the activity and the `Authentication` header from the REST request. The adapter uses a connector object and your application's credentials to authenticate the outbound activities to the user. - -Bot Connector Service authentication uses JWT (JSON Web Token) `Bearer` tokens and the **Microsoft app ID** and **Microsoft app password** that Azure creates for you when you create a bot service or register your bot. Your application will need these credentials at initialization time, to allow the adapter to authenticate traffic. - -> [!NOTE] -> If you are running or testing your bot locally, for example, using the Bot Framework Emulator, you can do so without configuring the adapter to authenticate traffic to and from your bot. - -## Turn context - -When an adapter receives an activity, it generates a **turn context** object, which provides information about the incoming activity, the sender and receiver, the channel, the conversation, and other data needed to process the activity. The adapter then passes this context object to the bot. The context object persists for the length of a turn, and provides information on the following: - -* Conversation - Identifies the conversation and includes information about the bot and the user participating in the conversation. -* Activity - The requests and replies in a conversation are all types of activities. This context provides information about the incoming activity, including routing information, information about the channel, the conversation, the sender, and the receiver. -* Custom information – If you extend your bot either by implementing middleware or within your bot logic, you can make additional information available in each turn. - -The context object can also be used to send a response to the user, and get a reference to the adapter. - -> [!NOTE] -> Your application and the adapter will handle requests asynchronously; however, your business logic does not need to be request-response driven. - -## Middleware - -You can add middleware to the adapter. The middleware and the bot logic use the context object to retrieve information about the activity and act accordingly. The middleware and the bot can also update or add information to the context object, such as to track state for a turn, a conversation, or other scope. For more in depth information about middleware, see the [middleware article](~/v4sdk/bot-builder-concept-middleware.md). - -## Generating responses - -The context object provides activity response methods to allow code to respond to an activity: - -* The _send activity_ and _send activities_ methods send one or more activities to the conversation. -* If supported by the channel, the _update activity_ method updates an activity within the conversation. -* If supported by the channel, the _delete activity_ method removes an activity from the conversation. - -Each response method runs in an asynchronous process. When it is called, the activity response method clones the associated [event handler](#response-event-handlers) list before starting to call the handlers, which means it will contain every handler added up to this point but will not contain anything added after the process starts. - -This also means the order of your responses is not guaranteed, particularly when one task is more complex than another. If your bot can generate multiple responses to an incoming activity, make sure that they make sense in whatever order they are received by the user. - -> [!IMPORTANT] -> The thread handling the primary bot turn deals with disposing of the context object when it is done. If a response (including its handlers) take any significant amount of time and try to act on the context object, they may get a `Context was disposed` error. **Be sure to `await` any activity calls** so the primary thread will wait on the generated activity before finishing it's processing and disposing of the turn context. - -## Response event handlers - -In addition to the bot and middleware logic, response handlers (also sometimes referred to as event handlers, or activity event handlers) can be added to the context object. These handlers are called when the associated [response](#generating-responses) happens on the current context object, before executing the actual response. These handlers are useful when you know you'll want to do something, either before or after the actual event, for every activity of that type for the rest of the current response. - -> [!WARNING] -> Be careful to not call an activity response method from within it's respective response event handler, for example, calling the send activity method from within an _on send activity_ handler. Doing so can generate an infinite loop. - -Each new activity gets a new thread to execute on. When the thread to process the activity is created, the list of handlers for that activity is copied to that new thread. No handlers added after that point will be executed for that specific activity event. - -The handlers registered on a context object are handled very similarly to how the adapter manages the [middleware pipeline](~/v4sdk/bot-builder-concept-middleware.md#the-bot-middleware-pipeline). Namely, handlers get called in the order they're added, and calling the _next_ delegate passes control to the next registered event handler. If a handler doesn’t call the next delegate, none of the subsequent event handlers are called, the event [short circuits](~/v4sdk/bot-builder-concept-middleware.md#short-circuiting), and the adapter does not send the response to the channel. - -## Next steps - -> [!div class="nextstepaction"] -> [Middleware](~/v4sdk/bot-builder-concept-middleware.md) diff --git a/articles/v4sdk/bot-builder-concept-authentication.md b/articles/v4sdk/bot-builder-concept-authentication.md deleted file mode 100644 index 86cba5b35..000000000 --- a/articles/v4sdk/bot-builder-concept-authentication.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -title: User authentication in the Azure Bot Service - Bot Service -description: Learn about user authentication features in the Azure Bot Service. -keywords: azure bot service, authentication, bot framework token service -author: JonathanFingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/31/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# User authentication within a conversation - -To perform certain operations on behalf of a user, such as checking email, referencing a calendar, checking on flight status, or placing an order, the bot will need to call an external service, such as the Microsoft Graph, GitHub, or a company's REST service. -Each external services has a way of securing those calls, and a common way to secure such a call is to issue those requests using a _user token_ that uniquely identifies the user on that external service (sometimes referred to as a JWT). - -To secure the call to an external service, the bot must ask the user to sign-in, so it can acquire the user's token for that service. -Many services support token retrieval via the OAuth or OAuth2 protocol. -The Azure Bot Service provides specialized sign-in cards and services that work with the OAuth protocol and manage the token life-cycle, and a bot can use these features to acquire a user token. - -- As part of bot configuration, an _OAuth connection setting_ is registered within the Azure Bot Service resource in Azure. - - Each connection setting contains information about the external service or identity provider to be use, along with a valid OAuth client id and secret, the OAuth scopes to enable, and any other connection metadata required by that external service or identity provider. - -- In the bot's code, an OAuth connection setting is used to help sign in a user and get a user token. - -These services are involved in the sign-in workflow. - -![Authentication overview](./media/bot-builder-concept-authentication.png) - -## About the Bot Framework Token Service - -The Bot Framework Token Service is responsible for: - -- Facilitating the use of the OAuth protocol with a wide variety of external services. -- Securely storing tokens for a particular bot, channel, conversation, and user. -- Acquiring user tokens. - > [!TIP] - > If the bot has an expired user token, the bot should: - > - Log the user out - > - Initiate the sign in flow again - -For example, a bot that can check a user's recent emails, using the Microsoft Graph API, will require an Azure Active Directory user token. At design time, the bot developer would register an Azure Active Directory application with the Bot Framework Token Service (via the Azure Portal), and then configure an OAuth connection setting ( named `GraphConnection`) for the bot. When a user interacts with the bot, the workflow would be: - -1. The user asks the bot, "please check my email". -1. An activity with this message is sent from the user to the Bot Framework channel service. The channel service ensures that the `userid` field within the activity has been set and the message is sent to the bot. - - User ID's are channel specific, such as the user's facebook ID or their SMS phone number. - -1. The bot receives the message activity and determines that the intent is to check the user's email. The bot makes a request to the Bot Framework Token Service asking if it already has a token for the UserId for the OAuth connection setting `GraphConnection`. -1. Since this is the first time this user has interacted with the bot, the Bot Framework Token Service does not yet have a token for this user, and returns a _NotFound_ result to the bot. -1. The bot creates an OAuthCard with a connection name of `GraphConnection` and replies to the user asking them to sign-in using this card. -1. The activity passes through the Bot Framework Channel Service, which calls into the Bot Framework Token Service to create a valid OAuth sign-in URL for this request. This sign-in URL is added to the OAuthCard and the card is returned to the user. -1. The user is presented with a message to sign-in by clicking on the OAuthCard's sign-in button. -1. When the user clicks the sign-in button, the channel service opens a web browser and calls out to the external service to load its sign-in page. -1. The user signs-in to this page for the external service. Once complete, the external service completes the OAuth protocol exchange with the Bot Framework Token Service, resulting in the external service sending the Bot Framework Token Service the user token. The Bot Framework Token Service securely stores this token and sends an activity to the bot with this token. -1. The bot receives the activity with the token and is able to use it to make calls against the Graph API. - -## Securing the sign-in URL - -An important consideration when the Bot Framework facilitates a user login is how to secure the sign-in URL. When a user is presented with a sign-in URL, this URL is associated with a specific conversation ID and user ID for that bot. This URL should not be shared, as it would cause the wrong sign-in to occur for a particular bot conversation. To mitigate security attacks regarding sharing the sign-in URL, it is necessary to ensure that the machine and person who clicks on the sign-in URL is the person who _owns_ the conversation window. - -Some channels such as Cortana, Teams, Direct Line, and WebChat are able to do this without the user noticing. For example, WebChat uses session cookies to ensure that the sign-in flow took place in the same browser as the WebChat conversation. However, for other channels the user is often presented with a 6-digit _magic code_. This is similar to a built-in multi-factor authentication, as the Bot Framework Token Service will not release the token to the bot unless the user finishes the final authentication, proving that the person who signed-in has access to the chat experience by entering the 6-digit code. - -## Azure Activity Directory application registration - -Every bot that is registered as an Azure Bot Service uses an Azure Activity Directory (AD) application ID. It is important **not** to re-use this application ID and password to sign-in users. The Azure Bot Service's Azure AD application ID is to secure the service to service communication between the bot and the Bot Framework Channel Services. If you want to sign-in users to Azure AD, you should create a separate Azure AD application registration with the appropriate permissions and scopes. - -## Configure an OAuth connection setting - -For more on how to register and use an OAuth connection setting, see [Add authentication to your bot](bot-builder-authentication.md). diff --git a/articles/v4sdk/bot-builder-concept-dialog.md b/articles/v4sdk/bot-builder-concept-dialog.md deleted file mode 100644 index fada1b67c..000000000 --- a/articles/v4sdk/bot-builder-concept-dialog.md +++ /dev/null @@ -1,212 +0,0 @@ ---- -title: Dialogs within the Bot Framework SDK - Bot Service -description: Describes what a dialog is and how it work within the Bot Framework SDK. -keywords: conversation flow, prompt, dialog state, recognize intent, single turn, multiple turn, bot conversation, dialogs, prompts, waterfalls, dialog set -author: johnataylor -ms.author: johtaylo -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Dialogs library - -[!INCLUDE [applies-to-v4](../includes/applies-to.md)] - -*Dialogs* are a central concept in the SDK, and provide a useful way to manage a conversation with the user. Dialogs are structures in your bot that act like functions in your bot's program; each dialog is designed to perform a specific task, in a specific order. You can specify the order of individual dialogs to guide the conversation, and invoke them in different ways - sometimes in response to a user, sometimes in response to some outside stimuli, or from other dialogs. - -The dialogs library provides a few built-in features, such as *prompts* and *waterfall dialogs* to make your bot's conversation easier to manage. [Prompts](#prompts) are used to ask for different types of information, such as text, a number, or a date. [Waterfall dialogs](#waterfall-dialogs) can combine multiple steps together in a sequence, allowing your bot to follow easily that predefined sequence and pass information along to the next step. - - - -## Dialogs and their pieces - -The dialogs library has a few additional pieces included to make dialogs more useful. Besides the different [types of dialogs](#dialog-types) discussed below, the library contains the idea of a *dialog set*, the *dialog context*, and the *dialog result*. - -*Dialog sets* are, in the simplest terms, a collection of dialogs. This can be things like prompts, waterfall dialogs, or [component dialogs](#component-dialog). Each of these are implementations of a dialog, and each are added to the dialog set with a specific string ID. When your bot wants to start a certain dialog or prompt within the dialog set, it uses that string ID to specify which dialog to use. - -*Dialog context* contains information pertaining to the dialog, and is used to interact with a dialog set from within your bot's turn handler. The dialog context includes the current turn context, the parent dialog, and the [dialog state](#dialog-state), which provides a method for preserving information within the dialog. The dialog context allows you to start a dialog with its string ID or continue the current dialog (such as a waterfall dialog that has multiple steps). - -When a dialog ends, it can return a *dialog result* with some resulting information from the dialog. This is returned to let the calling method see what happened within the dialog and save the information to some persisted location, if desired. - -## Dialog state - -Dialogs are an approach to implementing a multi-turn conversation, and as such, they are an example of a feature in the SDK that relies on persisted state across multiple turns. Without state in dialogs, your bot wouldn't know where in the dialog set it is or what information it has already gathered. - -A dialog based bot typically holds a dialog set collection as a member variable in its bot implementation. That dialog set is created with a handle to an object called an accessor that provides access to persisted state. For background on state within bots, see [managing state](bot-builder-concept-state.md). - -Within the bot’s on turn handler, the bot initializes the dialog subsystem by calling *create context* on the dialog set, which returns a *dialog context*. That dialog context contains the necessary information needed by the dialog. - -The creation of a dialog context requires state, which is accessed with the accessor provided when creating the dialog set. With that accessor, the dialog set can get the appropriate dialog state. Details on state accessors can be found in [Save conversation and user data](bot-builder-howto-v4-state.md). - -## Dialog types - -Dialogs come in a few different types: prompts, waterfall dialogs, and component dialogs, as shown in this class hierarchy. - -![dialog classes](media/bot-builder-dialog-classes.png) - -### Prompts - -Prompts, within the dialogs library, provide an easy way to ask the user for information and evaluate their response. For example for a *number prompt*, you specify the question or information you are asking for, and the prompt automatically checks to see if it received a valid number response. If it did, the conversation can continue; if it didn't, it will re-prompt the user for a valid answer. - -Behind the scenes, prompts are a two-step dialog. First, the prompt asks for input; second, it returns the valid value, or starts from the top with a reprompt. - -Prompts have *prompt options* given when the prompt is called, which is where you can specify the text to prompt with, the retry prompt if validation fails, and choices to answer the prompt. In general, the prompt and retry prompt properties are activities, though there is some variation on how this is handled in different programming languages. - -Additionally, you can choose to add some custom validation for your prompt when you create it. For example, say we wanted to get a party size using the number prompt, but that party size has to be more than 2 and less than 12. The prompt first checks to see if it received a valid number, then runs the custom validation if it is provided. If the custom validation fails, it will re-prompt the user as above. - -When a prompt completes, it explicitly returns the resulting value that was asked for. When that value is returned, we can be sure it has passed both the built in prompt validation and any additional custom validation that may have been provided. - -For examples on using various prompts, take a look at how to use the [dialogs library to gather user input](bot-builder-prompts.md). - -#### Prompt types - -Behind the scenes, prompts are a two-step dialog. First, the prompt asks for input; second, it returns the valid value, or restarts from the top with a re-prompt. The dialogs library offers a number of basic prompts, each used for collecting a different type of response. The basic prompts can interpret natural language input, such as "ten" or "a dozen" for a number, or "tomorrow" or "Friday at 10am" for a date-time. - -| Prompt | Description | Returns | -|:----|:----|:----| -| _Attachment prompt_ | Asks for one or more attachments, such as a document or image. | A collection of _attachment_ objects. | -| _Choice prompt_ | Asks for a choice from a set of options. | A _found choice_ object. | -| _Confirm prompt_ | Asks for a confirmation. | A Boolean value. | -| _Date-time prompt_ | Asks for a date-time. | A collection of _date-time resolution_ objects. | -| _Number prompt_ | Asks for a number. | A numeric value. | -| _Text prompt_ | Asks for general text input. | A string. | - -To prompt a user for input, define a prompt using one of the built-in classes, such as the _text prompt_, and add it to your dialog set. Prompts have fixed IDs that must be unique within a dialog set. You can have a custom validator for each prompt, and for some prompts, you can specify a _default locale_. - -#### Prompt locale - -The locale is used to determine language-specific behavior of the **choice**, **confirm**, **date-time**, and **number** prompts. For any given input from the user, if the channel provided a _locale_ property in user's message, then that is used. Otherwise, if the prompt's _default locale_ is set, by providing it when calling the prompt's constructor or by setting it later, then that is used. If neither of those are provided, English ("en-us") is used as the locale. Note: The locale is a 2, 3, or 4 character ISO 639 code that represents a language or language family. - -### Waterfall dialogs - -A waterfall dialog is a specific implementation of a dialog that is commonly used to collect information from the user or guide the user through a series of tasks. Each step of the conversation is implemented as an asynchronous function that takes a *waterfall step context* (`step`) parameter. At each step, the bot [prompts the user for input](bot-builder-prompts.md) (or can begin a child dialog, but that it is often a prompt), waits for a response, and then passes the result to the next step. The result of the first function is passed as an argument into the next function, and so on. - -The following diagram shows a sequence of waterfall steps and the stack operations that take place. Details on the use of the dialog stack are below in the [using dialogs](#using-dialogs) section. - -![Dialog concept](media/bot-builder-dialog-concept.png) - -Within waterfall steps, the context of the waterfall dialog is stored in its *waterfall step context*. This is similar to the dialog context as it provides access to the current turn context and state. Use the waterfall step context object to interact with a dialog set from within a waterfall step. - -You can handle a return value from a dialog either within a waterfall step in a dialog or from your bot's on turn handler, although you generally only need to check the status of the dialog turn result from your bot's turn logic. -Within a waterfall step, the dialog provides the return value in the waterfall step context's _result_ property. - -#### Waterfall step context properties - -The waterfall step context contains the following: - -* *Options*: contains input information for the dialog. -* *Values*: contains information you can add to the context, and is carried forward into subsequent steps. -* *Result*: contains the result from the previous step. - -Additionally, the *next* method (**NextAsync** in C#, **next** in JS) continues to the next step of the waterfall dialog within the same turn, enabling your bot to skip a certain step if needed. - -#### Prompt options - -The second parameter of the step context's _prompt_ method takes a _prompt options_ object, which has the following properties. - -| Property | Description | -| :--- | :--- | -| _Prompt_ | The initial activity to send the user, to ask for their input. | -| _Retry prompt_ | The activity to send the user if their first input did not validate. | -| _Choices_ | A list of choices for the user to choose from, for use with a choice prompt. | -| _Validations_ | Additional parameters to use with a custom validator. | -| _Style_ | Defines how the choices for a choice prompt or confirm prompt will be presented to a user. | - -You should always specify the initial prompt activity to send the user, as well as a retry prompt for instances when the user's input doesn't validate. - -If the user's input isn't valid, the retry prompt is sent to the user; if there was no retry specified, then the initial prompt is re-sent. However, if an activity is sent back to the user from within the validator, no retry prompt is sent. - -##### Prompt validation - -You can validate a prompt response before returning the value to the next step of the waterfall. A validator function has a _prompt validator context_ parameter and returns a Boolean, indicating whether the input passes validation. -The prompt validator context includes the following properties: - -| Property | Description | -| :--- | :--- | -| _Context_ | The current turn context for the bot. | -| _Recognized_ | A _prompt recognizer result_ that contains information about the user input, as processed by the recognizer. | -| _Options_ | Contains the _prompt options_ that were provided in the call to start the prompt. | - -The prompt recognizer result has the following properties: - -| Property | Description | -| :--- | :--- | -| _Succeeded_ | Indicates whether the recognizer was able to parse the input. | -| _Value_ | The return value from the recognizer. If necessary, the validation code can modify this value. | - -### Component dialog - -Sometimes you want to write a reusable dialog that you want to use in different scenarios, such as an address dialog that asks the user to provide values for street, city and zip code. - -The *component dialog* provides a strategy for creating independent dialogs to handle specific scenarios, breaking a large dialog set into more manageable pieces. Each of these pieces has its own dialog set, and avoids any name collisions with the dialog set that contains it. See the [component dialog how to](bot-builder-compositcontrol.md) for more on these. - -## Using dialogs - -You can use the dialog context to begin, continue, replace, or end a dialog. You can also cancel all dialogs on the dialog stack. - -Dialogs can be thought of as a programmatic stack, which we call the *dialog stack*, with the turn handler as the one directing it and serving as the fallback if the stack is empty. The topmost item on that stack is considered the *active dialog*, and the dialog context directs all input to the active dialog. - -When a dialog begins, it is pushed onto the stack, and is now the active dialog. It remains the active dialog until it either ends, it is removed by the [replace dialog](#repeating-a-dialog) method, or another dialog is pushed onto the stack (by either the turn handler or active dialog itself) and becomes the active dialog. When that new dialog ends, it is popped off the stack and the next dialog down becomes the active dialog again. This allows for [repeating a dialog](#repeating-a-dialog) or [branching a conversation](#branch-a-conversation), discussed below. - - -### Create the dialog context - -To create your dialog context, call the *create context* method of your dialog set. Create context gets the dialog set's *dialog state* property and uses that to create the dialog context. The dialog context is then used to start, continue, or otherwise control the dialogs in the set. - -The dialog set requires use of a *state property accessor* to access the dialog state. The accessor is created and used the same way as other state accessors, but is created as it's own property based off of the conversation state. Details on managing state can be found in the [managing state topic](bot-builder-concept-state.md), and usage of dialog state is shown in the [sequential conversation flow](bot-builder-dialog-manage-conversation-flow.md) how-to. - -### To start a dialog - -To start a dialog, pass the *dialog ID* you want to start into the dialog context's *begin dialog*, *prompt*, or *replace dialog* method. - -* The begin dialog method will push the dialog onto the top of the stack. -* The replace dialog method will pop the current dialog off the stack and push the replacing dialog onto the stack. The replaced dialog is canceled and any information that instance contained is disposed of. - -Use the _options_ parameter to pass information to the new instance of the dialog. -The options passed into the new dialog can be accessed via the step context's *options* property in any step of the dialog. -See the [Create advanced conversation flow using branches and loops](bot-builder-dialog-manage-complex-conversation-flow.md) how-to for example code. - -### To continue a dialog - -To continue a dialog, call the *continue dialog* method. The continue method will always continue the topmost dialog on the stack (the active dialog), if there is one. If the continued dialog ends, control is passed to the parent context which continues within the same turn. - -Use the step context's *values* property to persist state between turns. -Any value added to this collection in a previous turn is available in subsequent turns. -See the [Create advanced conversation flow using branches and loops](bot-builder-dialog-manage-complex-conversation-flow.md) how-to for example code. - -### To end a dialog - -The *end dialog* method ends a dialog by popping it off the stack and returns an optional result to the parent context (such as the dialog that called it, or the bot's turn handler). This is most often called from within the dialog to end the current instance of itself. - -You can call the end dialog method from anywhere you have a dialog context, but it will appear to the bot that it was called from the current active dialog. - -> [!TIP] -> It is best practice to explicitly call the *end dialog* method at the end of the dialog. - -### To clear all dialogs - -If you want to pop all dialogs off the stack, you can clear the dialog stack by calling the dialog context's *cancel all dialogs* method. - -### Repeating a dialog - -You can replace a dialog with itself, creating a loop, by using the *replace dialog* method. -This is a great way to handle [complex interactions](~/v4sdk/bot-builder-dialog-manage-complex-conversation-flow.md) and a good technique to manage menus. - -> [!NOTE] -> If you need to persist the internal state for the current dialog, you will need to pass information to the new instance of the dialog in the call to the *replace dialog* method, and then initialize the dialog appropriately. - -### Branch a conversation - -The dialog context maintains the dialog stack and for each dialog on the stack, tracks which step is next. Its *begin dialog* method creates a child and pushes that dialog onto the top of the stack, and its *end dialog* method pops the top dialog off the stack. *End dialog* is usually called from within the dialog that's ending. - -A dialog can start a new dialog within the same dialog set by calling the dialog context's *begin dialog* method and providing the ID of the new dialog, which then makes the new dialog the currently active dialog. The original dialog is still on the stack, but calls to the dialog context's *continue dialog* method are only sent to the dialog that is on top of the stack, the *active dialog*. When a dialog is popped off the stack, the dialog context will resume with the next step of the waterfall on the stack where it left off of the original dialog. - -Therefore, you can create a branch within your conversation flow by including a step in one dialog that can conditionally choose a dialog to start out of a set of available dialogs. - -## Next steps - -> [!div class="nextstepaction"] -> [Use dialog library to gather user input](bot-builder-prompts.md) diff --git a/articles/v4sdk/bot-builder-concept-luis.md b/articles/v4sdk/bot-builder-concept-luis.md deleted file mode 100644 index f4e01d262..000000000 --- a/articles/v4sdk/bot-builder-concept-luis.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: Language Understanding - Bot Service -description: Learn how to add artificial intelligence to your bots with Microsoft Cognitive Services to make them more useful and engaging. -keywords: LUIS, intent, recognizer, dispatch tool, qna, qna maker -author: ivorb -ms.author: kamrani -manager: rstand -ms.topic: article -ms.service: bot-service -ms.date: 09/19/2018 -ms.reviewer: -monikerRange: 'azure-bot-service-4.0' ---- - - -# Language Understanding - -[!INCLUDE [pre-release-label](../includes/pre-release-label.md)] - -Bots can use a variety of conversational styles, from the structured and guided to the free-form and open-ended. A bot needs to decide what to do next in its conversation flow, based on what the user said, and in an open-ended conversation, there is a wider range of user replies. - -| Guided | Open | -|------|------| -| I'm the travel bot. Select one of the following options: find flights, find hotels, find rental car. | I can help you book travel. What would you like to do? | -| Do you need anything else? Click yes or no. | Do you need anything else? | - -The interaction between users and bots is often free-form, and bots need to understand language naturally and contextually. This article explains how Language Understanding (LUIS) help you to determine what users want, to identify concepts and entities in sentences, and ultimately to allow your bots to respond with the appropriate action. - -## Recognize intent - -[LUIS](https://docs.microsoft.com/azure/cognitive-services/luis/home) helps you by determining the user’s **intent**, which is what they want to do, from what they say, so your bot can respond appropriately. LUIS is especially helpful when what they say to your bot doesn’t follow a predictable structure or a specific pattern. If a bot has a conversational user interface, in which the user speaks or types a response, there can be endless variations on *utterances*, which are the spoken or textual input from the user. - -For example, consider the many ways a user of a travel bot can ask to book a flight. - -![Various differently formed utterances for book a flight](media/cognitive-services-add-bot-language/cognitive-services-luis-utterances.png) - -These utterances can have different structures and contain various synonyms for “flight” that you haven't thought of. In your bot, it can be challenging to write the logic that matches all the utterances, and still distinguishes them from other intents that contain the same words. Additionally, your bot needs to extract *entities*, which are other important words like locations and times. LUIS makes this process easy by contextually identifying intents and entities for you. - -When you design your bot for natural language input, you determine what intents and entities your bot needs to recognize, and think about how they'll connect to actions that your bot takes. In [luis.ai](https://www.luis.ai), you define custom intents and entities and you specify their behavior by providing examples for each intent and labeling the entities within them. - -Your bot uses the intent recognized by LUIS to determine the conversation topic, or begin a conversation flow. For example, when a user says "I'd like to book a flight", your bot detects the BookFlight intent and invokes the conversation flow for starting a search for flights. LUIS detects entities like the destination city and the departure date, both in the original utterance that triggers the intent and later in the conversation flow. Once the bot has all the information it needs, it can fulfill the user's intent. - -![A conversation with a bot is triggered by the BookFlight intent](media/cognitive-services-add-bot-language/cognitive-services-luis-conversation-high-level.png) - -### Recognize intent in common scenarios - -To save development time, LUIS provides pre-trained language models that recognize common utterances for common categories of bots. - -**Prebuilt domains** are pre-trained, ready-to-use collections of intents and entities that work well together for common scenarios like appointments, reminders, management, fitness, entertainment, communication, reservations, and more. The **Utilities** prebuilt domain helps your bot handle common tasks like Cancel, Confirm, Help, Repeat, and Stop. Take a look at the [prebuilt domains](https://docs.microsoft.com/azure/cognitive-services/LUIS/luis-how-to-use-prebuilt-domains) that LUIS offers. - -**Prebuilt entities** help your bot recognize common types of information like dates, times, numbers, temperature, currency, geography, and age. See [use prebuilt entities](https://docs.microsoft.com/azure/cognitive-services/LUIS/pre-builtentities) for background on the types that LUIS can recognize. - -## How your bot gets messages from LUIS - -Once you have set up and connected LUIS, your bot can send the message to your LUIS app, which returns a JSON response that contains the intents and entities. Then, you can use the [turn context](~/v4sdk/bot-builder-basics.md#defining-a-turn) in your bot's _turn handler_ to route the conversation flow based on the intent in the LUIS response. - -![How intents and entities are passed to your bot](./media/cognitive-services-add-bot-language/cognitive-services-luis-message-flow-bot-code.png) - -To get started using a LUIS app with your bot, check out [using LUIS for language understanding](https://docs.microsoft.com/azure/bot-service/bot-builder-howto-v4-luis?view=azure-bot-service-4.0). - -## Best practices for Language Understanding - -Consider the following practices when designing a language model for your bot. - -### Consider the number of intents - -LUIS apps recognize intent by classifying an utterance into one of multiple categories. A natural result is that determining the correct category from among a large number of intents can reduce a LUIS app's ability to distinguish between them. - -One way of reducing the number of intents is to use a hierarchical design. Consider the case of a personal assistant bot that has three intents related to weather, three intents related to home automation, and three other utility intents which are Help, Cancel and Greeting. If you put all the intents in the same LUIS app, you already have 9, and as you add features to the bot, you could end up with dozens. Instead, you can use a dispatcher LUIS app to determine whether the user's request is for weather, home automation, or utility, then call the LUIS app for the category that the dispatcher determines. In this case each of the LUIS apps only starts with 3 intents. - -### Use a None intent - -It's often the case that users of your bot will say something unexpected or unrelated to the current conversation flow. The _None_ intent is provided for handling those messages. - -If you don't train an intent for handling the fallback, default or "none of the above" cases, your LUIS app can only classify messages into the intents it has defined. So for example, let's say you have a LUIS app with two intents: `HomeAutomation.TurnOn` and `HomeAutomation.TurnOff`. If those are the only intents, and the input is something unrelated like "schedule an appointment on Friday", your LUIS app has no choice but to classify that message as either HomeAutomation.TurnOn or HomeAutomation.TurnOff. If your LUIS app has a `None` intent with a few examples, you can provide some fallback logic in your bot to handle unexpected utterances. - -The `None` intent is very useful for improving recognition results. In this home automation scenario, "schedule an appointment on Friday" may produce the `HomeAutomation.TurnOn` intent with a low confidence, and your bot should reject it. You can add such phrases to your model under the `None` intent, so that they resolve correctly to `None`. - -### Review the utterances that LUIS app receives - -LUIS apps provide a feature for improving your app performance, by reviewing messages that users sent to it. See [suggested utterances](https://docs.microsoft.com/azure/cognitive-services/LUIS/label-suggested-utterances) for a step-by-step walkthrough. - - -## Integrate multiple LUIS apps and QnA services with the Dispatch tool - -When building a multi-purpose bot that understands multiple conversational topics, you can start to develop services for each function separately, and then integrate them together. These services can include Language Understanding (LUIS) apps and QnAMaker services. Here are a few example scenarios in which a bot might combine multiple LUIS apps, multiple QnAMaker services or a combination of the two: - -* A personal assistant bot lets the user invoke a variety of commands. Each category of commands form a "skill" that can be developed separately, and each skill has a LUIS app. -* A bot searches many knowledge bases to find answers to frequently asked questions (FAQs). -* A bot for a business has LUIS apps for creating customer accounts and placing orders, and also has a QnAMaker service for its FAQ. - -### The Dispatch tool - -The Dispatch tool helps you integrate multiple LUIS apps and QnA Maker services with your bot, by creating a *dispatch app*, which is a new LUIS app that routes messages to the appropriate LUIS and QnAMaker services. See the [dispatch tutorial](./bot-builder-tutorial-dispatch.md) for a step-by-step tutorial that combines multiple LUIS apps and QnA Maker in one bot. - -## Use LUIS to improve speech recognition - -For a bot that users will speak to, integrating it with LUIS can help your bot identify words that might be misunderstood when converting speech to text. For example, in a chess scenario, a user might say: "Move knight to A 7". Without context for the user's intent, the utterance might be recognized as: "Move night 287". By creating entities that represent chess pieces and coordinates and labeling them in utterances, you provide context for speech recognition to identify them. You can [enable speech recognition priming](https://docs.microsoft.com/azure/bot-service/bot-service-manage-speech-priming?view=azure-bot-service-4.0) with Bot Framework channels that are integrated with Bing Speech, such as Web Chat, the Bot Framework Emulator and Cortana. - -## Additional resources -Refer to [Cognitive Services](https://docs.microsoft.com/azure/cognitive-services/) documentation for more information. diff --git a/articles/v4sdk/bot-builder-concept-middleware.md b/articles/v4sdk/bot-builder-concept-middleware.md deleted file mode 100644 index 54dc5a004..000000000 --- a/articles/v4sdk/bot-builder-concept-middleware.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Middleware - Bot Service -description: Understand middleware and it's uses within the bot SDK. -keywords: middleware, middleware pipeline, short circuit, middleware uses -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Middleware - -[!INCLUDE [applies-to-v4](../includes/applies-to.md)] - -Middleware is simply a class that sits between the adapter and your bot logic, added to your adapter's middleware collection during initialization. The SDK allows you to write your own middleware or add middleware created by others. Every activity coming into or out of your bot flows through your middleware. - -The adapter processes and directs incoming activities in through the bot middleware pipeline to your bot’s logic and then back out again. As each activity flows in and out of the bot, each piece of middleware can inspect or act upon the activity, both before and after the bot logic runs. - -Before jumping into middleware, it is important to understand [bots in general](~/v4sdk/bot-builder-basics.md) and [how they process activities](~/v4sdk/bot-builder-basics.md#the-activity-processing-stack). - -## Uses for middleware -The question often comes up: "When should I implement actions as middleware versus using my normal bot logic?" Middleware provides you with additional opportunities to interact with your users' conversation flow both before and after each _turn_ of the conversation is processed. Middleware also allows you to store and retrieve information concerning the conversation and call additional processing logic when required. Below are some common scenarios that show where middleware can be useful. - -### Looking at or acting on every activity -There are plenty of situations that require your bot to do something on every activity, or for every activity of a certain type. For example, you may want to log every message activity your bot receives or provide a fallback response if the bot has not otherwise generated a response this turn. Middleware is a great place for this, with its ability to act both before and after the rest of the bot logic has executed. - -### Modifying or enhancing the turn context -Certain conversations can be much more fruitful if the bot has more information than what is provided in the activity. Middleware in this case could look at the conversation state information it has so far, query an external data source, and append that to the [turn context](~/v4sdk/bot-builder-basics.md#defining-a-turn) object before passing execution on to the bot logic. - -The SDK defines logging middleware that can record incoming and outgoing activities, but you can also define your own middleware. - -## The bot middleware pipeline -For each activity, the adapter calls middleware in the order in which you added it. The adapter passes in the context object for the turn and a _next_ delegate, and the middleware calls the delegate to pass control to the next middleware in the pipeline. Middleware also has an opportunity to do things after the _next_ delegate returns before completing the method. You can think of it as each middleware object has the first-and-last chance to act with respect to the middleware objects that follow it in the pipeline. - -For example: - -- 1st middleware object’s turn handler executes code before calling _next_. - - 2nd middleware object’s turn handler executes code before calling _next_. - - The bot’s turn handler executes and returns. - - 2nd middleware object’s turn handler executes any remaining code before returning. -- 1st middleware object’s turn handler executes any remaining code before returning. - -If middleware doesn’t call the next delegate, the adapter does not call any of the subsequent middleware or bot turn handlers, and the pipeline short circuits. - -Once the bot middleware pipeline completes, the turn is over, and the turn context goes out of scope. - -Middleware or the bot can generate responses and register response event handlers, but keep in mind that responses are handled in separate processes. - -## Order of middleware -Since the order in which middleware is added determines the order in which the middleware processes an activity, it's important to decide the sequence that middleware should be added. - -> [!NOTE] -> This is meant to give you a common pattern that works for most bots, but be sure to consider how each piece of middleware will interact with the others for your situation. - -The first things in your middleware pipeline should likely be those that take care of the lowest-level tasks that are used every time. Examples include logging, exception handling, and translation. Ordering these can vary depending on your needs, such as whether you want the incoming message to be translated first, before messages are stored, or if message storage should occur first, which could mean stored messages wouldn't be translated. - -The last things in your middleware pipeline should be bot-specific middleware, which is middleware you implement to do some processing on every message sent to your bot. If your middleware uses state information or other information set in the bot context, add it to the middleware pipeline after the middleware that modifies state or context. - -## Short circuiting -An important idea around middleware and response handlers is _short circuiting_. If execution is to continue through the layers that follow it, middleware (or a response handler) is required to pass execution on by calling its _next_ delegate. If the next delegate is not called within that middleware (or response handler), the associated pipeline short circuits and subsequent layers are not executed. This means all bot logic, and any middleware further along the pipeline, is skipped. There is a subtle difference between your middleware and your response handler short circuiting a turn. - -When middleware short circuits a turn, your bot turn handler will not be called, but all middleware code executed prior to this point in the pipeline will still run to completion. - -For event handlers, not calling _next_ means that the event is cancelled, which is a significantly different result than middleware skipping logic. By not processing the rest of the event, the adapter never sends it. - -> [!TIP] -> If you do short-circuit a response event, such as `SendActivities`, be sure it's the behavior you intend. Otherwise, it can result in difficult to fix bugs. - -## Response event handlers -In addition to the application and middleware logic, response handlers (also sometimes referred to as event handlers, or activity event handlers) can be added to the context object. These handlers are called when the associated response happens on the current context object, before executing the actual response. These handlers are useful when you know you'll want to do something, either before or after the actual event, for every activity of that type for the rest of the current response. - -> [!WARNING] -> Be careful to not call an activity response method from within its respective response event handler, for example, calling the send activity method from within an on send activity handler. Doing so can generate an infinite loop. - -Remember, each new activity gets a new thread to execute on. When the thread to process the activity is created, the list of handlers for that activity is copied to that new thread. No handlers added after that point will be executed for that specific activity event. -The handlers registered on a context object are handled very similarly to how the adapter manages the middleware pipeline. Namely, handlers get called in the order they're added, and calling the next delegate passes control to the next registered event handler. If a handler doesn’t call the next delegate, none of the subsequent event handlers are called, the event short circuits, and the adapter does not send the response to the channel. - -## Handling state in middleware - -A common method to save state is to call the save changes method at the end of the turn handler. Here is a diagram with a focus on the call. - -![state middleware issues](media/bot-builder-dialog-state-problem.png) - -The problem with this approach is that any state updates made from some custom middleware that happens after the bot’s turn handler has returned will not be saved to durable storage. The solution is to move the call to the save changes method to after the custom middleware has completed by adding an instance of the _auto-save changes_ middleware to the beginning of the middleware stack, or at least before any of the middleware that might update state. The execution is shown below. - -![state middleware solution](media/bot-builder-dialog-state-solution.png) - -Add the state management objects that will need updating to a _bot state set_ object, and then use that when you create your auto-save changes middleware. - - -## Additional resources -You can take a look at the transcript logger middleware, as implemented in the Bot Framework SDK [[C#](https://github.com/Microsoft/botbuilder-dotnet/blob/master/libraries/Microsoft.Bot.Builder/TranscriptLoggerMiddleware.cs) | [JS](https://github.com/Microsoft/botbuilder-js/blob/master/libraries/botbuilder-core/src/transcriptLogger.ts)]. diff --git a/articles/v4sdk/bot-builder-concept-state.md b/articles/v4sdk/bot-builder-concept-state.md deleted file mode 100644 index 243cb0df2..000000000 --- a/articles/v4sdk/bot-builder-concept-state.md +++ /dev/null @@ -1,139 +0,0 @@ ---- -title: Managing State - Bot Service -description: Describes how state works within the Bot Framework SDK. -keywords: state, bot state, conversation state, user state -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Managing state - -[!INCLUDE [applies-to-v4](../includes/applies-to.md)] - -State within a bot follows the same paradigms as modern web applications, and the Bot Framework SDK provides some abstractions to make state management easier. - -As with web apps, a bot is inherently stateless; a different instance of your bot may handle any given turn of the conversation. For some bots, this simplicity is preferred - the bot can either operate without additional information, or the information required is guaranteed to be within the incoming message. For others, state (such as where in the conversation we are or previously received data about the user) is necessary for the bot to have a useful conversation. - -**Why do I need state?** - -Maintaining state allows your bot to have more meaningful conversations by remembering certain things about a user or conversation. For example, if you've talked to a user previously, you can save previous information about them, so that you don't have to ask for it again. State also keeps data for longer than the current turn, so that your bot keeps information over the course of a multi-turn conversation. - -As it pertains to bots, there are a few layers to using state which we'll cover here: the storage layer, state management (contained in the bot state in the diagram below), and state property accessors. This diagram illustrates parts of the interaction sequence between these layers, with the solid arrows representing a method call, and the dashed arrows representing the response (with or without a return value). - -![bot state](media/bot-builder-state.png) - -The flow of this diagram is explained in following sections with details each of these layers. - -## Storage layer - -Starting at the backend, where the state information is actually stored, is our *storage layer*. This can be thought of as our physical storage, such as in-memory, Azure, or a third party server. - -The Bot Framework SDK includes some implementations for the storage layer: - -- **Memory storage** implements in-memory storage for testing purposes. In-memory data storage is intended for local testing only as this storage is volatile and temporary. The data is cleared each time the bot is restarted. -- **Azure Blob Storage** connects to an Azure Blob Storage object database. -- **Azure Cosmos DB storage** connects to a Cosmos DB NoSQL database. - -For instructions on how to connect to other storage options, see [write directly to storage](bot-builder-howto-v4-storage.md). - -## State management - -*State management* automates the reading and writing of your bot's state to the underlying storage layer. State is stored as *state properties*, which are effectively key-value pairs that your bot can read and write through the state management object without worrying about the specific underlying implementation. Those state properties define how that information is stored. For example, when you retrieve a property that you defined as a specific class or object, you know how that data will be structured. - -These state properties are lumped into scoped "buckets", which are just collections to help organize those properties. The SDK includes three of these "buckets": - -- User state -- Conversation state -- Private conversation state - -All of these buckets are subclasses of the *bot state* class, which can be derived to define other types of buckets with different scopes. - -These predefined buckets are scoped to a certain visibility, depending on the bucket: - -- User state is available in any turn that the bot is conversing with that user on that channel, regardless of the conversation -- Conversation state is available in any turn in a specific conversation, regardless of user (i.e. group conversations) -- Private conversation state is scoped to both the specific conversation and to that specific user - -> [!TIP] -> Both user and conversation state are scoped by channel. -> The same person using different channels to access your bot appears as different users, one for each channel, and each with a distinct user state. - -The keys used for each of these predefined buckets are specific to the user and conversation, or both. When setting the value of your state property, the key is defined for you internally with information contained on the turn context to ensure that each user or conversation gets placed in the correct bucket and property. Specifically, the keys are defined as follows: - -- The user state creates a key using the *channel ID* and *from ID*. For example, _{Activity.ChannelId}/users/{Activity.From.Id}#YourPropertyName_ -- The conversation state creates a key using the *channel ID* and the *conversation ID*. For example, _{Activity.ChannelId}/conversations/{Activity.Conversation.Id}#YourPropertyName_ -- The private conversation state creates a key using the *channel ID*, *from ID* and the *conversation ID*. For example, _{Activity.ChannelId}/conversations/{Activity.Conversation.Id}/users/{Activity.From.Id}#YourPropertyName_ - -### When to use each type of state - -Conversation state is good for tracking the context of the conversation, such as: - -- Whether the bot asked the user a question, and which question that was -- What the current topic of conversation is, or what the last one was - -User state is good for tracking information about the user, such as: - -- Non-critical user information, such as name and preferences, an alarm setting, or an alert preference -- Information about the last conversation they had with the bot - - For instance, a product-support bot might track which products the user has asked about. - -Private conversation state is good for channels that support group conversations, but where you want to track both user and conversation specific information. For example, if you had a classroom clicker bot: - -- The bot could aggregate and display student responses for a given question. -- The bot could aggregate each student's performance and privately relay that back to them at the end of the session. - -For details on using these predefined buckets, see the [state how-to article](bot-builder-howto-v4-state.md). - -### Connecting to multiple databases - -If your bot needs to connect to multiple databases, create a storage layer for each database. -For each storage layer, create the state management objects you need to support your state properties. - -## State property accessors - -*State property accessors* are used to actually read or write one of your state properties, and provide *get*, *set*, and *delete* methods for accessing your state properties from within a turn. To create an accessor, you must provide the property name, which usually takes place when you're initializing your bot. Then, you can use that accessor to get and manipulate that property of your bot's state. - -The accessors allow the SDK to get state from the underlying storage, and update the bot's *state cache* for you. The state cache is a local cache maintained by your bot that stores the state object for you, allowing read and write operations without accessing the underlying storage. If it isn't already in the cache, calling the accessor's *get* method retrieves state and also places it in the cache. Once retrieved, the state property can be manipulated just like a local variable. - -The accessor's *delete* method removes the property from the cache, and also deletes it from the underlying storage. - -> [!IMPORTANT] -> For the first call to an accessor's *get* method, you must provide a factory method to create the object if it doesn't yet exist in your state. If no factory method is given, you will get an exception. Details on how to use a factory method can be found in the [state how-to article](bot-builder-howto-v4-state.md). - -To persist any changes you make to the state property you get from the accessor, the property in the state cache must be updated. You can do so via a call the accessors *set* method, which sets the value of your property in the cache, and is available if that needs to be read or updated later in that turn. To actually persist that data to the underlying storage (and thus make it available after the current turn), you must then [save your state](#saving-state). - -### How the state property accessor methods work - -The accessor methods are the primary way for your bot to interact with state. How each work, and how the underlying layers interact, are as follows: - -- The accessor's *get* method: - - Accessor requests property from the state cache. - - If the property is in the cache, return it. Otherwise, get it from the state management object. - (If it is not yet in state, use the factory method provided in the accessors *get* call.) -- The accessor's *set* method: - - Update the state cache with the new property value. -- The state management object's *save changes* method: - - Check the changes to the property in the state cache. - - Write that property to storage. - -## Saving state - -When you call the accessor's set method to record the updated state, that state property has not yet been saved to your persisted storage, and instead is only saved to your bot's state cache. To save any changes in the state cache to your persisted state, you must call the state management object's *save changes* method, which is available on the implementation of the bot state class mentioned above (such as user state or conversation state). - -Calling the save changes method for a state management object (i.e. the buckets mentioned above) saves all properties in the state cache that you have set up to that point for that bucket, but not for any of the other buckets you may have in your bot's state. - -> [!TIP] -> Bot state implements a "last write wins" behavior, where the last write will stamp over the previously written state. This may work for many applications but has implications, particularly in scaled-out scenarios, where there may be some level of concurrency or latency in play. - -If you have some custom middleware that might update state after your turn handler completes, consider [handling state in middleware](bot-builder-concept-middleware.md#handling-state-in-middleware). - -## Additional resources - -- [Dialog state](bot-builder-concept-dialog.md#dialog-state) -- [Write directly to storage](bot-builder-howto-v4-storage.md) -- [Save conversation and user data](bot-builder-howto-v4-state.md) diff --git a/articles/v4sdk/bot-builder-conversations.md b/articles/v4sdk/bot-builder-conversations.md deleted file mode 100644 index ca75b87d9..000000000 --- a/articles/v4sdk/bot-builder-conversations.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: Conversations within the Bot Framework SDK - Bot Service -description: Describes what a conversation is within the Bot Framework SDK. -keywords: conversation flow, recognize intent, single turn, multiple turn, bot conversation -author: jonathanfingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Conversation flow -[!INCLUDE[applies-to](../includes/applies-to.md)] - -Designing a bot's conversation flow involves deciding how a bot responds when the user says something to it. A bot first recognizes the task or conversation topic based on a message from the user. To determine the task or topic (known as the *intent*) associated with a user's message, the bot can look for words or patterns in the text of the user's message, or it can take advantage of services like [Language Understanding](bot-builder-concept-luis.md) and [QnA Maker](https://docs.microsoft.com/azure/cognitive-services/qnamaker/overview/overview). - -Once the bot has recognized the user's intent, depending on the scenario, the bot could fulfill the user's request with a single reply, completing the conversation in one turn, or it might require a series of turns. For multi-turn conversation flows, the Bot Framework SDK provides [state management](./bot-builder-howto-v4-state.md) for keeping track of a conversation, [prompts](bot-builder-prompts.md) for asking for information, and [dialogs](bot-builder-dialog-manage-conversation-flow.md) for encapsulating conversation flows. - -In a complex bot with multiple subsystems, it can be the case that you use multiple services to recognize intent, one for each subcomponent of the bot. The [dispatch tool](bot-builder-tutorial-dispatch.md) gets the results of multiple services in one place when you combine conversational subsystems into one bot. - - - -## Single turn conversation - -The simplest conversational flow is single-turn. In a single-turn flow, the bot finishes its task in one turn, consisting of one message from the user and one reply from the bot. - - - -The simplest kind of single-turn bot doesn't need to keep track of conversation state. Each time it receives a message, it responds based only on the context of the current incoming message, without knowledge of past conversational turns. - -![Single-turn weather bot](./media/concept-conversation/weather-single-turn.png) - -A weather bot might have a single-turn flow, it just gives the user a weather report, without going back and forth asking for the city or the date. All the logic for displaying the weather report is based on the message the bot just received. In each turn of a conversation, the bot receives a [turn context](bot-builder-concept-activity-processing.md#turn-context), which your bot can use to determine what to do next and how the conversation flows. - -## Multiple turns - -Most types of conversation can't be completed in a single turn, so a bot can also have a multi-turn conversation flow. Some scenarios that require multiple conversational turns include: - -* A bot that prompts the user for additional information that it needs to complete a task. The bot needs to track whether it has all the parameters for fulfilling the task. -* A bot that guides the user through steps in a process, such as placing an order. The bot needs to track where the user is in the sequence of steps. - -For example, a weather bot might have a multi-turn flow, if the bot responds to "what's the weather?" by asking for the city. - -![multi-turn weather bot](./media/concept-conversation/weather-multi-turn.png) - -When the user replies to the bot's prompt for the city and the bot receives "Seattle", the bot needs to have some context saved to understand that the current message is the response to a previous prompt and part of a request to get weather. Multi-turn bots keep track of state to respond appropriately to new messages. - -See [how to manage conversation and user state](bot-builder-howto-v4-state.md) for more information. - -> [!NOTE] -> Multi-turn conversations with REST API clients will need to keep track of their own state, for example in a database or table storage. - -## Conversation topics - -You might design your bot to handle more than one type of task. For example, you might have a bot that provides different conversation flows for greeting the user, placing an order, canceling an order, and getting help. One way to handle this switch between conversation for different tasks or conversation topics is to recognize the intent (what the user wants to do) from the current message. - -### Recognize intent - -The Bot Framework SDK supplies _recognizers_ that can process a message to determine intent, so your bot can initiate the appropriate conversational flow. Call the recognizer's _recognize_ async method to determine the user's intent from their message content. You can then call the _get top scoring intent_ method on the result to get the recognizer's top prediction. - -A recognizer could use regular expressions, language understanding, or other logic that you develop. The following are examples of possible recognizers: - -* A recognizer that uses QnA Maker to detect when a user asks a question covered in a knowledgebase. -* A recognizer that uses Language Understanding (LUIS) to train a service with examples of ways user might ask for help, and map that to the `Help` intent. -* A custom recognizer that uses regular expressions to look for commands. -* A custom recognizer that uses a service to translate input. - -### Consider how to interrupt conversation flow or change topics - -One way to keep track of where you are in a conversation is to use [conversation state](bot-builder-howto-v4-state.md) to save information about the currently active topic or what steps in a sequence have been completed. - -When a bot becomes more complex, you can also imagine a sequence of conversation flows occurring in a stack; for instance, the bot will invoke the new order flow, and then invoke the product search flow. Then the user will select a product and confirm, completing the product search flow, and then complete the order. - -However, conversations rarely follow such a linear, logical path. Users do not communicate in "stacks", instead they tend to frequently change their minds. Consider the following example: - -![User says something unexpected](./media/concept-conversation/interruption.png) - -While your bot may have logically constructed a stack of flows, the user may decide to do something entirely different or ask a question that may be unrelated to the current topic. In the example, the user asks a question rather than providing the yes/no response that the flow expects. How should your flow respond? - -* Insist that the user answer the question first. -* Disregard everything that the user had done previously, reset the whole flow stack, and start from the beginning by attempting to answer the user's question. -* Attempt to answer the user's question and then return to that yes/no question and try to resume from there. - -There is no right answer to this question, as the best solution will depend upon the specifics of your scenario and how the user would reasonably expect the bot to respond. Refer to how to [use dialogs](bot-builder-dialog-manage-conversation-flow.md) and [handle interruptions](bot-builder-howto-handle-user-interrupt.md) to manage conversation flow. - -## Conversation lifetime - - -A bot receives a _conversation update_ activity whenever it has been added to a conversation, other members have been added to or removed from a conversation, or conversation metadata has changed. -You may want to have your bot react to conversation update activities by greeting users or introducing itself. - -A bot receives an _end of conversation_ activity to indicate that the user has ended the conversation. A bot may send an _end of conversation_ activity to indicate that the conversation is ending. -If you are storing information about the conversation, you may want to clear that information when the conversation ends. - - - -Your bot can support multi-turn interactions where it prompts users for multiple pieces of information. It can be focused on a very specific task or support multiple types of tasks. -The Bot Framework SDK has some built-in support for language understanding (LUIS) and QnA Maker for adding natural language "question and answer" features to your bot. - -## Conversations, channels, and users - -Conversations can be either a _direct_ conversation with a specific user or a _group_ conversation with multiple users. -A bot communicates with a user on a channel by receiving activities from, and sending activities to the user. - -* Each user has an ID that is unique per channel. -* Each conversation has an ID that is unique per channel. -* The channel sets the conversation ID when it starts the conversation. -* The bot cannot start a conversation; however, once it has a conversation ID, it can resume that conversation. -* Not all channels support group conversations. - -## Next steps - -> [!div class="nextstepaction"] -> [Manage simple conversation flow with dialogs](bot-builder-dialog-manage-conversation-flow.md) - - - diff --git a/articles/v4sdk/bot-builder-custom-assistant-introduction.md b/articles/v4sdk/bot-builder-custom-assistant-introduction.md deleted file mode 100644 index 33bb9753c..000000000 --- a/articles/v4sdk/bot-builder-custom-assistant-introduction.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: Custom Assistant Overview - Bot Service -description: Learn about creating your own Custom Assistant -author: darrenj -ms.author: darrenj -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/01/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Custom Assistant Overview - -## Overview - -We have seen significant need from our customers and partners to deliver a conversational assistant tailored to their brand, personalized to their customers and made available across a broad range of conversational canvases and devices. Continuing Microsoft open-sourced approach toward Bot Framework SDK, the open source Custom Personal Assistant provides full control over the end user experience built on a set of foundational capabilities. Additionally, the experience can be infused with intelligence about the end-user and any device/ecosystem information for a truly integrated and intelligent experience. - -We strongly believe our customers should own and enrich their customer relationships and insights. Therefore, any custom assistant provides complete control of the user experience to our customers and partners. The name, voice and personality can be changed to suit the organization’s needs. Our Custom Assistant solution simplifies creation of your own assistant enabling you to get started in minutes. - -The scope of Custom Personal Assistant functionality is broad, typically offering end users a range of capabilities. To increase developer productivity and to enable a vibrant ecosystem of reusable conversational experiences, we are providing developers initial examples of reusable conversational skills. These skills can be added into the conversational application to light up a specific conversation experience, such as finding a point of interest, interacting with calendar, tasks, email and many other scenarios. Skills are fully customizable and consist of language models for multiple languages, dialogs and code. - -At this time we are running an initial preview and working closely with initial customers and partners in an open-source repository to bring to life the first experiences and make it available more broadly in the coming months. - -![Custom Assistant Diagram](media/enterprise-template/CustomAssistantDiagram.jpg) - -## Complete control of the user experience - -All aspects of the end user experience are owned and controlled by you. This includes the Branding, Name, Voice, Personality, Responses and Avatar. The source-code to the Custom Assistant and supporting Skills are provided in full enabling you to adjust as required. - -## Complete ownership and control of data - -Your Custom Assistant will be deployed within your Azure subscription. Therefore all data generated by your assistant (questions asked, user behaviour, etc.) is entirely contained within your Azure subscription. See [Cognitive Services Azure Trusted Cloud](https://www.microsoft.com/trustcenter/cloudservices/cognitiveservices) and the [Azure section of the Trust Center](https://www.microsoft.com/TrustCenter/CloudServices/Azure) more specifically for more information. - -## Your Assistant, anywhere.. - -The Custom Assistant leverages the Microsoft Conversational AI platform and therefore can be surfaced through any Bot Framework [channel](https://docs.microsoft.com/azure/bot-service/bot-service-manage-channels?view=azure-bot-service-4.0) – e.g. WebChat, FaceBook Messenger, Skype, etc. In addition, through the [Direct Line](https://docs.microsoft.com/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-concepts?view=azure-bot-service-4.0) channel we can embed experiences into Desktop and Mobile Apps including devices such as Cars, Speakers, Alarm Clocks, etc. - -## Built on Enterprise grade technology - -The Custom Assistant solution is built on the Azure Bot Service, Language Understanding Cognitive Service, Unified Speech along with a broad set of supporting Azure components meaning that you benefit from the [Azure global infrastructure](https://azure.microsoft.com/global-infrastructure/). - -In addition, Language Understanding support is provided by the LUIS Cognitive Service which supports a broad set of languages [listed here](https://docs.microsoft.com/azure/cognitive-services/luis/luis-supported-languages). The [Translator Cognitive Service](https://azure.microsoft.com/services/cognitive-services/translator-text-api/) provides additional Machine Translation capabilities to extend the reach of your Custom Assistant even further. - -## Integrated and Context Aware - -Your Custom Assistant can be integrated into your device and ecosystem enabling a truly integrated and intelligent experience . Through this contextual awareness more intelligent experiences can be developed and deliver further personalisation than otherwise possible. - -## 3rd Party assistant integration - -The Custom Assistant enables you to deliver your own unique experience but also hand-off to the end-users chosen Digital Assistant for certain types of questions. - -## Flexible integration - -Our Custom Assistant architecture is flexible and can be integrated with existing investments you may have made into device based Speech or Natural Language processing capabilities and of course integrate with your existing back-end systems and APIs. - -## Adaptive Cards - -[Adaptive Cards](https://adaptivecards.io/) provide the ability for your Custom Assistant to return User Experience elements (e.g. Cards, Images, Buttons) alongside text base responses. If the device or conversation canvas has a screen these Adaptive Cards can be rendered across a broad range of devices and platforms providing supporting User Experience where appropriate. Examples of Adaptive Cards can be found [here](https://adaptivecards.io/samples/) with information on Rendering options in the documentation [here](https://docs.microsoft.com/adaptive-cards/rendering-cards/getting-started). - - -## Skills - -In addition to the base assistant, there exists a broad set of common capabilities which require each developer to build themselves. Productivity is a great example where each organisation would need to create Language Models (LUIS), Dialogs (Code), Integration (Code) and Language Generation (Responses) to enable common scenarios such as Point of Interest, Email, Calendar or Tasks. - -This is then further complicated by the need to support multiple languages and results in a large amount of work -required for any organisation building their own assistant. - -Our Custom Assistant solution includes a new Skill capability enabling new capabilities to be plugged into an custom-assistant through configuration only. - -All aspects of each Skill (Language Model, Dialogs, Integration Code and Language Generation) are completely customisable by developers as the full source code is provided on GitHub along with the Custom Assistant. - -## Example Scenarios - -The Custom Assistant extends across a broad number of industry scenarios, example scenarios are shown below for reference purposes: - -- Automotive Industry: Voice enabled Personal Assistant integrated into the car providing end users the ability to perform traditional car operations (e.g. navigation, radio) along with productivity focused scenarios such as moving meetings when your running late, adding items to your task list and proactive experiences where the car can suggest tasks to complete based on events such as starting the engine, traveling home or enabling cruise control. Adaptive Cards are rendered within the Head Unit and Speech integration performed through Push-To-Talk or Wake Word interactions. - -- Hospitality: Voice enabled Personal Assistant integrated into a hotel-room device providing a broad range of Hospitality focused scenarios (e.g. extend your stay, request late checkout, room service) including concierge and the ability to find local restuarants and attractions. Optional linking to your Productivity accounts open up more personalised experiences such as suggested alarm calls, Weather warnings and learning of patterns across stays. An evolution of the current TV personalisation experienced in room today. - -- Enterprise: Voice and Text enabled branded Employee Assistant experiences integrated into enterprise devices and existing conversation canvases (e.g. Teams, WebChat, Slack) enabling employees to manage their calendars, find available meeting rooms, find people with specific skills or perform HR related operations. - -## Getting Started - -At this time we are running an initial preview and working closely with initial customers and partners in an open-source repository to bring to life the first experiences and make it available more broadly in the coming months. To register your interest and get started please fill in [this form](https://aka.ms/customassistantpreviewform) and we'll be in touch. - diff --git a/articles/v4sdk/bot-builder-custom-storage.md b/articles/v4sdk/bot-builder-custom-storage.md deleted file mode 100644 index 232538ab7..000000000 --- a/articles/v4sdk/bot-builder-custom-storage.md +++ /dev/null @@ -1,197 +0,0 @@ ---- -title: Implement custom storage for your bot - Bot Service -description: How to build custom storage in Bot Framework SDK v4.0 -keywords: custom, storage, state, dialog -author: johnataylor -ms.author: johtaylo -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Implement custom storage for your bot - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -A bot’s interactions fall into three areas: firstly, the exchange of Activities with the Azure Bot Service, secondly, -the loading and saving of dialog state with a Store and finally any other backend services the bot needs to work with -to get its job done. - -![scaleout diagram](../media/scale-out/scale-out-interaction.png) - - -## Prerequisites -- The full sample code used in this article can be found here: [C# sample](https://aka.ms/scale-out). - -In this article, we will be exploring the semantics around the bot’s interactions with the Azure Bot Service and the Store. - -The Bot Framework includes a default implementation; this implementation will most likely fit the needs of many -applications, and all that is needed to be done to make use of it is to plug the pieces together with a few lines of -initialization code. Many of the samples illustrate just that. - -The goal here, however, is to describe what you can do when the semantics of the default implementation doesn’t quite work -as you might like in your application. The basic point is that this is a framework and not a canned application with -fixed behavior, in other words, the implementation of many of the mechanisms in the framework is just the default -implementation and not the only implementation. - -Specifically, the framework does not dictate the relationship between the exchange of Activities with the Azure -Bot Service and the loading and saving of any Bot state; it simply provides a default. To illustrate this point further, -we will be developing an alternative implementation that has different semantics. This alternative solution sits -equally well in the framework and may even be more appropriate for the application being developed. It all depends on the scenario. - -## Behavior of the default BotFrameworkAdapter and Storage providers - -Firstly, let’s review the default implementation that ships as part of the framework packages as shown by the following -sequence diagram: - -![scaleout diagram](../media/scale-out/scale-out-default.png) - -On receiving an Activity, the bot loads the state corresponding to this conversation. It then runs the dialog logic -with this state and the Activity that has just arrived. In the process of executing the dialog, one or more outbound -activities are created and immediately sent. When the processing of the dialog is complete, the bot saves the updated -state, overwriting the old state with new. - -It is worth considering a couple of things that can go wrong with this behavior. - -Firstly, if the Save operation were to fail for some reason the state has implicitly slipped out of sync with -what is seen on the channel because the user having seen the responses is under the impression that the state -has moved forward, but it hasn’t. This is generally worse than if the state was successful and the response -messaging were successful. This can have implications for the conversation design: for example, the dialog might -include additional, otherwise redundant confirmation exchanges with the user. - -Secondly, if the implementation is deployed scaled out across multiple nodes, the state can accidentally get -overwritten - this can be particularly confusing because the dialog will likely have sent activities to the channel -carrying confirmation messages. Consider the example of a pizza order bot, if the user, on being asked for a topping, -adds mushroom and without delay adds cheese, in a scaled-out scenario with multiple instances running subsequent -activities can be sent concurrently to different machines running the bot. When this happens, there is what is referred -to as a “race condition” where one machine might overwrite the state written by another. However, in our scenario, -because the responses were already sent, the user has received confirmation that both mushroom and cheese were added. -Unfortunately, when the pizza arrives, it will only contain mushroom or cheese, not both. - -## Optimistic locking - -The solution is to introduce some locking around the state. The particular style of locking we will be using here is called -optimistic locking because we will let everything run as if they were each the only thing running and then we will detect any -concurrency violations after the processing has been done. This may sound complicated but is very easy to build using cloud -storage technologies and the right extension points in the bot framework. - -We will use a standard HTTP mechanism based on the entity tag header, (ETag). Understanding this mechanism is crucial to -understanding the code that follows. The following diagram illustrates the sequence. - -![scaleout diagram](../media/scale-out/scale-out-precondition-failed.png) - -The diagram illustrates the case of two clients that are performing an update to some resource. When a client issues a -GET request and a resource is returned from the server, it is accompanied by an ETag header. The ETag header is an opaque -value that represents the state of the resource. If a resource is changed, the ETag will be updated. When the client has -done its update to the state, it POSTs it back to the server, making this request the client attaches the ETag value it had -previously received in a precondition If-Match header. If this ETag does not match the value, the server last returned -(on any response, to any client) the precondition check fails with a 412 Precondition Failure. This failure is an indicator -to the client making the POST request that the resource has been updated. On seeing this failure, the typical behavior for -a client will be to GET the resource again, apply the update it wanted, and POST the resource back. This second -POST will be successful, assuming of course, that no other client has come and updated the resource, and if it has the -client will just have to try again. - -This process is called “optimistic” because the client, having got hold of a resource proceeds to do its processing, -the resource itself is not “locked” in the sense that other clients can access it without any restriction. Any contention -between clients over what the state of the resource should be is not determined until the processing has been done. As a -rule, in a distributed system this strategy is more optimal than the opposite “pessimistic” approach. - -The optimistic locking mechanism we’ve covered assumes program logic can be safely retried, needless, to say the important -thing to consider here is what happens to external service calls. The ideal solution here is if these services can be made -idempotent. In computer science, an idempotent operation is one that has no additional effect if it is called more than once -with the same input parameters. Pure HTTP REST services that implement GET, PUT and DELETE fit this description. The reasoning -here is intuitive: we might be retrying the processing and so making any calls it needs to make have no additional effect as -they are re-executed as part of that retry is a good thing. For the sake of this discussion, we will assume we are living in -an ideal world and the backend services shown to the right of the system picture at the beginning of this article are all -idempotent HTTP REST services, from here on we will focus only on the exchange of activities. - -## Buffering outbound activities - -The sending of an Activity is not an idempotent operation, nor is it clear that would make much sense in the end-to-end scenario. -After all the Activity is often just carrying a message that is appended to a view or perhaps spoken by a text to speech agent. - -The key thing we want to avoid with sending the activities is sending them multiple times. The problem we have is that the optimistic locking mechanism requires that we with rerun our logic possibly multiple times. The solution is simple: we must -buffer the outbound activities from the dialog until we are sure we are not going to rerun the logic. That is until after we -have a successful Save operation. We are looking for a flow that looks something like the following: - -![scaleout diagram](../media/scale-out/scale-out-buffer.png) - -Assuming we can build a retry loop around the dialog execution we get the following behavior when there is a -precondition failure on the Save operation: - -![scaleout diagram](../media/scale-out/scale-out-save.png) - -Applying this mechanism and revisiting our example from earlier we should never see an erroneous positive acknowledgment of a pizza topping being added to an order. In fact, although we might have scaled out our deployment across multiple machines, we have effectively serialized our state updates with the optimistic locking scheme. In our pizza ordering but the acknowledgement from adding an item can now even be written to reflect the full state accurately. For example, if the user immediately types “cheese” and then before the bot has had a chance to reply “mushroom” the two replies can now be “pizza with cheese” and then “pizza with cheese and mushroom.” - -Looking at the sequence diagram we can see that the replies could be lost after a successful Save operation, however, they could be lost anywhere in the end to end communication. The point is this is not a problem the state management infrastructure can fix. It will require a higher-level protocol and possibly one involving the user of the channel. For example, if the bot appears to the user not to have replied it is reasonable to expect the user to ultimately try again or some such behavior. So while it is reasonable for a scenario to have occasional transient outages such as this it is far less reasonable to expect a user to be able to filter out erroneous positive acknowledgements or other unintended messages. - -Pulling this all together, in our new custom storage solution, we are going to do three things the default implementation in the framework doesn’t do. Firstly, we are going to use ETags to detect contention, secondly we are going to retry the processing when the ETag failure is detected and thirdly we are going to buffer any outbound Activities until we have a successful save. The remainder of this article describes the implementation of these three parts. - -## Implementing ETag Support - -To support unit testing we start out by defining an interface for our new store with ETag support. Having the interface means we can write two versions, one for the unit tests that runs in memory without the need of hitting the network and another for production. The interface will make it very easy to leverage the dependency injection mechanisms we have in ASP.NET. - -The interface consists of Load and Save methods. Both these take the key we will use for the state. The Load will return the data and the associated ETag. And the Save will take these in. Additionally, the Save will return bool. This bool will indicate whether the ETag has matched and the Save was successful. This is not intended as a general error indicator but rather a specific indicator of precondition failure, we model this as a return code rather than an exception because we will be writing control flow logic around this in the shape of our retry loop. - -As we would like this lowest level storage piece to be pluggable, we will make sure to avoid placing any serialization requirements on it, however we would like to specify that the content save should be JSON, that way a store implementation can set the content-type. The easiest and most natural way to do this in .NET is through the argument types, specifically we will type the content argument as JObject. In JavaScript or TypeScript this will just be a regular native object. - -This is the resulting interface: - -**IStore.cs** -[!code-csharp[IStore](~/../botbuilder-samples/samples/csharp_dotnetcore/42.scaleout/IStore.cs?range=14-19)] - -Implementing this against Azure Blob Storage is straight forward. - -**BlobStore.cs** -[!code-csharp[BlobStore](~/../botbuilder-samples/samples/csharp_dotnetcore/42.scaleout/BlobStore.cs?range=18-101)] - -As you can see Azure Blob Storage is doing the real work here. Note the catch of specific exceptions and how that is translated across to meet what will be the expectations of the calling code. That is, on the load we want a Not Found exception to return null and the Precondition Failed exception on the Save to return bool. - -All this source code will be available in a corresponding [sample](https://aka.ms/scale-out) and that sample will include a memory store implementation. - -## Implementing the Retry Loop -The basic shape of the loop is derived directly from the behavior shown in the sequence diagrams. - -On receiving an Activity we create a key for the corresponding state for that conversation. We are not changing the relationship between Activity and conversation state, so we will be creating the key in exactly the same way as in the default state implementation. - -After having created the appropriate key we will attempt to Load the corresponding state. Then run the bot’s dialogs and then attempt to Save. If that Save is successful, we will send the outbound Activities that resulted from running the dialog and be done. Otherwise we will go back and repeat the whole process from before the Load. Redoing the Load will give us a new ETag and so next time the Save will hopefully be successful. - -The resulting OnTurn implementation looks like this: - -**ScaleoutBot.cs** -[!code-csharp[OnMessageActivity](~/../botbuilder-samples/samples/csharp_dotnetcore/42.scaleout/Bots/ScaleOutBot.cs?range=43-72)] - -Note that we have modeled the dialog execution as a function call. Perhaps a more sophisticated implementation would have defined an interface and made this dependency injectable but for our purposes having the dialog all sit behind a static function emphasize the functional nature of our approach. As a general statement, organizing our implementation such that the crucial parts become functional puts us in a very good place when it comes to having it work successfully on networks. - - -## Implementing outbound Activity buffering - -The next requirement is that we buffer outbound Activities until a successful Save has been performed. This will require a custom BotAdapter implementation. In this code, we will implement the abstract SendActivity function to add the Activity to a list rather than sending it. The dialog we will be hosting will be non-the-wiser. -In this particular scenario UpdateActivity and DeleteActivity operations are not supported and so will just throw Not Implemented from those methods. We also don’t care about the return value from the SendActivity. This is used by some channels in scenarios where updates to Activities need to be sent, for example, to disable buttons on cards displayed in the channel. These message exchanges can get complicated particularly when state is required, that is outside the scope of this article. The full implementation of the custom BotAdapter looks like this: - -**DialogHostAdapter.cs** -[!code-csharp[DialogHostAdapter](~/../botbuilder-samples/samples/csharp_dotnetcore/42.scaleout/DialogHostAdapter.cs?range=19-46)] - -## Integration - -All that is left to do is glue these various new pieces together and plug them into the existing framework pieces. The main retry loop just sits in the IBot OnTurn function. It holds our custom IStore implementation which for testing purposes we have made dependency injectable. We have put all the dialog hosting code into a class called DialogHost that exposes a single public static function. This function is defined to take the inbound Activity and the old state and then return the resulting Activities and new state. - -The first thing to do in this function is to create the custom BotAdapter we introduced earlier. Then we will just run the dialog in exactly the same was as we usually do by creating a DialogSet and DialogContext and doing the usual Continue or Begin flow. The only piece we haven’t covered is the need for a custom Accessor. This turns out to be a very simple shim that facilitates passing the dialog state into the dialog system. The Accessor uses ref semantics when working with the dialog system and so all that is needed is to pass the handle across. To make things even clearer we have constrained the class template we are using to ref semantics. - -We are being very cautious in the layering, we are putting the JsonSerialization inline in our hosting code because we didn’t want it inside the pluggable storage layer when different implementations might serialize differently. - -Here is the driver code: - -**DialogHost.cs** -[!code-csharp[DialogHost](~/../botbuilder-samples/samples/csharp_dotnetcore/42.scaleout/DialogHost.cs?range=22-72)] - -And finally, the custom Accessor, we only need to implement Get because the state is by ref: - -**RefAccessor.cs** -[!code-csharp[RefAccessor](~/../botbuilder-samples/samples/csharp_dotnetcore/42.scaleout/RefAccessor.cs?range=22-60)] - -## Additional information -The [C# sample](https://aka.ms/scale-out) code used in this article is available on GitHub. - diff --git a/articles/v4sdk/bot-builder-debug-transcript.md b/articles/v4sdk/bot-builder-debug-transcript.md deleted file mode 100644 index b8535dd7d..000000000 --- a/articles/v4sdk/bot-builder-debug-transcript.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Debug your bot using transcript files - Bot Service -description: Understand how use a transcript file to help debug your bot. -keywords: debugging, faq, transcript file, emulator -author: DanDev33 -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.subservices: sdk -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Debug your bot using transcript files - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -One of the keys to successful testing and debugging a bot is your ability to record and examine the set of conditions that occur when running your bot. This article discusses the creation and use of a bot transcript file to provide a detailed set of user interactions and bot responses for testing and debugging. - -## The bot transcript file -A bot transcript file is a specialized JSON file that preserves the interactions between a user and your bot. A transcript file preserves not only the contents of a message, but also interaction details such as the user id, channel id, channel type, channel capabilities, time of the interaction, etc. All of this information can then be used to help find and resolve issues when testing or debugging your bot. - -## Creating/Storing a bot transcript file -This article shows how to create bot transcript files using Microsoft's [Bot Framework Emulator](https://github.com/Microsoft/BotFramework-Emulator). Transcript files may also be created programatically; you can read more concerning that approach [here](./bot-builder-howto-v4-storage.md#blob-transcript-storage). In this article we will use the Bot Framework sample code for [Multi Turn Prompt Bot](https://aka.ms/cs-multi-prompts-sample) that requests a user's mode of transportation, name and age, but any code that can be accessed using Microsoft's Bot Framework Emulator may be used to create a transcript file. - -To begin this process ensure that the bot code you want to test is running within your development environment. Start the bot framework emulator, select the _Open Bot_ button, then enter the address of _localhost:port_ shown in your browser followed by "/api/messages" as shown in the image below. Now click the _Connect_ button to connect the emulator to your bot. - -![connect emulator to your code](./media/emulator_open_bot_configuration.png) - -After connecting the emulator to your running code, test your code by sending simulated user interactions to the bot. For this example we have passed in the user's mode of transportation, name and age. After you have entered all of the user interactions you want to preserve, use the bot framework emulator to create and save a transcript file containing this conversation. - -Within the _Live Chat_ tab (shown below), select the _Save transcript_ button. - -![select save transcript](./media/emulator_transcript_save.png) - -Choose a location and name for your transcript file and then select the save button. - -![transcript saveas ursula](./media/emulator_transcript_saveas_ursula.png) - -All of the user interactions and bot responses that you entered to test your code with the emulator have now been saved into a transcript file that you can later reload to help debug interactions between your user and your bot. - -## Retrieving a bot transcript file -To retrieve a bot transcript file using the Bot Framework Emulator, select the _File_ then _Open Transcript..._ in the upper left corner of the emulator, as shown below. Next, select the transcript file that you want to retrieve. (Transcripts may also be accessed from within the _TRANSCRIPTS_ list control in the _RESOURCES_ section of the emulator) - -In this example we are retrieving the transcript file named "ursula_user.transcript". Selecting a transcript file will automatically load the entire preserved converation into a new Tab titled _Transcript_. - -![retrieve saved transcript](./media/emulator_transcript_retrieve.png) - -## Debug using transcript file -With your transcript file loaded, you are now ready to debug interactions that you captured between a user and your bot. To do this, simply click on any event or activity recorded in the _LOG_ section shown in the lower right area of the emulator. In the example shown below, we selected the user's first interaction when they sent the message "Hello". When we do this, all of the information in your transcript file concerning this specific interaction is displayed in the emulator's _INSPECTOR_ window in JSON format. Looking at some of these values from the bottom upward, we see the: -* Interaction type was _message_. -* Time the message was sent. -* Plain text sent contained "Yes". -* Message was sent to our bot. -* User id and information. -* Channel id, capabilities and information. - -![debug using transcript](./media/emulator_transcript_debug.png) - -This detailed level of information allows you to follow the step-by-step interactions between the user's input and your bot's response, which is useful for debugging situations where your bot either did not respond back in the manner that you anticipated or did not respond back to the user at all. Having both these values and a record of the steps leading up to the failed interaction allows you to step through your code, find the location where your bot does not respond as anticipated, and resolve those issues. - -Using transcript files together with the Bot Framework Emulator is just one of the many tools you can use to help you test and debug your bot's code and user interactions. To find more ways to test and debug your bot, see the additional resources listed below. - -## Additional information - -For additional testing and debugging information see: - -* [Bot testing and debugging guidelines](./bot-builder-testing-debugging.md) -* [Debug with the bot framework emulator](../bot-service-debug-emulator.md) -* [Troubleshoot general problems](../bot-service-troubleshoot-bot-configuration.md) and the other troubleshooting articles in that section. -* [Debugging in Visual Studio](https://docs.microsoft.com/visualstudio/debugger/index) diff --git a/articles/v4sdk/bot-builder-dialog-manage-complex-conversation-flow.md b/articles/v4sdk/bot-builder-dialog-manage-complex-conversation-flow.md deleted file mode 100644 index e9a65e399..000000000 --- a/articles/v4sdk/bot-builder-dialog-manage-complex-conversation-flow.md +++ /dev/null @@ -1,282 +0,0 @@ ---- -title: Create advanced conversation flow using branches and loops - Bot Service -description: Learn how to manage a complex conversation flow with dialogs in the Bot Framework SDK. -keywords: complex conversation flow, repeat, loop, menu, dialogs, prompts, waterfalls, dialog set -author: JonathanFingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/30/2020 -monikerRange: 'azure-bot-service-4.0' ---- - -# Create advanced conversation flow using branches and loops - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -You can create complex conversation flows using the dialogs library. -This article covers how to manage complex conversations that branch and loop and how to pass arguments between different parts of the dialog. - -## Prerequisites - -- Knowledge of [bot basics][concept-basics], [managing state][concept-state], the [dialogs library][concept-dialogs], and how to [implement sequential conversation flow][simple-dialog]. -- A copy of the complex dialog sample in [**C#**][cs-sample], [**JavaScript**][js-sample], or [**Python**][python-sample]. - -## About this sample - -This sample represents a bot that can sign users up to review up to two companies from a list. -The bot uses 3 component dialogs to manage the conversation flow. -Each component dialog includes a waterfall dialog and any prompts needed to gather user input. -These dialogs are described in more detail in the following sections. -It uses conversation state to manage its dialogs and uses user state to save information about the user and which companies they want to review. - -The bot derives from the activity handler. Like many of the sample bots, it welcomes the user, uses dialogs to handle messages from the user, and saves user and conversation state before the turn ends. - -### [C#](#tab/csharp) - -To use dialogs, install the **Microsoft.Bot.Builder.Dialogs** NuGet package. - -![Complex bot flow](./media/complex-conversation-flow.png) - -### [JavaScript](#tab/javascript) - -To use dialogs, your project needs to install the **botbuilder-dialogs** npm package. - -![Complex bot flow](./media/complex-conversation-flow-js.png) - -### [Python](#tab/python) - -To use dialogs, your project needs to install the **botbuilder-dialogs** PyPI package by running `pip install botbuilder-dialogs`. - -![Complex bot flow](./media/complex-conversation-flow-python.png) - ---- - -## Define the user profile - -The user profile will contain information gathered by the dialogs, the user's name, age, and companies selected to review. - -### [C#](#tab/csharp) - -**UserProfile.cs** - -[!code-csharp[UserProfile class](~/../botbuilder-samples/samples/csharp_dotnetcore/43.complex-dialog/UserProfile.cs?range=8-16)] - -### [JavaScript](#tab/javascript) - -**userProfile.js** - -[!code-javascript[UserProfile class](~/../botbuilder-samples/samples/javascript_nodejs/43.complex-dialog/userProfile.js?range=4-12)] - -### [Python](#tab/python) - -**data_models/user_profile.py** - -[!code-python[UserProfile class](~/../botbuilder-samples/samples/python/43.complex-dialog/data_models/user_profile.py?range=7-13)] - ---- - -## Create the dialogs - -This bot contains 3 dialogs: - -- The main dialog starts the overall process and then summarizes the collected information. -- The top-level dialog collects the user information and includes branching logic, based on the user's age. -- The review-selection dialog allows the user to iteratively select companies to review. It uses looping logic to do so. - -### The main dialog - -The main dialog has 2 steps: - -1. Start the top-level dialog. -1. Retrieve and summarize the user profile that the top-level dialog collected, save that information to user state, and then signal the end of the main dialog. - -#### [C#](#tab/csharp) - -**Dialogs\MainDialog.cs** - -[!code-csharp[step implementations](~/../botbuilder-samples/samples/csharp_dotnetcore/43.complex-dialog/Dialogs/MainDialog.cs?range=31-50)] - -#### [JavaScript](#tab/javascript) - -**dialogs/mainDialog.js** - -[!code-javascript[step implementations](~/../botbuilder-samples/samples/javascript_nodejs/43.complex-dialog/dialogs/mainDialog.js?range=43-55)] - -#### [Python](#tab/python) - -**dialogs\main_dialog.py** - -[!code-python[step implementations](~/../botbuilder-samples/samples/python/43.complex-dialog/dialogs/main_dialog.py?range=29-50)] - ---- - -### The top-level dialog - -The top-level dialog has 4 steps: - -1. Ask for the user's name. -1. Ask for the user's age. -1. Either start the review-selection dialog or progress to the next step, based on the user's age. -1. Finally, thank the user for participating and return the collected information. - -The first step creates an empty user profile as part of the dialog state. The dialog starts with an empty profile and adds information to the profile as it progresses. When it ends, the last step returns the collected information. - -In the third (start selection) step, the conversation flow branches, based on the user's age. - -#### [C#](#tab/csharp) - -**Dialogs\TopLevelDialog.cs** - -[!code-csharp[step implementations](~/../botbuilder-samples/samples/csharp_dotnetcore/43.complex-dialog/Dialogs/TopLevelDialog.cs?range=39-96&highlight=30-42)] - -#### [JavaScript](#tab/javascript) - -**dialogs/topLevelDialog.js** - -[!code-javascript[step implementations](~/../botbuilder-samples/samples/javascript_nodejs/43.complex-dialog/dialogs/topLevelDialog.js?range=32-76&highlight=25-33)] - -#### [Python](#tab/python) - -**dialogs\top_level_dialog.py** - -[!code-python[step implementations](~/../botbuilder-samples/samples/python/43.complex-dialog/dialogs/top_level_dialog.py?range=43-95&highlight=29-38)] - ---- - -### The review-selection dialog - -The review-selection dialog has 2 steps: - -1. Ask the user to choose a company to review or `done` to finish. - - If the dialog was started with any initial information, the information is available through the _options_ property of the waterfall step context. The review-selection dialog can restart itself, and it uses this to allow the user to choose more than one company to review. - - If the user has already selected a company to review, that company is removed from the available choices. - - A `done` choice is added to allow the user to exit the loop early. -1. Repeat this dialog or exit, as appropriate. - - If the user chose a company to review, add it to their list. - - If the user has chosen 2 companies or they chose to exit, end the dialog and return the collected list. - - Otherwise, restart the dialog, initializing it with the contents of their list. - -#### [C#](#tab/csharp) - -**Dialogs\ReviewSelectionDialog.cs** - -[!code-csharp[step implementations](~/../botbuilder-samples/samples/csharp_dotnetcore/43.complex-dialog/Dialogs/ReviewSelectionDialog.cs?range=42-106&highlight=55-64)] - -#### [JavaScript](#tab/javascript) - -**dialogs/reviewSelectionDialog.js** - -[!code-javascript[step implementations](~/../botbuilder-samples/samples/javascript_nodejs/43.complex-dialog/dialogs/reviewSelectionDialog.js?range=33-78&highlight=39-45)] - -#### [Python](#tab/python) - -**dialogs/review_selection_dialog.py** - -[!code-python[step implementations](~/../botbuilder-samples/samples/python/43.complex-dialog/dialogs/review_selection_dialog.py?range=42-99&highlight=51-58)] - ---- - -## Run the dialogs - -The _dialog bot_ class extends the activity handler, and it contains the logic for running the dialogs. -The _dialog and welcome bot_ class extends the dialog bot to also welcome a user when they join the conversation. - -The bot's turn handler repeats the conversation flow defined by the 3 dialogs. -When it receives a message from the user: - -1. It runs the main dialog. - - If the dialog stack is empty, this will start the main dialog. - - Otherwise, the dialogs are still in mid-process, and this will continue the active dialog. -1. It saves state, so that any updates to the user, conversation, and dialog state are persisted. - -### [C#](#tab/csharp) - -**Bots\DialogBot.cs** - -[!code-csharp[Overrides](~/../botbuilder-samples/samples/csharp_dotnetcore/43.complex-dialog/Bots/DialogBot.cs?range=33-48&highlight=5-7,14-15)] - -### [JavaScript](#tab/javascript) - -**bots/dialogBot.js** - -[!code-javascript[onMessage](~/../botbuilder-samples/samples/javascript_nodejs/43.complex-dialog/bots/dialogBot.js?range=24-32&highlight=4-5)] -[!code-javascript[run](~/../botbuilder-samples/samples/javascript_nodejs/43.complex-dialog/bots/dialogBot.js?range=35-44&highlight=7-9)] - -### [Python](#tab/python) - -**bots/dialog_bot.py** - -[!code-python[Overrides](~/../botbuilder-samples/samples/python/43.complex-dialog/bots/dialog_bot.py?range=29-41&highlight=4-6,9-13)] - ---- - -## Register services for the bot - -Create and register services as needed: - -- Basic services for the bot: an adapter and the bot implementation. -- Services for managing state: storage, user state, and conversation state. -- The root dialog the bot will use. - -### [C#](#tab/csharp) - -**Startup.cs** - -[!code-csharp[ConfigureServices](~/../botbuilder-samples/samples/csharp_dotnetcore/43.complex-dialog/Startup.cs?range=18-37)] - -### [JavaScript](#tab/javascript) - -**index.js** - -[!code-javascript[ConfigureServices](~/../botbuilder-samples/samples/javascript_nodejs/43.complex-dialog/index.js?range=26-43)] - -### [Python](#tab/python) - -**app.py** - -[!code-python[ConfigureServices](~/../botbuilder-samples/samples/python/43.complex-dialog/app.py?range=29-32)] -[!code-python[ConfigureServices](~/../botbuilder-samples/samples/python/43.complex-dialog/app.py?range=70-77)] - ---- - -> [!NOTE] -> Memory storage is used for testing purposes only and is not intended for production use. -> Be sure to use a persistent type of storage for a production bot. - -## To test the bot - -1. If you have not done so already, install the [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme). -1. Run the sample locally on your machine. -1. Start the emulator, connect to your bot, and send messages as shown below. - -![test complex dialog sample](~/media/emulator-v4/test-complex-dialog.png) - -## Additional resources - -For an introduction on how to implement a dialog, see [implement sequential conversation flow][simple-dialog], which uses a single waterfall dialog and a few prompts to create a simple interaction that asks the user a series of questions. - -The Dialogs library includes basic validation for prompts. You can also add custom validation. For more information, see [gather user input using a dialog prompt][dialog-prompts]. - -To simplify your dialog code and reuse it multiple bots, you can define portions of a dialog set as a separate class. -For more information, see [reuse dialogs][component-dialogs]. - -## Next steps - -> [!div class="nextstepaction"] -> [Reuse dialogs](bot-builder-compositcontrol.md) - - - -[concept-basics]: bot-builder-basics.md -[concept-state]: bot-builder-concept-state.md -[concept-dialogs]: bot-builder-concept-dialog.md - -[simple-dialog]: bot-builder-dialog-manage-conversation-flow.md -[dialog-prompts]: bot-builder-prompts.md -[component-dialogs]: bot-builder-compositcontrol.md - -[cs-sample]: https://aka.ms/cs-complex-dialog-sample -[js-sample]: https://aka.ms/js-complex-dialog-sample -[python-sample]: https://aka.ms/python-complex-dialog-sample diff --git a/articles/v4sdk/bot-builder-dialog-manage-conversation-flow.md b/articles/v4sdk/bot-builder-dialog-manage-conversation-flow.md deleted file mode 100644 index 2067ce4b8..000000000 --- a/articles/v4sdk/bot-builder-dialog-manage-conversation-flow.md +++ /dev/null @@ -1,320 +0,0 @@ ---- -title: Implement sequential conversation flow - Bot Service -description: Learn how to manage a simple conversation flow with dialogs in the Bot Framework SDK. -keywords: simple conversation flow, sequential conversation flow, dialogs, prompts, waterfalls, dialog set -author: JonathanFingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/28/2020 -monikerRange: 'azure-bot-service-4.0' ---- - -# Implement sequential conversation flow - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -Gathering information by posing questions is one of the main ways a bot interacts with users. The dialogs library provides useful built-in features such as *prompt* classes that make it easy to ask questions and validate the response to make sure it matches a specific data type or meets custom validation rules. - -You can manage simple and complex conversation flows using the dialogs library. In a simple interaction, the bot runs through a fixed sequence of steps, and the conversation finishes. In general, a dialog is useful when the bot needs to gather information from the user. This topic details how to implement simple conversation flow by creating prompts and calling them from a waterfall dialog. - -> [!TIP] -> For examples of how to write your own prompts without using the dialogs library, see the [Create your own prompts to gather user input](bot-builder-primitive-prompts.md) article. - -## Prerequisites - -- Knowledge of [bot basics][concept-basics], [managing state][concept-state], and the [dialogs library][concept-dialogs]. -- A copy of the **multi-turn prompt** sample in either [**C#**][cs-sample], [**JavaScript**][js-sample], or [**Python**][python-sample]. - -## About this sample - -In the multi-turn prompt sample, we use a waterfall dialog, a few prompts, and a component dialog to create a simple interaction that asks the user a series of questions. The code uses a dialog to cycle through these steps: - -| Steps | Prompt type | -|:-------------|:-------------| -| Ask the user for their mode of transportation | Choice prompt | -| Ask the user for their name | Text prompt | -| Ask the user if they want to provide their age | Confirm prompt | -| If they answered yes, asks for their age | Number prompt with validation to only accept ages greater than 0 and less than 150 | -| If they're not using Microsoft Teams, ask them for a profile picture | Attachment prompt with validation to allow a missing attachment | -| Asks if the collected information is "ok" | Reuse Confirm prompt | - -Finally, if they answered yes, display the collected information; otherwise, tell the user that their information will not be kept. - -## Create the main dialog - -# [C#](#tab/csharp) - -To use dialogs, install the **Microsoft.Bot.Builder.Dialogs** NuGet package. - -The bot interacts with the user via `UserProfileDialog`. When we create the bot's `DialogBot` class, we will set the `UserProfileDialog` as its main dialog. The bot then uses a `Run` helper method to access the dialog. - -![user profile dialog](media/user-profile-dialog.png) - -**Dialogs\UserProfileDialog.cs** - -We begin by creating the `UserProfileDialog` that derives from the `ComponentDialog` class, and has 7 steps. - -In the `UserProfileDialog` constructor, create the waterfall steps, prompts and the waterfall dialog, and add them to the dialog set. The prompts need to be in the same dialog set in which they are used. - -[!code-csharp[Constructor snippet](~/../botbuilder-samples/samples/csharp_dotnetcore/05.multi-turn-prompt/Dialogs/UserProfileDialog.cs?range=21-48)] - -Next, we implement the steps that the dialog uses. To use a prompt, call it from a step in your dialog and retrieve the prompt result in the following step using `stepContext.Result`. Behind the scenes, prompts are a two-step dialog. First, the prompt asks for input; second, it returns the valid value, or starts over from the beginning with a reprompt until it receives a valid input. - -You should always return a non-null `DialogTurnResult` from a waterfall step. If you do not, your dialog may not work as designed. Here we show the implementation for the `NameStepAsync` in the waterfall dialog. - -[!code-csharp[Name step](~/../botbuilder-samples/samples/csharp_dotnetcore/05.multi-turn-prompt/Dialogs/UserProfileDialog.cs?range=62-67)] - -In `AgeStepAsync`, we specify a retry prompt for when the user's input fails to validate, either because it is in a format that the prompt can not parse, or the input fails a validation criteria. In this case, if no retry prompt was provided, the prompt will use the initial prompt text to re-prompt the user for input. - -[!code-csharp[Age step](~/../botbuilder-samples/samples/csharp_dotnetcore/05.multi-turn-prompt/Dialogs/UserProfileDialog.cs?range=80-99&highlight=10)] - -**UserProfile.cs** - -The user's mode of transportation, name, and age are saved in an instance of the `UserProfile` class. - -[!code-csharp[UserProfile class](~/../botbuilder-samples/samples/csharp_dotnetcore/05.multi-turn-prompt/UserProfile.cs?range=11-20)] - -**Dialogs\UserProfileDialog.cs** - -In the last step, we check the `stepContext.Result` returned by the dialog called in the previous waterfall step. If the return value is true, we use the user profile accessor to get and update the user profile. To get the user profile, we call the `GetAsync` method, and then set the values of the `userProfile.Transport`, `userProfile.Name`, `userProfile.Age` and `userProfile.Picture` properties. Finally, we summarize the information for the user before calling `EndDialogAsync` which ends the dialog. Ending the dialog pops it off the dialog stack and returns an optional result to the dialog's parent. The parent is the dialog or method that started the dialog that just ended. - -[!code-csharp[SummaryStepAsync](~/../botbuilder-samples/samples/csharp_dotnetcore/05.multi-turn-prompt/Dialogs/UserProfileDialog.cs?range=137-179&highlight=5-11,41-42)] - -# [JavaScript](#tab/javascript) - -To use dialogs, your project needs to install the **botbuilder-dialogs** npm package. - -The bot interacts with the user via a `UserProfileDialog`. When we create the bot's `DialogBot`, we will set the `UserProfileDialog` as its main dialog. The bot then uses a `run` helper method to access the dialog. - -![user profile dialog](media/user-profile-dialog-js.png) - -**dialogs/userProfileDialog.js** - -We begin by creating the `UserProfileDialog` that derives from the `ComponentDialog` class, and has 7 steps. - -In the `UserProfileDialog` constructor, create the waterfall steps, prompts and the waterfall dialog, and add them to the dialog set. The prompts need to be in the same dialog set in which they are used. - -[!code-javascript[Constructor snippet](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/dialogs/userProfileDialog.js?range=29-51)] - -Next, we implement the steps that the dialog uses. To use a prompt, call it from a step in your dialog and retrieve the prompt result in the following step from the step context, in this case by using `step.result`. Behind the scenes, prompts are a two-step dialog. First, the prompt asks for input; second, it returns the valid value, or starts over from the beginning with a reprompt until it receives a valid input. - -You should always return a non-null `DialogTurnResult` from a waterfall step. If you do not, your dialog may not work as designed. Here we show the implementation for the `nameStep` in the waterfall dialog. - -[!code-javascript[name step](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/dialogs/userProfileDialog.js?range=79-82)] - -In `ageStep`, we specify a retry prompt for when the user's input fails to validate, either because it is in a format that the prompt can not parse, or the input fails a validation criteria, specified in the constructor above. In this case, if no retry prompt was provided, the prompt will use the initial prompt text to re-prompt the user for input. - -[!code-javascript[age step](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/dialogs/userProfileDialog.js?range=94-105&highlight=5)] - -**userProfile.js** - -The user's mode of transportation, name, and age are saved in an instance of the `UserProfile` class. - -[!code-javascript[user profile](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/userProfile.js?range=4-11)] - -**dialogs/userProfileDialog.js** - -In the last step, we check the `step.result` returned by the dialog called in the previous waterfall step. If the return value is true, we use the user profile accessor to get and update the user profile. To get the user profile, we call the `get` method, and then set the values of the `userProfile.transport`, `userProfile.name`, `userProfile.age` and `userProfile.picture` properties. Finally, we summarize the information for the user before calling `endDialog` which ends the dialog. Ending the dialog pops it off the dialog stack and returns an optional result to the dialog's parent. The parent is the dialog or method that started the dialog that just ended. - -[!code-javascript[summary step](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/dialogs/userProfileDialog.js?range=137-167&highlight=3-9,29-30)] - -**Create the extension method to run the waterfall dialog** - -We've defined a `run` helper method inside `userProfileDialog` that we will use to create and access the dialog context. Here, `accessor` is the state property accessor for the dialog state property, and `this` is the user profile component dialog. Since component dialogs define an inner dialog set, we must create an outer dialog set that's visible to the message handler code and use that to create a dialog context. - -The dialog context is created by calling the `createContext` method, and is used to interact with the dialog set from within the bot's turn handler. The dialog context includes the current turn context, the parent dialog, and the dialog state, which provides a method for preserving information within the dialog. - -The dialog context allows you to start a dialog with the string ID, or continue the current dialog (such as a waterfall dialog that has multiple steps). The dialog context is passed through to all the bot's dialogs and waterfall steps. - -[!code-javascript[run method](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/dialogs/userProfileDialog.js?range=59-68)] - -# [Python](#tab/python) - -To use dialogs, install the **botbuilder-dialogs** and **botbuilder-ai** PyPI packages by running `pip install botbuilder-dialogs` and `pip install botbuilder-ai` from a terminal. - -The bot interacts with the user via `UserProfileDialog`. When we create the bot's `DialogBot` class, we will set the `UserProfileDialog` as its main dialog. The bot then uses a `run_dialog` helper method to access the dialog. - -![user profile dialog](media/user-profile-dialog-python.png) - -**dialogs\user_profile_dialog.py** - -We begin by creating the `UserProfileDialog` that derives from the `ComponentDialog` class, and has 7 steps. - -In the `UserProfileDialog` constructor, create the waterfall steps, prompts and the waterfall dialog, and add them to the dialog set. The prompts need to be in the same dialog set in which they are used. - -[!code-python[Constructor snippet](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/dialogs/user_profile_dialog.py?range=26-57)] - -Next, we implement the steps that the dialog uses. To use a prompt, call it from a step in your dialog and retrieve the prompt result in the following step using `step_context.result`. Behind the scenes, prompts are a two-step dialog. First, the prompt asks for input; second, it returns the valid value, or starts over from the beginning with a reprompt until it receives a valid input. - -You should always return a non-null `DialogTurnResult` from a waterfall step. If you do not, your dialog may not work as designed. Here we show the implementation for the `name_step` in the waterfall dialog. - -[!code-python[name step](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/dialogs/user_profile_dialog.py?range=73-79)] - -In `age_step`, we specify a retry prompt for when the user's input fails to validate, either because it is in a format that the prompt can not parse, or the input fails a validation criteria, specified in the constructor above. In this case, if no retry prompt was provided, the prompt will use the initial prompt text to re-prompt the user for input - -[!code-python[age step](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/dialogs/user_profile_dialog.py?range=100-116)] - -**data_models\user_profile.py** - -The user's mode of transportation, name, and age are saved in an instance of the `UserProfile` class. - -[!code-python[user profile](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/data_models/user_profile.py?range=7-16)] - -**dialogs\user_profile_dialog.py** - -In the last step, we check the `step_context.result` returned by the dialog called in the previous waterfall step. If the return value is true, we use the user profile accessor to get and update the user profile. To get the user profile, we call the `get` method, and then set the values of the `user_profile.transport`, `user_profile.name`, and `user_profile.age` properties. Finally, we summarize the information for the user before calling `end_dialog` which ends the dialog. Ending the dialog pops it off the dialog stack and returns an optional result to the dialog's parent. The parent is the dialog or method that started the dialog that just ended. - -[!code-python[summary step](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/dialogs/user_profile_dialog.py?range=166-204)] - -**Create the extension method to run the waterfall dialog** - -We've defined a `run_dialog()` helper method inside **helpers\dialog_helper.py** that we will use to create and access the dialog context. Here, `accessor` is the state property accessor for the dialog state property, and `dialog` is the user profile component dialog. Since component dialogs define an inner dialog set, we must create an outer dialog set that's visible to the message handler code and use that to create a dialog context. - -The dialog context is created by calling the `create_context` method, and is used to interact with the dialog set from within the bot's turn handler. The dialog context includes the current turn context, the parent dialog, and the dialog state, which provides a method for preserving information within the dialog. - -The dialog context allows you to start a dialog with the string ID, or continue the current dialog (such as a waterfall dialog that has multiple steps). The dialog context is passed through to all the bot's dialogs and waterfall steps. - -[!code-python[run method](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/helpers/dialog_helper.py?range=8-19)] - ---- - -## Run the dialog - -# [C#](#tab/csharp) - -**Bots\DialogBot.cs** - -The `OnMessageActivityAsync` handler uses the `RunAsync` method to start or continue the dialog. In `OnTurnAsync`, we use the bot's state management objects to persist any state changes to storage. The `ActivityHandler.OnTurnAsync` method calls the various activity handler methods, such as `OnMessageActivityAsync`. In this way, we are saving state after the message handler completes but before the turn itself completes. - -[!code-csharp[overrides](~/../botbuilder-samples/samples/csharp_dotnetcore/05.multi-turn-prompt/Bots/DialogBot.cs?range=33-48&highlight=5-7)] - -# [JavaScript](#tab/javascript) - -The `onMessage` method registers a listener that calls the dialog's `run` method to start or continue the dialog. - -Separately, the bot overrides the `ActivityHandler.run` method to save conversation and user state to storage. In this way, we are saving state after the message handler completes but before the turn itself completes. - -**bots/dialogBot.js** - -[!code-javascript[message listener](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/bots/dialogBot.js?range=24-31&highlight=5)] - -[!code-javascript[override](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/bots/dialogBot.js?range=34-43&highlight=7-9)] - -# [Python](#tab/python) - -The `on_message_activity` handler uses the helper method to start or continue the dialog. In `on_turn`, we use the bot's state management objects to persist any state changes to storage. The `on_message_activity` method gets called last after other defined handlers are run, such as `on_turn`. In this way, we are saving state after the message handler completes but before the turn itself completes. - -**bots\dialog_bot.py** -[!code-python[overrides](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/bots/dialog_bot.py?range=39-51&highlight=4-6)] - ---- - -## Register services for the bot - -This bot uses the following _services_. - -- Basic services for a bot: a credential provider, an adapter, and the bot implementation. -- Services for managing state: storage, user state, and conversation state. -- The dialog the bot will use. - -# [C#](#tab/csharp) - -**Startup.cs** - -We register services for the bot in `Startup`. These services are available to other parts of the code through dependency injection. - -[!code-csharp[ConfigureServices](~/../botbuilder-samples/samples/csharp_dotnetcore/05.multi-turn-prompt/Startup.cs?range=17-39)] - -# [JavaScript](#tab/javascript) - -**index.js** - -We register services for the bot in `index.js`. - -[!code-javascript[overrides](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/index.js?range=19-59)] - -# [Python](#tab/python) - -We register services for the bot in `app.py`. - -[!code-python[configure services](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/app.py?range=27-76)] - ---- - -> [!NOTE] -> Memory storage is used for testing purposes only and is not intended for production use. -> Be sure to use a persistent type of storage for a production bot. - -## To test the bot - -1. If you have not done so already, install the [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme). -1. Run the sample locally on your machine. -1. Start the emulator, connect to your bot, and send messages as shown below. - -![Sample run of the multi-turn prompt dialog](../media/emulator-v4/multi-turn-prompt.png) - -## Additional information - -### About dialog and bot state - -In this bot, we've defined two state property accessors: - -- One created within conversation state for the dialog state property. The dialog state tracks where the user is within the dialogs of a dialog set, and it is updated by the dialog context, such as when we call the begin dialog or continue dialog methods. -- One created within user state for the user profile property. The bot uses this to track information it has about the user, and we explicitly manage this state in our dialog code. - -The _get_ and _set_ methods of a state property accessor get and set the value of the property in the state management object's cache. The cache is populated the first time the value of a state property is requested in a turn, but it must be persisted explicitly. In order to persist changes to both of these state properties, we call the _save changes_ method of the corresponding state management object. - -This sample updates the user profile state from within the dialog. This practice can work for a simple bot, but will not work if you want to reuse a dialog across bots. - -There are various options for keeping dialog steps and bot state separate. For example, once your dialog gathers complete information, you can: - -- Use the end dialog method to provide the collected data as return value back to the parent context. This can be the bot's turn handler or an earlier active dialog on the dialog stack. This is how the prompt classes are designed. -- Generate a request to an appropriate service. This might work well if your bot acts as a front end to a larger service. - -### Definition of a prompt validator method - -# [C#](#tab/csharp) - -**UserProfileDialog.cs** - -Below is an example validator code for the `AgePromptValidatorAsync` method definition. `promptContext.Recognized.Value` contains the parsed value, which is an integer here for the number prompt. `promptContext.Recognized.Succeeded` indicates whether the prompt was able to parse the user's input or not. The validator should return false to indicate that the value was not accepted and the prompt dialog should reprompt the user; otherwise, return true to accept the input and return from the prompt dialog. Note that you can change the value in the validator per your scenario. - -[!code-csharp[prompt validator method](~/../botbuilder-samples/samples/csharp_dotnetcore/05.multi-turn-prompt/Dialogs/UserProfileDialog.cs?range=181-185)] - -# [JavaScript](#tab/javascript) - -**dialogs\userProfileDialog.js** - -Below is an example validator code for the `agePromptValidator` method definition. `promptContext.recognized.value` contains the parsed value, which is an integer here for the number prompt. `promptContext.recognized.succeeded` indicates whether the prompt was able to parse the user's input or not. The validator should return false to indicate that the value was not accepted and the prompt dialog should reprompt the user; otherwise, return true to accept the input and return from the prompt dialog. Note that you can change the value in the validator per your scenario. - -[!code-javascript[prompt validator method](~/../botbuilder-samples/samples/javascript_nodejs/05.multi-turn-prompt/dialogs/userProfileDialog.js?range=169-172)] - -# [Python](#tab/python) - -**dialogs/user_profile_dialog.py** - -Below is an example validator code for the `age_prompt_validator` method definition. `prompt_context.recognized.value` contains the parsed value, which is an integer here for the number prompt. `prompt_context.recognized.succeeded` indicates whether the prompt was able to parse the user's input or not. The validator should return false to indicate that the value was not accepted and the prompt dialog should reprompt the user; otherwise, return true to accept the input and return from the prompt dialog. Note that you can change the value in the validator per your scenario. - -[!code-python[prompt validator method](~/../botbuilder-samples/samples/python/05.multi-turn-prompt/dialogs/user_profile_dialog.py?range=207-212)] - ---- - -## Next steps - -> [!div class="nextstepaction"] -> [Add natural language understanding to your bot](bot-builder-howto-v4-luis.md) - - - -[concept-basics]: bot-builder-basics.md -[concept-state]: bot-builder-concept-state.md -[concept-dialogs]: bot-builder-concept-dialog.md - -[prompting]: bot-builder-prompts.md -[component-dialogs]: bot-builder-compositcontrol.md - -[cs-sample]: https://aka.ms/cs-multi-prompts-sample -[js-sample]: https://aka.ms/js-multi-prompts-sample -[python-sample]: https://aka.ms/python-multi-prompts-sample diff --git a/articles/v4sdk/bot-builder-dialogs-greeting.md b/articles/v4sdk/bot-builder-dialogs-greeting.md deleted file mode 100644 index 656a71289..000000000 --- a/articles/v4sdk/bot-builder-dialogs-greeting.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: Implement a greeting dialog - Bot Service -description: Use a dialog to greet a user when they join a conversation. -keywords: greeting, dialogs, conversation flow, dialog set -author: JonathanFingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Implement a greeting dialog - -[!INCLUDE [pre-release-label](../includes/pre-release-label.md)] - -You can use a dialog to welcome a user to a conversation. - -For more information about welcoming users, see how to [send welcome messages to users][send-welcome]. - -## Prerequisites - -- Knowledge of [managing state][concept-state], the [dialogs library][concept-dialogs], how to [manage conversations][simple-flow], and how to [gather user input using a dialog prompt][prompting]. -- A copy of the ??? sample in either [**CSharp**][cs-sample] or [**JavaScript**][js-sample]. - -## \ [as in to do X, do these things] - - - -## About the sample code - - - -- Additional packages needed (AI.Luis, Dialogs, etc.) - - - -## To test the bot - -1. If you have not done so already, install the [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme). -1. Run the sample locally on your machine. -1. Start the emulator, connect to your bot, and send messages as shown below. - -TODO: Take new screenshot. - - - -## Discussion [optional] - - - -## Addition information - - - -- link to the "about the core bot" landing page for the overall sample (for CoreBot-derived articles). - -## Next steps - -> [!div class="nextstepaction"] -> [Handle user interruptions](bot-builder-howto-handle-user-interrupt.md) - - - -[concept-basics]: bot-builder-basics.md -[concept-state]: bot-builder-concept-state.md -[concept-dialogs]: bot-builder-concept-dialog.md - -[send-welcome]: bot-builder-send-welcome-message.md - -[simple-flow]: bot-builder-dialog-manage-conversation-flow.md -[prompting]: bot-builder-prompts.md -[component-dialogs]: bot-builder-compositcontrol.md - -[cs-sample]: ??? -[js-sample]: ??? diff --git a/articles/v4sdk/bot-builder-howto-add-media-attachments.md b/articles/v4sdk/bot-builder-howto-add-media-attachments.md deleted file mode 100644 index 4636213fd..000000000 --- a/articles/v4sdk/bot-builder-howto-add-media-attachments.md +++ /dev/null @@ -1,494 +0,0 @@ ---- -title: Add media to messages - Bot Service -description: Learn how to add media to messages using the Bot Framework SDK. -keywords: media, messages, images, audio, video, files, MessageFactory, rich cards, messages, adaptive cards, hero card, suggested actions -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 02/03/2020 -monikerRange: 'azure-bot-service-4.0' ---- - -# Add media to messages - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -Messages exchanged between user and bot can contain media attachments, such as images, video, audio, and files. The Bot Framework SDK supports the task of sending rich messages to the user. To determine the type of rich messages a channel (Facebook, Skype, Slack, etc.) supports, consult the channel's documentation for information about limitations. - -## Prerequisites - -- Knowledge of [bot basics](bot-builder-basics.md). -- The code in this article is based on the following samples: - - | Sample code | C# | JS | Python | - | :------ | :----- | :---| :---| - | Cards | [C# sample](https://aka.ms/bot-cards-sample-code) | [JS sample](https://aka.ms/bot-cards-js-sample-code) |[Python sample](https://aka.ms/bot-cards-python-sample-code) | - | Attachments | [C# sample](https://aka.ms/bot-attachments-sample-code) | [JS sample](https://aka.ms/bot-attachments-sample-code-js) | [Python sample](https://aka.ms/bot-media-attachments-python-sample-code) | - | Suggested actions | [C# sample](https://aka.ms/SuggestedActionsCSharp) | [JS sample](https://aka.ms/SuggestedActionsJS) | [Python sample](https://aka.ms/SuggestedActionsPython) | - -## Send attachments - -To send the user content like an image or a video, you can add an attachment or list of attachments to a message. - -See [design user experience](../bot-service-design-user-experience.md) for examples of available cards. - -### [C#](#tab/csharp) - -The `Attachments` property of the `Activity` object contains an array of `Attachment` objects that represent the media attachments and rich cards attached to the message. To add a media attachment to a message, create an `Attachment` object for the `reply` activity (that was created off the activity with `CreateReply()`) and set the `ContentType`, `ContentUrl`, and `Name` properties. - -The source code shown here is based on the [Handling Attachments](https://aka.ms/bot-attachments-sample-code) sample. - -To create the reply message, define the text and then set up the attachments. Assigning the attachments to the reply is the same for each attachment type, however the various attachments are set up and defined differently, as seen in the following snippets. The code below is setting up the reply for an inline attachment: - -**Bots/AttachmentsBot.cs** -[!code-csharp[inline attachment](~/../botbuilder-samples/samples/csharp_dotnetcore/15.handling-attachments/Bots/AttachmentsBot.cs?range=105-106)] - -Next, we look at the types of attachments. First is an inline attachment: - -**Bots/AttachmentsBot.cs** -[!code-csharp[inline attachment](~/../botbuilder-samples/samples/csharp_dotnetcore/15.handling-attachments/Bots/AttachmentsBot.cs?range=167-178)] - -Then, an uploaded attachment: - -**Bots/AttachmentsBot.cs** -[!code-csharp[uploaded attachment](~/../botbuilder-samples/samples/csharp_dotnetcore/15.handling-attachments/Bots/AttachmentsBot.cs?range=181-214)] - -Lastly, an internet attachment: - -**Bots/AttachmentsBot.cs** -[!code-csharp[online attachment](~/../botbuilder-samples/samples/csharp_dotnetcore/15.handling-attachments/Bots/AttachmentsBot.cs?range=217-226)] - -### [JavaScript](#tab/javascript) - -The source code shown here is based on the [JS Handling Attachments](https://aka.ms/bot-attachments-sample-code-js) sample. - -To use attachments, include the following libraries in your bot: - -**bots/attachmentsBot.js** -[!code-javascript[attachments libraries](~/../botbuilder-samples/samples/javascript_nodejs/15.handling-attachments/bots/attachmentsBot.js?range=4)] - -To create the reply message, define the text and then set up the attachments. Assigning the attachments to the reply is the same for each attachment type, however the various attachments are set up and defined differently, as seen in the following snippets. The code below is setting up the reply for an inline attachment: - -**bots/attachmentsBot.js** -[!code-javascript[attachments](~/../botbuilder-samples/samples/javascript_nodejs/15.handling-attachments/bots/attachmentsBot.js?range=119,128-129)] - -To send the user a single piece of content like an image or a video, you can send media in a few different ways. First, as an inline attachment: - -**bots/attachmentsBot.js** -[!code-javascript[inline attachments](~/../botbuilder-samples/samples/javascript_nodejs/15.handling-attachments/bots/attachmentsBot.js?range=170-179)] - -Then, an uploaded attachment: - -**bots/attachmentsBot.js** -[!code-javascript[uploaded attachments](~/../botbuilder-samples/samples/javascript_nodejs/15.handling-attachments/bots/attachmentsBot.js?range=197-215)] - -Lastly, an internet attachment contained in a URL: - -**bots/attachmentsBot.js** -[!code-javascript[internet attachments](~/../botbuilder-samples/samples/javascript_nodejs/15.handling-attachments/bots/attachmentsBot.js?range=184-191)] - -### [Python](#tab/python) - -To create the reply message, define the text and then set up the attachments. Assigning the attachments to the reply is the same for each attachment type, however the various attachments are set up and defined differently, as seen in the following snippets. - -The source code shown here is based on the [Handling Attachments](https://aka.ms/bot-media-attachments-python-sample-code) sample. - -The code below is setting up the reply for an inline attachment: - -**bots/attachments_bot.py** -[!code-python[attachments](~/../botbuilder-samples/samples/python/15.handling-attachments/bots/attachments_bot.py?range=112-113)] - -To send the user a single piece of content like an image or a video, you can send media in a few different ways. First, as an inline attachment: - -**bots/attachments_bot.py** -[!code-python[inline attachments](~/../botbuilder-samples/samples/python/15.handling-attachments/bots/attachments_bot.py?range=153-170)] - -Then, an uploaded attachment: - -**bots/attachments_bot.py** -[!code-python[upload attachments](~/../botbuilder-samples/samples/python/15.handling-attachments/bots/attachments_bot.py?range=172-207)] - -Lastly, an internet attachment contained in a URL: - -**bots/attachments_bot.py** -[!code-python[internet attachments](~/../botbuilder-samples/samples/python/15.handling-attachments/bots/attachments_bot.py?range=209-218)] - ---- - -If an attachment is an image, audio, or video, the Connector service will communicate attachment data to the channel in a way that enables the [channel](bot-builder-channeldata.md) to render that attachment within the conversation. If the attachment is a file, the file URL will be rendered as a hyperlink within the conversation. - -## Send a hero card - -Besides simple image or video attachments, you can attach a **hero card**, which allows you to combine images and buttons in one object, and send them to the user. Markdown is supported for most text fields, but support may vary by channel. - -### [C#](#tab/csharp) - -To compose a message with a hero card and button, you can attach a `HeroCard` to a message. - -The source code shown here is based on the [Handling Attachments](https://aka.ms/bot-attachments-sample-code) sample. - -**Bots/AttachmentsBot.cs** -[!code-csharp[Hero card](~/../botbuilder-samples/samples/csharp_dotnetcore/15.handling-attachments/Bots/AttachmentsBot.cs?range=39-58)] - -### [JavaScript](#tab/javascript) - -To compose a message with a hero card and button, you can attach a `HeroCard` to a message. - -The source code shown here is based on the [JS Handling Attachments](https://aka.ms/bot-attachments-sample-code-js) sample. - -**bots/attachmentsBot.js** -[!code-javascript[hero card](~/../botbuilder-samples/samples/javascript_nodejs/15.handling-attachments/bots/attachmentsBot.js?range=147-165)] - -### [Python](#tab/python) - -To compose a message with a hero card and button, you can attach a `HeroCard` to a message. - -The source code shown here is based on the [Handling Attachments](https://aka.ms/bot-media-attachments-python-sample-code) sample. - -**bots/attachments_bot.py** -[!code-python[hero card](~/../botbuilder-samples/samples/python/15.handling-attachments/bots/attachments_bot.py?range=125-148)] - ---- - -## Process events within rich cards - -To process events within rich cards, use _card action_ objects to specify what should happen when the user clicks a button or taps a section of the card. Each card action has a _type_ and _value_. - -To function correctly, assign an action type to each clickable item on the card. This table lists and describes the available action types and what should be in the associated value property. - -| Type | Description | Value | -| :---- | :---- | :---- | -| openUrl | Opens a URL in the built-in browser. | The URL to open. | -| imBack | Sends a message to the bot, and posts a visible response in the chat. | Text of the message to send. | -| postBack | Sends a message to the bot, and may not post a visible response in the chat. | Text of the message to send. | -| call | Initiates a phone call. | Destination for the phone call in this format: `tel:123123123123`. | -| playAudio | Plays audio. | The URL of the audio to play. | -| playVideo | Plays a video. | The URL of video to play. | -| showImage | Displays an image. | The URL of the image to display. | -| downloadFile | Downloads a file. | The URL of the file to download. | -| signin | Initiates an OAuth signin process. | The URL of the OAuth flow to initiate. | - -## Hero card using various event types - -The following code shows examples using various rich card events. - -### [C#](#tab/csharp) - -For examples of all the available cards, see the [C# cards sample](https://aka.ms/bot-cards-sample-code). - -**Cards.cs** -[!code-csharp[hero cards](~/../botbuilder-samples/samples/csharp_dotnetcore/06.using-cards/Cards.cs?range=27-40)] - -**Cards.cs** -[!code-csharp[cards](~/../botbuilder-samples/samples/csharp_dotnetcore/06.using-cards/Cards.cs?range=91-100)] - -### [JavaScript](#tab/javascript) - -For examples of all the available cards, see the [JS cards sample](https://aka.ms/bot-cards-js-sample-code). - -**dialogs/mainDialog.js** -[!code-javascript[hero cards](~/../botbuilder-samples/samples/javascript_nodejs/06.using-cards/dialogs/mainDialog.js?range=206-218)] - -**dialogs/mainDialog.js** -[!code-javascript[sign in cards](~/../botbuilder-samples/samples/javascript_nodejs/06.using-cards/dialogs/mainDialog.js?range=259-265)] - -### [Python](#tab/python) - -For examples of all the available cards, see the [Python cards sample](https://aka.ms/bot-cards-python-sample-code). - -**dialogs/main_dialog.py** -[!code-python[hero cards](~/../botbuilder-samples/samples/python/06.using-cards/dialogs/main_dialog.py?range=163-179)] - -**dialogs/main_dialog.py** -[!code-python[hero cards](~/../botbuilder-samples/samples/python/06.using-cards/dialogs/main_dialog.py?range=245-256)] - ---- - -## Send an Adaptive Card -Adaptive Card and MessageFactory are used to send rich messages including texts, images, video, audio and files to communicate with users. However, there are some differences between them. - -First, only some channels support Adaptive Cards, and channels that do support it might partially support Adaptive Cards. For example, if you send an Adaptive Card in Facebook, the buttons won't work while texts and images work well. MessageFactory is just a helper class within the Bot Framework SDK to automate creation steps for you, and supported by most channels. - -Second, Adaptive Card delivers messages in the card format, and the channel determines the layout of the card. The format of messages MessageFactory delivers depends on the channel, and is not necessarily in the card format unless Adaptive Card is part of the attachment. - -To find the latest information on Adaptive Card channel support, see the Adaptive Cards Designer. - -To use adaptive cards, be sure to add the `AdaptiveCards` NuGet package. - -> [!NOTE] -> You should test this feature with the channels your bot will use to determine whether those channels support adaptive cards. - -### [C#](#tab/csharp) - -To use Adaptive Cards, be sure to add the `AdaptiveCards` NuGet package. - -The source code shown here is based on the [Using cards](https://aka.ms/bot-cards-sample-code) sample. - -**Cards.cs** -[!code-csharp[adaptive cards](~/../botbuilder-samples/samples/csharp_dotnetcore/06.using-cards/Cards.cs?range=13-25)] - -### [JavaScript](#tab/javascript) - -To use Adaptive Cards, be sure to add the `adaptivecards` npm package. - -The source code shown here is based on the [JS Using Cards](https://aka.ms/bot-cards-js-sample-code) sample. - -Here, the Adaptive card is stored in it's own file and included in our bot: - -**resources/adaptiveCard.json** -[!code-json[adaptive cards](~/../botbuilder-samples/samples/javascript_nodejs/06.using-cards/resources/adaptiveCard.json)] - -The card is created as follows: - -**dialogs/mainDialog.js** -[!code-javascript[adaptive cards](~/../botbuilder-samples/samples/javascript_nodejs/06.using-cards/dialogs/mainDialog.js?range=6)] -[!code-javascript[adaptive cards](~/../botbuilder-samples/samples/javascript_nodejs/06.using-cards/dialogs/mainDialog.js?range=170-172)] - -### [Python](#tab/python) - -The source code shown here is based on the [Using cards](https://aka.ms/bot-cards-python-sample-code) sample. - -**dialogs/resources/adaptive_card_example.py** -[!code-python[adaptive cards](~/../botbuilder-samples/samples/python/06.using-cards/dialogs/resources/adaptive_card_example.py)] - -The card is created as follows: - -**bots/main_dialog.py** -[!code-python[hero cards](~/../botbuilder-samples/samples/python/06.using-cards/dialogs/main_dialog.py?range=127-128)] - ---- - -## Send a carousel of cards - -Messages can also include multiple attachments in a carousel layout, which places the attachments side by side and allows the user to scroll across. - -### [C#](#tab/csharp) - -The source code shown here is based on the [Cards sample](https://aka.ms/bot-cards-sample-code). - -First, create the reply and define the attachments as a list. - -**Dialogs/MainDialog.cs** -[!code-csharp[carousel of cards](~/../botbuilder-samples/samples/csharp_dotnetcore/06.using-cards/Dialogs/MainDialog.cs?range=61-66)] - -Then add the attachments. Here we're adding them one at a time, but feel free to manipulate the list to add the cards however you prefer. - -**Dialogs/MainDialog.cs** -[!code-csharp[carousel of cards](~/../botbuilder-samples/samples/csharp_dotnetcore/06.using-cards/Dialogs/MainDialog.cs?range=104-113)] - -Once the attachments are added, you can send the reply just like any other. - -**Dialogs/MainDialog.cs** -[!code-csharp[carousel of cards](~/../botbuilder-samples/samples/csharp_dotnetcore/06.using-cards/Dialogs/MainDialog.cs?range=117-118)] - -### [JavaScript](#tab/javascript) - -The source code shown here is based on the [JS cards sample](https://aka.ms/bot-cards-js-sample-code). - -To send a carousel of cards, send a reply with the attachments as an array and the layout type defined as `Carousel`: - -**dialogs/mainDialog.js** -[!code-javascript[carousel of cards](~/../botbuilder-samples/samples/javascript_nodejs/06.using-cards/dialogs/mainDialog.js?range=97-108)] - -[!code-javascript[carousel of cards](~/../botbuilder-samples/samples/javascript_nodejs/06.using-cards/dialogs/mainDialog.js?range=113-116)] - -### [Python](#tab/python) - -The source code shown here is based on [Python cards sample](https://aka.ms/bot-cards-python-sample-code). - -To send a carousel of cards, send a reply with the attachments as an array and the layout type defined as `Carousel`: - -**dialogs/main_dialog.py** -[!code-python[hero cards](~/../botbuilder-samples/samples/python/06.using-cards/dialogs/main_dialog.py?range=104-112)] - -Once the attachments are added, you can send the reply. - -**dialogs/main_dialog.py** -[!code-python[hero cards](~/../botbuilder-samples/samples/python/06.using-cards/dialogs/main_dialog.py?range=114-115)] - ---- - - - -## Additional resources - -See [design user experience](../bot-service-design-user-experience.md) for examples of available cards. - -For detailed information on the schema, see the [Bot Framework card schema](https://aka.ms/botSpecs-cardSchema) and the [message activity section](https://aka.ms/botSpecs-activitySchema#message-activity) of the Bot Framework Activity schema. - -### Code sample for processing Adaptive Card input - -This sample code shows one way to use Adaptive Card inputs within a bot dialog class. -It extends the current sample 06.using-cards by validating the input received in the text field from the responding client. -We first added text input and button functionality to the existing adaptive card by adding the following code just before the final bracket of adaptiveCard.json, found in the resources folder: - -```json -... - "actions": [ - { - "type": "Action.ShowCard", - "title": "Text", - "card": { - "type": "AdaptiveCard", - "body": [ - { - "type": "Input.Text", - "id": "text", - "isMultiline": true, - "placeholder": "Enter your comment" - } - ], - "actions": [ - { - "type": "Action.Submit", - "title": "OK" - } - ] - } - } -] - -``` - -Note that the input field is labeled "text" so our adaptive card will attach comment text data as Value.[text.] - -### [C#](#tab/csharp) - -Our validator uses Newtonsoft.json to first convert this to a JObject, -and then create a trimmed text string for comparison. So add: - -```csharp -using System; -using System.Linq; -using Newtonsoft.Json.Linq; -``` - -to MainDialog.cs and install the latest stable nuget package of Newtonsoft.Json. -In the validator code we added the logic flow into the code comments. -This ChoiceValidator() code is placed into the 06.using-cards sample just after the closed brace public for declaration of MainDialog: - -```csharp -private async Task ChoiceValidator( - PromptValidatorContext promptContext, - CancellationToken cancellationToken) -{ - // Retrieves Adaptive Card comment text as JObject. - // looks for JObject field "text" and converts that input into a trimmed text string. - var jobject = promptContext.Context.Activity.Value as JObject; - var jtoken = jobject?["text"]; - var text = jtoken?.Value().Trim(); - - // Logic: 1. if succeeded = true, just return promptContext - // 2. if false, see if JObject contained Adaptive Card input. - // No = (bad input) return promptContext - // Yes = update Value field with JObject text string, return "true". - if (!promptContext.Recognized.Succeeded && text != null) - { - var choice = promptContext.Options.Choices.FirstOrDefault( - c => c.Value.Equals(text, StringComparison.InvariantCultureIgnoreCase)); - if (choice != null) - { - promptContext.Recognized.Value = new FoundChoice - { - Value = choice.Value, - }; - return true; - } - } - return promptContext.Recognized.Succeeded; -} -``` - -Now above in the MainDialog declaration change: - -```csharp -// Define the main dialog and its related components. -AddDialog(new ChoicePrompt(nameof(ChoicePrompt))); -``` - -to: - -```csharp -// Define the main dialog and its related components. -AddDialog(new ChoicePrompt(nameof(ChoicePrompt), ChoiceValidator)); -``` - -This will invoke your validator to look for Adaptive Card input each time a new ChoicePrompt is created. - -### [JavaScript](#tab/javascript) - -Open mainDialog.js and find the run method _async run(turnContext, accessor)_ -This method handles incoming activity. -Just after the call _dialogSet.add(this);_ add the following: - -```JavaScript -// The following check looks for a non-existant text input -// plus Adaptive Card input in _activity.value.text -// If both conditions exist, the Activity Card text -// is copied into the text input field. -if(turnContext._activity.text == null - && turnContext._activity.value.text != null) { - this.logger.log('replacing null text with Activity Card text input'); - turnContext._activity.text = turnContext._activity.value.text; - } -``` - -If this check finds a non-existent text input from the client, it looks to see if there is input from an Adaptive Card. -If an Adaptive Card input exists at \_activity.value.text, it copies this into the normal text input field. - -### [Python](#tab/python) - -The source code shown here is based on the [Suggested actions](https://aka.ms/SuggestedActionsPython) sample. - -Create and sends an activity with suggested actions to the user. - -This choice_validator() code is placed into the 06.using-cards sample just after the closed brace public for declaration of MainDialog: - -```python -@staticmethod -async def choice_validator(prompt_context: PromptValidatorContext) -> bool: - if prompt_context.context.activity.value: - text = prompt_context.context.activity.value["text"].lower() - if not prompt_context.recognized.succeeded and text: - matching_choices = [choice for choice in prompt_context.options.choices if choice.value.lower() == text] - if matching_choices: - choice = matching_choices[0] - prompt_context.recognized.value = FoundChoice( - value=choice.value, - index=0, - score=1.0 - ) - return True - - return prompt_context.recognized.succeeded -``` - -Now above in the MainDialog declaration change: - -```python -self.add_dialog(ChoicePrompt(CARD_PROMPT)) -``` - -to: - -```python -self.add_dialog(ChoicePrompt(CARD_PROMPT, MainDialog.choice_validator)) -``` - -This will invoke your validator to look for Adaptive Card input each time a new ChoicePrompt is created. - ---- - -To test your code, once an Adaptive Card has been displayed, Click the "Text" button, Enter a valid selection such as "Hero Card" and click the "OK" button. - -![Test Adaptive Card](media/adaptive-card-input.png) - -1. The first input will be used to start a new dialog. -2. Click the "OK" button again and this input will be used to select a new card. - -## Next steps - -> [!div class="nextstepaction"] -> [Add buttons to guide user action](./bot-builder-howto-add-suggested-actions.md) diff --git a/articles/v4sdk/bot-builder-howto-add-suggested-actions.md b/articles/v4sdk/bot-builder-howto-add-suggested-actions.md deleted file mode 100644 index 6c3b8d4ba..000000000 --- a/articles/v4sdk/bot-builder-howto-add-suggested-actions.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Use button for input - Bot Service -description: Learn how to send suggested actions within messages using the Bot Framework SDK for JavaScript. -keywords: suggested actions, buttons, extra input -author: Kaiqb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 12/10/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Use button for input - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -You can enable your bot to present buttons that the user can tap to provide input. Buttons enhance user experience by enabling the user to answer a question or make a selection with a simple tap of a button, rather than having to type a response with a keyboard. Unlike buttons that appear within rich cards (which remain visible and accessible to the user even after being tapped), buttons that appear within the suggested actions pane will disappear after the user makes a selection. This prevents the user from tapping stale buttons within a conversation and simplifies bot development (since you will not need to account for that scenario). - -## Suggest action using button - -*Suggested actions* enable your bot to present buttons. You can create a list of suggested actions (also known as "quick replies") that will be shown to the user for a single turn of the conversation: - -# [C#](#tab/csharp) - -The source code shown here is based on the [suggest actions sample](https://aka.ms/SuggestedActionsCSharp). - -[!code-csharp[suggested actions](~/../botbuilder-samples/samples/csharp_dotnetcore/08.suggested-actions/Bots/SuggestedActionsBot.cs?range=87-101)] - -# [JavaScript](#tab/javascript) - -The source code shown here is based on the [suggested actions sample](https://aka.ms/SuggestActionsJS). - -[!code-javascript[suggested actions](~/../botbuilder-samples/samples/javascript_nodejs/08.suggested-actions/bots/suggestedActionsBot.js?range=61-64)] - - -# [Python](#tab/python) - -The source code shown here is based on the [suggested actions sample](https://aka.ms/SuggestActionsPython). - -[!code-python[suggested actions](~/../botbuilder-samples/samples/python/08.suggested-actions/bots/suggested_actions_bot.py?range=63-81)] - - ---- - -## Additional resources - -You can access the complete source code shown here: -- [C# sample](https://aka.ms/SuggestedActionsCSharp) -- [JavaScript sample](https://aka.ms/SuggestActionsJS) -- [Python sample](https://aka.ms/SuggestActionsPython) - -## Next steps - -> [!div class="nextstepaction"] -> [Save user and conversation data](./bot-builder-howto-v4-state.md) diff --git a/articles/v4sdk/bot-builder-howto-handle-user-interrupt.md b/articles/v4sdk/bot-builder-howto-handle-user-interrupt.md deleted file mode 100644 index 63ffdf1cd..000000000 --- a/articles/v4sdk/bot-builder-howto-handle-user-interrupt.md +++ /dev/null @@ -1,256 +0,0 @@ ---- -title: Handle user interruptions - Bot Service -description: Learn how to handle user interrupt and direct conversation flow. -keywords: interrupt, interruptions, switching topic, break -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/24/2020 -monikerRange: 'azure-bot-service-4.0' ---- - -# Handle user interruptions - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -Handling interruptions is an important aspect of a robust bot. Users will not always follow your defined conversation flow, step by step. They may try to ask a question in the middle of the process, or simply want to cancel it instead of completing it. In this topic, we will explore some common ways to handle user interruptions in your bot. - -## Prerequisites - -- Knowledge of [bot basics][concept-basics], [managing state][concept-state], the [dialogs library][concept-dialogs], and how to [reuse dialogs][component-dialogs]. -- A copy of the core bot sample in either [**CSharp**][cs-sample], [**JavaScript**][js-sample] or [**Python**][python-sample]. - -## About this sample - -The sample used in this article models a flight booking bot that uses dialogs to get flight information from the user. At any time during the conversation with the bot, the user can issue _help_ or _cancel_ commands to cause an interruption. There are two types of interruptions we handle here: - -- **Turn level**: Bypass processing at the turn level but leave the dialog on the stack with the information that was provided. In the next turn, continue from where we left off. -- **Dialog level**: Cancel the processing completely, so the bot can start all over again. - -## Define and implement the interruption logic - -First, we define and implement the _help_ and _cancel_ interruptions. - -# [C#](#tab/csharp) - -To use dialogs, install the **Microsoft.Bot.Builder.Dialogs** NuGet package. - -**Dialogs\CancelAndHelpDialog.cs** - -We begin by implementing the `CancelAndHelpDialog` class to handle user interruptions. - -[!code-csharp[Class signature](~/../botbuilder-samples/samples/csharp_dotnetcore/13.core-bot/Dialogs/CancelAndHelpDialog.cs?range=12)] - -In the `CancelAndHelpDialog` class the `OnContinueDialogAsync` method calls the `InerruptAsync` method to check if the user has interrupted the normal flow. If the flow is interrupted, base class methods are called; otherwise, the return value from the `InterruptAsync` is returned. - -[!code-csharp[Overrides](~/../botbuilder-samples/samples/csharp_dotnetcore/13.core-bot/Dialogs/CancelAndHelpDialog.cs?range=22-31)] - -If the user types "help", the `InterrupAsync` method sends a message and then calls `DialogTurnResult (DialogTurnStatus.Waiting)` to indicate that the dialog on top is waiting for a response from the user. In this way, the conversation flow is interrupted for a turn only, and in the next turn we continue from where we left off. - -If the user types "cancel", it calls `CancelAllDialogsAsync` on its inner dialog context, which clears its dialog stack and causes it to exit with a cancelled status and no result value. To the `MainDialog` (shown later on), it will appear that the booking dialog ended and returned null, similar to when the user chooses not to confirm their booking. - -[!code-csharp[Interrupt](~/../botbuilder-samples/samples/csharp_dotnetcore/13.core-bot/Dialogs/CancelAndHelpDialog.cs?range=33-56)] - -# [JavaScript](#tab/javascript) - -To use dialogs, install the **botbuilder-dialogs** npm package. - -**dialogs/cancelAndHelpDialog.js** - -We begin by implementing the `CancelAndHelpDialog` class to handle user interruptions. - -[!code-javascript[Class signature](~/../botbuilder-samples/samples/javascript_nodejs/13.core-bot/dialogs/cancelAndHelpDialog.js?range=11)] - -In the `CancelAndHelpDialog` class the `onContinueDialog` method calls the `interrupt` method to check if the user has interrupted the normal flow. If the flow is interrupted, base class methods are called; otherwise, the return value from the `interrupt` is returned. - -[!code-javascript[Overrides](~/../botbuilder-samples/samples/javascript_nodejs/13.core-bot/dialogs/cancelAndHelpDialog.js?range=12-18)] - -If the user types "help", the `interrupt` method sends a message and then returns a `{ status: DialogTurnStatus.waiting }` object to indicate that the dialog on top is waiting for a response from the user. In this way, the conversation flow is interrupted for a turn only, and in the next turn we continue from where we left off. - -If the user types "cancel", it calls `cancelAllDialogs` on its inner dialog context, which clears its dialog stack and causes it to exit with a cancelled status and no result value. To the `MainDialog` (shown later on), it will appear that the booking dialog ended and returned null, similar to when the user chooses not to confirm their booking. - -[!code-javascript[Interrupt](~/../botbuilder-samples/samples/javascript_nodejs/13.core-bot/dialogs/cancelAndHelpDialog.js?range=20-39)] - -## [Python](#tab/python) - -To use dialogs, install the `botbuilder-dialogs` package and make sure that the sample `requirements.txt` file contains the proper reference such as `botbuilder-dialogs>=4.5.0`. -For more information, about installing the packages, see the samples repository [README](https://github.com/microsoft/botbuilder-python) file. -> [!NOTE] -> Doing `pip install botbuilder-dialogs` will also install `botbuilder-core`, `botbulder-connector`, and `botbuilder-schema`. - -**dialogs/cancel-and-help-dialog.py** - -We begin by implementing the `CancelAndHelpDialog` class to handle user interruptions. - -[!code-python[class signature](~/../botbuilder-samples/samples/python/13.core-bot/dialogs/cancel_and_help_dialog.py?range=14)] - -In the `CancelAndHelpDialog` class the `on_continue_dialog` method calls the `interrupt` method to check if the user has interrupted the normal flow. If the flow is interrupted, base class methods are called; otherwise, the return value from the `InterruptAsync` is returned. - -[!code-python[dialog](~/../botbuilder-samples/samples/python/13.core-bot/dialogs/cancel_and_help_dialog.py?range=18-23)] - -If the user types *help* or *?*, the `interrupt` method sends a message and then calls -`DialogTurnResult(DialogTurnStatus.Waiting)` to indicate that the dialog on top of the stack is waiting for a response from the user. In this way, the conversation flow is interrupted for a turn only, and in the next turn we continue from where we left off. - -If the user types *cancel* or *quit*, it calls `cancel_all_dialogs()` on its inner dialog context, which clears its dialog stack and causes it to exit with a cancelled status and no result value. To the `MainDialog`, shown later, it will appear that the booking dialog ended and returned null, similar to when the user chooses not to confirm their booking. - -[!code-python[interrupt](~/../botbuilder-samples/samples/python/13.core-bot/dialogs/cancel_and_help_dialog.py?range=25-47)] - ---- - -## Check for interruptions each turn - -Now that we've covered how the interrupt handling class works, let's step back and look at what happens when the bot receives a new message from the user. - -# [C#](#tab/csharp) - -**Dialogs\MainDialog.cs** - -As the new message activity arrives, the bot runs the `MainDialog`. The `MainDialog` prompts the user for what it can help with. And then it starts the `BookingDialog` in the `MainDialog.ActStepAsync` method, with a call to `BeginDialogAsync` as shown below. - -[!code-csharp[ActStepAsync](~/../botbuilder-samples/samples/csharp_dotnetcore/13.core-bot/Dialogs/MainDialog.cs?range=58-101&highlight=6,26)] - -Next, in the `FinalStepAsync` method of the `MainDialog` class, the booking dialog ended and the booking is considered to be complete or cancelled. - -[!code-csharp[FinalStepAsync](~/../botbuilder-samples/samples/csharp_dotnetcore/13.core-bot/Dialogs/MainDialog.cs?range=130-150)] - -The code in `BookingDialog` is not shown here as it is not directly related to interruption handling. It is used to prompt users for booking details. You can find that code in **Dialogs\BookingDialogs.cs**. - -# [JavaScript](#tab/javascript) - -**dialogs/mainDialog.js** - -As the new message activity arrives, the bot runs the `MainDialog`. The `MainDialog` prompts the user for what it can help with. And then it starts the `bookingDialog` in the `MainDialog.actStep` method, with a call to `beginDialog` as shown below. - -[!code-javascript[Act step](~/../botbuilder-samples/samples/javascript_nodejs/13.core-bot/dialogs/mainDialog.js?range=71-115&highlight=6,27)] - -Next, in the `finalStep` method of the `MainDialog` class, the booking dialog ended and the booking is considered to be complete or cancelled. - -[!code-javascript[Final step](~/../botbuilder-samples/samples/javascript_nodejs/13.core-bot/dialogs/mainDialog.js?range=142-159)] - -The code in `BookingDialog` is not shown here as it is not directly related to interruption handling. It is used to prompt users for booking details. You can find that code in **dialogs/bookingDialogs.js**. - -## [Python](#tab/python) - -**dialogs/main_dialog.py** - -As the new message activity arrives, the bot runs the `MainDialog`. The `MainDialog` prompts the user for what it can help with. And then it starts the `bookingDialog` in the `MainDialog.act_step` method, with a call to `begin_dialog` as shown below. - -[!code-python[act step](~/../botbuilder-samples/samples/python/13.core-bot/dialogs/main_dialog.py?range=63-100&highlight=4-5,20)] - -Next, in the `final_step` method of the `MainDialog` class, the booking dialog ended and the booking is considered to be complete or cancelled. - -[!code-python[final step](~/../botbuilder-samples/samples/python/13.core-bot/dialogs/main_dialog.py?range=102-118)] - ---- - -## Handle unexpected errors - -Next, we deal with any unhandled exceptions that might occur. - -# [C#](#tab/csharp) - -**AdapterWithErrorHandler.cs** - -In our sample, the adapter's `OnTurnError` handler receives any exceptions thrown by your bot's turn logic. If there is an exception thrown, the handler deletes the conversation state for the current conversation to prevent the bot from getting stuck in a error-loop caused by being in a bad state. - -[!code-csharp[AdapterWithErrorHandler](~/../botbuilder-samples/samples/csharp_dotnetcore/13.core-bot/AdapterWithErrorHandler.cs?range=19-50)] - -# [JavaScript](#tab/javascript) - -**index.js** - -In our sample, the adapter's `onTurnError` handler receives any exceptions thrown by your bot's turn logic. If there is an exception thrown, the handler deletes the conversation state for the current conversation to prevent the bot from getting stuck in a error-loop caused by being in a bad state. - -[!code-javascript[AdapterWithErrorHandler](~/../botbuilder-samples/samples/javascript_nodejs/13.core-bot/index.js?range=35-57)] - -## [Python](#tab/python) - -**adapter_with_error_handler.py** - -In our sample, the adapter's `on_error` handler receives any exceptions thrown by your bot's turn logic. If there is an exception thrown, the handler deletes the conversation state for the current conversation to prevent the bot from getting stuck in a error-loop caused by being in a bad state. - -[!code-python[adapter_with_error_handler](~/../botbuilder-samples/samples/python/13.core-bot/adapter_with_error_handler.py?range=16-56)] - ---- - -## Register services - -# [C#](#tab/csharp) - -**Startup.cs** - -Finally, in `Startup.cs`, the bot is created as a transient, and on every turn, a new instance of the bot is created. - -[!code-csharp[Add transient bot](~/../botbuilder-samples/samples/csharp_dotnetcore/13.core-bot/Startup.cs?range=43-44)] - -For reference, here are the class definitions that are used in the call to create the bot above. - -[!code-csharp[MainDialog signature](~/../botbuilder-samples/samples/csharp_dotnetcore/13.core-bot/Dialogs/MainDialog.cs?range=17)] -[!code-csharp[DialogAndWelcomeBot signature](~/../botbuilder-samples/samples/csharp_dotnetcore/13.core-bot/Bots/DialogAndWelcomeBot.cs?range=16)] -[!code-csharp[DialogBot signature](~/../botbuilder-samples/samples/csharp_dotnetcore/13.core-bot/Bots/DialogBot.cs?range=18)] - -# [JavaScript](#tab/javascript) - -**index.js** - -Finally, in `index.js`, the bot is created. - -[!code-javascript[Create bot](~/../botbuilder-samples/samples/javascript_nodejs/13.core-bot/index.js?range=78-81)] - -For reference, here are the class definitions that are used in the call to create the bot above. - -[!code-javascript[MainDialog signature](~/../botbuilder-samples/samples/javascript_nodejs/13.core-bot/dialogs/mainDialog.js?range=11)] -[!code-javascript[DialogAndWelcomeBot signature](~/../botbuilder-samples/samples/javascript_nodejs/13.core-bot/bots/dialogAndWelcomeBot.js?range=8)] -[!code-javascript[DialogBot signature](~/../botbuilder-samples/samples/javascript_nodejs/13.core-bot/bots/dialogBot.js?range=6)] - -## [Python](#tab/python) - -**app.py** -Finally, in `app.py`, the bot is created. - -[!code-python[create bot](~/../botbuilder-samples/samples/python/13.core-bot/app.py?range=45-49)] - -For reference, here are the class definitions that are used in the call to create the bot. - -[!code-python[main dialog](~/../botbuilder-samples/samples/python/13.core-bot/dialogs/main_dialog.py?range=20)] - -[!code-python[dialog and welcome](~/../botbuilder-samples/samples/python/13.core-bot/bots/dialog_and_welcome_bot.py?range=21)] - -[!code-python[dialog](~/../botbuilder-samples/samples/python/13.core-bot/bots/dialog_bot.py?range=9)] - ---- - -## To test the bot - -1. If you have not done so already, install the [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme). -1. Run the sample locally on your machine. -1. Start the emulator, connect to your bot, and send messages as shown below. - - - -## Additional information - -- The [authentication sample](https://aka.ms/logout) shows how to handle logout which uses similar pattern shown here for handling interruptions. - -- You should send a default response instead of doing nothing and leaving the user wondering what is going on. The default response should tell the user what commands the bot understands so the user can get back on track. - -- At any point in the turn, the turn context's _responded_ property indicates whether the bot has sent a message to the user this turn. Before the turn ends, your bot should send some message to the user, even if it is a simple acknowledgement of their input. - - - -[concept-basics]: bot-builder-basics.md -[concept-state]: bot-builder-concept-state.md -[concept-dialogs]: bot-builder-concept-dialog.md - -[using-luis]: bot-builder-howto-v4-luis.md -[using-qna]: bot-builder-howto-qna.md - -[simple-flow]: bot-builder-dialog-manage-conversation-flow.md -[prompting]: bot-builder-prompts.md -[component-dialogs]: bot-builder-compositcontrol.md - -[cs-sample]: https://aka.ms/cs-core-sample -[js-sample]: https://aka.ms/js-core-sample -[python-sample]: https://aka.ms/bot-core-python-sample-code diff --git a/articles/v4sdk/bot-builder-howto-proactive-message.md b/articles/v4sdk/bot-builder-howto-proactive-message.md deleted file mode 100644 index b6269e3ac..000000000 --- a/articles/v4sdk/bot-builder-howto-proactive-message.md +++ /dev/null @@ -1,161 +0,0 @@ ---- -title: Send proactive notifications to users - Bot Service -description: Understand how to send notification messages -keywords: proactive message, notification message, bot notification, -author: jonathanfingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/24/2020 -monikerRange: 'azure-bot-service-4.0' ---- - -# Send proactive notifications to users - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -Typically, each message that a bot sends to the user directly relates to the user's prior input. -In some cases, a bot may need to send the user a message that is not directly related to the current topic of conversation or to the last message the user sent. These types of messages are called _proactive messages_. - -Proactive messages can be useful in a variety of scenarios. For example, if the user has previously asked the bot to monitor the price of a product, the bot can alert the user if the price of the product has dropped by 20%. Or, if a bot requires some time to compile a response to the user's question, it may inform the user of the delay and allow the conversation to continue in the meantime. When the bot finishes compiling the response to the question, it will share that information with the user. - -When implementing proactive messages in your bot, don't send several proactive messages within a short amount of time. Some channels enforce restrictions on how frequently a bot can send messages to the user, and will disable the bot if it violates those restrictions. - -An ad hoc proactive message is the simplest type of proactive message. The bot simply interjects the message into the conversation whenever it is triggered, without any regard for whether the user is currently engaged in a separate topic of conversation with the bot and will not attempt to change the conversation in any way. - -To handle notifications more smoothly, consider other ways to integrate the notification into the conversation flow, such as setting a flag in the conversation state or adding the notification to a queue. - -## Prerequisites - -- Understand [bot basics](bot-builder-basics.md). -- A copy of the proactive messages sample in [**C#**](https://aka.ms/proactive-sample-cs) or [**JavaScript**](https://aka.ms/proactive-sample-js) or [**Python**](https://aka.ms/bot-proactive-python-sample-code). The sample is used to explain proactive messaging in this article. - -## About the proactive sample - -The sample has a bot and an additional controller that is used to send proactive messages to the bot, as shown in the following illustration. - -![proactive bot](media/proactive-sample-bot.png) - -## Retrieve and store conversation reference - -When the emulator connects to the bot, the bot receives two conversation update activities. In the bot's conversation update activity handler, the conversation reference is retrieved and stored in a dictionary as shown below. - -# [C#](#tab/csharp) - -**Bots\ProactiveBot.cs** - -[!code-csharp[OnConversationUpdateActivityAsync](~/../botbuilder-samples/samples/csharp_dotnetcore/16.proactive-messages/Bots/ProactiveBot.cs?range=26-37&highlight=3-4,9)] - -# [JavaScript](#tab/javascript) - -**bots/proactiveBot.js** - -[!code-javascript[onConversationUpdateActivity](~/../botbuilder-samples/samples/javascript_nodejs/16.proactive-messages/bots/proactiveBot.js?range=13-17&highlight=2)] - -[!code-javascript[onConversationUpdateActivity](~/../botbuilder-samples/samples/javascript_nodejs/16.proactive-messages/bots/proactiveBot.js?range=41-44&highlight=2-3)] - -# [Python](#tab/python) - -**bots/proactive_bot.py** -[!code-python[on_conversation_update_activity](~/../botbuilder-samples/samples/python/16.proactive-messages/bots/proactive_bot.py?range=14-16&highlight=2)] - -[!code-python[on_conversation_update_activity](~/../botbuilder-samples/samples/python/16.proactive-messages/bots/proactive_bot.py?range=35-45)] - ---- - -Note: In a real-world scenario you would persist conversation references in a database instead of using an object in memory. - -The conversation reference has a _conversation_ property that describes the conversation in which the activity exists. The conversation has a _user_ property that lists the users participating in the conversation, and a _service URL_ property that channels use to denote the URL where replies to the current activity may be sent. A valid conversation reference is needed to send proactive messages to users. - -## Send proactive message - -The second controller, the _notify_ controller, is responsible for sending the proactive message to the bot. Use the following steps to generate a proactive message. - -1. Retrieve the reference for the conversation to which to send the proactive message. -1. Call the adapter's _continue conversation_ method, providing the conversation reference and the turn handler delegate to use. The continue conversation method generates a turn context for the referenced conversation and then calls the specified turn handler delegate. -1. In the delegate, use the turn context to send the proactive message. - -# [C#](#tab/csharp) - -**Controllers\NotifyController .cs** - -Each time the bot's notify page is requested, the notify controller retrieves the conversation references from the dictionary. -The controller then uses the `ContinueConversationAsync` and `BotCallback` methods to send the proactive message. - -[!code-csharp[Notify logic](~/../botbuilder-samples/samples/csharp_dotnetcore/16.proactive-messages/Controllers/NotifyController.cs?range=17-62&highlight=28,40-44)] - -To send a proactive message, the adapter requires an app ID for the bot. In a production environment, you can use the bot's app ID. In a local test environment, you can use any GUID. If the bot is not currently assigned an app ID, the notify controller self-generates a placeholder ID to use for the call. - -# [JavaScript](#tab/javascript) - -**index.js** - -Each time the server's `/api/notify` page is requested, the server retrieves the conversation references from the dictionary. -The server then uses the `continueConversation` method to send the proactive message. -The parameter to `continueConversation` is a function that serves as the bot's turn handler for this turn. - -[!code-javascript[Notify logic](~/../botbuilder-samples/samples/javascript_nodejs/16.proactive-messages/index.js?range=68-82&highlight=4-8)] - -# [Python](#tab/python) - -Each time the bot's notify page is requested, the server retrieves the conversation references from the dictionary. -The server then uses the `_send_proactive_message` to send the proactive message. - -[!code-python[Notify logic](~/../botbuilder-samples/samples/python/16.proactive-messages/app.py?range=97-105&highlight=5-9)] - ---- - -## Test your bot - -1. If you have not done so already, install the [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme). -1. Run the sample locally on your machine. -1. Start the emulator and connect to your bot. -1. Load to your bot's api/notify page. This will generate a proactive message in the emulator. - -## Additional information - -Besides the sample used in this article, additional samples are available in C# and JS on [GitHub](https://github.com/Microsoft/BotBuilder-Samples/). - -### Avoiding 401 "Unauthorized" Errors - -By default, the BotBuilder SDK adds a `serviceUrl` to the list of trusted host names if the incoming request is authenticated by BotAuthentication. They are maintained in an in-memory cache. If your bot is restarted, a user awaiting a proactive message cannot receive it unless they have messaged the bot again after it restarted. - -To avoid this, you must manually add the `serviceUrl` to the list of trusted host names by using: - -# [C#](#tab/csharp) - -```csharp -MicrosoftAppCredentials.TrustServiceUrl(serviceUrl); -``` - -For proactive messaging, `serviceUrl` is the URL of the channel that the recipient of the proactive message is using and can be found in `Activity.ServiceUrl`. - -You'll want to add the above code just prior to the the code that sends the proactive message. In the [Proactive Messages Sample](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/16.proactive-messages), you would put it in `NotifyController.cs` just before `await turnContext.SendActivityAsync("proactive hello");`. - -# [JavaScript](#tab/javascript) - -```js -MicrosoftAppCredentials.trustServiceUrl(serviceUrl); -``` - -For proactive messaging, `serviceUrl` is the URL of the channel that the recipient of the proactive message is using and can be found in `activity.serviceUrl`. - -You'll want to add the above code just prior to the the code that sends the proactive message. In the [Proactive Messages Sample](https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/javascript_nodejs/16.proactive-messages), you would put it in `index.js` just before `await turnContext.sendActivity('proactive hello');`. - -# [Python](#tab/python) - -```python -MicrosoftAppCredentials.trustServiceUrl(serviceUrl) -``` - -For proactive messaging, `serviceUrl` is the URL of the channel that the recipient of the proactive message is using and can be found in `activity.serviceUrl`. - -You'll want to add the above code just prior to the the code that sends the proactive message. In the [Proactive Messages Sample](https://aka.ms/bot-proactive-python-sample-code), you add it in `app.py` prior sending the *proactive hello* message. - ---- - -## Next steps - -> [!div class="nextstepaction"] -> [Implement sequential conversation flow](bot-builder-dialog-manage-conversation-flow.md) diff --git a/articles/v4sdk/bot-builder-howto-qna.md b/articles/v4sdk/bot-builder-howto-qna.md deleted file mode 100644 index 316fb7cf2..000000000 --- a/articles/v4sdk/bot-builder-howto-qna.md +++ /dev/null @@ -1,373 +0,0 @@ ---- -title: Use QnA Maker to answer questions - Bot Service -description: Learn how to use QnA maker in your bot. -keywords: question and answer, QnA, FAQs, qna maker -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/06/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Use QnA Maker to answer questions - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -QnA Maker provides a conversational question and answer layer over your data. This allows your bot to send a question to the QnA Maker and receive an answer without needing to parse and interpret the question intent. - -One of the basic requirements in creating your own QnA Maker service is to populate it with questions and answers. In many cases, the questions and answers already exist in content like FAQs or other documentation; other times, you may want to customize your answers to questions in a more natural, conversational way. - -## Prerequisites - -- The code in this article is based on the QnA Maker sample. You'll need a copy of it either in **[C#](https://aka.ms/cs-qna)** or **[JavaScript](https://aka.ms/js-qna-sample)** or **[Python](https://aka.ms/bot-qna-python-sample-code)**. -- [QnA Maker](https://www.qnamaker.ai/) account -- Knowledge of [bot basics](bot-builder-basics.md), [QnA Maker](https://docs.microsoft.com/azure/cognitive-services/qnamaker/overview/overview), and [managing bot resources](bot-file-basics.md). - -## About this sample - -To use QnA Maker in your bot, you need to create a knowledge base in the [QnA Maker](https://www.qnamaker.ai/) portal, as shown in the next section. Your bot then can send the user's questions to the maker which provides the best answers. - -## [C#](#tab/cs) - -![QnABot logic flow](./media/qnabot-logic-flow.png) - -`OnMessageActivityAsync` is called for each user input received. When called, it accesses `_configuration` information stored within the sample code's `appsetting.json` file to find the value to connect to your pre-configured QnA Maker knowledge base. - -## [JavaScript](#tab/js) - -![QnABot JS logic flow](./media/qnabot-js-logic-flow.png) - -`OnMessage` is called for each user input received. When called, it accesses your `qnamaker` connector that was pre-configured using values provided from your sample code's `.env` file. The qnamaker method `getAnswers` connects your bot to your external QnA Maker knowledge base. - -## [Python](#tab/python) - -![QnABot JS logic flow](./media/qnabot-python-logic-flow.png) - -`on_message_activity` is called for each user input received. When called, it accesses your `qna_maker` connector that was pre-configured using values provided from your sample code's `config.py` file. The method `qna_maker.getAnswers` connects your bot to your external QnA Maker knowledge base. - ---- - -The user's input is sent to your knowledge base and the best returned answer is displayed back to your user. - -## Create a QnA Maker service and publish a knowledge base - -The first step is to create a QnA Maker service. Follow the steps listed in the QnA Maker [documentation](https://docs.microsoft.com/azure/cognitive-services/qnamaker/how-to/set-up-qnamaker-service-azure) to create the service in Azure. - -Next, you'll create a knowledge base using the `smartLightFAQ.tsv` file located in the CognitiveModels folder of the sample project. The steps to create, train, and publish your QnA Maker [knowledge base](https://docs.microsoft.com/azure/cognitive-services/qnamaker/quickstarts/create-publish-knowledge-base) are listed in the QnA Maker documentation. As you follow these steps, name your KB `qna`, and use the `smartLightFAQ.tsv` file to populate your KB. - -> Note. This article may also be used to access your own user developed QnA Maker knowledge base. - -## Obtain values to connect your bot to the knowledge base - -1. In the [QnA Maker](https://www.qnamaker.ai/) site, select your knowledge base. -1. With your knowledge base open, select the **Settings**. Record the value shown for _service name_. This value is useful for finding your knowledge base of interest when using the QnA Maker portal interface. It is not used to connect your bot app to this knowledge base. -1. Scroll down to find **Deployment details** record the following values from the Postman sample HTTP request: - - POST /knowledgebases/\/generateAnswer - - Host: \ // Full URL ending with /qnamaker - - Authorization: EndpointKey \ - -The full URL string for your Hostname will look like "https://< >.azure.net/qnamaker". These three values will provide the information necessary for your app to connect to your QnA Maker knowledge base via your Azure QnA service. - -## Update the settings file - -First, add the information required to access your knowledge base including hostname, endpoint key and knowledge base Id (kbId) into the settings file. These are the values you saved from the **Settings** tab of your knowledge base in QnA Maker. - -If you aren't deploying this for production, the app ID and password fields can be left blank. - -> [!NOTE] -> If you are adding access to a QnA Maker knowledge base into an existing bot application, be sure to add informative titles for your QnA entries. The "name" value within this section provides the key required to access this information from within your app. - -## [C#](#tab/cs) - -### Update your appsettings.json file - -[!code-csharp[appsettings](~/../botbuilder-samples/samples/csharp_dotnetcore/11.qnamaker/appsettings.json)] - -## [JavaScript](#tab/js) - -### Update your .env file - -[!code-javascript[.env file](~/../botbuilder-samples/samples/javascript_nodejs/11.qnamaker/.env)] - -## [Python](#tab/python) - -### Update your config.py file - -[!code-python[config.py](~/../botbuilder-samples/samples/python/11.qnamaker/config.py?range=10-18)] - ---- - -## Set up the QnA Maker instance - -First, we create an object for accessing our QnA Maker knowledge base. - -## [C#](#tab/cs) - -Be sure that the **Microsoft.Bot.Builder.AI.QnA** NuGet package is installed for your project. - -In **QnABot.cs**, in the `OnMessageActivityAsync` method, we create a QnAMaker instance. The `QnABot` class is also where the names of the connection information, saved in `appsettings.json` above, are pulled in. If you have chosen different names for your knowledge base connection information in your settings file, be sure to update the names here to reflect your chosen name. - -**Bots/QnABot.cs** - -[!code-csharp[qna connection](~/../botbuilder-samples/samples/csharp_dotnetcore/11.qnamaker/Bots/QnABot.cs?range=32-39)] - -## [JavaScript](#tab/js) - -Be sure that npm package **botbuilder-ai** is installed for your project. - -In our sample the code for the bot logic is in the **QnABot.js** file. - -In the **QnABot.js** file, we use the connection information provided by your .env file to establish a connection to the QnA Maker service: _this.qnaMaker_. - -**bots/QnABot.js** - -[!code-javascript[QnAMaker](~/../botbuilder-samples/samples/javascript_nodejs/11.qnamaker/bots/QnABot.js?range=12-16)] - -## [Python](#tab/python) - -In the **qna_bot.py** file, we use the connection information provided by the `config.py` file to establish a connection to the QnA Maker service: `self.qna_maker`. - -**bots/qna_bot.py** -[!code-python[QnAMaker](~/../botbuilder-samples/samples/python/11.qnamaker/bots/qna_bot.py?range=13-19)] - ---- - -## Calling QnA Maker from your bot - -## [C#](#tab/cs) - -When your bot needs an answer from QnAMaker, call `GetAnswersAsync()` from your bot code to get the appropriate answer based on the current context. If you are accessing your own knowledge base, change the _no answers found_ message below to provide useful instructions for your users. - -**Bots/QnABot.cs** - -[!code-csharp[qna get answers](~/../botbuilder-samples/samples/csharp_dotnetcore/11.qnamaker/Bots/QnABot.cs?range=43-52)] - -## [JavaScript](#tab/js) - -In the **QnABot.js** file, we pass the user's input to the QnA Maker service's `getAnswers` method to get answers from the knowledge base. If QnA Maker returns a response, this is shown to the user. Otherwise, the user receives the message 'No QnA Maker answers were found.' - -**bots/QnABot.js** - -[!code-javascript[OnMessage](~/../botbuilder-samples/samples/javascript_nodejs/11.qnamaker/bots/QnABot.js?range=46-55)] - -## [Python](#tab/python) - -In the **qna_bot.py** file, we pass the user's input to the QnA Maker service's `get_answers` method to get answers from the knowledge base. If QnA Maker returns a response, this is shown to the user. Otherwise, the user receives the message *No QnA Maker answers were found.* - -**bots/qna_bot.py** -[!code-python[get_answers](~/../botbuilder-samples/samples/python/11.qnamaker/bots/qna_bot.py?range=33-37)] - ---- - -## Test the bot - -Run the sample locally on your machine. If you have not done so already, install the [Bot Framework Emulator](https://github.com/Microsoft/BotFramework-Emulator/blob/master/README.md#download). For further instructions, refer to the readme file for [C# sample](https://aka.ms/cs-qna) or [Javascript sample](https://aka.ms/js-qna-sample). -or [Python sample](https://aka.ms/bot-qna-python-sample-code). - -Start the emulator, connect to your bot, and send a message as shown below. - -![test qna sample](../media/emulator-v4/qna-test-bot.png) - -## Additional information - -### Multi-turn prompts - -QnA Maker supports follow-up prompts, also known as multi-turn prompts. -If the QnA Maker knowledge base requires an additional response from the user, QnA Maker sends context information that you can use to prompt the user. This information is also used to make any follow-up calls to the QnA Maker service. -In version 4.6, the Bot Framework SDK added support for this feature. - -To construct such a knowledge base, see the QnA Maker documentation on how to [Use follow-up prompts to create multiple turns of a conversation](https://aka.ms/qnamaker-multiturn-conversation). - - - -## Next steps - -QnA Maker can be combined with other Cognitive Services, to make your bot even more powerful. The Dispatch tool provides a way to combine QnA with Language Understanding (LUIS) in your bot. - -> [!div class="nextstepaction"] -> [Combine LUIS and QnA services using the Dispatch tool](./bot-builder-tutorial-dispatch.md) diff --git a/articles/v4sdk/bot-builder-howto-send-messages.md b/articles/v4sdk/bot-builder-howto-send-messages.md deleted file mode 100644 index 126867eb5..000000000 --- a/articles/v4sdk/bot-builder-howto-send-messages.md +++ /dev/null @@ -1,164 +0,0 @@ ---- -title: Send and receive text message - Bot Service -description: Learn about how to send and receive text messages within the Bot Framework SDK. -keywords: sending message, message activities, simple text message, message, text message, receive message -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Send and receive text message - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -The primary way your bot will communicate with users, and likewise receive communication, is through **message** activities. Some messages may simply consist of plain text, while others may contain richer content such as cards or attachments. Your bot's turn handler receives messages from the user, and you can send responses to the user from there. The turn context object provides methods for sending messages back to the user. This article describes how to send simple text messages. - -Markdown is supported for most text fields, but support may vary by channel. - -For a running bot sending and receiving messages, follow the quickstarts at the top of the table of contents or check out the [article on how bots work](bot-builder-basics.md#bot-structure), which also links to simple samples available for you to run yourself. - -## Send a text message - -To send a simple text message, specify the string you want to send as the activity: - -# [C#](#tab/csharp) - -In the bot's activity handlers, use the turn context object's `SendActivityAsync` method to send a single message response. You can also use the object's `SendActivitiesAsync` method to send multiple responses at once. - -```cs -await turnContext.SendActivityAsync($"Welcome!"); -``` - -# [JavaScript](#tab/javascript) - -In the bot's activity handlers, use the turn context object's `sendActivity` method to send a single message response. You can also use the object's `sendActivities` method to send multiple responses at once. - -```javascript -await context.sendActivity("Welcome!"); -``` - -# [Python](#tab/python) - -In the bot's activity handlers, use the turn context object's `send_activity` method to send a single message response. - -```python -await turn_context.send_activity("Welcome!") -``` - ---- -## Receive a text message - -To receive a simple text message, use the *text* property of the *activity* object. - -# [C#](#tab/csharp) - -In the bot's activity handlers, use the following code to receive a message. - -```cs -var responseMessage = turnContext.Activity.Text; -``` - -# [JavaScript](#tab/javascript) - -In the bot's activity handlers, use the following code to receive a message. - -```javascript -let text = turnContext.activity.text; -``` - -# [Python](#tab/python) - -In the bot's activity handlers, use the following code to receive a message. - -```python -response = context.activity.text -``` - ---- - -## Send a typing indicator -Users expect a timely response to their messages. If your bot performs some long-running task like calling a server or executing a query without giving the user some indication that the bot heard them, the user could get impatient and send additional messages or just assume the bot is broken. - -Web Chat and Direct Line channel bots can support the sending of a typing indication to show the user that the message was received and is being processed. Be aware that your bot needs to let the turn end within 15 seconds or the Connector service will timeout. For longer processes read more about sending [proactive messages](bot-builder-howto-proactive-message.md). - -The following example demonstrates how to send a typing indication. - -# [C#](#tab/csharp) - -```csharp -protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) -{ - if (string.Equals(turnContext.Activity.Text, "wait", System.StringComparison.InvariantCultureIgnoreCase)) - { - await turnContext.SendActivitiesAsync( - new Activity[] { - new Activity { Type = ActivityTypes.Typing }, - new Activity { Type = "delay", Value= 3000 }, - MessageFactory.Text("Finished typing", "Finished typing"), - }, - cancellationToken); - } - else - { - var replyText = $"Echo: {turnContext.Activity.Text}. Say 'wait' to watch me type."; - await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken); - } -} -``` - -# [JavaScript](#tab/javascript) - -```javascript -this.onMessage(async (context, next) => { - if (context.activity.text === 'wait') { - await context.sendActivities([ - { type: ActivityTypes.Typing }, - { type: 'delay', value: 3000 }, - { type: ActivityTypes.Message, text: 'Finished typing' } - ]); - } else { - await context.sendActivity(`You said '${ context.activity.text }'. Say "wait" to watch me type.`); - } - await next(); -}); -``` - -# [Python](#tab/python) - -```python -async def on_message_activity(self, turn_context: TurnContext): - if turn_context.activity.text == "wait": - return await turn_context.send_activities([ - Activity( - type=ActivityTypes.typing - ), - Activity( - type="delay", - value=3000 - ), - Activity( - type=ActivityTypes.message, - text="Finished Typing" - ) - ]) - else: - return await turn_context.send_activity( - f"You said {turn_context.activity.text}. Say 'wait' to watch me type." - ) -``` - ---- - -## Additional resources - -- For more information about activity processing in general, see [activity processing](~/v4sdk/bot-builder-basics.md#the-activity-processing-stack). -- For more information on formatting, see the [message activity section](https://aka.ms/botSpecs-activitySchema#message-activity) of the Bot Framework Activity schema. - -## Next steps - -> [!div class="nextstepaction"] -> [Add media to messages](./bot-builder-howto-add-media-attachments.md) diff --git a/articles/v4sdk/bot-builder-howto-v4-luis.md b/articles/v4sdk/bot-builder-howto-v4-luis.md deleted file mode 100644 index 7b7b0376a..000000000 --- a/articles/v4sdk/bot-builder-howto-v4-luis.md +++ /dev/null @@ -1,204 +0,0 @@ ---- -title: Add natural language understanding to your bot - Bot Service -description: Learn how to use LUIS for natural language understanding with the Bot Framework SDK. -keywords: Language Understanding, LUIS, intent, recognizer, entities, middleware -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/24/2020 -monikerRange: 'azure-bot-service-4.0' ---- - -# Add natural language understanding to your bot - -[!INCLUDE[applies-to](../includes/applies-to.md)] -The ability to understand what your user means conversationally and contextually can be a difficult task, but can provide your bot a more natural conversation feel. Language Understanding, called LUIS, enables you to do just that so that your bot can recognize the intent of user messages, allow for more natural language from your user, and better direct the conversation flow. This topic walks you through adding LUIS to a flight booking application to recognize different intents and entities contained within user input. - -## Prerequisites - -- [LUIS](https://www.luis.ai) account -- The code in this article is based on the **Core Bot** sample. You'll need a copy of the sample in **[C#](https://aka.ms/cs-core-sample)**, **[JavaScript](https://aka.ms/js-core-sample)**, or **[Python](https://aka.ms/python-core-sample)**. -- Knowledge of [bot basics](bot-builder-basics.md), [natural language processing](https://docs.microsoft.com/azure/cognitive-services/luis/what-is-luis), and [managing bot resources](bot-file-basics.md). - -## About this sample - -This core bot coding sample shows an example of an airport flight booking application. It uses a LUIS service to recognize the user input and return the top recognized LUIS intent. - -# [C#](#tab/csharp) - -After each processing of user input, `DialogBot` saves the current state of both `UserState` and `ConversationState`. Once all the required information has been gathered the coding sample creates a demo flight booking reservation. In this article we'll be covering the LUIS aspects of this sample. However, the general flow of the sample is shown below: - -- `OnMembersAddedAsync` is called when a new user is connected and displays a welcome card. -- `OnMessageActivityAsync` is called for each user input received. - -![LUIS sample logic flow](./media/how-to-luis/luis-logic-flow.png) - -The `OnMessageActivityAsync` module runs the appropriate dialog through the `Run` dialog extension method. Then the main dialog calls the LUIS helper to find the the top scoring user intent. If the top intent for the user input returns "BookFlight", the helper fills out information from the user that LUIS returned. After that, the main dialog starts the `BookingDialog`, which acquires additional information as needed from the user such as: - -- `Origin` the originating city -- `TravelDate` the date to book the flight -- `Destination` the destination city - -# [JavaScript](#tab/javascript) - -After each processing of user input, `dialogBot` saves the current state of both `userState` and `conversationState`. Once all the required information has been gathered the coding sample creates a demo flight booking reservation. In this article we'll be covering the LUIS aspects of this sample. However, the general flow of the sample is shown below: - -- `onMembersAdded` is called when a new user is connected and displays a welcome card. -- `OnMessage` is called for each user input received. - -![LUIS sample javascript logic flow](./media/how-to-luis/luis-logic-flow-js.png) - -The `onMessage` module runs the `mainDialog` which gathers user input. -Then the main dialog calls the LUIS helper `FlightBookingRecognizer` to find the top scoring user intent. If the top intent for the user input returns "BookFlight", the helper fills out information from the user that LUIS returned. -Upon the response back, `mainDialog` preserves information for the user returned by LUIS and starts `bookingDialog`. `bookingDialog` acquires additional information as needed from the user such as - -- `destination` the destination city. -- `origin` the originating city. -- `travelDate` the date to book the flight. - -# [Python](#tab/python) - -After each processing of user input, `DialogBot` saves the current state of both `user_state` and `conversation_state`. Once all the required information has been gathered the coding sample creates a demo flight booking reservation. In this article we'll be covering the LUIS aspects of this sample. However, the general flow of the sample is shown below: - -- `on_members_added_activity` is called when a new user is connected and displays a welcome card. -- `on_message_activity` is called for each user input received. - -![LUIS sample Python logic flow](./media/how-to-luis/luis-logic-flow-python.png) - -The `on_message_activity` module runs the appropriate dialog through the `run_dialog` dialog extension method. Then the main dialog calls `LuisHelper` to find the the top scoring user intent. If the top intent for the user input returns "BookFlight", the helper function fills out information from the user that LUIS returned. After that, the main dialog starts the `BookingDialog`, which acquires additional information as needed from the user such as: - -- `destination` the destination city. -- `origin` the originating city. -- `travel_date` the date to book the flight. - ---- - -For details on the other aspects of the sample like dialogs or state, see [Gather user input using a dialog prompt](bot-builder-prompts.md) or [Save user and conversation data](bot-builder-howto-v4-state.md). - -## Create a LUIS app in the LUIS portal - -Sign in to the LUIS portal to create your own version of the sample LUIS app. You can create and manage your applications on **My Apps**. - -1. Select **Import new app**. -1. Click **Choose App file (JSON format)...** -1. Select `FlightBooking.json` file located in the `CognitiveModels` folder of the sample. In the **Optional Name**, enter **FlightBooking**. This file contains three intents: 'Book Flight', 'Cancel', and 'None'. We'll use these intents to understand what the user meant when they send a message to the bot. -1. [Train](https://docs.microsoft.com/azure/cognitive-services/LUIS/luis-how-to-train) the app. -1. [Publish](https://docs.microsoft.com/azure/cognitive-services/LUIS/publishapp) the app to *production* environment. - -### Why use entities - -LUIS entities allow your bot to intelligently understand certain things or events that are different than the standard intents. This enables you to gather extra information from the user, which lets your bot respond more intelligently or possibly skip certain questions where it asks the user for that information. Along with definitions for the three LUIS intents 'Book Flight', 'Cancel', and 'None' the FlightBooking.json file also contains a set of entities such as 'From.Airport' and 'To.Airport'. These entities allow LUIS to detect and return additional information contained within the user's original input when they request a new travel booking. - -For information on how entity information appears in a LUIS result, see [Extract data from utterance text with intents and entities](https://docs.microsoft.com/azure/cognitive-services/luis/luis-concept-data-extraction). - -## Obtain values to connect to your LUIS app - -Once your LUIS app is published, you can access it from your bot. You will need to record several values to access your LUIS app from within your bot. You can retrieve that information using the LUIS portal. - -### Retrieve application information from the LUIS.ai portal - -The settings file (`appsettings.json` or `.env`) acts as the place to bring all service references together in one place. The information you retrieve will be added to this file in the next section. - -1. Select your published LUIS app from [luis.ai](https://www.luis.ai). -1. With your published LUIS app open, select the **MANAGE** tab. -![Manage LUIS app](./media/how-to-luis/manage-luis-app.png) -1. Select the **Application Information** tab on the left side, record the value shown for _Application ID_ as . -1. Select the **Keys and Endpoints** tab on the left side, record the value shown for _Authoring Key_ as . -1. Scroll down to the end of the page, record the value shown for _Region_ as . - -### Update the settings file - -# [C#](#tab/csharp) - -Add the information required to access your LUIS app including application id, authoring key, and region into the `appsettings.json` file. These are the values you saved previously from your published LUIS app. Note that the API host name should be in the format `.api.cognitive.microsoft.com`. - -**appsetting.json** -[!code-json[appsettings](~/../BotBuilder-Samples/samples/csharp_dotnetcore/13.core-bot/appsettings.json?range=1-7)] - -# [JavaScript](#tab/javascript) - -Add the information required to access your LUIS app including application id, authoring key, and region into the `.env` file. These are the values you saved previously from your published LUIS app. Note that the API host name should be in the format `.api.cognitive.microsoft.com`. - -**.env** -[!code[env](~/../BotBuilder-Samples/samples/javascript_nodejs/13.core-bot/.env?range=1-5)] - -# [Python](#tab/python) - -Add the information required to access your LUIS app including application id, authoring key, and region into the `config.py` file. These are the values you saved previously from your published LUIS app. Note that the API host name should be in the format `.api.cognitive.microsoft.com`. - -**config.py** -[!code-python[config.py](~/../botbuilder-samples/samples/python/13.core-bot/config.py?range=14-19)] - ---- - -## Configure your bot to use your LUIS app - -# [C#](#tab/csharp) - -Be sure that the **Microsoft.Bot.Builder.AI.Luis** NuGet package is installed for your project. - -To connect to the LUIS service, the bot pulls the information you added above from the appsetting.json file. The `FlightBookingRecognizer` class contains code with your settings from the appsetting.json file and queries the LUIS service by calling `RecognizeAsync` method. - -**FlightBookingRecognizer.cs** - -[!code-csharp[luisHelper](~/../BotBuilder-Samples/samples/csharp_dotnetcore/13.core-bot/FlightBookingRecognizer.cs?range=12-48)] - -The `FlightBookingEx.cs` contains the logic to extract *From*, *To* and *TravelDate*; it extends the partial class `FlightBooking.cs` used to store LUIS results when calling `FlightBookingRecognizer.RecognizeAsync` from the `MainDialog.cs`. - -**CognitiveModels\FlightBookingEx.cs** - -[!code-csharp[luis helper](~/../BotBuilder-Samples/samples/csharp_dotnetcore/13.core-bot/CognitiveModels/FlightBookingEx.cs?range=8-35)] - -# [JavaScript](#tab/javascript) - -To use LUIS, your project needs to install the **botbuilder-ai** npm package. - -To connect to the LUIS service, the bot uses the information you added above from the `.env` file. The `flightBookingRecognizer.js` class contains the code that imports your settings from the `.env` file and queries the LUIS service by calling `recognize()` method. - -**dialogs/flightBookingRecognizer.js** - -[!code-javascript[luis helper](~/../BotBuilder-Samples/samples/javascript_nodejs/13.core-bot/dialogs/flightBookingRecognizer.js?range=6-70)] - -The logic to extract From, To and TravelDate is implemented as helper methods inside `flightBookingRecognizer.js`. These methods are used after calling `flightBookingRecognizer.executeLuisQuery()` from `mainDialog.js` - -# [Python](#tab/python) - -Be sure that the **botbuilder-ai** PyPI package is installed for your project. - -To connect to the LUIS service, the bot uses the information you added above from the `config.py` file. The `FlightBookingRecognizer` class contains the code that imports your settings from the `config.py` file and queries the LUIS service by calling `recognize()` method. - -**flight_booking_recognizer.py** - -[!code-python[config.py](~/../botbuilder-samples/samples/python/13.core-bot/flight_booking_recognizer.py?range=10-34)] - -The logic to extract *From*, *To* and *travel_date* is implemented as helper methods from the `LuisHelper` class inside `luis_helper.py`. These methods are used after calling `LuisHelper.execute_luis_query()` from `main_dialog.py` - -**helpers/luis_helper.py** -[!code-python[luis helper](~/../botbuilder-samples/samples/python/13.core-bot/helpers/luis_helper.py?range=30-102)] - ---- - -LUIS is now configured and connected for your bot. - -## Test the bot - -Download and install the latest [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme) - -1. Run the sample locally on your machine. If you need instructions, refer to the readme file for the [C# Sample](https://aka.ms/cs-core-sample), [JS Sample](https://aka.ms/js-core-sample) or [Python Sample](https://aka.ms/python-core-sample). - -1. In the emulator, type a message such as "travel to paris" or "going from paris to berlin". Use any utterance found in the file FlightBooking.json for training the intent "Book flight". - -![LUIS booking input](./media/how-to-luis/luis-user-travel-input.png) - -If the top intent returned from LUIS resolves to "Book flight" your bot will ask additional questions until it has enough information stored to create a travel booking. At that point it will return this booking information back to your user. - -![LUIS booking result](./media/how-to-luis/luis-travel-result.png) - -At this point the code bot logic will reset and you can continue to create additional bookings. - -## Next steps - -> [!div class="nextstepaction"] -> [Use QnA Maker to answer questions](./bot-builder-howto-qna.md) diff --git a/articles/v4sdk/bot-builder-howto-v4-state.md b/articles/v4sdk/bot-builder-howto-v4-state.md deleted file mode 100644 index 62fc971cf..000000000 --- a/articles/v4sdk/bot-builder-howto-v4-state.md +++ /dev/null @@ -1,214 +0,0 @@ ---- -title: Save user and conversation data - Bot Service -description: Learn how to save and retrieve state data with the Bot Framework SDK. -keywords: conversation state, user state, conversation, saving state, managing bot state -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 2/7/2020 -monikerRange: 'azure-bot-service-4.0' ---- - -# Save user and conversation data - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -A bot is inherently stateless. Once your bot is deployed, it may not run in the same process or on the same machine from one turn to the next. However, your bot may need to track the context of a conversation so that it can manage its behavior and remember answers to previous questions. The state and storage features of the Bot Framework SDK allow you to add state to your bot. Bots use state management and storage objects to manage and persist state. The state manager provides an abstraction layer that lets you access state properties using property accessors, independent of the type of underlying storage. - -## Prerequisites - -- Knowledge of [bot basics](bot-builder-basics.md) and how bots [manage state](bot-builder-concept-state.md) is required. -- The code in this article is based on the **State Management Bot sample**. You'll need a copy of the sample in either [CSharp](https://aka.ms/statebot-sample-cs), [JavaScript](https://aka.ms/statebot-sample-js) or [Python](https://aka.ms/bot-state-python-sample-code). - -## About this sample - -Upon receiving user input, this sample checks the stored conversation state to see if this user has previously been prompted to provide their name. If not, the user's name is requested and that input is stored within user state. If so, the name stored within user state is used to converse with the user and their input data, along with the time received and input channel Id, is returned back to the user. The time and channel Id values are retrieved from the user conversation data and then saved to conversation state. The following diagram shows the relationship between the bot, user profile, and conversation data classes. - -## [C#](#tab/csharp) - -![state bot sample](media/StateBotSample-Overview.png) - -## [JavaScript](#tab/javascript) - -![state bot sample](media/StateBotSample-JS-Overview.png) - -## [Python](#tab/python) - -![state bot sample](media/StateBotSample-Python-Overview.png) - ---- - -## Define classes - -## [C#](#tab/csharp) - -The first step in setting up state management is to define the classes containing the information to manage in the user and conversation state. The example used in this article, defines the following classes: - -- In **UserProfile.cs**, we define a `UserProfile` class for the user information that the bot will collect. -- In **ConversationData.cs**, we define a `ConversationData` class to control our conversation state while gathering user information. - -The following code examples show the definitions for the `UserProfile` and `ConversationData` classes. - -**UserProfile.cs** -[!code-csharp[UserProfile](~/../BotBuilder-Samples/samples/csharp_dotnetcore/45.state-management/UserProfile.cs?range=7-11)] - -**ConversationData.cs** -[!code-csharp[ConversationData](~/../BotBuilder-Samples/samples/csharp_dotnetcore/45.state-management/ConversationData.cs?range=6-17)] - -## [JavaScript](#tab/javascript) - -This step is not necessary in JavaScript. - -## [Python](#tab/python) - -The first step in setting up state management is to define the classes containing the information to manage in the user and conversation state. The example used in this article, defines the following classes: - -- The **user_profile.py** contains the `UserProfile` class which stores the user information collected by the bot. -- The **conversation_data.py** contains the `ConversationData` class which controls the conversation state while gathering user information. - -The following code examples show the definitions for the `UserProfile` and `ConversationData` classes. - -**user_profile.py** -[!code-python[user_profile](~/../botbuilder-samples/samples/python/45.state-management/data_models/user_profile.py?range=5-7)] - -**conversation_data.py** -[!code-python[conversation_data](~/../botbuilder-samples/samples/python/45.state-management/data_models/conversation_data.py?range=5-14)] - ---- - -## Create conversation and user state objects - -## [C#](#tab/csharp) - -Next, we register `MemoryStorage` that is used to create `UserState` and `ConversationState` objects. The user and conversation state objects are created at `Startup` and dependency injected into the bot constructor. Other services for a bot that are registered are: a credential provider, an adapter, and the bot implementation. - -**Startup.cs** -[!code-csharp[ConfigureServices](~/../BotBuilder-Samples/samples/csharp_dotnetcore/45.state-management/Startup.cs?range=26-29)] -[!code-csharp[ConfigureServices](~/../BotBuilder-Samples/samples/csharp_dotnetcore/45.state-management/Startup.cs?range=51-57)] - -**Bots/StateManagementBot.cs** -[!code-csharp[Bot constructor](~/../BotBuilder-Samples/samples/csharp_dotnetcore/45.state-management/Bots/StateManagementBot.cs?range=15-22)] - -## [JavaScript](#tab/javascript) - -Next, we register `MemoryStorage` that is then used to create `UserState` and `ConversationState` objects. These are created in **index.js** and consumed when the bot is created. - -**index.js** -[!code-javascript[index.js](~/../BotBuilder-Samples/samples/javascript_nodejs/45.state-management/index.js?range=33-39)] - -**bots/stateManagementBot.js** -[!code-javascript[bot constructor](~/../BotBuilder-Samples/samples/javascript_nodejs/45.state-management/bots/stateManagementBot.js?range=10-12)] -[!code-javascript[bot constructor](~/../BotBuilder-Samples/samples/javascript_nodejs/45.state-management/bots/stateManagementBot.js?range=17-19)] - -## [Python](#tab/python) - -Next, we register `MemoryStorage` that is used to create `UserState` and `ConversationState` objects. These are created in **app.py** and consumed when the bot is created. - -**app.py** -[!code-python[app.py](~/../botbuilder-samples/samples/python/45.state-management/app.py?range=67-70)] - -**bots/state_management_bot.py** -[!code-python[bot constructor](~/../botbuilder-samples/samples/python/45.state-management/bots/state_management_bot.py?range=13-25)] - ---- - -## Add state property accessors - -## [C#](#tab/csharp) - -Now we create property accessors using the `CreateProperty` method that provides a handle to the `BotState` object. Each state property accessor allows you to get or set the value of the associated state property. Before we use our state properties, we use each accessor to load the property from storage and get it from the state cache. To get the properly scoped key associated with the state property, we call the `GetAsync` method. - -**Bots/StateManagementBot.cs** -[!code-csharp[Create accessors](~/../BotBuilder-Samples/samples/csharp_dotnetcore/45.state-management/Bots/StateManagementBot.cs?range=42,45)] - -## [JavaScript](#tab/javascript) - -Now we create property accessors for `UserState` and `ConversationState`. Each state property accessor allows you to get or set the value of the associated state property. We use each accessor to load the associated property from storage and retrieve its current state from cache. - -**bots/stateManagementBot.js** -[!code-javascript[Create accessors](~/../BotBuilder-Samples/samples/javascript_nodejs/45.state-management/bots/stateManagementBot.js?range=13-15)] - -## [Python](#tab/python) - -Now we create property accessors for `UserProfile` and `ConversationData`. Each state property accessor allows you to get or set the value of the associated state property. We use each accessor to load the associated property from storage and retrieve its current state from cache. - -**bots/state_management_bot.py** -[!code-python[Create accessors](~/../botbuilder-samples/samples/python/45.state-management/bots/state_management_bot.py?range=27-30)] - ---- - -## Access state from your bot - -The preceding section covers the initialization-time steps to add state property accessors to our bot. Now, we can use those accessors at run-time to read and write state information. The sample code below uses the following logic flow: - -## [C#](#tab/csharp) - -- If userProfile.Name is empty and conversationData.PromptedUserForName is _true_, we retrieve the user name provided and store this within user state. -- If userProfile.Name is empty and conversationData.PromptedUserForName is _false_, we ask for the user's name. -- If userProfile.Name was previously stored, we retrieve message time and channel Id from the user input, echo all data back to the user, and store the retrieved data within conversation state. - -**Bots/StateManagementBot.cs** -[!code-csharp[OnMessageActivityAsync](~/../BotBuilder-Samples/samples/csharp_dotnetcore/45.state-management/bots/StateManagementBot.cs?range=38-85)] - -Before we exit the turn handler, we use the state management objects' _SaveChangesAsync()_ method to write all state changes back to storage. - -**Bots/StateManagementBot.cs** -[!code-csharp[OnTurnAsync](~/../BotBuilder-Samples/samples/csharp_dotnetcore/45.state-management/bots/StateManagementBot.cs?range=24-31)] - -## [JavaScript](#tab/javascript) - -- If userProfile.Name is empty and conversationData.PromptedUserForName is _true_, we retrieve the user name provided and store this within user state. -- If userProfile.Name is empty and conversationData.PromptedUserForName is _false_, we ask for the user's name. -- If userProfile.Name was previously stored, we retrieve message time and channel Id from the user input, echo all data back to the user, and store the retrieved data within conversation state. - -**bots/stateManagementBot.js** -[!code-javascript[OnMessage](~/../BotBuilder-Samples/samples/javascript_nodejs/45.state-management/bots/stateManagementBot.js?range=21-58)] - -Before we exit each dialog turn, we use the state management objects' _saveChanges()_ method to persist all changes by writing state back out to storage. - -**bots/stateManagementBot.js** -[!code-javascript[OnDialog](~/../BotBuilder-Samples/samples/javascript_nodejs/45.state-management/bots/stateManagementBot.js?range=72-81)] - -## [Python](#tab/python) - -- If `user_profile.name` is empty and `conversation_data.prompted_for_user_name` is *true*, the bot retrieves the name provided by the user and stores it in the user's state. -- If `user_profile.name` is empty and `conversation_data.prompted_for_user_name` is *false*,the bot asks for the user's name. -- If `user_profile.name` was previously stored, the bot retrieves **message time** and **channel Id** from the user input, echoes the data back to the user, and stores the retrieved data in the conversation state. - -**bots/state_management_bot.py** -[!code-python[state_message_activity](~/../botbuilder-samples/samples/python/45.state-management/bots/state_management_bot.py?range=47-89)] - -Before exiting each dialog turn, the bot uses the state management objects' `save_changes` method to persist all changes by writing state information in the storage. - -**bots/state_management_bot.py** -[!code-python[state_storage](~/../botbuilder-samples/samples/python/45.state-management/bots/state_management_bot.py?range=32-36)] - ---- - -## Test the bot - -Download and install the latest [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme) - -1. Run the sample locally on your machine. If you need instructions, refer to the README file for [C# Sample](https://aka.ms/statebot-sample-cs) or [JS Sample](https://aka.ms/statebot-sample-js). -1. Use the emulator to test the bot as shown below. - -![test state bot sample](media/state-bot-testing-emulator.png) - -## Additional resources - -**Privacy:** If you intend to store user's personal data, you should ensure compliance with [General Data Protection Regulation](https://blog.botframework.com/2018/04/23/general-data-protection-regulation-gdpr). - -**State management:** All of the state management calls are asynchronous, and last-writer-wins by default. In practice, you should get, set, and save state as close together in your bot as possible. - -**Critical business data:** Use bot state to store preferences, user name, or the last thing they ordered, but do not use it to store critical business data. For critical data, [create your own storage components](bot-builder-custom-storage.md) or write directly to [storage](bot-builder-howto-v4-storage.md). - -**Recognizer-Text:** The sample uses the Microsoft/Recognizers-Text libraries to parse and validate user input. For more information, see the [overview](https://github.com/Microsoft/Recognizers-Text#microsoft-recognizers-text-overview) page. - -## Next steps - -Now that you know how to configure state to help you read and write bot data to storage, let's learn how ask the user a series of questions, validate their answers, and save their input. - -> [!div class="nextstepaction"] -> [Create your own prompts to gather user input](bot-builder-primitive-prompts.md). diff --git a/articles/v4sdk/bot-builder-howto-v4-storage.md b/articles/v4sdk/bot-builder-howto-v4-storage.md deleted file mode 100644 index 026ef20a2..000000000 --- a/articles/v4sdk/bot-builder-howto-v4-storage.md +++ /dev/null @@ -1,1025 +0,0 @@ ---- -title: Write directly to storage - Bot Service -description: Learn how to write directly to storage with the Bot Framework SDK for .NET. -keywords: storage, read and write, memory storage, eTag -author: DeniseMak -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 11/01/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Write directly to storage - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -You can read and write directly to your storage object without using middleware or context object. This can be appropriate for data your bot uses to preserve a conversation, or data that comes from a source outside your bot's conversation flow. In this data storage model, data is read in directly from storage instead of using a state manager. The code examples in this article show you how to read and write data to storage using **Memory Storage**, **Cosmos DB**, **Blob Storage**, **Azure Table storage** and **Azure Blob Transcript Store**. - -## Prerequisites -- If you don't have an Azure subscription, create a [free](https://azure.microsoft.com/free/) account before you begin. -- Familiarity with article: Create a bot locally for [dotnet](https://aka.ms/bot-framework-www-c-sharp-quickstart), [nodeJS](https://aka.ms/bot-framework-www-node-js-quickstart) or [Python](https://aka.ms/bot-framework-www-node-python-quickstart). -- Bot Framework SDK v4 template for [C# template](https://aka.ms/bot-vsix), [nodeJS](https://nodejs.org) and [yeoman](http://yeoman.io). - -## About this sample -The sample code in this article begins with the structure of a basic echo bot, then extends that bot's functionality by adding additional code (provided below). This extended code creates a list to preserve user inputs as they are received. Each turn, the full list of user inputs is echoed back to the user. The data structure containing this list of inputs is then saved to storage at the end of that turn. Various types of storage are explored as additional funtionality is added to this sample code. - -## Memory storage - -The Bot Framework SDK allows you to store user inputs using in-memory storage. Memory storage is used for testing purposes only and is not intended for production use. In-memory storage is volatile and temporary since the data is cleared each time the bot is restarted. Persistent storage types, such as database storage, are best for production bots. Be sure to set storage to **Cosmos DB**, **Blob Storage**, or [**Azure Table storage**](~/nodejs/bot-builder-nodejs-state-azure-table-storage.md) before publishing your bot. - -#### Build a basic bot - -The rest of this topic builds off of an Echo bot. The Echo bot sample code can be locally built by following the Quickstart instructions for building either a [C# EchoBot](https://aka.ms/bot-framework-www-c-sharp-quickstart), [JS EchoBot](https://aka.ms/bot-framework-www-node-js-quickstart) or [Python EchoBot](https://aka.ms/bot-framework-www-node-python-quickstart). - -### [C#](#tab/csharp) - -**EchoBot.cs** -```csharp -using System; -using System.Threading.Tasks; -using Microsoft.Bot.Builder; -using Microsoft.Bot.Schema; -using System.Collections.Generic; -using System.Linq; -using System.Threading; - -// Represents a bot saves and echoes back user input. -public class EchoBot : ActivityHandler -{ - // Create local Memory Storage. - private static readonly MemoryStorage _myStorage = new MemoryStorage(); - - // Create cancellation token (used by Async Write operation). - public CancellationToken cancellationToken { get; private set; } - - // Class for storing a log of utterances (text of messages) as a list. - public class UtteranceLog : IStoreItem - { - // A list of things that users have said to the bot - public List UtteranceList { get; } = new List(); - - // The number of conversational turns that have occurred - public int TurnNumber { get; set; } = 0; - - // Create concurrency control where this is used. - public string ETag { get; set; } = "*"; - } - - // Echo back user input. - protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) - { - // preserve user input. - var utterance = turnContext.Activity.Text; - // make empty local logitems list. - UtteranceLog logItems = null; - - // see if there are previous messages saved in storage. - try - { - string[] utteranceList = { "UtteranceLog" }; - logItems = _myStorage.ReadAsync(utteranceList).Result?.FirstOrDefault().Value; - } - catch - { - // Inform the user an error occured. - await turnContext.SendActivityAsync("Sorry, something went wrong reading your stored messages!"); - } - - // If no stored messages were found, create and store a new entry. - if (logItems is null) - { - // add the current utterance to a new object. - logItems = new UtteranceLog(); - logItems.UtteranceList.Add(utterance); - // set initial turn counter to 1. - logItems.TurnNumber++; - - // Show user new user message. - await turnContext.SendActivityAsync($"{logItems.TurnNumber}: The list is now: {string.Join(", ", logItems.UtteranceList)}"); - - // Create Dictionary object to hold received user messages. - var changes = new Dictionary(); - { - changes.Add("UtteranceLog", logItems); - } - try - { - // Save the user message to your Storage. - await _myStorage.WriteAsync(changes, cancellationToken); - } - catch - { - // Inform the user an error occured. - await turnContext.SendActivityAsync("Sorry, something went wrong storing your message!"); - } - } - // Else, our Storage already contained saved user messages, add new one to the list. - else - { - // add new message to list of messages to display. - logItems.UtteranceList.Add(utterance); - // increment turn counter. - logItems.TurnNumber++; - - // show user new list of saved messages. - await turnContext.SendActivityAsync($"{logItems.TurnNumber}: The list is now: {string.Join(", ", logItems.UtteranceList)}"); - - // Create Dictionary object to hold new list of messages. - var changes = new Dictionary(); - { - changes.Add("UtteranceLog", logItems); - }; - - try - { - // Save new list to your Storage. - await _myStorage.WriteAsync(changes,cancellationToken); - } - catch - { - // Inform the user an error occured. - await turnContext.SendActivityAsync("Sorry, something went wrong storing your message!"); - } - } - ... // OnMessageActivityAsync( ) - } -} - -``` - -### [JavaScript](#tab/javascript) - -To use the .env configuration file, your bot needs an extra package included. If not already installed, get the dotnet package from npm: - -```powershell -npm install --save dotenv -``` - -**bot.js** -```javascript -const { ActivityHandler, MemoryStorage } = require('botbuilder'); -const restify = require('restify'); - -// Add memory storage. -var storage = new MemoryStorage(); - -// Process incoming requests - adds storage for messages. -class MyBot extends ActivityHandler { - constructor() { - super(); - // See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types. - this.onMessage(async turnContext => { console.log('this gets called (message)'); - await turnContext.sendActivity(`You said '${ turnContext.activity.text }'`); - // Save updated utterance inputs. - await logMessageText(storage, turnContext); - }); - this.onConversationUpdate(async turnContext => { console.log('this gets called (conversation update)'); - await turnContext.sendActivity('[conversationUpdate event detected]'); }); - } -} - -// This function stores new user messages. Creates new utterance log if none exists. -async function logMessageText(storage, turnContext) { - let utterance = turnContext.activity.text; - // debugger; - try { - // Read from the storage. - let storeItems = await storage.read(["UtteranceLogJS"]) - // Check the result. - var UtteranceLogJS = storeItems["UtteranceLogJS"]; - if (typeof (UtteranceLogJS) != 'undefined') { - // The log exists so we can write to it. - storeItems["UtteranceLogJS"].turnNumber++; - storeItems["UtteranceLogJS"].UtteranceList.push(utterance); - // Gather info for user message. - var storedString = storeItems.UtteranceLogJS.UtteranceList.toString(); - var numStored = storeItems.UtteranceLogJS.turnNumber; - - try { - await storage.write(storeItems) - await turnContext.sendActivity(`${numStored}: The list is now: ${storedString}`); - } catch (err) { - await turnContext.sendActivity(`Write failed of UtteranceLogJS: ${err}`); - } - } - else{ - await turnContext.sendActivity(`Creating and saving new utterance log`); - var turnNumber = 1; - storeItems["UtteranceLogJS"] = { UtteranceList: [`${utterance}`], "eTag": "*", turnNumber } - // Gather info for user message. - var storedString = storeItems.UtteranceLogJS.UtteranceList.toString(); - var numStored = storeItems.UtteranceLogJS.turnNumber; - - try { - await storage.write(storeItems) - await turnContext.sendActivity(`${numStored}: The list is now: ${storedString}`); - } catch (err) { - await turnContext.sendActivity(`Write failed: ${err}`); - } - } - } - catch (err){ - await turnContext.sendActivity(`Read rejected. ${err}`); - } -} - -module.exports.MyBot = MyBot; - -``` - -### [Python](#tab/python) - -**bot.py** -```py -from botbuilder.core import ActivityHandler, TurnContext, StoreItem, MemoryStorage - - -class UtteranceLog(StoreItem): - """ - Class for storing a log of utterances (text of messages) as a list. - """ - - def __init__(self): - super(UtteranceLog, self).__init__() - self.utterance_list = [] - self.turn_number = 0 - self.e_tag = "*" - - -class MyBot(ActivityHandler): - """ - Represents a bot saves and echoes back user input. - """ - - def __init__(self): - self.storage = MemoryStorage() - - async def on_message_activity(self, turn_context: TurnContext): - utterance = turn_context.activity.text - - # read the state object - store_items = await self.storage.read(["UtteranceLog"]) - - if "UtteranceLog" not in store_items: - # add the utterance to a new state object. - utterance_log = UtteranceLog() - utterance_log.utterance_list.append(utterance) - utterance_log.turn_number = 1 - else: - # add new message to list of messages existing state object. - utterance_log: UtteranceLog = store_items["UtteranceLog"] - utterance_log.utterance_list.append(utterance) - utterance_log.turn_number = utterance_log.turn_number + 1 - - # Show user list of utterances. - await turn_context.send_activity(f"{utterance_log.turn_number}: " - f"The list is now: {','.join(utterance_log.utterance_list)}") - - try: - # Save the user message to your Storage. - changes = {"UtteranceLog": utterance_log} - await self.storage.write(changes) - except Exception as exception: - # Inform the user an error occurred. - await turn_context.send_activity("Sorry, something went wrong storing your message!") -``` - ---- - -### Start your bot -Run your bot locally. - -### Start the emulator and connect your bot -- Install the Bot Framework [Emulator](https://aka.ms/bot-framework-emulator-readme) -Next, start the emulator and then connect to your bot in the emulator: - -1. Click the **Create new bot configuration** link in the emulator "Welcome" tab. -2. Fill in fields to connect to your bot, given the information on the webpage displayed when you started your bot. - -### Interact with your bot -Send a message to your bot. The bot will list the messages it has received. - -![Emulator test storage bot](./media/emulator-direct-storage-test.png) - -## Using Cosmos DB -Now that you've used memory storage, we'll update the code to use Azure Cosmos DB. Cosmos DB is Microsoft's globally distributed, multi-model database. Azure Cosmos DB enables you to elastically and independently scale throughput and storage across any number of Azure's geographic regions. It offers throughput, latency, availability, and consistency guarantees with comprehensive service level agreements (SLAs). - -### Set up -To use Cosmos DB in your bot, you'll need to create a database resource before getting into the code. For an in-depth description of Cosmos DB database and app creation access the documentation here for [Cosmos DB dotnet](https://aka.ms/Bot-framework-create-dotnet-cosmosdb) or [Cosmos DB nodejs](https://aka.ms/Bot-framework-create-nodejs-cosmosdb). - -### Create your database account - -1. In a new browser window, sign in to the [Azure portal](https://portal.azure.com). - -![Create Cosmos DB database account](./media/create-cosmosdb-database.png) - -2. Click **Create a resource > Databases > Azure Cosmos DB** - -![Cosmos DB new account page](./media/cosmosdb-new-account-page.png) - -3. On the **New account page**, provide **Subscription**, **Resource group** information. Create a unique name for your **Account Name** field - this eventually becomes part of your data access URL name. For **API**, select **Core(SQL)**, and provide a nearby **Location** to improve data access times. -4. Then click **Review + Create**. -5. Once validation has been successful, click **Create**. - -The account creation takes a few minutes. Wait for the portal to display the Congratulations! Your Azure Cosmos DB account was created page. - -### Add a database - -1. Navigate to the **Data Explorer** page within your newly created Cosmos DB account, then choose **Create Database** from the drop-down box next to the **Create Container** button. A panel will then open on the right hand side of the window, where you can enter the details for the new container. - -![Cosmos DB](./media/create-cosmosdb-database-resource.png) - -2. Enter an ID for your new database and, optionally, set the throughput (you can change this later) and finally click **OK** to create your database. Make a note of this database ID for use later on when configuring your bot. - -![Cosmos DB](./media/create-cosmosdb-database-resource-details.png) - -3. Now that you have created a Cosmos DB account and a database, you need to copy over some of the values for integrating your new database into your bot. To retrieve these, navigate to the **Keys** tab within the database settings section of your Cosmos DB account. From this page you will need your Cosmos DB endpoint (**URI**) and your authorization key (**PRIMARY KEY**). - -![Cosmos DB Keys](./media/comos-db-keys.png) - -You should now have a Cosmos DB account, containing a database and have the following details ready to configure your bot. - -- Cosmos DB Endpoint -- Authorization Key -- Database ID - -### Add configuration information -Our configuration data to add Cosmos DB storage is short and simple. Use the details you made a note of in the previous part of this article to set your endpoint, authorization key and database ID. Finally, you should choose an appropriate name for the container that will be created within your database to store your bot state. In the example below the container will be called "bot-storage". - -> [!NOTE] -> You should not create the container yourself. Your bot will create it for you when creating its internal Cosmos DB client, ensuring it is configured correctly for storing bot state. - -### [C#](#tab/csharp) - -**EchoBot.cs** -```csharp -public class EchoBot : ActivityHandler -{ - private const string CosmosServiceEndpoint = ""; - private const string CosmosDBKey = ""; - private const string CosmosDBDatabaseId = ""; - private const string CosmosDBContainerId = "bot-storage"; - ... - -} -``` - -### [JavaScript](#tab/javascript) - -Add the following information to your `.env` file. - -**.env** -```javascript -DB_SERVICE_ENDPOINT="" -AUTH_KEY="" -DATABASE_ID="" -CONTAINER="bot-storage" -``` - -### [Python](#tab/python) - -Add the following information to your `bot.py` file. - -```javascript -COSMOSDB_SERVICE_ENDPOINT = "" -COSMOSDB_KEY = "" -COSMOSDB_DATABASE_ID = "" -COSMOSDB_CONTAINER_ID = "bot-storage" -``` - ---- - -#### Installing packages -Make sure you have the packages necessary for Cosmos DB - -### [C#](#tab/csharp) - -```powershell -Install-Package Microsoft.Bot.Builder.Azure -``` - -### [JavaScript](#tab/javascript) - -you can add a references to botbuilder-azure in your project via npm. ->**Note** - this npm package relies on an installation of Python existing on your development machine. If you have not previously installed Python you can find installation resources for your machine here: [Python.org](https://www.python.org/downloads/) - -```powershell -npm install --save botbuilder-azure -``` - -If not already installed, get the dotnet package from npm in order to access your `.env` file settings. - -```powershell -npm install --save dotenv -``` - -### [Python](#tab/python) - -you can add a references to botbuilder-azure in your project via pip. - -```powershell -pip install botbuilder-azure -``` - ---- - -### Implementation - -> [!NOTE] -> Version 4.6 introduced a new Cosmos DB storage provider, `CosmosDbPartitionedStorage`. Existing bots using the original `CosmosDbStorage` should continue using `CosmosDbStorage`. Bots using the older provider will continue to work as expected. New bots should use `CosmosDbPartitionedStorage` as partitioning offers increased performance. - -### [C#](#tab/csharp) - -The following sample code runs using the same bot code as the [memory storage](#memory-storage) sample provided above. -The code snippet below shows an implementation of Cosmos DB storage for '_myStorage_' that replaces local Memory storage. Memory Storage is commented out and replaced with a reference to Cosmos DB. - -**EchoBot.cs** -```csharp - -using System; -... -using Microsoft.Bot.Builder.Azure; -... -public class EchoBot : ActivityHandler -{ - // Create local Memory Storage - commented out. - // private static readonly MemoryStorage _myStorage = new MemoryStorage(); - - // Replaces Memory Storage with reference to Cosmos DB. - private static readonly CosmosDbStorage _myStorage = new CosmosDbPartitionedStorage(new CosmosDbPartitionedStorageOptions - { - CosmosDbEndpoint = CosmosServiceEndpoint, - AuthKey = CosmosDBKey, - DatabaseId = CosmosDBDatabaseId, - ContainerId = CosmosDBContainerId, - }); - - ... -} - -``` - -### [JavaScript](#tab/javascript) - -The following sample code is similar to [memory storage](#memory-storage) but with some slight changes. - -Require `CosmosDbPartitionedStorage` from `botbuilder-azure` and configure dotenv to read the `.env` file. - -**bot.js** - -```javascript -const { CosmosDbPartitionedStorage } = require("botbuilder-azure"); -``` -Comment out Memory Storage, replace with reference to Cosmos DB. - -**bot.js** -```javascript -// initialized to access values in .env file. -const ENV_FILE = path.join(__dirname, '.env'); -require('dotenv').config({ path: ENV_FILE }); - -// Create local Memory Storage - commented out. -// var storage = new MemoryStorage(); - -// Create access to CosmosDb Storage - this replaces local Memory Storage. -var storage = new CosmosDbPartitionedStorage({ - cosmosDbEndpoint: process.env.DB_SERVICE_ENDPOINT, - authKey: process.env.AUTH_KEY, - databaseId: process.env.DATABASE_ID, - containerId: process.env.CONTAINER -}) - -``` - -### [Python](#tab/python) - -The following sample code is similar to [memory storage](#memory-storage) but with some slight changes. - -Require `CosmosDbStorage` from `botbuilder-azure` and create the CosmosDBStorage object. - -**bot.py** - -```py -from botbuilder.azure import CosmosDbStorage, CosmosDbConfig -``` - -Comment out Memory Storage in `__init__` and replace with reference to Cosmos DB. Use the endpoint, auth key, database id and container id used above. - -**bot.py** -```py -def __init__(self): - cosmos_config = CosmosDbConfig( - endpoint=COSMOSDB_SERVICE_ENDPOINT, - masterkey=COSMOSDB_KEY, - database=COSMOSDB_DATABASE_ID, - container=COSMOSDB_CONTAINER_ID - ) - self.storage = CosmosDbStorage(cosmos_config) -``` - ---- - -## Start your bot -Run your bot locally. - -## Test your bot with bot framework emulator -Now start your bot framework emulator and connect to your bot: - -1. Click the **Create new bot configuration** link in the emulator "Welcome" tab. -2. Fill in fields to connect to your bot, given the information on the webpage displayed when you started your bot. - -## Interact with your bot -Send a message to your bot, and the bot will list the messages it received. -![Emulator running](./media/emulator-direct-storage-test.png) - - -### View your data -After you have run your bot and saved your information, we can view the data stored in the Azure portal under the **Data Explorer** tab. - -![Data Explorer example](./media/data_explorer.PNG) - - -## Using Blob storage -Azure Blob storage is Microsoft's object storage solution for the cloud. Blob storage is optimized for storing massive amounts of unstructured data, such as text or binary data. - -### Create your Blob storage account -To use Blob storage in your bot, you'll need to get a few things set up before getting into the code. -1. In a new browser window, sign in to the [Azure portal](https://portal.azure.com). - -![Create Blob storage](./media/create-blob-storage.png) - -2. Click **Create a resource > Storage > Storage account - blob, file, table, queue** - -![Blob storage new account page](./media/blob-storage-new-account.png) - -3. In the **New account page**, enter **Name** for the storage account, select **Blob storage** for **Account kind**, provide **Location**, **Resource group** and **Subscription** information. -4. Then click **Review + Create**. -5. Once validation has been successful, click **Create**. - -### Create Blob storage container -Once your Blob storage account is created, open this account by -1. Selecting the resource. -2. Now "Open" using Storage Explorer (preview) - -![Create Blob storage container](./media/create-blob-container.png) - -3. Right click BLOB CONTAINERS, select _Create blob container_. -4. Add a name. You will use this name for the value "your-blob-storage-container-name" to provide access to your Blob Storage account. - -#### Add configuration information -Find the Blob Storage keys you need to configure Blob Storage for your bot as shown above: -1. In the Azure portal, open your Blob Storage account and select **Settings > Access keys**. - -![Find Blob Storage Keys](./media/find-blob-storage-keys.png) - -We will use key1 _Connection string_ as the value "your-blob-storage-account-string" to provide access to your Blob Storage account. - -#### Installing packages -If not previously installed to use Cosmos DB, install the following packages. - -### [C#](#tab/csharp) - -```powershell -Install-Package Microsoft.Bot.Builder.Azure -``` - -### [JavaScript](#tab/javascript) - -Add references to botbuilder-azure in your project via npm. ->**Note** - this npm package relies on an installation of Python existing on your development machine. If you have not previously installed Python you can find installation resources for your machine here: [Python.org](https://www.python.org/downloads/) - -```powershell -npm install --save botbuilder-azure -``` - -If not already installed, get the dotnet package from npm in order to access your `.env` file settings. - -```powershell -npm install --save dotenv -``` - -### [Python](#tab/python) - -you can add a references to botbuilder-azure in your project via pip. - -```powershell -pip install botbuilder-azure -``` - ---- - -### Implementation - -### [C#](#tab/csharp) - -**EchoBot.cs** -```csharp -using Microsoft.Bot.Builder.Azure; -``` -Update the line of code that points "_myStorage_" to your existing Blob Storage account. - -**EchoBot.cs** -```csharp -private static readonly AzureBlobStorage _myStorage = new AzureBlobStorage("", ""); -``` - -### [JavaScript](#tab/javascript) - -Add the following information to your `.env` file. - -**.env** -```javascript -BLOB_NAME="" -BLOB_STRING="" -``` - -Update your `bot.js` file as follows. Require `BlobStorage` from `botbuilder-azure` - -**bot.js** -```javascript -const { BlobStorage } = require("botbuilder-azure"); -``` - -If you did not add code to load your `.env` file to implement Cosmos DB storage, add this here. - -```javascript -// initialized to access values in .env file. -const ENV_FILE = path.join(__dirname, '.env'); -require('dotenv').config({ path: ENV_FILE }); -``` -Now update your code to point "_storage_" to your existing Blob Storage account, by commenting out previous storage definitions and adding the following. - -**bot.js** -```javascript -var storage = new BlobStorage({ - containerName: process.env.BLOB_NAME, - storageAccountOrConnectionString: process.env.BLOB_STRING -}); -``` - - - -### [Python](#tab/python) - -The following sample code is similar to [memory storage](#memory-storage) but with some slight changes. - -Require `BlobStorage` from `botbuilder-azure` and create the CosmosDBStorage object. - -**bot.py** - -```py -from botbuilder.azure import BlobStorage, BlobStorageSettings -``` - -Comment out Memory Storage in `__init__` and replace with reference to Cosmos DB. Use the container name and connection string used above. - -**bot.py** -```py -def __init__(self): - blob_settings = BlobStorageSettings( - container_name="", - connection_string="" - ) - self.storage = BlobStorage(blob_settings) -``` - ---- - -Once your storage is set to point to your Blob Storage account, your bot code will now store and retrieve data from Blob Storage. - -## Start your bot -Run your bot locally. - -## Start the emulator and connect your bot -Next, start the emulator and then connect to your bot in the emulator: - -1. Click the **Create new bot configuration** link in the emulator "Welcome" tab. -2. Fill in fields to connect to your bot, given the information on the webpage displayed when you started your bot. - -## Interact with your bot -Send a message to your bot, and the bot will list the messages it receives. - -![Emulator test storage bot](./media/emulator-direct-storage-test.png) - -### View your data -After you have run your bot and saved your information, we can view it in under the **Storage Explorer** tab in the Azure portal. - -## Blob transcript storage -Azure blob transcript storage provides a specialized storage option that allows you to easily save and retrieve user conversations in the form of a recorded transcript. Azure blob transcript storage is particularly useful for automatically capturing user inputs to examine while debugging your bot's performance. - -**NOTE: Javascript and Python do not currently support AzureBlobTranscriptStore. The following directions are for C# only** - -### Set up -Azure blob transcript storage can use the same blob storage account created following the steps detailed in sections "_Create your blob storage account_" and "_Add configuration information_" above. We now add a container to hold our transcripts - - -![Create transcript container](./media/create-blob-transcript-container.png) - -1. Open your Azure blob storage account. -1. Click on _Storage Explorer_. -1. Right click on _BLOB CONTAINERS_ and select _create blob container_. -1. enter a name for your transcript container and then select _OK_. (We entered mybottranscripts) - -### Implementation -The following code connects transcript storage pointer `_myTranscripts` to your new Azure blob transcript storage account. To create this link with a new container name, , creates a new container within Blob storage to hold your transcript files. - -**echoBot.cs** -```csharp -using Microsoft.Bot.Builder.Azure; - -public class EchoBot : ActivityHandler -{ - ... - - private readonly AzureBlobTranscriptStore _myTranscripts = new AzureBlobTranscriptStore("", ""); - - ... -} - -``` - -### Store user conversations in azure blob transcripts -After a blob container is available to store transcripts you can begin to preserve your users' conversations with your bot. These conversations can later be used as a debugging tool to see how users interact with your bot. Each emulator _Restart conversation_ initiates the creation of a new transcript conversation list. The following code preserves user conversation inputs within a stored transcript file. -- The current transcript is saved using `LogActivityAsync`. -- Saved transcripts are retrieved using `ListTranscriptsAsync`. -In this sample code the Id of each stored transcript is saved into a list named "storedTranscripts". This list is later used to manage the number of stored blob transcripts we retain. - -**echoBot.cs** -```csharp - -protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) -{ - await _myTranscripts.LogActivityAsync(turnContext.Activity); - - List storedTranscripts = new List(); - PagedResult pagedResult = null; - var pageSize = 0; - do - { - pagedResult = await _myTranscripts.ListTranscriptsAsync("emulator", pagedResult?.ContinuationToken); - pageSize = pagedResult.Items.Count(); - - // transcript item contains ChannelId, Created, Id. - // save the channelIds found by "ListTranscriptsAsync" to a local list. - foreach (var item in pagedResult.Items) - { - storedTranscripts.Add(item.Id); - } - } while (pagedResult.ContinuationToken != null); - - ... -} - -``` - -### Manage stored blob transcripts -While stored transcripts can be used as a debugging tool, over time the number of stored transcripts can grow larger than you care to preserve. The additional code included below uses `DeleteTranscriptAsync` to remove all but the last three retrieved transcript items from your blob transcript store. - -**echoBot.cs** -```csharp - -protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) -{ - await _myTranscripts.LogActivityAsync(turnContext.Activity); - - List storedTranscripts = new List(); - PagedResult pagedResult = null; - var pageSize = 0; - do - { - pagedResult = await _myTranscripts.ListTranscriptsAsync("emulator", pagedResult?.ContinuationToken); - pageSize = pagedResult.Items.Count(); - - // transcript item contains ChannelId, Created, Id. - // save the channelIds found by "ListTranscriptsAsync" to a local list. - foreach (var item in pagedResult.Items) - { - storedTranscripts.Add(item.Id); - } - } while (pagedResult.ContinuationToken != null); - - // Manage the size of your transcript storage. - for (int i = 0; i < pageSize; i++) - { - // Remove older stored transcripts, save just the last three. - if (i < pageSize - 3) - { - string thisTranscriptId = storedTranscripts[i]; - try - { - await _myTranscripts.DeleteTranscriptAsync("emulator", thisTranscriptId); - } - catch (System.Exception ex) - { - await turnContext.SendActivityAsync("Debug Out: DeleteTranscriptAsync had a problem!"); - await turnContext.SendActivityAsync("exception: " + ex.Message); - } - } - } - ... -} - -``` - -The following link provides more information concerning [Azure Blob Transcript Storage](https://docs.microsoft.com/dotnet/api/microsoft.bot.builder.azure.azureblobtranscriptstore) - -## Additional Information - -### Manage concurrency using eTags -In our bot code example we set the `eTag` property of each `IStoreItem` to `*`. The `eTag` (entity tag) member of your store object is used within Cosmos DB to manage concurrency. The `eTag` tells your database what to do if another instance of the bot has changed the object in the same storage that your bot is writing to. - - - -#### Last write wins - allow overwrites -An `eTag` property value of asterisk (`*`) indicates that the last writer wins. When creating a new data store, you can set `eTag` of a property to `*` to indicate that you have not previously saved the data that you are writing, or that you want the last writer to overwrite any previously saved property. If concurrency is not an issue for your bot, setting the `eTag` property to `*` for any data that you are writing enables overwrites. - -#### Maintain concurrency and prevent overwrites -When storing your data into Cosmos DB, use a value other than `*` for the `eTag` if you want to prevent concurrent access to a property and avoid overwriting changes from another instance of the bot. The bot receives an error response with the message `etag conflict key=` when it attempts to save state data and the `eTag` is not the same value as the `eTag` in storage. - -By default, the Cosmos DB store checks the `eTag` property of a storage object for equality every time a bot writes to that item, and then updates it to a new unique value after each write. If the `eTag` property on write doesn't match the `eTag` in storage, it means another bot or thread changed the data. - -For example, let's say you want your bot to edit a saved note, but you don't want your bot to overwrite changes that another instance of the bot has done. If another instance of the bot has made edits, you want the user to edit the version with the latest updates. - -### [C#](#tab/csharp) - -First, create a class that implements `IStoreItem`. - -**EchoBot.cs** -```csharp -public class Note : IStoreItem -{ - public string Name { get; set; } - public string Contents { get; set; } - public string ETag { get; set; } -} -``` - -Next, create an initial note by creating a storage object, and add the object to your store. - -**EchoBot.cs** -```csharp -// create a note for the first time, with a non-null, non-* ETag. -var note = new Note { Name = "Shopping List", Contents = "eggs", ETag = "x" }; - -var changes = Dictionary(); -{ - changes.Add("Note", note); -}; -await NoteStore.WriteAsync(changes, cancellationToken); -``` - -Then, access and update the note later, keeping its `eTag` that you read from the store. - -**EchoBot.cs** -```csharp -var note = NoteStore.ReadAsync("Note").Result?.FirstOrDefault().Value; - -if (note != null) -{ - note.Contents += ", bread"; - var changes = new Dictionary(); - { - changes.Add("Note1", note); - }; - await NoteStore.WriteAsync(changes, cancellationToken); -} -``` - -If the note was updated in the store before you write your changes, the call to `Write` will throw an exception. - - -### [JavaScript](#tab/javascript) - -Add a helper function to the end of your bot that will write a sample note to a data store. -First create `myNoteData` object. - -**bot.js** -```javascript -// Helper function for writing a sample note to a data store -async function createSampleNote(storage, context) { - var myNoteData = { - name: "Shopping List", - contents: "eggs", - // If any Note file is already stored, the eTag field - // must be set to "*" in order to allow writing without first reading the stored eTag - // otherwise you'll likely get an exception indicating an eTag conflict. - eTag: "*" - } -} -``` - -Within the `createSampleNote` helper function initialize a `changes` object and add your *notes* to it, then write it to storage. - -**bot.js** -```javascript -// Write the note data to the "Note" key -var changes = {}; -changes["Note"] = myNoteData; -// Creates a file named Note, if it doesn't already exist. -// specifying eTag= "*" will overwrite any existing contents. -// The act of writing to the file automatically updates the eTag property -// The first time you write to Note, the eTag is changed from *, and file contents will become: -// {"name":"Shopping List","contents":"eggs","eTag":"1"} -try { - await storage.write(changes); - var list = changes["Note"].contents; - await context.sendActivity(`Successful created a note: ${list}`); -} catch (err) { - await context.sendActivity(`Could not create note: ${err}`); -} -``` - -The helper function is accessed from within your bot's logic by adding the following call: - -**bot.js** -```javascript -// Save a note with etag. -await createSampleNote(storage, turnContext); -``` - -Once created, to later retrieve and update the note we create another helper function that can be accessed when the user types in "update note". - -**bot.js** -```javascript -async function updateSampleNote(storage, context) { - try { - // Read in a note - var note = await storage.read(["Note"]); - console.log(`note.eTag=${note["Note"].eTag}\n note=${JSON.stringify(note)}`); - // update the note that we just read - note["Note"].contents += ", bread"; - console.log(`Updated note=${JSON.stringify(note)}`); - - try { - await storage.write(note); // Write the changes back to storage - var list = note["Note"].contents; - await context.sendActivity(`Successfully updated note: ${list}`); - } catch (err) { - console.log(`Write failed: ${err}`); - } - } - catch (err) { - await context.sendActivity(`Unable to read the Note: ${err}`); - } -} -``` - -This helper function is accessed from within your bot's logic by adding the following call: - -**bot.js** -```javascript -// Update a note with etag. -await updateSampleNote(storage, turnContext); -``` - -If the note was updated in the store by another user before you attempted to write back your changes, the `eTag` value will no longer match and the call to `write` will throw an exception. - -### [Python](#tab/python) - -First, create a class that implements `StoreItem`. - -**bot.py** -```py -class Note(StoreItem): - def __init__(self, name: str, contents: str, e_tag="*"): - super(Note, self).__init__() - self.name = name - self.contents = contents - self.e_tag = e_tag -``` - -Next, create an initial note by creating a storage object, and add the object to your store. - -**bot.py** -```py -# create a note for the first time, with a non-null, non-* ETag. -changes = {"Note": Note(name="Shopping List", contents="eggs", e_tag="x")} - -await self.storage.write(changes) -``` - -Then, access and update the note later, keeping its `eTag` that you read from the store. - -**bot.py** -```py -store_items = await self.storage.read(["Note"]) - note = store_items["Note"] - note.contents = note.contents + ", bread" - - changes = {"Note": note} - await self.storage.write(changes) -``` - -If the note was updated in the store before you write your changes, the call to `write` will throw an exception. - ---- - -To maintain concurrency, always read a property from storage, then modify the property you read, so that the `eTag` is maintained. If you read user data from the store, the response will contain the eTag property. If you change the data and write updated data to the store, your request should include the eTag property that specifies the same value as you read earlier. However, writing an object with its `eTag` set to `*` will allow the write to overwrite any other changes. - -## Next steps -Now that you know how to read read and write directly from storage, lets take a look at how you can use the state manager to do that for you. - -> [!div class="nextstepaction"] -> [Save state using conversation and user properties](bot-builder-howto-v4-state.md) diff --git a/articles/v4sdk/bot-builder-primitive-prompts.md b/articles/v4sdk/bot-builder-primitive-prompts.md deleted file mode 100644 index b1207dc62..000000000 --- a/articles/v4sdk/bot-builder-primitive-prompts.md +++ /dev/null @@ -1,232 +0,0 @@ ---- -title: Create your own prompts to gather user input - Bot Service -description: Learn how to manage a conversation flow with primitive prompts in the Bot Framework SDK. -keywords: conversation flow, prompts, conversation state, user state, custom prompts -author: JonathanFingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 2/7/2020 -monikerRange: 'azure-bot-service-4.0' ---- - -# Create your own prompts to gather user input - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -A conversation between a bot and a user often involves asking (prompting) the user for information, parsing the user's response, and then acting on that information. Your bot should track the context of a conversation, so that it can manage its behavior and remember answers to previous questions. A bot's *state* is information it tracks to respond appropriately to incoming messages. - -> [!TIP] -> The dialogs library provides built in prompts that provide more functionality that users can use. Examples of those prompts can be found in the [Implement sequential conversation flow](bot-builder-dialog-manage-conversation-flow.md) article. - -## Prerequisites - -- The code in this article is based on the Prompt Users for Input sample. You'll need a copy of either the **[C# sample](https://aka.ms/cs-primitive-prompt-sample), [JavaScript sample](https://aka.ms/js-primitive-prompt-sample), or [Python sample](https://aka.ms/python-primitive-prompt-sample)**. -- Knowledge of [managing state](bot-builder-concept-state.md) and how to [save user and conversation data](bot-builder-howto-v4-state.md). - -## About the sample code - -The sample bot asks the user a series of questions, validates some of their answers, and saves their input. The following diagram shows the relationship between the bot, user profile, and conversation flow classes. - -## [C#](#tab/csharp) - -![custom-prompts](media/CustomPromptBotSample-Overview.png) - -- A `UserProfile` class for the user information that the bot will collect. -- A `ConversationFlow` class to control our conversation state while gathering user information. -- An inner `ConversationFlow.Question` enumeration for tracking where we are in the conversation. - -## [JavaScript](#tab/javascript) - -![custom-prompts](media/CustomPromptBotSample-JS-Overview.png) - -- A `userProfile` class for the user information that the bot will collect. -- A `conversationFlow` class to control our conversation state while gathering user information. -- An inner `conversationFlow.question` enumeration for tracking where we are in the conversation. - -## [Python](#tab/python) - -![custom-prompts](media/CustomPromptBotSample-Python-Overview.png) - -- A `UserProfile` class for the user information that the bot will collect. -- A `ConversationFlow` class to control our conversation state while gathering user information. -- An inner `ConversationFlow.Question` enumeration for tracking where we are in the conversation. - ---- - -The user state will track the user's name, age, and chosen date, and conversation state will track what we've just asked the user. -Since we don't plan to deploy this bot, we'll configure both user and conversation state to use _memory storage_. - -We use the bot's message turn handler plus user and conversation state properties to manage the flow of the conversation and the collection of input. In our bot, we'll record the state property information received during each iteration of the message turn handler. - -## Create conversation and user objects - -## [C#](#tab/csharp) - -Create the user and conversation state objects at startup and consume them via dependency injection in the bot constructor. - -**Startup.cs** -[!code-csharp[Startup.cs](~/../botbuilder-samples/samples/csharp_dotnetcore/44.prompt-users-for-input/Startup.cs?range=28-35)] - -**Bots/CustomPromptBot.cs** -[!code-csharp[constructor](~/../botbuilder-samples/samples/csharp_dotnetcore/44.prompt-users-for-input/Bots/CustomPromptBot.cs?range=21-28)] - -## [JavaScript](#tab/javascript) - -Create the user and conversation state objects in **index.js** and consume them in the bot constructor. - -**index.js** -[!code-javascript[index.js](~/../botbuilder-samples/samples/javascript_nodejs/44.prompt-for-user-input/index.js?range=33-39)] - -**bots/customPromptBot.js** -[!code-javascript[constructor](~/../botbuilder-samples/samples/javascript_nodejs/44.prompt-for-user-input/bots/customPromptBot.js?range=20-22)] -[!code-javascript[constructor](~/../botbuilder-samples/samples/javascript_nodejs/44.prompt-for-user-input/bots/customPromptBot.js?range=27-29)] - -## [Python](#tab/python) - -Create the user and conversation state objects in **app.py** and consume them in the bot constructor. - -**app.py** -[!code-python[app.py](~/../botbuilder-samples/samples/python/44.prompt-for-user-input/app.py?range=67-73)] - -**bots/custom_prompt_bot.py** -[!code-python[constructor](~/../botbuilder-samples/samples/python/44.prompt-for-user-input/bots/custom_prompt_bot.py?range=29-41)] - ---- - -## Create property accessors - -## [C#](#tab/csharp) - -Create property accessors for the user profile and conversation flow properties and then call `GetAsync` to retrieve the property value from state. - -**Bots/CustomPromptBot.cs** -[!code-csharp[OnMessageActivityAsync](~/../botbuilder-samples/samples/csharp_dotnetcore/44.prompt-users-for-input/Bots/CustomPromptBot.cs?range=30-37)] - -Before the turn ends, call `SaveChangesAsync` to write any state changes to storage. - -[!code-csharp[OnMessageActivityAsync](~/../botbuilder-samples/samples/csharp_dotnetcore/44.prompt-users-for-input/Bots/CustomPromptBot.cs?range=41-44)] - -## [JavaScript](#tab/javascript) - -Create property accessors for the user profile and conversation flow properties and then call `get` to retrieve the property value from state. - -**bots/customPromptBot.js** -[!code-javascript[onMessage](~/../botbuilder-samples/samples/javascript_nodejs/44.prompt-for-user-input/bots/customPromptBot.js?range=31-33)] - -Before the turn ends, call `saveChanges` to write any state changes to storage. - -[!code-javascript[custom prompt bot](~/../botbuilder-samples/samples/javascript_nodejs/44.prompt-for-user-input/bots/customPromptBot.js?range=42-51)] - -## [Python](#tab/python) - -In the constructor, we create the state property accessors and set up the state management objects (created above) for our conversation. - -**bots/custom_prompt_bot.py** -[!code-python[on_message_activity](~/../botbuilder-samples/samples/python/44.prompt-for-user-input/bots/custom_prompt_bot.py?range=46-49)] - -Before the turn ends, call `SaveChangesAsync` to write any state changes to storage. - -[!code-python[on_message_activity](~/../botbuilder-samples/samples/python/44.prompt-for-user-input/bots/custom_prompt_bot.py?range=53-55)] - ---- - -## The bot's message turn handler - -When handling message activities, the message handler uses a helper method to manage the conversation and prompt the user. The helper method is described in the following section. - -## [C#](#tab/csharp) - -**Bots/CustomPromptBot.cs** -[!code-csharp[message handler](~/../botbuilder-samples/samples/csharp_dotnetcore/44.prompt-users-for-input/Bots/CustomPromptBot.cs?range=30-44)] - -## [JavaScript](#tab/javascript) - -**bots/customPromptBot.js** -[!code-javascript[message handler](~/../botbuilder-samples/samples/javascript_nodejs/44.prompt-for-user-input/bots/customPromptBot.js?range=31-39)] - -## [Python](#tab/python) - -**bots/custom_prompt_bot.py** -[!code-python[message handler](~/../botbuilder-samples/samples/python/44.prompt-for-user-input/bots/custom_prompt_bot.py?range=46-55)] - ---- - -## Filling out the user profile - -The bot prompts the user for information, based on which question, if any, that the bot asked on the previous turn. Input is parsed using a validation method. - -Each validation method follows a similar design: - -- The return value indicates whether the input is a valid answer for this question. -- If validation passes, it produces a parsed and normalized value to save. -- If validation fails, it produces a message with which the bot can ask for the information again. - -The validation methods are described in the following section. - -## [C#](#tab/csharp) - -**Bots/CustomPromptBot.cs** -[!code-csharp[FillOutUserProfileAsync](~/../botbuilder-samples/samples/csharp_dotnetcore/44.prompt-users-for-input/Bots/CustomPromptBot.cs?range=46-103)] - -## [JavaScript](#tab/javascript) - -**bots/customPromptBot.js** -[!code-javascript[fillOutUserProfile](~/../botbuilder-samples/samples/javascript_nodejs/44.prompt-for-user-input/bots/customPromptBot.js?range=53-118)] - -## [Python](#tab/python) - -**bots/custom_prompt_bot.py** -[!code-python[_fill_out_user_profile](~/../botbuilder-samples/samples/python/44.prompt-for-user-input/bots/custom_prompt_bot.py?range=57-125)] - ---- - -## Parse and validate input - -The bot uses the following criteria to validate input. - -- The **name** must be a non-empty string. It's normalized by trimming white-space. -- The **age** must be between 18 and 120. It's normalized by returning an integer. -- The **date** must be any date or time at least an hour in the future. - It's normalized by returning just the date portion of the parsed input. - -> [!NOTE] -> For the age and date input, we use the [Microsoft/Recognizers-Text](https://github.com/Microsoft/Recognizers-Text/) libraries to perform the initial parsing. -> While we provide sample code, we do not explain how the text recognizers libraries work, and this is just one way to parse the input. -> For more information about these libraries, see the repository's **README**. - -## [C#](#tab/csharp) - -**Bots/CustomPromptBot.cs** -[!code-csharp[validation methods](~/../botbuilder-samples/samples/csharp_dotnetcore/44.prompt-users-for-input/Bots/CustomPromptBot.cs?range=105-203)] - -## [JavaScript](#tab/javascript) - -**bots/customPromptBot.cs** -[!code-javascript[validation methods](~/../botbuilder-samples/samples/javascript_nodejs/44.prompt-for-user-input/bots/customPromptBot.js?range=120-190)] - -## [Python](#tab/python) - -**bots/custom_prompt_bot.py** -[!code-python[validation methods](~/../botbuilder-samples/samples/python/44.prompt-for-user-input/bots/custom_prompt_bot.py?range=127-189)] - ---- - -## Test the bot locally - -Download and install the [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme) to test the bot locally. - -1. Run the sample locally on your machine. If you need instructions, refer to the README file for [C# sample](https://aka.ms/cs-primitive-prompt-sample), [JS sample](https://aka.ms/js-primitive-prompt-sample), or the [Python sample](https://aka.ms/python-primitive-prompt-sample). -1. Test it using the emulator as shown below. - -![primitive-prompts](media/primitive-prompts.png) - -## Additional resources - -The [Dialogs library](bot-builder-concept-dialog.md) provides classes that automate many aspects of managing conversations. - -## Next step - -> [!div class="nextstepaction"] -> [Implement sequential conversation flow](bot-builder-dialog-manage-conversation-flow.md) diff --git a/articles/v4sdk/bot-builder-send-welcome-message.md b/articles/v4sdk/bot-builder-send-welcome-message.md deleted file mode 100644 index f0970996b..000000000 --- a/articles/v4sdk/bot-builder-send-welcome-message.md +++ /dev/null @@ -1,262 +0,0 @@ ---- -title: Send welcome message to users - Bot Service -description: Learn how to develop your bot to provide a welcoming user experience. -keywords: overview, develop, user experience, welcome, personalized experience, C#, JS, welcome message, bot, greet, greeting -author: DanDev33 -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 2/7/2020 -monikerRange: 'azure-bot-service-4.0' ---- -# Send welcome message to users - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -The primary goal when creating any bot is to engage your user in a meaningful conversation. One of the best ways to achieve this goal is to ensure that from the moment a user first connects, they understand your bot’s main purpose and capabilities, the reason your bot was created. This article provides code examples to help you welcome users to your bot. - -## Prerequisites - -- Understand [bot basics](bot-builder-basics.md). -- A copy of the **Welcome user sample** in either [C# Sample](https://aka.ms/welcome-user-mvc), [JS Sample](https://aka.ms/bot-welcome-sample-js) or [Python Sample](https://aka.ms/bot-welcome-python-sample-code). The code from the sample is used to explain how to send welcome messages. - -## About this sample code - -This sample code shows how to detect and welcome new users when they are initially connected to your bot. The following diagram shows the logic flow for this bot. - -### [C#](#tab/csharp) - -The two main events encountered by the bot are: - -- `OnMembersAddedAsync` which is called whenever a new user is connected to your bot -- `OnMessageActivityAsync` which is called whenever a new user input is received. - -![welcome user logic flow](media/welcome-user-flow.png) - -Whenever a new user is connected, they are provided with a `WelcomeMessage`, `InfoMessage`, and `PatternMessage` by the bot. -When a new user input is received, WelcomeUserState is checked to see if `DidBotWelcomeUser` is set to _true_. If not, an initial welcome user message is returned to the user. - -### [JavaScript](#tab/javascript) - -The two main events encountered by the bot are: - -- `onMembersAdded` which is called whenever a new user is connected to your bot -- `onMessage` which is called whenever a new user input is received. - -![welcome user logic flow](media/welcome-user-flow-js.png) - -Whenever a new user is connected, they are provided with a `welcomeMessage`, `infoMessage`, and `patternMessage` by the bot. -When a new user input is received, `welcomedUserProperty` is checked to see if `didBotWelcomeUser` is set to _true_. If not, an initial welcome user message is returned to the user. -If `DidBotWelcomeUser` is _true_, the user's input is evaluated. Based on the content of the user's input this bot will do one of the following: - -- Echo back a greeting received from the user. -- Display a hero card providing addition information about bots. -- Resend the `WelcomeMessage` explaining expected inputs for this bot. - -### [Python](#tab/python) - -The two main events encountered by the bot are: - -- `on_members_added_activity` which is called whenever a new user is connected to your bot -- `on_message_activity` which is called whenever a new user input is received. - -![welcome user logic flow](media/welcome-user-flow-python.png) - -Whenever a new user is connected, they are provided with a *welcome message*, *information message*, and a *pattern message* by the bot. -When a new user input is received, the `welcome_user_state.did_welcome_user` property is checked to see if it is set to *true*. If it is not set to *true*, an initial welcome user message is returned to the user. If it is set to *true*, based on the content of the user's input this bot will do one of the following: - -- Echo back a greeting received from the user. -- Display a hero card providing addition information about bots. - ---- - -## Create user state - -### [C#](#tab/csharp) - -The user state object is created at startup and dependency injected into the bot constructor. - -**Startup.cs** -[!code-csharp[define state](~/../botBuilder-samples/samples/csharp_dotnetcore/03.welcome-user/Startup.cs?range=30-34)] - -**Bots\WelcomeUserBot.cs** -[!code-csharp[consume state](~/../BotBuilder-Samples/samples/csharp_dotnetcore/03.welcome-user/bots/WelcomeUserBot.cs?range=41-47)] - -### [JavaScript](#tab/javascript) - -At startup, user state is defined in `index.js` and consumed by the bot constructor. - -**index.js** -[!code-javascript[define state](~/../BotBuilder-Samples/samples/javascript_nodejs/03.welcome-users/index.js?range=51-55)] - -**bots/welcomeBot.js** -[!code-javascript[consume state](~/../BotBuilder-Samples/samples/javascript_nodejs/03.welcome-users/bots/welcomeBot.js?range=16-22)] - -### [Python](#tab/python) - -At startup, user state is defined in `app.py` and consumed by the bot constructor. - -**app.py** -[!code-python[define state](~/../botbuilder-samples/samples/python/03.welcome-user/app.py?range=61-66)] - -**bots/welcome-user-bot.py** -[!code-python[consume state](~/../botbuilder-samples/samples/python/03.welcome-user/bots/welcome_user_bot.py?range=23-29)] - ---- - -## Create property accessors - -### [C#](#tab/csharp) - -We now create a property accessor that provides us a handle to `WelcomeUserState` inside the `OnMessageActivityAsync` method. -Then call the `GetAsync` method to get the properly scoped key. We then save user state data after each user input iteration using the `SaveChangesAsync` method. - -**Bots\WelcomeUserBot.cs** -[!code-csharp[Get state](~/../BotBuilder-Samples/samples/csharp_dotnetcore/03.welcome-user/bots/WelcomeUserBot.cs?range=68-71)] -[!code-csharp[Save state](~/../BotBuilder-Samples/samples/csharp_dotnetcore/03.welcome-user/bots/WelcomeUserBot.cs?range= 103-105)] - -### [JavaScript](#tab/javascript) - -We now create a property accessor that provides us a handle to welcomedUserProperty which is persisted within userState. - -**bots/welcomeBot.js** -[!code-javascript[Get state](~/../BotBuilder-Samples/samples/javascript_nodejs/03.welcome-users/bots/welcomebot.js?range=24-27)] -[!code-javascript[Save state](~/../BotBuilder-Samples/samples/javascript_nodejs/03.welcome-users/bots/welcomebot.js?range=89-97)] - -### [Python](#tab/python) - -This sample creates a conversation state property accessor, `user_state_accessor`, in the bot constructor. - -**bots/welcome-user-bot.py** -[!code-python[constructor](~/../botbuilder-samples/samples/python/03.welcome-user/bots/welcome_user_bot.py?range=31)] - -It uses the property accessor in the `on_message_activity` handler and overrides the `on_turn` handler to save state before the end of the turn. - -[!code-python[Get state](~/../botbuilder-samples/samples/python/03.welcome-user/bots/welcome_user_bot.py?range=80-83)] -[!code-python[save state](~/../botbuilder-samples/samples/python/03.welcome-user/bots/welcome_user_bot.py?range=39-43)] - ---- - -## Detect and greet newly connected users - -### [C#](#tab/csharp) - -In **WelcomeUserBot**, we check for an activity update using `OnMembersAddedAsync()` to see if a new user has been added to the conversation and then send them a set of three initial welcome messages `WelcomeMessage`, `InfoMessage` and `PatternMessage`. Complete code for this interaction is shown below. - -**Bots\WelcomeUserBot.cs** -[!code-csharp[Define messages](~/../BotBuilder-Samples/samples/csharp_dotnetcore/03.welcome-user/bots/WelcomeUserBot.cs?range=20-39)] -[!code-csharp[Send messages](~/../BotBuilder-Samples/samples/csharp_dotnetcore/03.welcome-user/bots/WelcomeUserBot.cs?range=55-66)] - -### [JavaScript](#tab/javascript) - -This JavaScript code sends initial welcome messages when a user is added. This is done by checking the conversation activity and verifying that a new member was added to the conversation. - -**bots/welcomeBot.js** -[!code-javascript[onMembersAdded](~/../BotBuilder-Samples/samples/javascript_nodejs/03.welcome-users/bots/welcomebot.js?range=63-86)] - -### [Python](#tab/python) - -The `on_members_added_activity` checks to see if a new user has been added and then sends three initial welcome messages: a *welcome message*, an *information message* and a *pattern message*. - -**bots/welcome-user-bot.py** -[!code-python[on_members_added_activity](~/../botbuilder-samples/samples/python/03.welcome-user/bots/welcome_user_bot.py?range=45-74)] - ---- - -## Welcome new user and discard initial input - -### [C#](#tab/csharp) - -It is also important to consider when your user’s input might actually contain useful information, and this may vary for each channel. To ensure your user has a good experience on all possible channels, we check the status flag _didBotWelcomeUser_ and if this is "false", we do not process the initial user input. We instead provide the user with an initial welcome message. The bool _welcomedUserProperty_ is then set to "true", stored in UserState and our code will now process this user's input from all additional message activities. - -**Bots\WelcomeUserBot.cs** -[!code-csharp[DidBotWelcomeUser](~/../BotBuilder-Samples/samples/csharp_dotnetcore/03.welcome-user/bots/WelcomeUserBot.cs?range=68-84)] -[!code-csharp[DidBotWelcomeUser](~/../BotBuilder-Samples/samples/csharp_dotnetcore/03.welcome-user/bots/WelcomeUserBot.cs?range=101-105)] - -### [JavaScript](#tab/javascript) - -It is also important to consider when your user’s input might actually contain useful information, and this may vary for each channel. To ensure your user has a good experience on all possible channels, we check the didBotWelcomedUser property, if it does not exist, we set it to "false" and do not process the initial user input. We instead provide the user with an initial welcome message. The bool didBotWelcomeUser is then set to "true" and our code processes the user input from all additional message activities. - -**bots/welcomeBot.js** -[!code-javascript[DidBotWelcomeUser](~/../BotBuilder-Samples/samples/javascript_nodejs/03.welcome-users/bots/welcomebot.js?range=24-39)] -[!code-javascript[DidBotWelcomeUser](~/../BotBuilder-Samples/samples/javascript_nodejs/03.welcome-users/bots/welcomebot.js?range=57-61)] - -### [Python](#tab/python) - -It is also important to consider when the user’s input might actually contain useful information, this may vary for each channel. To ensure the user has a good experience on all possible channels, `on_message_activity` checks the `did_welcome_user` property. The first time, it sets it to *false* and does not process the user input. Instead, it provides the user with an initial welcome message. Then it sets `did_welcome_user` to *true* and processes the user input from all additional message activities. - -**bots/welcome-user-bot.py** -[!code-python[DidBotWelcomeUser](~/../botbuilder-samples/samples/python/03.welcome-user/bots/welcome_user_bot.py?range=85-95)] - ---- - -## Process additional input - -Once a new user has been welcomed, user input information is evaluated for each message turn and the bot provides a response based on the context of that user input. The following code shows the decision logic used to generate that response. - -### [C#](#tab/csharp) - -An input of 'intro' or 'help' calls the function `SendIntroCardAsync` to present the user with an informational hero card. That code is examined in the next section of this article. - -**Bots\WelcomeUserBot.cs** -[!code-csharp[SwitchOnUtterance](~/../BotBuilder-Samples/samples/csharp_dotnetcore/03.welcome-user/bots/WelcomeUserBot.cs?range=85-100)] - -### [JavaScript](#tab/javascript) - -An input of 'intro' or 'help' uses CardFactory to present the user with an Intro Adaptive Card. That code is examined in the next section of this article. - -**bots/welcomeBot.js** -[!code-javascript[SwitchOnUtterance](~/../BotBuilder-Samples/samples/javascript_nodejs/03.welcome-users/bots/welcomebot.js?range=40-56)] - -### [Python](#tab/python) - -An user's input of *intro* or *help* causes the bot to call `__send_intro_card` which presents the user with an intro adaptive card. - -**bots/welcome-user-bot.py** -[!code-python[SwitchOnUtterance](~/../botbuilder-samples/samples/python/03.welcome-user/bots/welcome_user_bot.py?range=101-106&highlight=97-106)] - ---- - -## Using hero card greeting - -As mentioned above, some user inputs generate a *Hero Card* in response to their request. You can learn more about hero card greetings here [Send an Intro Card](./bot-builder-howto-add-media-attachments.md). Below is the code required to create this bot's hero card response. - -### [C#](#tab/csharp) - -**Bots\WelcomeUserBot.cs** -[!code-csharp[SendHeroCardGreeting](~/../BotBuilder-Samples/samples/csharp_dotnetcore/03.welcome-user/bots/WelcomeUserBot.cs?range=107-125)] - -### [JavaScript](#tab/javascript) - -**bots/welcomeBot.js** -[!code-javascript[SendIntroCard](~/../BotBuilder-Samples/samples/javascript_nodejs/03.welcome-users/bots/welcomebot.js?range=99-124)] - -### [Python](#tab/python) - -**bots/welcome-user-bot.py** -[!code-python[SendIntroCard](~/../botbuilder-samples/samples/python/03.welcome-user/bots/welcome_user_bot.py?range=108-143)] - ---- - -## Test the bot - -Download and install the latest [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme) - -1. Run the sample locally on your machine. If you need instructions, refer to the README file for [C# Sample](https://aka.ms/welcome-user-mvc) or [JS Sample](https://aka.ms/bot-welcome-sample-js). -1. Use the emulator to test the bot as shown below. - -![test welcome bot sample](media/welcome-user-emulator-1.png) - -Test hero card greeting. - -![test welcome bot card](media/welcome-user-emulator-2.png) - -## Additional Resources - -Learn more about various media responses in [Add media to messages](./bot-builder-howto-add-media-attachments.md). - -## Next steps - -> [!div class="nextstepaction"] -> [Gather user input](bot-builder-prompts.md) diff --git a/articles/v4sdk/bot-builder-service-file.md b/articles/v4sdk/bot-builder-service-file.md deleted file mode 100644 index 71f6bd5ca..000000000 --- a/articles/v4sdk/bot-builder-service-file.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Create a bot using Bot Framework SDK for JavaScript - File - Bot Service -description: Quickly create a bot using the Bot Framework SDK for JavaScript. -keywords: quickstart, bot framework sdk, getting started -author: jonathanfingold -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- -# Sample .bot file - -``` -{ - "name": "BasicBot", - "description": "Demo", - "services": [ - { - "type": "endpoint", - "name": "development", - "id": "http://localhost:3978/api/messages", - "appId": "", - "appPassword": "", - "endpoint": "http://localhost:3978/api/messages" - }, - { - "type": "luis", - "name": "basic-bot-LUIS", - "appId": "", - "version": "0.1", - "authoringKey": "", - "subscriptionKey": "", - "region": "westus", - "id": "206" - } - ], - "secretKey": "", - "version": "2.0" -} -``` diff --git a/articles/v4sdk/bot-builder-skills-overview.md b/articles/v4sdk/bot-builder-skills-overview.md deleted file mode 100644 index d1e29909a..000000000 --- a/articles/v4sdk/bot-builder-skills-overview.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: Bot Framework Skills Overview - Bot Service -description: Learn more about the Bot Framework Skills -author: darrenj -ms.author: darrenj -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 10/09/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Virtual Assistant - Skills Overview - -> [!NOTE] -> This topic applies to v4 version of the SDK. - -## Overview - -Developers can compose conversational experiences by stitching together re-usable conversational capabilities, known as Skills. - -Within an Enterprise, this could be creating one parent bot bringing together multiple sub-bots owned by different teams, or more broadly leveraging common capabilities provided by other developers. With this preview of Skills, developers can create a new bot (typically through the Virtual Assistant template) and add/remove Skills with one command line operation incorporating all Dispatch and Configuration changes. - -Skills are themselves Bots, invoked remotely and a Skill developer template (.NET, TS) is available to facilitate creation of new Skills. - -A key design goal for Skills was to maintain the consistent Activity protocol and ensure the development experience was as close to any normal V4 SDK bot as possible. - -![Skills Scenarios](./media/enterprise-template/skills-scenarios.png) - -## Bot Framework Skills - -At this time we have made available the following Bot Framework Skills, powered by the Microsoft Graph and available in multiple languages. - -![Skills Scenarios](./media/enterprise-template/skills-at-build.png) - -| Name | Description | -| ---- | ----------- | -|[Calendar Skill](https://aka.ms/bf-calendar-skill)|Add calendar capabilities to your assistant. Powered by Microsoft Graph and Google.| -|[Email Skill](https://aka.ms/bf-email-skill)|Add email capabilities to your assistant. Powered by Microsoft Graph and Google.| -|[To Do Skill](https://aka.ms/bf-todo-skill)|Add task management capabilities to your assistant. Powered by Microsoft Graph.| -|[Point of Interest Skill](https://aka.ms/bf-poi-skill)|Find points of interest and directions. Powered by Azure Maps and FourSquare.| -|[Automotive Skill](https://aka.ms/bf-auto-skill)|Industry-vertical Skill for showcasing enabling car feature control.| -|[Experimental Skills](https://aka.ms/bf-experimental-skills)|News, Restaurant Booking and Weather.| - -## Getting Started - -Refer to the [tutorials](https://aka.ms/bfs-tutorials) to learn how to leverage existing skills and build your own. diff --git a/articles/v4sdk/bot-builder-telemetry-analytics-queries.md b/articles/v4sdk/bot-builder-telemetry-analytics-queries.md deleted file mode 100644 index a3e156517..000000000 --- a/articles/v4sdk/bot-builder-telemetry-analytics-queries.md +++ /dev/null @@ -1,564 +0,0 @@ ---- -title: Analyze the telemetry data from your bot - Bot Service -description: Learn how to analyze bot behavior with Kusto queries. -keywords: telemetry, appinsights, monitor bot, Kusto, queries -author: WashingtonKayaker -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/10/2020 ---- - -# Analyze your bot's telemetry data - -## Analyzing Bot behavior - -The following collection of queries can be used to analyze bot behavior. You can use the collection to author custom queries in [Azure Monitor Log Analytics](https://aka.ms/log-analytics-azure-monitor) and to create monitoring and [PowerBI](https://aka.ms/power-bi-overview) visualization dashboards. - -## Prerequisites -It is helpful to have a basic understanding of the following concepts: - -* [Kusto queries](https://aka.ms/Kusto-query-overview) - -* How to use [Log Analytics](https://aka.ms/azure-monitor-log-queries-get-started) in the Azure portal to write Azure Monitor log queries - -* The basic concepts of [Log queries](https://aka.ms/azure-monitor-log-queries-get-started) in Azure Monitor - -## Dashboards -Azure Dashboards offer a great way to view and share the information generated from your queries. You can build custom dashboards to help monitor your bots activity by associating your queries with the tiles that you add to your dashboard. For more information on dashboards and how to associate your queries with them, see [Create and share dashboards of Log Analytics data](https://aka.ms/log-analytics-create-share-dashboards). The remainder of this article shows examples of some of the queries that you may find useful in monitoring your bots behavior. - -## Example Kusto queries - -> [!NOTE] -> It is recommended to pivot on different dimensions such as period, channel, and locale for all queries in this article. - -### Number of users per period -This example results in a line chart that shows how many distinct users communicated with your bot per day for the past 14 days. The time period can be easily changed by assigning different values to the `queryStartDate`, `queryEndDate` and `interval` variables. - -> [!IMPORTANT] -> You will only get a correct count of unique users in this query if they are authenticated users, and the results may also depend on the channel capabilities. - -```Kusto -// number of users per period -let queryStartDate = ago(14d); -let queryEndDate = now(); -let groupByInterval = 1d; -customEvents -| where timestamp > queryStartDate -| where timestamp < queryEndDate -| summarize uc=dcount(user_Id) by bin(timestamp, groupByInterval) -| render timechart -``` - -> [!TIP] -> The Kusto [summarize operator](https://aka.ms/kusto-summarize-operator) is used to produce a table that aggregates the content of the input table. -> -> The [Bin](https://docs.microsoft.com/azure/kusto/query/binfunction) function is a Kusto scalar function that when used in conjunction with the `summarize operator` will group the query results into the specified value. In the above example, this is grouped by day, Kusto also will accept h=hours, m=minutes, s=seconds, ms=milliseconds, microsecond=microseconds. -> -> The [render operator](https://aka.ms/kusto-query-render-operator?pivots=Kusto) enables you to easily render charts, such as the _timechart_, a line chart where the x-axis is a datetime and any other numeric column can be used for the y-axis. It automatically keeps the x-axis spaced nicely even if your data doesn't have every time specified. If no render statement is used, it defaults to `table`. - -#### Sample query results - - - -![Number of users per period](./media/userscount.png) - - - -### Activity per period -This example illustrates how to measure the volume of activity per desired dimension, whether that be a count of the number of conversations, dialogs, or messages per day for the past 14 days. The time period can be easily changed by assigning different values to the `querystartdate`, `queryEndDate` and `interval` variables. The desired dimension is defined by the `extend` clause in the following example, `metric` can be set to either _InstanceId_, _DialogId_ or _ActivityId_. - -Assign *metric* to the dimension that you want to display: - * *InstanceId* measures the number of [Conversations](https://aka.ms/bot-builder-conversations) - * *DialogId* measures the number of [Dialogs](https://aka.ms/bot-builder-concept-dialog) - * *ActivityId* measures the number of [Messages](https://aka.ms/bot-rest-create-messages) - -```Kusto -// measures the number of activity's (conversations, dialogs, messages) per period -let queryStartDate = ago(14d); -let queryEndDate = now(); -let groupByInterval = 1d; -customEvents -| where timestamp > queryStartDate -| where timestamp < queryEndDate -| extend InstanceId = tostring(customDimensions['']) -| extend DialogId = tostring(customDimensions['']) -| extend ActivityId = tostring(customDimensions['']) -| where DialogId != '' and InstanceId != '' and user_Id != '' -| extend metric = InstanceId // DialogId or ActivityId -| summarize Count=dcount(metric) by bin(timestamp, groupByInterval) -| order by Count desc nulls last -| render timechart -``` - -> [!TIP] -> The Kusto [extend operator](https://aka.ms/kusto-extend-operator) is used to create calculated columns and append them to the result set. - - -#### Sample query results - -![Activity per period](./media/convscount.PNG) - - -### Activity per user per period -This example demonstrates how to count the number of activities per user per period. This demonstrates drilling down in the _activity per period_ query to focus on the activity per user per period. The activities include dialogs, conversations or messages. This helps to measure user interaction with your bot and can help in determining potential problems, for example: - -- Days with lots of activity by a single user may mean attack or test -- Days with little interaction may indicate service health issues - -> [!TIP] -> You can remove _by user_Id_ to get the general bot activity volume which can be pivoted on time and dialogs, messages, or conversations. - -```Kusto -// number of users per period per dialogs -let queryStartDate = ago(14d); -let queryEndDate = now(); -let interval = 6h; -customEvents -| where timestamp > queryStartDate -| where timestamp < queryEndDate -| extend InstanceId = tostring(customDimensions['InstanceId']) -| extend DialogId = tostring(customDimensions['DialogId']) -| extend ActivityId = tostring(customDimensions['activityId']) -| where DialogId != '' and InstanceId != '' and user_Id != '' -| extend metric = ActivityId // InstanceId // DialogId // or InstanceId for conversation count -| summarize Count=dcount(metric) by user_Id, bin(timestamp, groupByInterval) -| order by Count desc nulls last -``` - -#### Sample query results - -| **user_Id** | **timestamp** | **Count** | -| ------------- | -------------------- | :------: | -| User-8107ffd2 | 2019-09-03T00:00:00Z | 14 | -| User-75f2cc8f | 2019-08-30T00:00:00Z | 13 | -| User-75f2cc8d | 2019-09-03T00:00:00Z | 13 | -| User-3060aada | 2019-09-03T00:00:00Z | 10 | - - -### Dialog completion -Once you set the telemetry client for a dialog, the dialog (and its children) will emit some default telemetry data, such as _started_ and _completed_. This example can be used to measure the *completed* dialogs relative to *started* dialogs. If the number of dialogs started is greater than the number completed, some of your users are not completing the dialog flow. This can be used as a starting point in identifying and troubleshooting any potential dialog logic. It can also be used to identify the more popular and less frequented dialogs. - -```Kusto -// % Completed Waterfall Dialog: shows completes relative to starts -let queryStartDate = ago(14d); -let queryEndDate = now(); -customEvents -| where timestamp > queryStartDate -| where timestamp < queryEndDate -| where name=="WaterfallStart" -| extend DialogId = customDimensions['DialogId'] -| extend InstanceId = tostring(customDimensions['InstanceId']) -| join kind=leftouter ( - customEvents - | where name=="WaterfallComplete" - | extend InstanceId = tostring(customDimensions['InstanceId']) - ) on InstanceId -| summarize started=countif(name=='WaterfallStart'), completed=countif(name1=='WaterfallComplete') by tostring(DialogId) -| where started > 100 // filter for sample -// Show starts vs. completes -| project tostring(DialogId), started, completed -| order by started desc, completed asc nulls last -| render barchart with (kind=unstacked, xcolumn=DialogId, ycolumns=completed, started, ysplit=axes) -``` - -> [!TIP] -> The Kusto [join operator](https://aka.ms/kusto-join-operator) is used to merge the rows of two tables to form a new table by matching values of the specified column(s) from each table. -> -> The [project operator](https://aka.ms/kusto-project-operator) is used to select the fields that you want to show up in your output. Similar to the `extend operator` that adds a new field, the `project operator` can either choose from the existing set of fields or add a new field. - -#### Sample query results - -![Dialog completion](./media/dialogwfratio.PNG) - - -### Dialog incompletion -This example can be used to count the number of dialog flows that started but never completed due to cancellation or abandonment during the specified time period. You can use it to review incomplete dialogs and examine whether they were actively cancelled due to user confusion or simply abandoned due to user distraction or loss of interest. - - - -```Kusto -// show incomplete dialogs -let queryStartDate = ago(14d); -let queryEndDate = now(); -customEvents -| where timestamp > queryStartDate -| where timestamp < queryEndDate -| where name == "WaterfallStart" -| extend DialogId = customDimensions['DialogId'] -| extend instanceId = tostring(customDimensions['InstanceId']) -| join kind=leftanti ( - customEvents - | where name == "WaterfallComplete" - | extend instanceId = tostring(customDimensions['InstanceId']) - ) on instanceId -| summarize cnt=count() by tostring(DialogId) -| order by cnt -| render barchart -``` - -> [!TIP] -> The Kusto [order operator](https://aka.ms/kusto-query-order-operator) (Same as the `sort operator`) is used to sort the rows of the input table into order by one or more columns. Note: If you want to exclude null values from the results of any query, you can filter them out in your where statement, for example you could add "and isnotnull(Timestamp)", or to return null values at the beginning or end, add the `nulls first` or `nulls first` to the end of the order statement. -> - -#### Sample query results - -![](./media/cancelleddialogs.PNG) - - - - - -### Dialog Sequence Drill Down - -#### Waterfall start/step/complete for dialog in conversation -This example shows the sequence of dialog steps, grouped by conversation (instanceId). This can be useful in determining which steps lead to dialog interruption. - -The run this query, enter the value of the desired `DialogId` in place of \ - -```Kusto -// Drill down: Show waterfall start/step/complete for specific dialog -let queryStartDate = ago(14d); -let queryEndDate = now(); -let DialogActivity=(dlgid:string) { -customEvents -| where timestamp > queryStartDate -| where timestamp < queryEndDate -| extend DialogId = customDimensions['DialogId'] -| extend StepName = customDimensions['StepName'] -| extend InstanceId = customDimensions['InstanceId'] -| where DialogId == dlgid -| project timestamp, name, StepName, InstanceId -| order by tostring(InstanceId), timestamp asc -}; -// For example see SampleDialogId behavior -DialogActivity("") -``` - -> [!TIP] -> This query was written using a [query-defined function](https://aka.ms/kusto-user-functions), which is a user-defined function that is defined and used within the scope of a single query, and is defined through a let statement. This query written without the use of the `query-defined function`: -> -> ```Kusto -> let queryStartDate = ago(14d); -> let queryEndDate = now(); -> customEvents -> | where timestamp > queryStartDate -> | where timestamp < queryEndDate -> | extend DialogId = customDimensions['DialogId'] -> | extend StepName = customDimensions['StepName'] -> | extend InstanceId = customDimensions['InstanceId'] -> | where DialogId == "" -> | project timestamp, name, StepName, InstanceId -> | order by tostring(InstanceId), timestamp asc -> ``` - -##### Sample query results - -| **timestamp** | **name** | **StepName** | **InstanceId** | -| ------------------- | -------------------------- | ------------------------------- | --------------- | -| 2019-08-23T20:04... | WaterfallStart | null | ...79c0f03d8701 | -| 2019-08-23T20:04... | WaterfallStep | GetPointOfInterestLocations | ...79c0f03d8701 | -| 2019-08-23T20:04... | WaterfallStep | ProcessPointOfInterestSelection | ...79c0f03d8701 | -| 2019-08-23T20:04... | WaterfallStep | GetRoutesToDestination | ...79c0f03d8701 | -| 2019-08-23T20:05... | WaterfallStep | ResponseToStartRoutePrompt | ...79c0f03d8701 | -| 2019-08-23T20:05... | WaterfallComplete _1_ | null | ...79c0f03d8701 | -| 2019-08-28T23:35... | WaterfallStart | null | ...6ac8b3211b99 | -| 2019-08-28T23:35... | WaterfallStep _2_ | GetPointOfInterestLocations | ...6ac8b3211b99 | -| 2019-08-28T19:41... | WaterfallStart | null | ...8137d76a5cbb | -| 2019-08-28T19:41... | WaterfallStep _2_ | GetPointOfInterestLocations | ...8137d76a5cbb | -| 2019-08-28T19:41... | WaterfallStart | null | ...8137d76a5cbb | - -1 _Completed_ - -2 _Abandoned_ - -_Interpretation: Users seem to abandon the conversation at the GetPointOfInterestLocations step._ - -> [!NOTE] -> Waterfall dialogs execute a sequence (start, multiple steps, complete). If a sequence shows start with no complete, it means the dialog was interrupted either due to user abandoning or canceling the dialog. In this detailed analysis, one can see this behavior (see completed vs. abandoned steps). - -#### Waterfall start/step/complete/cancel steps aggregate totals -This example shows the aggregate totals of the total number of times that a dialog sequence was started, the combined total number of waterfall steps, how many were successfully completed, how many were canceled and the difference between _WaterfallStart_ and the combined total of _WaterfallComplete_ plus _WaterfallCancel_ will give you the total number abandoned. - -```Kusto -// Drill down: Aggregate view of waterfall start/step/complete/cancel steps totals for specific dialog -let queryStartDate = ago(14d); -let queryEndDate = now(); -let DialogSteps=(dlgid:string) { -customEvents -| where timestamp > queryStartDate -| where timestamp < queryEndDate -| extend DialogId = customDimensions['DialogId'] -| where DialogId == dlgid -| project name -| summarize count() by name -}; -// For example see SampleDialogId behavior -DialogSteps("") -``` - -##### Sample query results - -| **name** | **count** | -| ----------------- | --------: | -| WaterfallStart | 21 | -| WaterfallStep | 47 | -| WaterfallComplete | 11 | -| WaterfallCancel | 1 | - -_Interpretation: Of 21 invocations of dialog sequence, only 11 has completed, 9 were abandoned, and one was cancelled by the user_ - - - -### Average duration in dialog -This example measures the average amount of time users spend in a given dialog. A long time spend in a dialog may suggest opportunities to simplify. - - ```Kusto -// Average dialog duration -let queryStartDate = ago(14d); -let queryEndDate = now(); -customEvents -| where timestamp > queryStartDate -| where timestamp < queryEndDate -| where name=="WaterfallStart" -| extend DialogId = customDimensions['DialogId'] -| extend instanceId = tostring(customDimensions['InstanceId']) -| join kind=leftouter (customEvents | where name=="WaterfallCancel" | extend instanceId = tostring(customDimensions['InstanceId'])) on instanceId -| join kind=leftouter (customEvents | where name=="WaterfallComplete" | extend instanceId = tostring(customDimensions['InstanceId'])) on instanceId -| extend duration = case(not(isnull(timestamp1)), timestamp1 - timestamp, -not(isnull(timestamp2)), timestamp2 - timestamp, 0s) // Abandoned are not counted. Alternate: now()-timestamp) -| extend seconds = round(duration / 1s) -| summarize AvgSeconds=avg(seconds) by tostring(DialogId) -| order by AvgSeconds desc nulls last -| render barchart with (title="Duration in Dialog") - ``` - -#### Sample query results - -![dialogduration](./media/dialogduration.PNG) - - -### Average steps in dialog -This example shows each executed dialogs "length" as calculated by average, min, max and standard deviation. This can help analyze dialog quality. For example: - -- Dialogs with a lot of steps should be evaluated for simplification opportunities -- Dialogs with a wide gap between min/max/average could mean that users get stalled trying to complete the tasks. You may need to evaluate the possibility of there being shorter paths to complete the tasks, or ways to reduce the dialog complexity. -- Dialogs with a large standard-deviation suggest complex paths or broken experience (abandon/cancel) -- Dialogs with very few steps may be so because they were never completed. Analyzing the completion/abandonment rates may help to make that determination. - -```Kusto -// min/max/std/avg steps per dialog -let queryStartDate = ago(14d); -let queryEndDate = now(); -customEvents -| where timestamp > queryStartDate -| where timestamp < queryEndDate -| extend DialogId = tostring(customDimensions['DialogId']) -| extend StepName = tostring(customDimensions['StepName']) -| extend InstanceId = tostring(customDimensions['InstanceId']) -| where name == "WaterfallStart" or name == "WaterfallStep" or name == "WaterfallComplete" -| order by InstanceId, timestamp asc -| project timestamp, DialogId, name, InstanceId, StepName -| summarize cnt=count() by InstanceId, DialogId -| summarize avg=avg(cnt), minsteps=min(cnt),maxsteps=max(cnt), std=stdev(cnt) by DialogId -| extend avgsteps = round(avg, 1) -| extend avgshortbysteps=maxsteps-avgsteps -| extend avgshortbypercent=round((1.0 - avgsteps/maxsteps)*100.0, 1) -| project DialogId, avgsteps, minsteps, maxsteps, std, avgshortbysteps, avgshortbypercent -| order by std desc nulls last -``` - -#### Sample query results - -| Dialog Id | avg steps | min steps | max steps | std | avg short by steps | avg short by percent | -| ----------------------- | --------: | :-------: | :-------: | ---: | :----------------: | -------------------: | -| FindArticlesDialog | 6.2 | 2 | 7 | 2.04 | 0.8 | 11.4% | -| CreateTicket | 4.3 | 2 | 5 | 1.5 | 0.7 | 14% | -| CheckForCurrentLocation | 3.9 | 2 | 5 | 1.41 | 1.1 | 22% | -| BaseAuth | 3.3 | 2 | 4 | 1.03 | 0.7 | 17.5% | -| onboarding | 2.7 | 2 | 4 | 0.94 | 1.3 | 32.5% | - -__Interpretation: For example, FindArticlesDialog has a wide spread between min/max and should be investigated and possibly redesigned & optimized. - - - -### Channel activity by activity metric -This example measures the amount of activity your bot receives per channel in the given period. It does this by counting any one of the following metrics: incoming messages, users, conversations or dialogs. This can be useful for service health analysis or to measure a channels popularity. - - -```Kusto -// number of metric: messages, users, conversations, dialogs by channel -let queryStartDate = ago(14d); -let queryEndDate = now(); -let groupByInterval = 1d; -customEvents -| where timestamp > queryStartDate -| where timestamp < queryEndDate -| extend InstanceId = tostring(customDimensions['InstanceId']) -| extend DialogId = tostring(customDimensions['DialogId']) -| extend ActivityId = tostring(customDimensions['activityId']) -| extend ChannelId = tostring(customDimensions['channelId']) -| where DialogId != '' and InstanceId != '' and user_Id != '' -| extend metric = user_Id // InstanceId or ActivityId or user_Id -| summarize Count=count(metric) by ChannelId, bin(timestamp, groupByInterval) -| order by Count desc nulls last -| render barchart with (title="Users", kind=stacked) // or Incoming Messages or Conversations or Users -``` - -> [!TIP] -> You may want to consider trying these variations: -> - Run the query without the timestamp bucketing: `bin(timestamp, groupByInterval)` -> - You can also use `dcount` for distinct users vs `count` for all user event activities. This also works for repeat users. -> - -#### Sample query results - -![ChannelsUsage](./media/ChannelsUsage.PNG) - - _Interpretation: Emulator testing used to be most popular but once we went live, DirectLineSpeech, is the most popular channel._ - - -### Total Intents by Popularity -This example applies to LUIS enabled bots. It shows a summary of all [intents](https://aka.ms/botbuilder-luis-concept#recognize-intent) by popularity, and corresponding intent detection certainty score. - -* In practice, the view should separated for each metric. -* Popular intent paths should be optimized for user experience. -* Low average scores indicate poor recognition & possible missing actual user intent. - -```Kusto -// show total intents -let queryStartDate = ago(14d); -let queryEndDate = now(); -customEvents -| where timestamp > queryStartDate -| where timestamp < queryEndDate -| where name startswith "LuisResult" -| extend intentName = tostring(customDimensions['intent']) -| extend intentScore = todouble(customDimensions['intentScore']) -| summarize ic=count(), ac=avg(intentScore)*100 by intentName -| project intentName, ic, ac -| order by ic desc nulls last -| render barchart with (kind=unstacked, xcolumn=intentName, ycolumns=ic,ac, title="Intents Popularity") -``` - -#### Sample query results - -![IntentPopularity](./media/Telemetry/IntentPopularity.PNG) - -_Interpretation: For example the most popular intent, confirm is detected only with 23% confidence on average._ - - -> [!TIP] -> Barcharts are one of over a dozen options available with Kusto queries. Some other options include: anomalychart, areachart, columnchart, linechart, scatterchart. for more details see the [render operator](https://aka.ms/kusto-query-render-operator?pivots=Kusto) topic. - - -## Schema of Bot Analytics Instrumentation -The following tables show the most common fields that your bot will log telemetry data into. - -### General Envelope - -Common log analytics fields in Application Insights instrumentation. - -| **Field** | **Description** | **Sample Values** | -| ---------------- | ---------------------- | ------------------------------------------------------------ | -| name | Message type | BotMessageSend, BotMessageReceived, LuisResult, WaterfallStep, WaterfallStart, SkillWebSocketProcessRequestLatency, SkillWebSocketOpenCloseLatency, WaterfallComplete, QnaMessage, WaterfallCancel, SkillWebSocketTurnLatency, AuthPromptValidatorAsyncFailure | -| customDimensions | SDK Bot Analytics | activityId=\, activityType=message, channelId=emulator, fromId=\, fromName=User, locale=en-us, recipientId=\, recipientName=Bot, text=find a coffee shop | -| timestamp | Time of event | 2019-09-05T18:32:45.287082Z | -| instance_Id | Conversation Id | f7b2c416-a680-4b2c-b4cc-79c0f03d8711 | -| operation_Id | Turn Id | 084b2856947e3844a5a18a8476d99aaa | -| user_Id | Unique channel user id | emulator7c259c8e-2f47... | -| client_IP | Client ip address | 127.0.0.1 (may be absent due to privacy block) | -| client_City | Client city | Redmond (if detected, may be absent) | - -### Custom Dimensions - -Most of bot specific activity data is stored in _customDimensions_ field. - -| **Field** | **Description** | **Sample Values** | -| ------------- | -------------------- | ------------------------------------------------- | -| activityId | Message id | \: 8da6d750-d00b-11e9-80e0-c14234b3bc2a | -| activityType | Type of message | message, conversationUpdate, event, invoke | -| channelId | Channel identifier | emulator, directline, msteams, webchat | -| fromId | From Identifier | \ | -| fromName | Username from client | John Bonham, Keith Moon, Steve Smith, Steve Gadd | -| locale | Client origin locale | en-us, zh-cn, en-GB, de-de, zh-CN | -| recipientId | Recipient identifier | \ | -| recipientName | Recipient name | John Bonham, Keith Moon, Steve Smith, Steve Gadd | -| text | Text in message | find a coffee shop | - -### Custom Dimensions: LUIS - -LUIS instrumentation stores its data in the following Custom Dimensions fields. - -| **Field** | **Description** | **Sample Values** | -| -------------- | ----------------------- | ------------------------------------------------------- | -| intent | LUIS detected intent | pointOfInterestSkill | -| intentScore | LUIS recognition score | 0.98 | -| Entities | LUIS detected entities | FoodOfGrocery = [["coffee"]], KEYWORD= ["coffee shop"] | -| Question | LUIS detected question | find a coffee shop | -| sentimentLabel | LUIS detected sentiment | positive | - -### Custom Dimensions: QnAMaker - -QnAMaker instrumentation stores its data in the following Custom Dimensions fields. - -| **Field** | **Description** | **Sample Values** | -| --------------- | -------------------------- | ------------------------------------------------------------ | -| question | QnA detected question | what can you do? | -| answer | QnA answer | You have questions, I may have answers. | -| articleFound | QnA | true | -| questionId | QnA question Id | 488 | -| knowledgeBaseId | QnA KB Id | 2a4936f3-b2c8-44ff-b21f-67bc413b9727 | -| matchedQuestion | Array of matched questions | ["Can you explain to me what your role is?","Can you tell me a bit about yourself?","Can you tell me about you?","could you help me","hmmm so what can you do?","how can you help me","How can you help me?","How can you help?","so how can i use you in my projects?","Talk to me about your capability","What are you capable of?",… | - - - -## See Also - -* For a tutorial on writing log queries, see [Get started with log queries in Azure Monitor](https://aka.ms/azure-monitor-log-queries-get-started) -* [Visualizing data from Azure Monitor](https://aka.ms/azure-monitor-visualize-data) -* Learn how to [Add telemetry to your bot](https://aka.ms/add-bot-telemetry) -* Learn more about [Azure Monitor log queries](https://aka.ms/azure-monitor-log-queries) -* [Create and share dashboards of Log Analytics data](https://aka.ms/log-analytics-create-share-dashboards) diff --git a/articles/v4sdk/bot-builder-telemetry-qnamaker.md b/articles/v4sdk/bot-builder-telemetry-qnamaker.md deleted file mode 100644 index 3599595c5..000000000 --- a/articles/v4sdk/bot-builder-telemetry-qnamaker.md +++ /dev/null @@ -1,388 +0,0 @@ ---- -title: Add telemetry to your QnA bot - Bot Service -description: Learn how to integrate the new telemetry features into your QnA Maker enabled bot. -keywords: telemetry, appinsights, Application Insights, monitor bot, QnA Maker -author: WashingtonKayaker -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 07/31/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Add telemetry to your QnAMaker bot - -[!INCLUDE[applies-to](../includes/applies-to.md)] - - -Telemetry logging was added to version 4.2 of the Bot Framework SDK. This enables bot applications to send event data to telemetry services such as [Application Insights](https://aka.ms/appinsights-overview). Telemetry offers insights into your bot by showing which features are used the most, detects unwanted behavior and offers visibility into availability, performance, and usage. - -Two new components were added to the Bot Framework SDK that enable telemetry logging in QnA Maker enabled bots: `TelemetryLoggerMiddleware` and the `QnAMaker` class. `TelemetryLoggerMiddleware` is a middleware component that logs every time messages are received, sent, updated, or deleted, and the 'QnAMaker' class provides custom logging that extends telemetry capabilities. - -In this article you will learn about: - -* The code required to wire up telemetry in your bot - -* The code required to enable the out-of-the-box QnA logging and reports that use the standard event properties. - -* Modifying or extending the SDK's default event properties to enable a wide range of reporting needs. - - -## Prerequisites - -* The [QnA Maker sample code](https://aka.ms/cs-qna) - -* A subscription to [Microsoft Azure](https://portal.azure.com/) - -* An [Application Insights key](../bot-service-resources-app-insights-keys.md) - -* Familiarity with [QnA Maker](https://qnamaker.ai/) is helpful. - -* A [QnA Maker](https://aka.ms/create-qna-maker) account. - -* A published QnA Maker knowledge base. If you do not have one, follow the steps in [Create and answer from KB](https://aka.ms/create-publish-query-in-portal) tutorial to create a QnA Maker knowledge base with questions and answers. - -> [!NOTE] -> This article will build on the [QnA Maker sample code](https://aka.ms/cs-qna) by stepping you through the steps required to incorporate telemetry. - -## Wiring up telemetry in your QnA Maker bot - -We will start with the [QnA Maker sample app](https://aka.ms/cs-qna) and add the code required to integrate telemetry into a bot using the QnA service. This will enable Application Insights to begin tracking requests. - -1. Open the [QnA Maker sample app](https://aka.ms/cs-qna) in Visual Studio - -2. Add the `Microsoft.Bot.Builder.Integration.ApplicationInsights.Core ` NuGet package. For more information on using NuGet, see [Install and manage packages in Visual Studio](https://aka.ms/install-manage-packages-vs): - -3. Include the following statements in `Startup.cs`: - ```csharp - using Microsoft.ApplicationInsights.Extensibility; - using Microsoft.Bot.Builder.ApplicationInsights; - using Microsoft.Bot.Builder.Integration.ApplicationInsights.Core; - ``` - - > [!NOTE] - > If you're following along by updating the QnA Maker sample code you will notice that the using statement for `Microsoft.Bot.Builder.Integration.AspNet.Core` already exists in the QnA Maker sample. - -4. Add the following code to the `ConfigureServices()` method in `Startup.cs`. This makes telemetry services available to your bot via [dependency injection (DI)](https://aka.ms/asp.net-core-dependency-interjection): - ```csharp - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - ... - // Create the Bot Framework Adapter with error handling enabled. - services.AddSingleton(); - - // Add Application Insights services into service collection - services.AddApplicationInsightsTelemetry(); - - // Add the standard telemetry client - services.AddSingleton(); - - // Create the telemetry middleware to track conversation events - services.AddSingleton(); - - // Add the telemetry initializer middleware - services.AddSingleton(); - - // Add telemetry initializer that will set the correlation context for all telemetry items - services.AddSingleton(); - - // Add telemetry initializer that sets the user ID and session ID (in addition to other bot-specific properties, such as activity ID) - services.AddSingleton(); - ... - } - ``` - - > [!NOTE] - > If you are following along by updating the QnA Maker sample code you will notice that `services.AddSingleton();` already exists. - -5. Instruct the adapter to use the middleware code that was added to the `ConfigureServices()` method. Open `AdapterWithErrorHandler.cs` and add `IMiddleware middleware` to the constructors parameter list. Add the `Use(middleware);` statement as the last line in the contructor: - ```csharp - public AdapterWithErrorHandler(ICredentialProvider credentialProvider, ILogger logger, IMiddleware middleware, ConversationState conversationState = null) - : base(credentialProvider) - { - ... - - Use(middleware); - } - ``` - -6. Add the Application Insights instrumentation key in your `appsettings.json` file. The `appsettings.json` file contains metadata about external services the Bot uses while running. For example, CosmosDB, Application Insights and the QnA Maker service connection and metadata is stored there. The addition to your `appsettings.json` file must be in this format: - - ```json - { - "MicrosoftAppId": "", - "MicrosoftAppPassword": "", - "QnAKnowledgebaseId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", - "QnAEndpointKey": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", - "QnAEndpointHostName": "https://xxxxxxxx.azurewebsites.net/qnamaker", - "ApplicationInsights": { - "InstrumentationKey": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - } - } - ``` - > [!Note] - > - > * Details on getting the _Application Insights instrumentation key_ can be found in the article [Application Insights keys](../bot-service-resources-app-insights-keys.md). - > - > * You should already have a [QnA maker account](https://aka.ms/create-qna-maker), if needed you can find information on getting the QnA Knowledgebase Id, Endpoint Key and HostName values [here](https://aka.ms/bot-framework-emulator-qna-keys). - > - - -At this point the preliminary work to enable telemetry using Application Insights is done. You can run your bot locally using the bot emulator and then go into Application Insights to see what is being logged such as response time, overall app health, and general running information. - -> [!TIP] -> For information on Enabling / disabling activity event and personal information logging see [Add telemetry to your bot](bot-builder-telemetry.md#enabling-or-disabling-activity-logging) - -Next we will see what needs to be included to add telemetry functionality to the QnA Maker service. - - -## Enabling telemetry to capture usage data from the QnA Maker service - -The QnA Maker service has built-in telemetry logging available so there is very little you need to do to start getting telemetry data from QnA Maker. First we will see how to incorporate telemetry into the QnA Maker code to enable the built-in telemetry logging, then we will learn how to replace or add additional properties to the existing event data to satisfy a wide range of reporting needs. - -### Enabling default QnA logging - -1. Create a private readonly field of type `IBotTelemetryClient` in your `QnABot` class in `QnABot.cs`: - - ```cs - public class QnABot : ActivityHandler - { - private readonly IBotTelemetryClient _telemetryClient; - ... - } - ``` - -2. Add an `IBotTelemetryClient` parameter to your `QnABot` class constructor in `QnABot.cs` and assign its value to the private field created in the previous step: - - ```cs - public QnABot(IConfiguration configuration, ILogger logger, IHttpClientFactory httpClientFactory, IBotTelemetryClient telemetryClient) - { - ... - _telemetryClient = telemetryClient; - } - ``` - -3. The _`telemetryClient`_ parameter is required when instantiating the new QnAMaker object in `QnABot.cs`: - - ```cs - var qnaMaker = new QnAMaker(new QnAMakerEndpoint - { - KnowledgeBaseId = _configuration["QnAKnowledgebaseId"], - EndpointKey = _configuration["QnAEndpointKey"], - Host = _configuration["QnAEndpointHostName"] - }, - null, - httpClient, - _telemetryClient); - ``` - - > [!TIP] - > Make sure that the property names that you use in the `_configuration` entries match the property names you used in the AppSettings.json file and the values for those properties are obtained by selecting the _View Code_ button in https://www.qnamaker.ai/Home/MyServices: - - - ![AppSettings](media/AppSettings.json-QnAMaker.png) - -#### Viewing Telemetry data logged from the QnA Maker default entries -You can view the results of your QnA Maker bot usage in Application Insights after running your bot in the bot emulator by taking the following steps : - -1. Go to the [Azure portal](https://portal.azure.com/) - -2. Navigate to your Application Insights by clicking on __Monitor > Applications__. - -3. Once in your Application Insights, click on _Logs (Analytics)_ on the navigation bar as shown below: - - ![Log Analytics](media/AppInsights-LogView-QnaBot.png) - -4. Enter the following Kusto query and then select _Run_ - - ```SQL - customEvents - | where name == 'QnaMessage' - | extend answer = tostring(customDimensions.answer) - | summarize count() by answer - ``` -5. Leave this page open in your browser, we will come back to it after adding a new custom property. - -> [!TIP] -> If you are new to the Kusto query language that is used to write log queries in Azure Monitor, but are familiar with SQL query language, you may find the [SQL to Azure Monitor log query cheat sheet](https://aka.ms/azureMonitor-SQL-cheatsheet) useful. - -### Modifying or extending the default event properties -If you need properties that are not defined in the `QnAMaker` class there are two ways of handling this, both require creating your own class derived from the `QnAMaker` class. The first is explained in the section below titled [Adding properties](#adding-properties) in which you add properties to the existing `QnAMessage` event. The second method allows you to create new events to which you can add properties as described in [Adding new events with custom properties](#adding-new-events-with-custom-properties). - -> [!Note] -> The `QnAMessage` event is part of the Bot Framework SDK and provides all of the out-of-the-box event properties that are logged to Application Insights. - - - -#### Adding properties - -The following demonstrates how you can derive from the `QnAMaker` class. The example shows adding the property "MyImportantProperty" to the `QnAMessage` event. The `QnAMessage` event is logged every time a QnA [GetAnswers](https://aka.ms/namespace-QnAMaker-GetAnswersAsync) call is performed. - -After learning how to add custom properties we will learn how to create a new custom event and associate properties with it, then we will run the bot locally using the Bot Framework Emulator and see what is being logged in Application Insights using the Kusto query language. - -1. Create a new class named `MyQnAMaker` in the `Microsoft.BotBuilderSamples` namespace that inherits from the `QnAMaker` class and save it as `MyQnAMaker.cs`. In order to inherit from the `QnAMaker` class you will need to add the `Microsoft.Bot.Builder.AI.QnA` using statement. Your code should appear as follows: - - - ```cs - using Microsoft.Bot.Builder.AI.QnA; - - namespace Microsoft.BotBuilderSamples - { - public class MyQnAMaker : QnAMaker - { - - } - } - ``` -2. Add a class constructor to `MyQnAMaker`. Note that you will need two additional using statements for the constructors parameters `System.Net.Http` and `Microsoft.Bot.Builder`: - - ```cs - ... - using Microsoft.Bot.Builder.AI.QnA; - using System.Net.Http; - using Microsoft.Bot.Builder; - - namespace Microsoft.BotBuilderSamples - { - public class MyQnAMaker : QnAMaker - { - public MyQnAMaker( - QnAMakerEndpoint endpoint, - QnAMakerOptions options = null, - HttpClient httpClient = null, - IBotTelemetryClient telemetryClient = null, - bool logPersonalInformation = false) - : base(endpoint, options, httpClient, telemetryClient, logPersonalInformation) - { - - } - } - } - ``` -3. Add the new property to the QnAMessage event after the constructor and include the statements `System.Collections.Generic`, `System.Threading`, and `System.Threading.Tasks`: - - ```cs - using Microsoft.Bot.Builder.AI.QnA; - using System.Net.Http; - using Microsoft.Bot.Builder; - using System.Collections.Generic; - using System.Threading; - using System.Threading.Tasks; - - namespace Microsoft.BotBuilderSamples - { - public class MyQnAMaker : QnAMaker - { - ... - - protected override async Task OnQnaResultsAsync( - QueryResult[] queryResults, - Microsoft.Bot.Builder.ITurnContext turnContext, - Dictionary telemetryProperties = null, - Dictionary telemetryMetrics = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - var eventData = await FillQnAEventAsync( - queryResults, - turnContext, - telemetryProperties, - telemetryMetrics, - cancellationToken) - .ConfigureAwait(false); - - // Add new property - eventData.Properties.Add("MyImportantProperty", "myImportantValue"); - - // Log QnAMessage event - TelemetryClient.TrackEvent( - QnATelemetryConstants.QnaMsgEvent, - eventData.Properties, - eventData.Metrics - ); - } - - } - } - ``` - -4. Modify your bot to use the new class, instead of creating a `QnAMaker` object you will create a `MyQnAMaker` object in `QnABot.cs`: - - ```cs - var qnaMaker = new MyQnAMaker(new QnAMakerEndpoint - { - KnowledgeBaseId = _configuration["QnAKnowledgebaseId"], - EndpointKey = _configuration["QnAEndpointKey"], - Host = _configuration["QnAEndpointHostName"] - }, - null, - httpClient, - _telemetryClient); - ``` - -##### Viewing telemetry data logged from the new property _MyImportantProperty_ -After running your bot in the emulator you can view the results in Application Insights by doing the following: - -1. Switch back to your browser that has the _Logs (Analytics)_ view active. - -2. Enter the following Kusto query and then select _Run_. This will give a count of the number of times the new property was executed: - - ```SQL - customEvents - | where name == 'QnaMessage' - | extend MyImportantProperty = tostring(customDimensions.MyImportantProperty) - | summarize count() by MyImportantProperty - ``` - -3. To show details instead of the count remove the last line and re-run the query: - - ```SQL - customEvents - | where name == 'QnaMessage' - | extend MyImportantProperty = tostring(customDimensions.MyImportantProperty) - ``` -### Adding new events with custom properties -If you need to log data to a different event than `QnaMessage`, you can create your own custom event with its own properties. To do this, we will add code to the end of the `MyQnAMaker` class as follows: - -```CS -public class MyQnAMaker : QnAMaker -{ - ... - - // Create second event. - var secondEventProperties = new Dictionary(); - - // Create new property for the second event. - secondEventProperties.Add( - "MyImportantProperty2", - "myImportantValue2"); - - // Log secondEventProperties event - TelemetryClient.TrackEvent( - "MySecondEvent", - secondEventProperties); - -} -``` -## The Application Insights dashboard - -Anytime you create an Application Insights resource in Azure, a new dashboard will automatically be created and associated with it. You can see that dashboard by selecting the button at the top of your Application Insights blade, labeled **Application Dashboard**. - -![Application Dashboard Link](media/Application-Dashboard-Link.png) - - -Alternatively, to view the data, go to the Azure portal. Click **Dashboard** on the left, then select the dashboard you want from the drop-down. - -There you'll see some default information about your bot performance and any additional queries that you've pinned to your dashboard. - - -## Additional Information - -* [Add telemetry to your bot](bot-builder-telemetry.md) - -* [What is Application Insights?](https://aka.ms/appinsights-overview) - -* [Using Search in Application Insights](https://aka.ms/search-in-application-insights) - -* [Create custom KPI dashboards using Azure Application Insights](https://aka.ms/custom-kpi-dashboards-application-insights) diff --git a/articles/v4sdk/bot-builder-telemetry-reference.md b/articles/v4sdk/bot-builder-telemetry-reference.md deleted file mode 100644 index e8b8496e8..000000000 --- a/articles/v4sdk/bot-builder-telemetry-reference.md +++ /dev/null @@ -1,234 +0,0 @@ ---- -title: Events generated by the Bot Framework Service telemetry - Bot Service -description: Learn what events are triggered with the new telemetry features. -keywords: telemetry, appinsights, monitor bot -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Events generated by the Bot Framework Service telemetry - -## Channel service events - -In addition to `WaterfallDialog`, which was discussed in the [telemetry topic](bot-builder-telemetry.md) and which generates events from your bot code, the Bot Framework Channel service also logs events. This helps you diagnose issues with Channels or overall bot failures. - -### CustomEvent: "Activity" -**Logged From:** Channel Service -Logged by the Channel Service when a message received. - -### Exception: "Bot Errors" -**Logged From:** Channel Service -Logged by the channel when a call to the Bot returns a non-2XX Http Response. - -## CustomEvent: "WaterfallStart" - -When a WaterfallDialog begins, a `WaterfallStart` event is logged. - -- `user_id` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `session_id` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.activityId` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.activityType` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.channelId` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.DialogId` (This is the dialogId (string) passed into your Waterfall. You can consider this the "waterfall type") -- `customDimensions.InstanceID` (unique per instance of the dialog) - -## CustomEvent: "WaterfallStep" - -Logs individual steps from a Waterfall Dialog. - -- `user_id` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `session_id` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.activityId` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.activityType` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.channelId` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.DialogId` (This is the dialogId (string) passed into your Waterfall. You can consider this the "waterfall type") -- `customDimensions.StepName` (either method name or `StepXofY` if lambda) -- `customDimensions.InstanceID` (unique per instance of the dialog) - -## CustomEvent: "WaterfallDialogComplete" - -Logs when a Waterfall Dialog completes. - -- `user_id` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `session_id` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.activityId` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.activityType` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.channelId` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.DialogId` (This is the dialogId (string) passed into your Waterfall. You can consider this the "waterfall type") -- `customDimensions.InstanceID` (unique per instance of the dialog) - -## CustomEvent: "WaterfallDialogCancel" - -Logs when a Waterfall Dialog is canceled. - -- `user_id` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `session_id` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.activityId` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.activityType` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.channelId` ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- `customDimensions.DialogId` (This is the dialogId (string) passed into your Waterfall. You can consider this the "waterfall type") -- `customDimensions.StepName` (either method name or `StepXofY` if lambda) -- `customDimensions.InstanceID` (unique per instance of the dialog) - -## CustomEvent: BotMessageReceived -Logged when bot receives new message from a user. - -When not overridden, this event is logged from `Microsoft.Bot.Builder.TelemetryLoggerMiddleware` using the `Microsoft.Bot.Builder.IBotTelemetry.TrackEvent()` method. - -- Session Identifier - - When using Application Insights, this is logged from the `TelemetryBotIdInitializer` as the **session** identifier (*Temeletry.Context.Session.Id*) used within Application Insights. - - Corresponds to the [Conversation ID](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#conversation) as defined by Bot Framework protocol.. - - The property name logged is `session_id`. - -- User Identifier - - When using Application Insights, this is logged from the `TelemetryBotIdInitializer` as the **user** identifier (*Telemetry.Context.User.Id*) used within Application Insights. - - The value of this property is a combination of the [Channel Identifier](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#channel-id) and the [User ID](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#from) (concatenated together) properties as defined by the Bot Framework protocol. - - The property name logged is `user_id`. - -- ActivityID - - When using Application Insights, this is logged from the `TelemetryBotIdInitializer` as a Property to the event. - - Corresponds to the [Activity ID](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#Id) as defined by Bot Framework protocol.. - - The property name is `activityId`. - -- Channel Identifier - - When using Application Insights, this is logged from the `TelemetryBotIdInitializer` as a Property to the event. - - Corresponds to the [Channel Identifier](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#id) of the Bot Framework protocol. - - The property name logged is `channelId`. - -- ActivityType - - When using Application Insights, this is logged from the `TelemetryBotIdInitializer` as a Property to the event. - - Corresponds to the [Activity Type](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#type) of the Bot Framework protocol. - - The property name logged is `activityType`. - -- Text - - **Optionally** logged when the `logPersonalInformation` property is set to `true`. - - Corresponds to the [Activity Text](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#text) field of the Bot Framework protocol. - - The property name logged is `text`. - -- Speak - - - **Optionally** logged when the `logPersonalInformation` property is set to `true`. - - Corresponds to the [Activity Speak](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#speak) field of the Bot Framework protocol. - - The property name logged is `speak`. - - - - -- FromId - - Corresponds to the [From Identifier](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#from) field of the Bot Framework protocol. - - The property name logged is `fromId`. - -- FromName - - **Optionally** logged when the `logPersonalInformation` property is set to `true`. - - Corresponds to the [From Name](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#from) field of the Bot Framework protocol. - - The property name logged is `fromName`. - -- RecipientId - - Corresponds to the [From Name](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#from) field of the Bot Framework protocol. - - The property name logged is `fromName`. - -- RecipientName - - Corresponds to the [From Name](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#from) field of the Bot Framework protocol. - - The property name logged is `fromName`. - -- ConversationId - - Corresponds to the [From Name](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#from) field of the Bot Framework protocol. - - The property name logged is `fromName`. - -- ConversationName - - Corresponds to the [From Name](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#from) field of the Bot Framework protocol. - - The property name logged is `fromName`. - -- Locale - - Corresponds to the [From Name](https://github.com/Microsoft/BotBuilder/blob/master/specs/botframework-activity/botframework-activity.md#from) field of the Bot Framework protocol. - - The property name logged is `fromName`. - -## CustomEvent: BotMessageSend -**Logged From:** TelemetryLoggerMiddleware - -Logged when bot sends a message. - -- UserID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- SessionID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- ActivityID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- Channel ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- ActivityType ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- ReplyToID -- RecipientId -- ConversationName -- Locale -- RecipientName (Optional for PII) -- Text (Optional for PII) -- Speak (Optional for PII) - - -## CustomEvent: BotMessageUpdate -**Logged From:** TelemetryLoggerMiddleware -Logged when a message is updated by the bot (rare case) -- UserID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- SessionID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- ActivityID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- Channel ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- ActivityType ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- RecipientId -- ConversationId -- ConversationName -- Locale -- Text (Optional for PII) - - -## CustomEvent: BotMessageDelete -**Logged From:** TelemetryLoggerMiddleware -Logged when a message is deleted by the bot (rare case) -- UserID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- SessionID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- ActivityID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- Channel ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- ActivityType ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- RecipientId -- ConversationId -- ConversationName - -## CustomEvent: LuisEvent -**Logged From:** LuisRecognizer - -Logs results from LUIS service. - -- UserID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- SessionID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- ActivityID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- Channel ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- ActivityType ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- ApplicationId -- Intent -- IntentScore -- Intent2 -- IntentScore2 -- FromId -- SentimentLabel -- SentimentScore -- Entities (as json) -- Question (Optional for PII) - -## CustomEvent: QnAMessage -**Logged From:** QnAMaker - -Logs results from QnA Maker service. - -- UserID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- SessionID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- ActivityID ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- Channel ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- ActivityType ([From Telemetry Initializer](https://aka.ms/telemetry-initializer)) -- Username (Optional for PII) -- Question (Optional for PII) -- MatchedQuestion -- QuestionId -- Answer -- Score -- ArticleFound - diff --git a/articles/v4sdk/bot-builder-telemetry.md b/articles/v4sdk/bot-builder-telemetry.md deleted file mode 100644 index 0b21862fe..000000000 --- a/articles/v4sdk/bot-builder-telemetry.md +++ /dev/null @@ -1,688 +0,0 @@ ---- -title: Add telemetry to your bot - Bot Service -description: Learn how to integrate your bot with the new telemetry features. -keywords: telemetry, appinsights, monitor bot -author: WashingtonKayaker -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 07/17/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Add telemetry to your bot - -[!INCLUDE[applies-to](../includes/applies-to.md)] - - -Telemetry logging was added to version 4.2 of the Bot Framework SDK. This enables bot applications to send event data to telemetry services such as [Application Insights](https://aka.ms/appinsights-overview). Telemetry offers insights into your bot by showing which features are used the most, detects unwanted behavior and offers visibility into availability, performance, and usage. - -***Note: In version 4.6, the standard method for implementing telemetry into a bot has been updated in order to ensure telemetry is logged correctly when using a custom adapter. This article has been updated to show the updated method. The changes are backwards compatible and bots using the previous method will continue to log telemetry correctly.*** - - -In this article you will learn how to implement telemetry into your bot using Application Insights: - -* The code required to wire up telemetry in your bot and connect to Application Insights - -* Enabling telemetry in your bots [Dialogs](bot-builder-concept-dialog.md) - -* Enabling telemetry to capture usage data from other services like [LUIS](bot-builder-howto-v4-luis.md) and [QnA Maker](bot-builder-howto-qna.md). - -* Visualizing your telemetry data in Application Insights - -## Prerequisites - -* The [CoreBot sample code](https://aka.ms/cs-core-sample) - -* The [Application Insights sample code](https://aka.ms/csharp-corebot-app-insights-sample) - -* A subscription to [Microsoft Azure](https://portal.azure.com/) - -* An [Application Insights key](../bot-service-resources-app-insights-keys.md) - -* Familiarity with [Application Insights](https://aka.ms/appinsights-overview) - -> [!NOTE] -> The [Application Insights sample code](https://aka.ms/csharp-corebot-app-insights-sample) was built on top of the [CoreBot sample code](https://aka.ms/cs-core-sample). This article will step you through modifying the CoreBot sample code to incorporate telemetry. If you are following along in Visual Studio you will have the Application Insights sample code by the time we are finished. - -## Wiring up telemetry in your bot - -We will start with the [CoreBot sample app](https://aka.ms/cs-core-sample) and add the code required to integrate telemetry into any bot. This will enable Application Insights to begin tracking requests. - -1. Open the [CoreBot sample app](https://aka.ms/cs-core-sample) in Visual Studio - -2. Add the `Microsoft.Bot.Builder.Integration.ApplicationInsights.Core ` NuGet package. For more information on using NuGet, see [Install and manage packages in Visual Studio](https://aka.ms/install-manage-packages-vs): - - -3. Include the following statements in `Startup.cs`: - ```csharp - using Microsoft.ApplicationInsights.Extensibility; - using Microsoft.Bot.Builder.ApplicationInsights; - using Microsoft.Bot.Builder.Integration.ApplicationInsights.Core; - using Microsoft.Bot.Builder.Integration.AspNet.Core; - ``` - - Note: If you're following along by updating the CoreBot sample code you will notice that the using statement for `Microsoft.Bot.Builder.Integration.AspNet.Core` already exists in the CoreBot sample. - -4. Include the following code in the `ConfigureServices()` method in `Startup.cs`. This will make telemetry services available to your bot via [dependency injection (DI)](https://aka.ms/asp.net-core-dependency-interjection): - ```csharp - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - ... - // Create the Bot Framework Adapter with error handling enabled. - services.AddSingleton(); - - // Add Application Insights services into service collection - services.AddApplicationInsightsTelemetry(); - - // Create the telemetry client. - services.AddSingleton(); - - // Add telemetry initializer that will set the correlation context for all telemetry items. - services.AddSingleton(); - - // Add telemetry initializer that sets the user ID and session ID (in addition to other bot-specific properties such as activity ID) - services.AddSingleton(); - - // Create the telemetry middleware to initialize telemetry gathering - services.AddSingleton(); - - // Create the telemetry middleware (used by the telemetry initializer) to track conversation events - services.AddSingleton(); - ... - } - ``` - - Note: If your following along by updating the CoreBot sample code you will notice that `services.AddSingleton();` already exists - -5. Instruct the adapter to use the middleware code that was added to the `ConfigureServices()` method. You do this in `AdapterWithErrorHandler.cs` with the parameter TelemetryInitializerMiddleware telemetryInitializerMiddleware in the constructors parameter list, and the `Use(telemetryInitializerMiddleware);` statement in the contructor as shown here: - ```csharp - public AdapterWithErrorHandler(IConfiguration configuration, ILogger logger, TelemetryInitializerMiddleware telemetryInitializerMiddleware, ConversationState conversationState = null) - : base(configuration, logger) - { - ... - Use(telemetryInitializerMiddleware); - } - ``` - -6. You will also need to add `Microsoft.Bot.Builder.Integration.ApplicationInsights.Core` to your list of using statements in `AdapterWithErrorHandler.cs`. - -7. Add the Application Insights instrumentation key in your `appsettings.json` file The `appsettings.json` file contains metadata about external services the Bot uses while running. For example, CosmosDB, Application Insights and the Language Understanding (LUIS) service connection and metadata is stored there. The addition to your `appsettings.json` file must be in this format: - - ```json - { - "MicrosoftAppId": "", - "MicrosoftAppPassword": "", - "ApplicationInsights": { - "InstrumentationKey": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - } - } - ``` - Note: Details on getting the _Application Insights instrumentation key_ can be found in the article [Application Insights keys](../bot-service-resources-app-insights-keys.md). - -At this point the preliminary work to enable telemetry using Application Insights is done. You can run your bot locally using the bot emulator and then go into Application Insights to see what is being logged such as response time, overall app health, and general running information. - -## Enabling / disabling activity event and personal information logging - -### Enabling or disabling Activity logging - -By default, the `TelemetryInitializerMiddleware` will use the `TelemetryLoggerMiddleware` to log telemetry when your bot sends / receives activities. Activity logging creates custom event logs in your Application Insights resource. If you wish, you can disable activity event logging by setting `logActivityTelemetry` to false on the `TelemetryInitializerMiddleware` when registering it in **Startup.cs**. - -```cs -public void ConfigureServices(IServiceCollection services) -{ - ... - // Add the telemetry initializer middleware - services.AddSingleton(sp => - { - var httpContextAccessor = sp.GetService(); - var loggerMiddleware = sp.GetService(); - return new TelemetryInitializerMiddleware(httpContextAccessor, loggerMiddleware, logActivityTelemetry: false); - }); - ... -} -``` - -The addition of `IHttpContextAccessor` will also require that you reference the Microsoft ASPNetCore HTTP library, which you achieve with the addition of this using statement: - -```cs -using Microsoft.AspNetCore.Http; -``` - -### Enable or disable logging personal information - -By default, if activity logging is enabled, some properties on the incoming / outgoing activities are excluded from logging as they are likely to contain personal information, such as user name and the activity text. You can choose to include these properties in your logging by making the following change to **Startup.cs** when registering the `TelemetryLoggerMiddleware`. - -```cs -public void ConfigureServices(IServiceCollection services) -{ - ... - // Add the telemetry initializer middleware - services.AddSingleton(sp => - { - var telemetryClient = sp.GetService(); - return new TelemetryLoggerMiddleware(telemetryClient, logPersonalInformation: true); - }); - ... -} -``` - -Next we will see what needs to be included to add telemetry functionality to the dialogs. This will enable you to get additional information such as what dialogs run, and statistics about each one. - -## Enabling telemetry in your bots Dialogs - -When adding a new dialog to any ComponentDialog, it will inherit the Microsoft.Bot.Builder.IBotTelemetryClient of its parent dialog. For example, In the CoreBot sample application all dialogs are added to the MainDialog which is a ComponentDialog. Once you set the TelemetryClient property to the MainDialog all dialogs added to it will automatically inherit the telemetryClient from it, so it does not need to be explicitly set when adding dialogs. - - Follow the steps below to update your CoreBot example: - -1. In `MainDialog.cs`, update the constructor's parameter list to include the `IBotTelemetryClient` parameter, then set the MainDialog's TelemetryClient property to that value as shown in the following code snippet: - - ```csharp - public MainDialog(IConfiguration configuration, ILogger logger, IBotTelemetryClient telemetryClient) - : base(nameof(MainDialog)) - { - // Set the telemetry client for this and all child dialogs. - this.TelemetryClient = telemetryClient; - ... - } - ``` - -> [!TIP] -> If you are following along and updating the CoreBot sample code, you can refer to the [Application Insights sample code](https://aka.ms/csharp-corebot-app-insights-sample) if you run into any problems. - -That's all there is to adding telemetry to your bots dialogs, at this point if you ran your bot you should see things being logged in Application Insights, however if you have any integrated technology such as LUIS and QnA Maker you will need to add the `TelemetryClient` to that code as well. - - -## Enabling telemetry to capture usage data from other services like LUIS and QnA Maker - -We will next implement telemetry functionality in your LUIS service. The LUIS service has built-in telemetry logging available so there is very little you need to do to start getting telemetry data from LUIS. If you are interested in enabling telemetry in a QnA Maker enabled bot, see [Add telemetry to your QnAMaker bot](bot-builder-telemetry-QnAMaker.md) - -1. The _`IBotTelemetryClient telemetryClient`_ parameter is required in the `FlightBookingRecognizer` constructor in `FlightBookingRecognizer.cs`: - - ```cs - public FlightBookingRecognizer(IConfiguration configuration, IBotTelemetryClient telemetryClient) - ``` - -2. Next you will need to enable the `telemetryClient` when creating your `LuisRecognizer` in the `FlightBookingRecognizer` constructor. You do this by adding the `telemetryClient` as a new _LuisPredictionOption_: - - ```cs - if (luisIsConfigured) - { - var luisApplication = new LuisApplication( - configuration["LuisAppId"], - configuration["LuisAPIKey"], - "https://" + configuration["LuisAPIHostName"]); - - // Set the recognizer options depending on which endpoint version you want to use. - // More details can be found in https://docs.microsoft.com/en-gb/azure/cognitive-services/luis/luis-migration-api-v3 - var recognizerOptions = new LuisRecognizerOptionsV3(luisApplication) - { - TelemetryClient = telemetryClient, - }; - _recognizer = new LuisRecognizer(recognizerOptions); - } - ``` - -3. You will need to have your LUIS - -That's it, you should have a functional bot that logs telemetry data into Application insights. You can use the [Bot Framework Emulator](https://aka.ms/bot-framework-emulator-readme) to run your bot locally. You shouldn't see any changes in the bot's behavior, but it will be logging information into Application Insights. Interact with the bot by sending multiple messages and in the next section we will review the telemetry results in Application Insights. - -For information on testing and debugging your bot, you can refer to the following articles: - - * [Debug a bot](../bot-service-debug-bot.md) - * [Testing and debugging guidelines](bot-builder-testing-debugging.md) - * [Debug with the emulator](../bot-service-debug-emulator.md) - - -## Visualizing your telemetry data in Application Insights -Application Insights monitors the availability, performance, and usage of your bot application whether it's hosted in the cloud or on-premises. It leverages the powerful data analysis platform in Azure Monitor to provide you with deep insights into your application's operations and diagnose errors without waiting for a user to report them. There are a few ways to see the telemetry data collected by Application Insights, two of the primary ways are through queries and the dashboard. - -### Querying your telemetry data in Application Insights using Kusto Queries -Use this section as a starting point to learn how to use log queries in Application Insights. It demonstrates two useful queries and provides links to other documentation with additional information. - -To query your data - -1. Go to the [Azure portal](https://portal.azure.com) -2. Navigate to your Application Insights. Easiest way to do so is click on **Monitor > Applications** and find it there. -3. Once in your Application Insights, you can click on _Logs (Analytics)_ on the navigation bar. - - ![Logs (Analytics)](media/AppInsights-LogView.png) - -4. This will bring up the Query window. Enter the following query and select _Run_: - - ```sql - customEvents - | where name=="WaterfallStart" - | extend DialogId = customDimensions['DialogId'] - | extend InstanceId = tostring(customDimensions['InstanceId']) - | join kind=leftouter (customEvents | where name=="WaterfallComplete" | extend InstanceId = tostring(customDimensions['InstanceId'])) on InstanceId - | summarize starts=countif(name=='WaterfallStart'), completes=countif(name1=='WaterfallComplete') by bin(timestamp, 1d), tostring(DialogId) - | project Percentage=max_of(0.0, completes * 1.0 / starts), timestamp, tostring(DialogId) - | render timechart - ``` -5. This will return the percentage of waterfall dialogs that run to completion. - - ![Logs (Analytics)](media/AppInsights-Query-PercentCompleteDialog.png) - - -> [!TIP] -> You can pin any query to your Application Insights dashboard by selecting the button on the top right of the **Logs (Analytics)** blade. Just select the dashboard you want it pinned to, and it will be available next time you visit that dashboard. - - -## The Application Insights dashboard - -Anytime you create an Application Insights resource in Azure, a new dashboard will automatically be created and associated with it. You can see that dashboard by selecting the button at the top of your Application Insights blade, labeled **Application Dashboard**. - -![Application Dashboard Link](media/Application-Dashboard-Link.png) - - -Alternatively, to view the data, go to the Azure portal. Click **Dashboard** on the left, then select the dashboard you want from the drop-down. - -There, you'll see some default information about your bot performance and any additional queries that you've pinned to your dashboard. - - - -## Additional Information - -* [Add telemetry to your QnAMaker bot](bot-builder-telemetry-qnamaker.md) - -* [What is Application Insights?](https://aka.ms/appinsights-overview) - -* [Using Search in Application Insights](https://aka.ms/search-in-application-insights) - -* [Create custom KPI dashboards using Azure Application Insights](https://aka.ms/custom-kpi-dashboards-application-insights) - - - - - diff --git a/articles/v4sdk/bot-builder-testing-debugging.md b/articles/v4sdk/bot-builder-testing-debugging.md deleted file mode 100644 index 1448af4c2..000000000 --- a/articles/v4sdk/bot-builder-testing-debugging.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: Debugging guidelines - Bot Service -description: Understand how to debug your bot. -keywords: debugging bots, botframework debugging -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 07/17/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Debugging guidelines - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -Bots are complex apps, with a lot of different parts working together. Like any other complex app, this can lead to some interesting bugs or cause your bot to behave differently than expected. - -Debugging, your bot can sometimes be a difficult task. Every developer has their own preferred way to accomplish that task; guidelines we present below are suggestions for you to use that apply to a large majority of bots. - -After verifying your bot appears to work how you’d like it to, the next step is connecting it to a channel. To do this, you can deploy your bot to a staging server and create your own direct line client for your bot to connect to. - - -Creating your own client allows you to define the inner workings of the channel, as well as specifically test how your bot responds to certain activity exchanges. Once connected to your client, run your tests to set up your bot state and verify your features. If your bot utilizes a feature like speech, using these channels can offer a way to verify that functionality. - -Use of both the Emulator and Web Chat via Azure portal here can provide further insight into how your bot performs while interacting with different channels. - -Debugging your bot works similarly to other multi-threaded apps, with the ability to set breakpoints or use features like the immediate window. - -Bots follow an event driven programming paradigm, which can be hard to rationalize if you’re not familiar with it. The idea of your bot being stateless, multi-threaded, and dealing with async/await calls can result in unexpected bugs. While debugging your bot works similarly to other multi-threaded apps, we’ll cover some suggestions, tools, and resources to help. - -## Understanding bot activities with the emulator - -Your bot deals with different types of [activities](bot-builder-basics.md#the-activity-processing-stack) besides the normal _message_ activity. Using the [emulator](../bot-service-debug-emulator.md) will show you what those activities are, when they happen, and what information they contain. Understanding those activities will help you code your bot efficiently and allows you to verify the activities your bot is sending and receiving are what you expect. - -## Saving and retrieving user interactions with transcripts - -Azure blob transcript storage provides a specialized resource where you can both [store and retrieve transcripts](bot-builder-howto-v4-storage.md) containing interactions between your users and your bot. - -Additionally, once user input interactions have been stored, you can use Azure's "_storage explorer_" to manually view data contained in transcripts stored within your blob transcript store. The following example opens "_storage explorer_" from settings for "_mynewtestblobstorage_." To open a saved user input select: Blob Container > ChannelId > TranscriptId > ConversationId - -![Examine_stored_transcript_text](./media/examine_transcript_text_in_azure.png) - -This opens the stored user conversation input in JSON format. User input is preserved together with the key "_text:_." - -## How middleware works - -[Middleware](bot-builder-concept-middleware.md) may not be intuitive when first attempting to use it, particularly regarding the continuation, or short-circuiting, of execution. Middleware can execute on the leading or trailing edge of a turn, with a call to the `next()` delegate dictating when execution is passed to the bot logic. - -If you are using multiple pieces of middleware the delegate may pass execution to a different piece of middleware if that is how your pipeline is oriented. Details on [the bot middleware pipeline](bot-builder-concept-middleware.md#the-bot-middleware-pipeline) can help make that idea clearer. - -If the `next()` delegate is not called, that’s referred to as [short circuit routing](bot-builder-concept-middleware.md#short-circuiting). This happens when the middleware satisfies the current activity and determines it’s not necessary to pass execution on. - -Understanding when, and why, middleware short-circuits helps indicate which piece of middleware should come first in your pipeline. Additionally, understanding what to expect is particularly important for built-in middleware provided by the SDK or other developers. Some find it helpful to try creating your own middleware first to experiment a bit before diving into the built-in middleware. - - - -## Understanding state - -Keeping track of state is an important part of your bot, particularly for complex tasks. In general, best practice is to process activities as quickly as possible and let the processing complete so that state gets persisted. Activities can be sent to your bot at nearly the same time, and that can introduce very confusing bugs because of the asynchronous architecture. - -Most importantly, make sure that state is persisting in a way that matches your expectations. Depending on where your persisted state lives, storage emulators for [Cosmos DB](https://docs.microsoft.com/azure/cosmos-db/local-emulator) and [Azure Table storage](https://docs.microsoft.com/azure/storage/common/storage-use-emulator) can help you verify that state before using production storage. - -## How to use activity handlers - -Activity handlers can introduce another layer of complexity, particularly since each activity runs on an independent thread (or web workers, depending on your language). Depending on what your handlers are doing, this can cause issues where the current state is not what you expect. - -Built-in state gets written at the end of a turn, however any activities generated by that turn are executing independently of the turn pipeline. Often this doesn’t impact us, but if an activity handler changes state we need the state written to contain that change. In that case, the turn pipeline can wait on the activity to finish processing before completing to make sure it records the correct state for that turn. - -The _send activity_ method, and its handlers, pose a unique problem. Simply calling _send activity_ from within the _on send activities_ handler causes an infinite forking of threads. There are ways you can work around that problem, such as by appending additional messages to the outgoing information or writing out to another location like the console or a file to avoid crashing your bot. - -## Next steps - -> [!div class="nextstepaction"] -> [How to unit test bots](unit-test-bots.md) - -## Additional resources - -* [Debugging in Visual Studio](https://docs.microsoft.com/visualstudio/debugger/index) -* [Debugging, Tracing, and Profiling](https://docs.microsoft.com/dotnet/framework/debug-trace-profile/) for the bot framework -* Use the [ConditionalAttribute](https://docs.microsoft.com/dotnet/api/system.diagnostics.conditionalattribute?view=netcore-2.0) for methods you don't want to include in production code -* Use tools like [Fiddler](https://www.telerik.com/fiddler) to see network traffic -* [Troubleshoot general problems](../bot-service-troubleshoot-bot-configuration.md) and the other troubleshooting articles in that section diff --git a/articles/v4sdk/bot-builder-tutorial-add-qna.md b/articles/v4sdk/bot-builder-tutorial-add-qna.md deleted file mode 100644 index 9f3003fae..000000000 --- a/articles/v4sdk/bot-builder-tutorial-add-qna.md +++ /dev/null @@ -1,437 +0,0 @@ ---- -title: Azure Bot Service tutorial to have a bot answer questions - Bot Service -description: Tutorial to use QnA Maker in your bot to answer questions. -keywords: QnA Maker, question and answer, knowledge base -author: JonathanFingold -ms.author: kamrani -manager: kamrani -ms.topic: tutorial -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Tutorial: Use QnA Maker in your bot to answer questions - -[!INCLUDE [applies-to-v4](../includes/applies-to.md)] - -You can use the QnA Maker service and a knowledge base to add question-and-answer support to your bot. When you create your knowledge base, you seed it with questions and answers. - -In this tutorial, you learn how to: - -> [!div class="checklist"] -> * Create a QnA Maker service and knowledge base -> * Add knowledge base information to your configuration file -> * Update your bot to query the knowledge base -> * Republish your bot - -If you don’t have an Azure subscription, create a [free account](https://azure.microsoft.com/free/?WT.mc_id=A261C142F) before you begin. - -## Prerequisites - -* The bot created in the [previous tutorial](bot-builder-tutorial-basic-deploy.md). We will add a question-and-answer feature to the bot. -* Some familiarity with [QnA Maker](https://qnamaker.ai/) is helpful. We will use the QnA Maker portal to create, train, and publish the knowledge base to use with the bot. -* Familiarity with [QnA bot creation](https://aka.ms/azure-create-qna) using Azure Bot Service. - -You should also already have the prerequisites for the previous tutorial. - -## Sign in to QnA Maker portal - - - -Sign into to the [QnA Maker portal](https://qnamaker.ai/) with your Azure credentials. - -## Create a QnA Maker service and knowledge base - -We will import an existing knowledge base definition from the QnA Maker sample in the [Microsoft/BotBuilder-Samples](https://github.com/Microsoft/BotBuilder-Samples) repo. - -1. Clone or copy the samples repo to your computer. -1. In the QnA Maker portal, **create a knowledge base**. - 1. If necessary, create a QnA service. (You can use an existing QnA Maker service or create a new one for this tutorial.) For more detailed QnA Maker instructions, see [Create a QnA Maker service](https://docs.microsoft.com/azure/cognitive-services/qnamaker/how-to/set-up-qnamaker-service-azure) and [Create, train, and publish your QnA Maker knowledge base](https://docs.microsoft.com/azure/cognitive-services/qnamaker/quickstarts/create-publish-knowledge-base). - 1. Connect your QnA service to your knowledge base. - 1. Name your knowledge base. - 1. To populate your knowledge base, use the `BotBuilder-Samples\samples\csharp_dotnetcore\11.qnamaker\CognitiveModels\smartLightFAQ.tsv` file from the samples repo. If you have downloaded the samples, upload the file *smartLightFAQ.tsv* from your computer. - 1. Click **Create your kb** to create the knowledge base. -1. **Save and train** your knowledge base. -1. **Publish** your knowledge base. - -Once your QnA Maker app is published, select the **SETTINGS** tab, and scroll down to *Deployment details*. Copy the following values from the *Postman* HTTP example request. - -```text -POST /knowledgebases//generateAnswer -Host: // NOTE - this is a URL ending in /qnamaker. -Authorization: EndpointKey -``` - -The full URL string for your hostname will look like "https://< >.azure.net/qnamaker". - -These values will be used within your `appsettings.json` or `.env` file in the next step. - -The knowledge base is now ready for your bot to use. - -## Add knowledge base information to your bot - -Beginning with bot framework v4.3 Azure no longer provides a .bot file as part of your downloaded bot source code. Use the following instructions connect your CSharp, JavaScript or Python bot to your knowledge base. - -# [C#](#tab/csharp) - -Add the following values to you appsetting.json file: - -```json -{ - "MicrosoftAppId": "", - "MicrosoftAppPassword": "", - "ScmType": "None", - - "QnAKnowledgebaseId": "knowledge-base-id", - "QnAAuthKey": "qna-maker-resource-key", - "QnAEndpointHostName": "your-hostname" // This is a URL ending in /qnamaker -} -``` - -# [JavaScript](#tab/javascript) - -Add the following values to your .env file: - -``` -MicrosoftAppId="" -MicrosoftAppPassword="" -ScmType=None - -QnAKnowledgebaseId="knowledge-base-id" -QnAAuthKey="qna-maker-resource-key" -QnAEndpointHostName="your-hostname" // This is a URL ending in /qnamaker -``` - -# [Python](#tab/python) - -Add the following values to your `config.py` file: - -```python -class DefaultConfig: - """ Bot Configuration """ - PORT = 3978 - APP_ID = os.environ.get("MicrosoftAppId", "") - APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "") - - QNA_KNOWLEDGEBASE_ID = os.environ.get("QnAKnowledgebaseId", "") - QNA_ENDPOINT_KEY = os.environ.get("QnAEndpointKey", "") - QNA_ENDPOINT_HOST = os.environ.get("QnAEndpointHostName", "") - -``` - ---- - -| Field | Value | -|:----|:----| -| QnAKnowledgebaseId | The knowledge base ID that the QnA Maker portal generated for you. | -| QnAAuthKey (QnAEndpointKey in Python) | The endpoint key that the QnA Maker portal generated for you. | -| QnAEndpointHostName | The host URL that the QnA Maker portal generated. Use the complete URL, starting with `https://` and ending with `/qnamaker`. The full URL string will look like "look like "https://< >.azure.net/qnamaker". | - -Now save your edits. - -## Update your bot to query the knowledge base - -Update your initialization code to load the service information for your knowledge base. - -# [C#](#tab/csharp) - -1. Add the **Microsoft.Bot.Builder.AI.QnA** NuGet package to your project. - - You can do this via the NuGet Package Manager or the command line: - - ```cmd - dotnet add package Microsoft.Bot.Builder.AI.QnA - ``` - - For more information on NuGet, see the [NuGet documentation](https://docs.microsoft.com/nuget/#pivot=start&panel=start-all). - -1. Add the **Microsoft.Extensions.Configuration** NuGet package to your project. - -1. In your **Startup.cs** file, add these namespace references. - - **Startup.cs** - - ```csharp - using Microsoft.Bot.Builder.AI.QnA; - using Microsoft.Extensions.Configuration; - ``` - -1. And, modify the _ConfigureServices_ method create a QnAMakerEndpoint that connects to the knowledge base defined in the **appsettings.json** file. - - **Startup.cs** - - ```csharp - // Create QnAMaker endpoint as a singleton - services.AddSingleton(new QnAMakerEndpoint - { - KnowledgeBaseId = Configuration.GetValue($"QnAKnowledgebaseId"), - EndpointKey = Configuration.GetValue($"QnAAuthKey"), - Host = Configuration.GetValue($"QnAEndpointHostName") - }); - - ``` - -1. In your **EchoBot.cs** file, add these namespace references. - - **EchoBot.cs** - - ```csharp - using System.Linq; - using Microsoft.Bot.Builder.AI.QnA; - ``` - -1. Add a `EchoBotQnA` connector and initialize it in the bot's constructor. - - **EchoBot.cs** - - ```csharp - public QnAMaker EchoBotQnA { get; private set; } - public EchoBot(QnAMakerEndpoint endpoint) - { - // connects to QnA Maker endpoint for each turn - EchoBotQnA = new QnAMaker(endpoint); - } - ``` - -1. Below the _OnMembersAddedAsync( )_ method create the method _AccessQnAMaker( )_ by adding the following code: - - **EchoBot.cs** - - ```csharp - private async Task AccessQnAMaker(ITurnContext turnContext, CancellationToken cancellationToken) - { - var results = await EchoBotQnA.GetAnswersAsync(turnContext); - if (results.Any()) - { - await turnContext.SendActivityAsync(MessageFactory.Text("QnA Maker Returned: " + results.First().Answer), cancellationToken); - } - else - { - await turnContext.SendActivityAsync(MessageFactory.Text("Sorry, could not find an answer in the Q and A system."), cancellationToken); - } - } - ``` - -1. Now within _OnMessageActivityAsync( )_ call your new method _AccessQnAMaker( )_ as follows: - - **EchoBot.cs** - - ```csharp - protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) - { - await turnContext.SendActivityAsync(MessageFactory.Text($"Echo: {turnContext.Activity.Text}"), cancellationToken); - - await AccessQnAMaker(turnContext, cancellationToken); - } - ``` - -# [JavaScript](#tab/javascript) - -1. Open a terminal or command prompt to the root directory for your project. -1. Add the **botbuilder-ai** npm package to your project. - ```shell - npm i botbuilder-ai - ``` - -1. In **index.js**, following the // Create Adapter section, add the following code to read your .env file configuration information needed to generate the QnA Maker services. - - **index.js** - ```javascript - // Map knowledge base endpoint values from .env file into the required format for `QnAMaker`. - const configuration = { - knowledgeBaseId: process.env.QnAKnowledgebaseId, - endpointKey: process.env.QnAAuthKey, - host: process.env.QnAEndpointHostName - }; - - ``` - -1. Update the bot construction to pass in the QnA services configuration information. - - **index.js** - ```javascript - // Create the main dialog. - const myBot = new MyBot(configuration, {}); - ``` - -1. In your **bot.js** file, add this require for QnAMaker - - **bot.js** - ```javascript - const { QnAMaker } = require('botbuilder-ai'); - ``` - -1. Modify the constructor to now receive passed configuration parameters required to create a QnAMaker connector and throw an error if these parameters are not provided. - - **bot.js** - ```javascript - class MyBot extends ActivityHandler { - constructor(configuration, qnaOptions) { - super(); - if (!configuration) throw new Error('[QnaMakerBot]: Missing parameter. configuration is required'); - // now create a qnaMaker connector. - this.qnaMaker = new QnAMaker(configuration, qnaOptions); - ``` - -1. Finally, update your `onMessage` function to query your knowledge bases for an answer. Pass each user input to your QnA Maker knowledge base, and return the first QnA Maker response back to the user. - - **bot.js** - - ```javascript - this.onMessage(async (context, next) => { - // send user input to QnA Maker. - const qnaResults = await this.qnaMaker.getAnswers(context); - - // If an answer was received from QnA Maker, send the answer back to the user. - if (qnaResults[0]) { - await context.sendActivity(`QnAMaker returned response: ' ${ qnaResults[0].answer}`); - } - else { - // If no answers were returned from QnA Maker, reply with help. - await context.sendActivity('No QnA Maker response was returned.' - + 'This example uses a QnA Maker Knowledge Base that focuses on smart light bulbs. ' - + `Ask the bot questions like "Why won't it turn on?" or "I need help."`); - } - await next(); - }); - ``` - -# [Python](#tab/python) - -1. Assure that you have installed the packages as described in the samples repository README file. -1. Add the `botbuilder-ai` reference to the `requirements.txt` file, as shown below. - - **requirements.txt** - - ```text - botbuilder-core - botbuilder-ai - flask - ``` - - Notice that the versions may vary. - -1. In the `app.py` file modify the bot instance creation as shown below. - - **app.py** - - ```python - # Create the main dialog - BOT = MyBot(APP.config) - ``` - -1. In the `bot.py` file import `QnAMaker` and `QnAMakerEndpoint`; also import `Config`, as shown below. - - **bot.py** - - ```python - from flask import Config - - from botbuilder.ai.qna import QnAMaker, QnAMakerEndpoint - from botbuilder.core import ActivityHandler, MessageFactory, TurnContext - from botbuilder.schema import ChannelAccount - ``` - -1. Add a __init__ function to instantiate a `qna-maker` object. using the configuration parameters provided in the `config.py` file. - - **bot.py** - - ```python - def __init__(self, config: Config): - self.qna_maker = QnAMaker( - QnAMakerEndpoint( - knowledge_base_id=config["QNA_KNOWLEDGEBASE_ID"], - endpoint_key=config["QNA_ENDPOINT_KEY"], - host=config["QNA_ENDPOINT_HOST"], - ) - ) - - ``` - -1. Update `on_message_activity` to query your knowledge base for an answer. Pass each user input to your QnA Maker knowledge base, and return the first QnA Maker response to the user. - - **bot.py** - - ```python - async def on_message_activity(self, turn_context: TurnContext): - # The actual call to the QnA Maker service. - response = await self.qna_maker.get_answers(turn_context) - if response and len(response) > 0: - await turn_context.send_activity(MessageFactory.text(response[0].answer)) - else: - await turn_context.send_activity("No QnA Maker answers were found.") - - ``` - -1. Optionally, update the welcome message in `on_members_added_activity` for example: - - **bot.py** - - ```python - await turn_context.send_activity("Hello and welcome to QnA!") - ``` - ---- - -### Test the bot locally - -At this point your bot should be able to answer some questions. Run the bot locally and open it in the Emulator. - -![test qna sample](./media/qna-test-bot.png) - -## Republish your bot -You can now republish your bot back to Azure. You need to zip your project folder and then run the command to deploy your bot to Azure. For details please read the [deploy a bot](https://docs.microsoft.com/azure/bot-service/bot-builder-deploy-az-cli?view=azure-bot-service-4.0&tabs=csharp) article. - -### Zip your project folder -[!INCLUDE [zip up code](~/includes/deploy/snippet-zip-code.md)] - - - -### Deploy your code to Azure -[!INCLUDE [deploy code to Azure](~/includes/deploy/snippet-deploy-code-to-az.md)] - - - -If you're not going to continue to use this application, delete -the associated resources with the following steps: - -1. In the Azure portal, open the resource group for your bot. -2. Click **Delete resource group** to delete the group and all the resources it contains. -3. In the confirmation pane, enter the resource group name, and click **Delete**. - -## Next steps - -For information on how to add features to your bot, see the **Send and receive text message** article and the other articles in the how-to develop section. -> [!div class="nextstepaction"] -> [Send and receive text message](bot-builder-howto-send-messages.md) diff --git a/articles/v4sdk/bot-builder-tutorial-basic-deploy.md b/articles/v4sdk/bot-builder-tutorial-basic-deploy.md deleted file mode 100644 index 28cedf741..000000000 --- a/articles/v4sdk/bot-builder-tutorial-basic-deploy.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -title: Tutorial to create and deploy a basic bot - Bot Service -description: Learn how to create a basic bot and then deploy it to Azure. -keywords: echo bot, deploy, azure, tutorial -author: Ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/28/2020 -monikerRange: 'azure-bot-service-4.0' ---- - -# Tutorial: Create and deploy a basic bot - -[!INCLUDE [applies-to-v4](../includes/applies-to.md)] - -This tutorial walks you through creating a basic bot with the Bot Framework SDK and deploying it to Azure. If you've already created a basic bot and have it running locally, skip ahead to the [Deploy your bot](#deploy-your-bot) section. - -In this tutorial, you learn how to: - -> [!div class="checklist"] -> * Create a basic Echo bot -> * Run and interact with it locally -> * Publish your bot - -If you don’t have an Azure subscription, create a [free account](https://azure.microsoft.com/free/?WT.mc_id=A261C142F) before you begin. - -# [C#](#tab/csharp) - -[!INCLUDE [dotnet quickstart](~/includes/quickstart-dotnet.md)] - -# [JavaScript](#tab/javascript) - -[!INCLUDE [javascript quickstart](~/includes/quickstart-javascript.md)] - -# [Python](#tab/python) - -[!INCLUDE [python quickstart](~/includes/quickstart-python.md)] - ---- - -## Deploy your bot - -### Prerequisites -[!INCLUDE [deploy prerequisite](~/includes/deploy/snippet-prerequisite.md)] - -### Prepare for deployment - -> [!TIP] -> This procedure uses a ZIP file to deploy your bot. In C#, this may fail if the solution configuration at build is set to **Debug**. -> In Visual Studio, make sure that the solution configuration is set to **Release** and perform a clean rebuild of the solution before continuing. - -[!INCLUDE [deploy prepare intro](~/includes/deploy/snippet-prepare-deploy-intro.md)] - -#### 1. Login to Azure -[!INCLUDE [deploy az login](~/includes/deploy/snippet-az-login.md)] - -#### 2. Set the subscription -[!INCLUDE [deploy az subscription](~/includes/deploy/snippet-az-set-subscription.md)] - -#### 3. Create an App registration -[!INCLUDE [deploy create app registration](~/includes/deploy/snippet-create-app-registration.md)] - -#### 4. Deploy via ARM template -You can deploy your bot in a new resource group or an existing resource group. Choose the option that works best for you. - -> [!NOTE] -> Python bots cannot be deployed to a resource group that contains Windows services/bots. Multiple Python bots can be deployed to the same resource group, but create other services (LUIS, QnA, etc.) in another resource group. -> - -##### **Deploy via ARM template with new Resource Group** -[!INCLUDE [ARM with new resourece group](~/includes/deploy/snippet-ARM-new-resource-group.md)] - -##### **Deploy via ARM template with existing Resource Group** -[!INCLUDE [ARM with existing resourece group](~/includes/deploy/snippet-ARM-existing-resource-group.md)] - -#### 5. Prepare your code for deployment -##### **Retrieve or create necessary IIS/Kudu files** -[!INCLUDE [retrieve or create IIS/Kudu files](~/includes/deploy/snippet-IIS-Kudu-files.md)] - -##### **Zip up the code directory manually** -[!INCLUDE [zip up code](~/includes/deploy/snippet-zip-code.md)] - -### Deploy code to Azure -[!INCLUDE [deploy code to Azure](~/includes/deploy/snippet-deploy-code-to-az.md)] - -### Test in Web Chat -[!INCLUDE [test in web chat](~/includes/deploy/snippet-test-in-web-chat.md)] - -## Additional resources - -[!INCLUDE [additional resources snippet](~/includes/deploy/snippet-additional-resources.md)] - -## Next steps -> [!div class="nextstepaction"] -> [Use QnA Maker in your bot to answer questions](bot-builder-tutorial-add-qna.md) \ No newline at end of file diff --git a/articles/v4sdk/bot-builder-tutorial-dispatch.md b/articles/v4sdk/bot-builder-tutorial-dispatch.md deleted file mode 100644 index 649b8089f..000000000 --- a/articles/v4sdk/bot-builder-tutorial-dispatch.md +++ /dev/null @@ -1,593 +0,0 @@ ---- -title: Use multiple LUIS and QnA models - Bot Service -description: Learn how to use LUIS and QnA maker in your bot. -keywords: Luis, QnA, Dispatch tool, multiple services, route intents -author: diberry -ms.author: diberry -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 01/27/2020 -monikerRange: 'azure-bot-service-4.0' ---- - -# Use multiple LUIS and QnA models - -[!INCLUDE[applies-to](../includes/applies-to.md)] - -If a bot uses multiple LUIS models and QnA Maker knowledge bases (knowledge bases), you can use Dispatch tool to determine which LUIS model or QnA Maker knowledge base best matches the user input. The dispatch tool does this by creating a single LUIS app to route user input to the correct model. For more information about the Dispatch, including the CLI commands, refer to the [README][dispatch-readme]. - -## Prerequisites - -- Knowledge of [bot basics](bot-builder-basics.md), [LUIS][howto-luis], and [QnA Maker][howto-qna]. -- [Dispatch tool](https://github.com/Microsoft/botbuilder-tools/tree/master/packages/Dispatch) -- A copy of the **NLP with Dispatch** from the [C# Sample][cs-sample], [JS Sample][js-sample], or [Python Sample][python-sample] code repository. -- A [luis.ai](https://www.luis.ai/) account to publish LUIS apps. -- A [QnA Maker](https://www.qnamaker.ai/) account to publish the QnA knowledge base. - -## About this sample - -This sample is based on a predefined set of LUIS and QnA Maker Apps. - -## [C#](#tab/cs) - -![Code sample logic flow](./media/tutorial-dispatch/dispatch-logic-flow.png) - -`OnMessageActivityAsync` is called for each user input received. This module finds the top scoring user intent and passes that result on to `DispatchToTopIntentAsync`. DispatchToTopIntentAsync, in turn, calls the appropriate app handler - -- `ProcessSampleQnAAsync` - for bot faq questions. -- `ProcessWeatherAsync` - for weather queries. -- `ProcessHomeAutomationAsync` - for home lighting commands. - -## [JavaScript](#tab/js) - -![Code sample logic flow](./media/tutorial-dispatch/dispatch-logic-flow-js.png) - -`onMessage` is called for each user input received. This module finds the top scoring user intent and passes that result on to `dispatchToTopIntentAsync`. dispatchToTopIntentAsync, in turn, calls the appropriate app handler - -- `processSampleQnA` - for bot faq questions. -- `processWeather` - for weather queries. -- `processHomeAutomation` - for home lighting commands. - -## [Python](#tab/python) - -![Code sample logic flow](./media/tutorial-dispatch/dispatch-logic-flow-python.png) - -`on_message_activity` is called for each user input received. This module finds the top scoring user intent and passes that result on to `_dispatch_to_top_intent`. _dispatch_to_top_intent, in turn, calls the appropriate app handler - -- `_process_sample_qna` - for bot faq questions. -- `_process_weather` - for weather queries. -- `_process_home_automation` - for home lighting commands. - ---- - -The handler calls the LUIS or QnA Maker service and returns the generated result back to the user. - -## Create LUIS apps and QnA knowledge base - -Before you can create the dispatch model, you'll need to have your LUIS apps and QnA knowledge bases created and published. In this article, we'll publish the following models that are included with the _NLP With Dispatch_ sample in the `\CognitiveModels` folder: - -| Name | Description | -|------|------| -| HomeAutomation | A LUIS app that recognizes a home automation intent with associated entity data.| -| Weather | A LUIS app that recognizes weather-related intents with location data.| -| QnAMaker | A QnA Maker knowledge base that provides answers to simple questions about the bot. | - -### Create LUIS apps - -1. Log into the [LUIS web portal](https://www.luis.ai/). Under the _My apps_ section, select the Tab _Import new app_. The following Dialog Box will appear: - - ![Import LUIS json file](./media/tutorial-dispatch/import-new-luis-app.png) - -2. Select the button _Choose app file_, navigate to the CognitiveModel folder of your sample code and select the file 'HomeAutomation.json'. Leave the optional name field blank. - -3. Select _Done_. - -4. Once LUIS opens up your Home Automation app, select the _Train_ button. This will train your app using the set of utterances you just imported using the 'home-automation.json' file. - -5. When training is complete, select the _Publish_ button. The following Dialog Box will appear: - - ![Publish LUIS app](./media/tutorial-dispatch/publish-luis-app.png) - -6. Choose the 'production' environment and then select the _Publish_ button. - -7. Once your new LUIS app has been published, select the _MANAGE_ Tab. From the 'Application Information' page, record the values `Application ID` as "_app-id-for-app_" and `Display name` as "_name-of-app_". From the 'Key and Endpoints' page, record the values `Authoring Key` as "_your-luis-authoring-key_" and `Region` as "_your-region_". These values will later be used within your 'appsetting.json' file. - -8. Once completed, _Train_ and _Publish_ both your LUIS **Home Automation** app and your LUIS **Weather** app by repeating the above steps for 'Weather.json' file. - -### Create QnA Maker knowledge base - -The first step to setting up a QnA Maker knowledge base is to set up a QnA Maker service in Azure. To do that, follow the step-by-step instructions found [here](https://aka.ms/create-qna-maker). - -Once your QnA Maker Service has been created in Azure, you need to record the Cognitive Services _Key 1_ provided for your QnA Maker service. This will be used as \ when adding the QnA Maker app to your dispatch application. - -Learn more about the [two different types of keys](https://docs.microsoft.com/azure/cognitive-services/qnamaker/how-to/set-up-qnamaker-service-azure#types-of-keys-in-qna-maker) used with QnA Maker. - -The following steps provide you with this key: - -![Select Cognitive Service](./media/tutorial-dispatch/select-qna-cognitive-service.png) - -1. From within your Azure portal, select your QnA Maker cognitive service. - - ![Select Cognitive Service Keys](./media/tutorial-dispatch/select-cognitive-service-keys.png) - -1. Select the Keys icon found under the _Resource Management_ section on the left-hand menu. - - ![Select Cognitive Service Key1](./media/tutorial-dispatch/select-cognitive-service-key1.png) - -1. Copy the value of _Key 1_ to your clipboard and save this locally. this will later be used for the (-k) key value \ when adding the QnA Maker app to your dispatch application. - -1. Now sign in to the [QnAMaker web portal](https://qnamaker.ai). - -1. At step 2, select the following: - - - Your Azure AD account. - - Your Azure subscription name. - - The name you created for your QnA Maker service. (If your Azure QnA service does not initially appear in this pull down list, try refreshing the page.) - - ![Create QnA Step 2](./media/tutorial-dispatch/create-qna-step-2.png) - -1. At step 3, provide a name for your QnA Maker knowledge base. For this example use the name 'sample-qna'. - - ![Create QnA Step 3](./media/tutorial-dispatch/create-qna-step-3.png) - -1. At step 4, select the option _+ Add File_, navigate to the CognitiveModel folder of your sample code, and select the file 'QnAMaker.tsv'. There is an additional selection to add a _Chit-chat_ personality to your knowledge base but our example does not include this option. - - ![Create QnA Step 4](./media/tutorial-dispatch/create-qna-step-4.png) - -1. At step 5, select _Create your knowledge base_. - -1. Once the knowledge base is created from your uploaded file, select _Save and train_ and when finished, select the _PUBLISH_ Tab and publish your app. - -1. Once your QnA Maker app is published, select the _SETTINGS_ Tab, and scroll down to 'Deployment details'. Record the following values from the _Postman_ Sample HTTP request. - - ```text - POST /knowledge bases//generateAnswer - Host: // NOTE - this is a URL. - Authorization: EndpointKey - ``` - - The full URL string for your hostname will look like "https://.azure.net/qnamaker". These values will later be used within your `appsettings.json` or `.env` file. - -## Dispatch app needs read access to existing apps - -The dispatch tool needs authoring access to read the existing LUIS and QnA Maker apps in order to create a new parent LUIS app that dispatches to the LUIS and QnA Maker apps. This access is provided with the app IDs and authoring keys. - -### Service authoring keys - -The **authoring key** is only used for creating and editing the models. You need an ID and key for each of the two LUIS apps and the QnA Maker app. - -|App|Location of information| -|--|--| -|LUIS|**App ID** - found in the [LUIS portal](https://www.luis.ai) for each app, Manage -> Application Information
**Authoring Key** - found in the LUIS portal, top-right corner, select your own User, then Settings.| -|QnA Maker| **App ID** - found in the [QnA Maker portal](https://http://qnamaker.ai) on the Settings page after you publish the app. This is the ID found in first part of the POST command after the knowledgebase. An example of where to find the app ID is `POST /knowledgebases//generateAnswer`.
**Authoring Key** - found in the Azure portal, for the QnA Maker resource, under the **Keys**. You only need one of the keys.| - -The authoring key is not used to get a prediction score or confidence score from the published application. You need the endpoint keys for this action. The **[endpoint keys](#service-endpoint-keys)** are found and used later in this tutorial. - -Learn more about the [two different types of keys](https://docs.microsoft.com/azure/cognitive-services/qnamaker/how-to/set-up-qnamaker-service-azure#types-of-keys-in-qna-maker) used with QnA Maker. - -## Create the dispatch model - -The CLI interface for the dispatch tool creates the model for dispatching to the correct LUIS or QnA Maker app. - -1. Open a command prompt or terminal window, and change directories to the **CognitiveModels** directory -1. Make sure you have the current version of npm and the Dispatch tool. - - ```cmd - npm i -g npm - npm i -g botdispatch - ``` - -1. Use `dispatch init` to initialize create a `.dispatch` file for your dispatch model. Create this using a filename you will recognize. - - ```cmd - dispatch init -n --luisAuthoringKey "" --luisAuthoringRegion - ``` - -1. Use `dispatch add` to add your LUIS apps and QnA Maker knowledge bases to the `.dispatch` file. - - ```cmd - dispatch add -t luis -i "" -n "" -v -k "" --intentName l_Weather - dispatch add -t luis -i "" -n "" -v -k "" --intentName l_HomeAutomation - dispatch add -t qna -i "" -n "" -k "" --intentName q_sample-qna - ``` - -1. Use `dispatch create` to generate a dispatch model from the `.dispatch` file. - - ```cmd - dispatch create - ``` - -1. Publish the dispatch LUIS app, just created. - -## Use the dispatch LUIS app - -The generated LUIS app defines intents for each of the child apps and the knowledge base, as well as a _none_ intent for when the utterance doesn't have a good fit. - -- `l_HomeAutomation` -- `l_Weather` -- `None` -- `q_sample-qna` - -These services need to be published under the correct names for the bot to run properly. -The bot needs information about the published services, so that it can access those services. - -### Service endpoint keys - -The bot needs the query prediction endpoints for the three LUIS apps (dispatch, weather, and home automation) and the single QnA Maker knowledge base. Use the following table to find the endpoint keys: - -|App|Query endpoint key location| -|--|--| -|LUIS|In the LUIS portal, for each LUIS app, in the Manage section, select **Keys and Endpoint settings** to find the keys associated with each app. If you are following this tutorial, the endpoint key is the same key as the ``. The authoring key allows for 1000 endpoint hits then expires.| -|QnA Maker|In the QnA Maker portal, for the knowledge base, in the Manage settings, use the key value shows in the Postman settings for the **Authorization** header, without the text of `EndpointKey`.| - -These values are used in the **appsettings.json** for C# and the **.env** file for javascript. - -## [C#](#tab/cs) - -### Installing packages - -Prior to running this app for the first time ensure that several NuGet packages are installed: - -- **Microsoft.Bot.Builder** -- **Microsoft.Bot.Builder.AI.Luis** -- **Microsoft.Bot.Builder.AI.QnA** - -### Manually update your appsettings.json file - -Once all of your service apps are created, the information for each needs to be added into your 'appsettings.json' file. The initial [C# Sample][cs-sample] code contains an empty appsettings.json file: - -**appsettings.json** - -[!code-json[AppSettings](~/../botbuilder-samples/samples/csharp_dotnetcore/14.nlp-with-dispatch/AppSettings.json?range=8-17)] - -For each of the entities shown below, add the values you recorded earlier in these instructions: - -**appsettings.json** - -```json -"MicrosoftAppId": "", -"MicrosoftAppPassword": "", - -"QnAKnowledgebaseId": "", -"QnAEndpointKey": "", -"QnAEndpointHostName": "", - -"LuisAppId": "", -"LuisAPIKey": "", -"LuisAPIHostName": "", -``` - -When all changes are complete, save this file. - -## [JavaScript](#tab/js) - -### Installing packages - -Prior to running this app for the first time you will need to install several npm packages. - -```powershell -npm install --save botbuilder -npm install --save botbuilder-ai -``` - -To use the .env configuration file, your bot needs an extra package included: - -```powershell -npm install --save dotenv -``` - -### Manually update your .env file - -Once all of your service apps are created, the information for each needs to be added into your '.env' file. The initial [JavaScript Sample][js-sample] code contains an empty .env file. - -**.env** -[!code-file[EmptyEnv](~/../botbuilder-samples/samples/javascript_nodejs/14.nlp-with-dispatch/.env?range=1-10)] - -Add your service connection values as shown below: - -**.env** - -```file -MicrosoftAppId="" -MicrosoftAppPassword="" - -QnAKnowledgebaseId="" -QnAEndpointKey="" -QnAEndpointHostName="" - -LuisAppId= -LuisAPIKey= -LuisAPIHostName= -``` - -When all changes are in place, save this file. - -## [Python](#tab/python) - -### Installing packages - -Prior to running this app for the first time you will need to install several PyPI packages. - -```powershell -pip install azure -pip install botbuilder-core -pip install botbuilder-ai -``` - -### Manually update your config.py file -Once all of your service apps are created, the information for each needs to be added into your 'config.py' file. The initial [Python Sample][python-sample] code contains an empty config.py file. - -**config.py** - -[!code-python[config.py](~/../botbuilder-samples/samples/python/14.nlp-with-dispatch/config.py?range=10-24)] - -For each of the entities shown below, add the values you recorded earlier in these instructions: - -```python -APP_ID = os.environ.get("MicrosoftAppId", "") -APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "") - -QNA_KNOWLEDGEBASE_ID = os.environ.get("QnAKnowledgebaseId", "") -QNA_ENDPOINT_KEY = os.environ.get("QnAEndpointKey", "") -QNA_ENDPOINT_HOST = os.environ.get("QnAEndpointHostName", "") - -LUIS_APP_ID = os.environ.get("LuisAppId", "") -LUIS_API_KEY = os.environ.get("LuisAPIKey", "") -# LUIS endpoint host name, ie "westus.api.cognitive.microsoft.com" -LUIS_API_HOST_NAME = os.environ.get("LuisAPIHostName", "") -``` - -When all changes are complete, save this file. - ---- - -### Connect to the services from your bot - -To connect to the Dispatch, LUIS, and QnA Maker services, your bot pulls information from the settings file. - -## [C#](#tab/cs) - -In **BotServices.cs**, the information contained within configuration file _appsettings.json_ is used to connect your dispatch bot to the `Dispatch` and `SampleQnA` services. The constructors use the values you provided to connect to these services. - -**BotServices.cs** - -[!code-csharp[ReadConfigurationInfo](~/../botbuilder-samples/samples/csharp_dotnetcore/14.nlp-with-dispatch/BotServices.cs?range=14-45)] - -## [JavaScript](#tab/js) - -In **dispatchBot.js** the information contained within configuration file _.env_ is used to connect your dispatch bot to the _LuisRecognizer(dispatch)_ and _QnAMaker_ services. The constructors use the values you provided to connect to these services. - -**bots/dispatchBot.js** - -[!code-javascript[ReadConfigurationInfo](~/../botbuilder-samples/samples/javascript_nodejs/14.nlp-with-dispatch/bots/dispatchBot.js?range=11-26)] - -## [Python](#tab/python) - -In **dispatch_bot.py**, the information contained within configuration file _config.py_ is used to connect your dispatch bot to the _QnAMaker_ and _LuisRecognizer_ services. The constructors use the values you provided to connect to these services. - -**bots/dispatch_bot.py** - -[!code-python[ReadConfigurationInfo](~/../botbuilder-samples/samples/python/14.nlp-with-dispatch/bots/dispatch_bot.py?range=14-34)] - ---- - -> [!NOTE] -> By default the `includeApiResults` parameter is set to false, meaning the recognizer will only return basic information about entities / intents. If you require the full response from LUIS (such as the `ConnectedServiceResult` used later in this tutorial), then set this parameter to true. This will then add the full response from the LUIS service into the Properties collection on the `RecognizerResult`. - -### Call the services from your bot - -For each input from your user, the bot logic checks user input against the combined Dispatch model, finds the top returned intent, and uses that information to call the appropriate service for the input. - -## [C#](#tab/cs) - -In the **DispatchBot.cs** file whenever the `OnMessageActivityAsync` method is called, we check the incoming user message against the Dispatch model. We then pass the Dispatch Model's `topIntent` and `recognizerResult` on to the correct method to call the service and return the result. - -**bots\DispatchBot.cs** - -[!code-csharp[OnMessageActivity](~/../botbuilder-samples/samples/csharp_dotnetcore/14.nlp-with-dispatch/bots/DispatchBot.cs?range=26-36)] - -## [JavaScript](#tab/js) - -In the **dispatchBot.js** `onMessage` method, we check the user input message against the Dispatch model, find the _topIntent_, then pass this on by calling _dispatchToTopIntentAsync_. - -[!code-javascript[onMessage](~/../botbuilder-samples/samples/javascript_nodejs/14.nlp-with-dispatch/bots/dispatchBot.js?range=31-44)] - -## [Python](#tab/python) - -In the **dispatch_bot.py** file whenever the `on_message_activity` method is called, we check the incoming user message against the Dispatch model. We then pass the Dispatch Model's `top_intent` and `recognize_result` on to the correct method to call the service and return the result. - -**bots/dispatch_bot.py** - -[!code-python[on_message](~/../botbuilder-samples/samples/python/14.nlp-with-dispatch/bots/dispatch_bot.py?range=46-54)] - ---- - -### Work with the recognition results - -## [C#](#tab/cs) - -When the model produces a result, it indicates which service can most appropriately process the utterance. The code in this bot routes the request to the corresponding service, and then summarizes the response from the called service. Depending on the _intent_ returned from Dispatch, this code uses the returned intent to route to the correct LUIS model or QnA service. - -**bots\DispatchBot.cs** - -[!code-csharp[DispatchToTop](~/../botbuilder-samples/samples/csharp_dotnetcore/14.nlp-with-dispatch/bots/DispatchBot.cs?range=51-69)] - -If method `ProcessHomeAutomationAsync` or `ProcessWeatherAsync` are invoked, they are passed the results from the dispatch model within _luisResult.ConnectedServiceResult_. The specified method then provides user feedback showing the dispatch model top intent, plus a ranked listing of all intents and entities that were detected. - -If method `q_sample-qna` is invoked, it uses the user input contained within the turnContext to generate an answer from the knowledge base and display that result to the user. - -## [JavaScript](#tab/js) - -When the model produces a result, it indicates which service can most appropriately process the utterance. The code in this sample uses the recognized _topIntent_ to show how to route the request on to the corresponding service. - -**bots/dispatchBot.js** -[!code-javascript[dispatchToTopIntentAsync](~/../botbuilder-samples/samples/javascript_nodejs/14.nlp-with-dispatch/bots/dispatchBot.js?range=61-77)] - -If method `processHomeAutomation` or `processWeather` are invoked, they are passed the results from the dispatch model within _recognizerResult.luisResult_. The specified method then provides user feedback showing the dispatch model's top intent, plus a ranked listing of all intents and entities that were detected. - -If method `q_sample-qna` is invoked, it uses the user input contained within the turnContext to generate an answer from the knowledge base and display that result to the user. - -## [Python](#tab/python) - -When the model produces a result, it indicates which service can most appropriately process the utterance. The code in this sample uses the recognized top _intent_ to show how to route the request on to the corresponding service. - -**bots\dispatch_bot.py** - -[!code-python[dispatch top intent](~/../botbuilder-samples/samples/python/14.nlp-with-dispatch/bots/dispatch_bot.py?range=56-70)] - -If method `_process_home_automation` or `_process_weather` are invoked, they are passed the results from the dispatch model within _recognizer_result.properties["luisResult"]_. The specified method then provides user feedback showing the dispatch model top intent, plus a ranked listing of all intents and entities that were detected. - -If method `q_sample-qna` is invoked, it uses the user input contained within the turnContext to generate an answer from the knowledge base and display that result to the user. - ---- - -> [!NOTE] -> If this were a production application, this is where the selected LUIS methods would connect to their specified service, pass in the user input, and process the returned LUIS intent and entity data. - -## Test your bot - -1. Using your development environment, start the sample code. Note the _localhost_ address shown in the address bar of the browser window opened by your App: "https://localhost:". -1. Open your Bot Framework Emulator, then select `Create a new bot configuration`. A `.bot` file enables you to use the _Inspector_ in the bot emulator to see the JSON returned from LUIS and QnA Maker. -1. In the **New bot configuration** dialog box, enter your bot name, and your endpoint URL, such as `http://localhost:3978/api/messages`. Save the file at the root of your bot sample code project. -1. Open the bot file and add sections for your LUIS and QnA Maker apps. Use [this example file](https://github.com/microsoft/botbuilder-tools/blob/master/packages/MSBot/docs/sample-bot-file.json) as a template for settings. Save the changes. -1. Select the bot name in the **My Bots** list to access your running bot. For your reference, here are some of the questions and commands that are covered by the services built for your bot: - - - QnA Maker - - `hi`, `good morning` - - `what are you`, `what do you do` - - LUIS (home automation) - - `turn on bedroom light` - - `turn off bedroom light` - - `make some coffee` - - LUIS (weather) - - `whats the weather in redmond washington` - - `what's the forecast for london` - - `show me the forecast for nebraska` - -## Dispatch for user utterance to QnA Maker - -1. In the bot emulator, enter the text `hi` and submit the utterance. The bot submits this query to the dispatch LUIS app and gets back a response indicating which child app should get this utterance for further processing. - -1. By selecting the `LUIS Trace` line in the log, you can see the LUIS response in the bot emulator . The LUIS result from the dispatch LUIS app displays in the Inspector. - - ```json - { - "luisResponse": { - "entities": [], - "intents": [ - { - "intent": "q_sample-qna", - "score": 0.9489713 - }, - { - "intent": "l_HomeAutomation", - "score": 0.0612499453 - }, - { - "intent": "None", - "score": 0.008567564 - }, - { - "intent": "l_Weather", - "score": 0.0025761195 - } - ], - "query": "Hi", - "topScoringIntent": { - "intent": "q_sample-qna", - "score": 0.9489713 - } - } - } - ``` - - Because the utterance, `hi`, is part of the dispatch LUIS app's **q_sample-qna** intent, and is selected as the `topScoringIntent`, the bot will make a second request, this time to the QnA Maker app, with the same utterance. - -1. Select the `QnAMaker Trace` line in the bot emulator log. The QnA Maker result displays in the Inspector. - -```json -{ - "questions": [ - "hi", - "greetings", - "good morning", - "good evening" - ], - "answer": "Hello!", - "score": 1, - "id": 96, - "source": "QnAMaker.tsv", - "metadata": [], - "context": { - "isContextOnly": false, - "prompts": [] - } -} -``` - -## Resolving incorrect top intent from Dispatch - -Once your bot is running, it is possible to improve the bot's performance by removing similar or overlapping utterances between the dispatched apps. - -You can use the [Dispatch][dispatch-readme] command-line tool to test and evaluate your dispatch model. - -### To update or create a new LUIS model - -This sample is based on a preconfigured LUIS model. Additional information to help you update this model, or create a new LUIS model, can be found [here](https://aka.ms/create-luis-model#updating-your-cognitive-models). - -After updating the underlying models (QnA or LUIS) run `dispatch refresh` to update your Dispatch LUIS app. `dispatch refresh` is basically the same command as `dispatch create` except no new LUIS app ID is created. - -Note that utterances that were added directly in LUIS will not be retained when running `dispatch refresh`. To keep those extra utterances in the Dispatch app add those utterances in a text file (one utterance per line), and then add the file to Dispatch by running the command: - -```powershell -dispatch add -t file -f --intentName -``` - -Once the file with extra utterances is added to Dispatch the utterances will stay with every refresh. - -### To delete resources - -This sample creates a number of applications and resources that you can delete using the steps listed below, but you should not delete resources that *any other apps or services* rely on. - -To delete LUIS resources: - -1. Sign in to the [luis.ai](https://www.luis.ai) portal. -1. Go to the _My Apps_ page. -1. Select the apps created by this sample. - - `Home Automation` - - `Weather` - - `NLP-With-Dispatch-BotDispatch` -1. Click _Delete_, and click _Ok_ to confirm. - -To delete QnA Maker resources: - -1. Sign in to the [qnamaker.ai](https://www.qnamaker.ai/) portal. -1. Go to the _My knowledge bases_ page. -1. Click the delete button for the `Sample QnA` knowledge base, and click _Delete_ to confirm. - -### Best practice - -To improve services used in this sample, refer to best practice for [LUIS](https://docs.microsoft.com/azure/cognitive-services/luis/luis-concept-best-practices), and [QnA Maker](https://docs.microsoft.com/azure/cognitive-services/qnamaker/concepts/best-practices). - - - - - -[howto-luis]: bot-builder-howto-v4-luis.md -[howto-qna]: bot-builder-howto-qna.md - -[cs-sample]: https://aka.ms/dispatch-sample-cs -[js-sample]: https://aka.ms/dispatch-sample-js -[python-sample]: https://aka.ms/dispatch-sample-python - -[dispatch-readme]: https://aka.ms/dispatch-command-line-tool - diff --git a/articles/v4sdk/bot-builder-virtual-assistant-introduction.md b/articles/v4sdk/bot-builder-virtual-assistant-introduction.md deleted file mode 100644 index ffb0eba30..000000000 --- a/articles/v4sdk/bot-builder-virtual-assistant-introduction.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: Virtual Assistant Overview - Bot Service -description: Learn about creating your own Virtual Assistant -author: darrenj -ms.author: darrenj -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Virtual Assistant Overview - -## Overview - -Customers and partners have a significant need to deliver a conversational assistant tailored to their brand, personalized to their users, and made available across a broad range of canvases and devices. - -Continuing Microsoft's open-sourced approach towards the Bot Framework SDK, the open-source Virtual Assistant solution provides you with a set of core foundational capabilities and full control over the end user experience. - -This template incorporates the previous Enterprise Template and brings together all of the best practices and supporting components identified through building conversational experiences and greatly simplifies the creation of a new bot project including: basic conversational intents, Dispatch integration, QnA Maker, Application Insights and an automated deployment. - -We strongly believe our customers should own and enrich their customer relationships and insights. Therefore, any Virtual Assistant provides complete control of the user experience to our customers and partners through open-sourcing the code on GitHub. The name, voice and personality can be changed to suit the organization’s needs. Our Virtual Assistant solution simplifies creation of your own assistant enabling you to get started in minutes and then extended using our end to end development tooling. - -The scope of Virtual Assistant functionality is broad, typically offering end users a range of capabilities. To increase developer productivity and to enable a vibrant ecosystem of reusable conversational experiences, we are providing developers initial examples of reusable conversational skills. These Skills can be added into a conversational application to lighten up a specific conversation experience, such as finding a point of interest, interacting with calendar, tasks, email and many other scenarios. Skills are fully customizable and consist of language models for multiple languages, dialogs and code. - -![Virtual Assistant Diagram](./media/enterprise-template/customassistantdiagram.jpg) - -## Getting Started - -Explore the [Virtual Assistant and Skills](https://aka.ms/bf-solutions-docs) documentation for more detailed information. - -## What's in the box - -The Virtual Assistant Template brings together a number of best practices we've identified through the building of conversational experiences and automates integration of components that we've found to be highly beneficial to Bot Framework developers. This section covers some background to key decisions to help explain why the template works the way it does. - -The Virtual Assistant template now incorporates the previous Enterprise Template capabilities including base conversational intents in multiple languages, Dispatching, QnA, and conversational insights. The following Assistant related capabilities are provided at this time; further capabilities are planned and we'll be working closely with customers and partners to help inform the roadmap. - -Feature | Description | ------------- | ------------- -Onboarding | An example OnBoarding flow enabling your Assistant to greet the user and collect initial information. -Eventing Architecture | Events in the context of the Virtual Assistant enable the client application hosting the assistant (in a web-browser or on a device such as a car or speaker) to exchange information about the user or device events while also receiving events to perform device operations. -Linked Accounts | In a speech-led scenario it's not practical for a user to enter their username and password for supporting systems through voice commands. Therefore, a separate companion experience provides an opportunity for the user to signin and provide permission for an Virtual Assistant to retrieve tokens for later use. -Skill Enablement | A broad set of common capabilities exist today, which require each developer to build themselves. Our Virtual Assistant solution includes a new Skill capability enabling new capabilities to be plugged into an Virtual Assistant through configuration only and provide an authentication mechanism for Skills to request tokens for down-stream activities. -Point of Interest Skill | The preview Point of Interest (PoI) skill provides a comprehensive language model for finding points of interest and requesting directions. The skill currently provides integration into Azure Maps. -Calendar Skill | The preview Calendar Skill provides a comprehensive language model for common calendar related activities, The skill is currently integrated into Microsoft Graph (Office 365/Outlook.com) with support for Google APIs to follow soon. -Email Skill | The preview Email Skill provides a comprehensive language model for common email related activities, The skill is currently integrated into Microsoft Graph (Office 365/Outlook.com) with support for Google APIs to follow soon. -To Do Skill | The preview To Do Skill provides a comprehensive language model for common task related activities, The skill is currently integrated into OneNote with Microsoft Graph (outlookTask) support to follow soon. -Device Integration | Our Azure Bot Service SDKs (DirectLine) along with Adaptive Card and Speech SDKs enable easy cross-platform integration to devices. Additional device integration examples and platform including Edge are planned. -Test Harnesses | In addition to the Bot Framework Emulator, a WebChat based test harness is provided enabling more complex authentication scenarios to be tested. A simple Console based test harness demonstrates the approach to exchange messages to help frame the ease of device integration. -Automated Deployment | All the Azure resources required for your Assistant are automatically deployed: Bot registration, Azure App Service, LUIS, QnAMaker, Content Moderator, CosmosDB, Azure Storage, and Application Insights. Additionally, LUIS models for all skills, QnAMaker, and Dispatch models are created, trained, and published to enable immediate testing. -Automotive Language Model | An Automotive language model covering core domains such as telephone, navigation and control of in-car features is coming soon. - -## Example Scenarios - -The Virtual Assistant extends across a broad number of industry scenarios. Some example scenarios are shown below for reference purposes. - -- **Automotive Industry**: Voice enabled Personal Assistant integrated into the car providing end users the ability to perform traditional car operations (e.g. navigation, radio) along with productivity focused scenarios such as moving meetings when you're running late, adding items to your task list and proactive experiences where the car can suggest tasks to complete based on events such as starting the engine, traveling home or enabling cruise control. Adaptive Cards are rendered within the Head Unit and speech integration performed through Push-To-Talk or Wake Word interactions. - -- **Hospitality**: Voice enabled Personal Assistant integrated into a hotel room device providing a broad range of hospitality focused scenarios (e.g. extend your stay, request late checkout, room service) including concierge and the ability to find local restaurants and attractions. Optional linking to your productivity accounts open up more personalized experiences such as suggested alarm calls, weather warnings and learning of patterns across stays. An evolution of the current TV personalization experienced in room today. - -- **Enterprise**: Voice and Text enabled branded Employee Assistant experiences integrated into enterprise devices and existing conversation canvases (e.g. Teams, WebChat, Slack) enabling employees to manage their calendars, find available meeting rooms, find people with specific skills, or perform HR related operations. - -## Virtual Assistant Principles - -### Your data, your brand and your experience -All aspects of the end user experience are owned and controlled by you. This includes the branding, name, voice, personality, responses, and avatar. The source code to the Virtual Assistant and supporting Skills are provided in full, enabling you to adjust as required. - -Your Virtual Assistant will be deployed within your Azure subscription. Therefore, all data generated by your assistant (questions asked, user behaviour, etc.) is entirely contained within your Azure subscription. See [Cognitive Services Azure Trusted Cloud](https://www.microsoft.com/trustcenter/cloudservices/cognitiveservices), and more specifically the [Azure section of the Trust Center](https://www.microsoft.com/TrustCenter/CloudServices/Azure), for additional information. - -### Write it once, embed it anywhere -The Virtual Assistant leverages the Microsoft Conversational AI platform and therefore can be surfaced through any Bot Framework [channel](https://docs.microsoft.com/azure/bot-service/bot-service-manage-channels?view=azure-bot-service-4.0). - -In addition, you can embed experiences into desktop and mobile apps (like cars, speakers, and alarm clocks) through the [Direct Line](https://docs.microsoft.com/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-concepts?view=azure-bot-service-4.0) channel. - -### Enterprise Grade Solutions -The Virtual Assistant solution is built on the Azure Bot Service, Language Understanding Cognitive Service, and Unified Speech along with a broad set of supporting Azure components. This means that you benefit from the [Azure global infrastructure](https://azure.microsoft.com/global-infrastructure/), including ISO 27018, HIPPA, PCI DSS, and SOC 1, 2, and 3 certification. - -In addition, Language Understanding support is provided by the LUIS Cognitive Service which supports a broad set of languages [listed here](https://docs.microsoft.com/azure/cognitive-services/luis/luis-supported-languages). The [Translator Cognitive Service](https://azure.microsoft.com/services/cognitive-services/translator-text-api/) provides additional machine translation capabilities to extend the reach of your Virtual Assistant even further. - -### Integrated and Context Aware -Your Virtual Assistant can be incoroporated into your device and ecosystem, enabling a truly integrated and intelligent experience. Through this contextual awareness more intelligent experiences can be developed and deliver further personalization than otherwise possible. - -### 3rd Party assistant integration -The Virtual Assistant enables you to deliver your own unique experience but also hand-off to the end-users chosen Digital Assistant for certain types of questions. - -### Flexible integration -Our Virtual Assistant architecture is flexible and can be integrated with existing investments you may have made into device-based speech or natural language processing capabilities that integrate with your existing back-end systems and APIs. - -### Adaptive Cards -[Adaptive Cards](https://adaptivecards.io/) provide the ability for your Virtual Assistant to return user experience (UX) elements (e.g. Cards, Images, Buttons) alongside text-based responses. If the device or conversation canvas has a screen these Adaptive Cards can be rendered across a broad range of devices and platforms, providing UX support where appropriate. Examples of Adaptive Cards can be found [here](https://adaptivecards.io/samples/) with information on rendering options in the documentation [here](https://docs.microsoft.com/adaptive-cards/rendering-cards/getting-started). - -### Skills -In addition to the base assistant there exists a broad set of common capabilities which require each developer to build themselves. Productivity is a great example where each organization would need to create language models (LUIS), dialogs (code), integration (code) and language generation (responses) to enable popular Calendar, Task or email experiences. - -This is then further complicated by the need to support multiple languages and results in a large amount of work required for any organisation building their own assistant. - -Our Virtual Assistant solution includes a new Skill capability that enables capabilities to be plugged into a custom-assistant through configuration only. - -All aspects of each Skill (language model, dialogs, integration code and language generation) are completely customizable by developers as the full source code is provided on GitHub along with the Virtual Assistant. - -## Getting Started - -Refer to the [tutorials](https://aka.ms/bfs-tutorials) to learn how to create and deploy your Virtual Assistant. - diff --git a/articles/v4sdk/bot-builder-virtual-assistant-template.md b/articles/v4sdk/bot-builder-virtual-assistant-template.md deleted file mode 100644 index 412cd46b4..000000000 --- a/articles/v4sdk/bot-builder-virtual-assistant-template.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: Overview of the Virtual Assistant Template - Bot Service -description: Learn more about the Virtual Assistant Template -author: darrenj -ms.author: darrenj -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 05/23/2019 -monikerRange: 'azure-bot-service-4.0' ---- - -# Virtual Assistant - Template Outline - -> [!NOTE] -> This topic applies to v4 version of the SDK. - -The Virtual Assistant Template brings together a number of best practices we've identified through the building of conversational experiences and automates integration of components that we've found to be highly beneficial to Bot Framework developers. This section covers some background to key decisions to help explain why the template works the way it does. - -Feature | Description | ------------- | ------------- -Introduction | Introduction message with an [Adaptive Card]() on conversation start -Typing indicators | Automated visual typing indicators during conversations and repeat for long running operations -Base LUIS model | Supports common intents such as **Cancel**, **Help**, **Escalate**, etc. -Base dialogs | Dialog flows for capturing basic user information as well as interruption logic for cancel and help intents -Base responses | Text and speech responses for base intents and dialogs -FAQ | Integration with [QnA Maker](https://www.qnamaker.ai) to answer general questions from a knowledgebase -Chit-chat | A professional chit-chat model to provide standard answers to common queries ([learn more](https://docs.microsoft.com/azure/cognitive-services/qnamaker/how-to/chit-chat-knowledge-base)) -Dispatcher | An integrated [Dispatch](https://docs.microsoft.com/azure/bot-service/bot-builder-tutorial-dispatch?view=azure-bot-service-4.0&tabs=csaddref%2Ccsbotconfig) model to identify whether a given utterance should be processed by LUIS or QnA Maker. -Language support | Available in English, French, Italian, German, Spanish and Chinese -Transcripts | Transcripts of all conversations stored in Azure Storage -Telemetry | [Application Insights](https://azure.microsoft.com/services/application-insights/) integration to collect telemetry for all conversations -Analytics | An example Power BI dashboard to get you started with insights into your conversational experiences. -Automated deployment | Easy deployment of all aforementioned services using Azure ARM templates. - -## Introduction Card - -A key issue with many conversational experiences is end-users not knowing how to get started, leading to general questions that the Bot may not be best placed to answer. First impressions matter! An introduction card offers an opportunity to introduce the Bot's capabilities to an end user and suggests a few initial questions the user can use to get started. It's also a great opportunity to surface the personality of your Bot. - -A simple introduction card is provided as standard which you can adapt as needed, a returning user card is shown on subsequent interactions when a user has completed the onboarding dialog (triggered by the Get Started button on the Introduction card) - -![Intro Card Example](./media/enterprise-template/vabotintrocard.png) - -## Basic Language Understanding (LUIS) intents - -Every Bot should handle a base level of conversational language understanding. Greetings for example are a basic thing every Bot should handle with ease. Typically, developers need to create these base intents and provide initial training data to get started. The Virtual Assistant template provides example .lu files to get you started and avoids every project having to create these each time and ensures a base level of capability out of the box. - -The .lu files provide the following intents across English, Chinese, French, Italian, German, Spanish. - -Intent | Sample Utterances | --------------|-------------| -Cancel |*cancel*, *nevermind*| -Escalate |*can I talk to a person?*| -FinishTask |*done*, *all finished*| -GoBack |*go back*| -Help |*can you help me?*| -Repeat |*can you say that again?*| -SelectAny |*any of these*| -SelectItem |*the first one*| -SelectNone |*none of these*| -ShowNext |*show more*| -ShowPrevious |*show previous*| -StartOver |*restart*| -Stop |*stop*| - -The [.lu](https://github.com/Microsoft/botbuilder-tools/blob/master/packages/Ludown/docs/lu-file-format.md) format is similar to Markdown, enabling easy modification and source control. The [LuDown](https://github.com/Microsoft/botbuilder-tools/tree/master/packages/Ludown) tool is then used to convert .lu files into LUIS models which can then be published to your LUIS subscription either through the portal or the associated [LUIS](https://github.com/Microsoft/botbuilder-tools/tree/master/packages/LUIS) CLI (command line) tool. - -## Telemetry - -Providing insights into the user engagement of your Bot has proven to be highly valuable. This insight can help you understand the levels of user engagement, what features of the Bot they are using (intents) along with questions people are asking that the Bot isn't able to answer - highlighting gaps in the Bot's knowledge that could be addressed through new QnA Maker articles for instance. - -Integration of Application Insights provides significant operational/technical insight out of the box but this can also be used to capture specific Bot related events - messages sent and received along with LUIS and QnA Maker operations. - -Bot level telemetry is intrinsically linked to technical and operational telemetry enabling you to inspect how a given user question was answered and vice versa. - -A middleware component combined with a wrapper class around the QnA Maker and LuisRecognizer SDK classes provides an elegant way to collect a consistent set of events. These consistent events can then be used by the Application Insights tooling along with tools like PowerBI. - -An example Power BI dashboard is as part of the Bot Framework Solutions github repo and works right out of the box with every Virtual Assistant template. See the [Analytics](https://aka.ms/bfs-analytics) section for more information. - -![Analytics Example](./media/enterprise-template/powerbi-conversationanalytics-luisintents.png) - -## Dispatcher - -A key design pattern used to good effect in the first wave of conversational experiences was to leverage Language Understanding (LUIS) and QnA Maker. LUIS would be trained with tasks that your Bot could do for an end user and QnA Maker would be trained with more general knowledge. - -All incoming utterances (questions) would be routed to LUIS for analysis. If the intent of a given utterance was not identified it was marked as a *None* intent. QnA Maker was then used to try and find an answer for the end-user. - -While this pattern worked well there were two key scenarios where problems could be experienced. - -- If utterances in the LUIS model and QnA Maker overlapped, sometimes slightly, this could lead to strange behavior where LUIS may try to process a question when it should have been directed to QnA Maker. -- When there were two or more LUIS models a Bot would have to invoke each one and perform some form of intent evaluation comparison to identify where to send a given utterance. As there is no common baseline score, comparison across models didn't work effectively, leading to a poor user experience. - -[Dispatch](https://docs.microsoft.com/azure/bot-service/bot-builder-tutorial-dispatch?view=azure-bot-service-4.0&tabs=csaddref%2Ccsbotconfig) provides an elegant solution to this by extracting utterances from each configured LUIS model and questions from QnA Maker and creating a central dispatch LUIS model. - -This enables a Bot to quickly identify which LUIS model or component should handle a given utterance and ensures QnA Maker data is considered at the top level of intent processing, not just the *None* intent as before. - -This Dispatch tool also enables evaluation which will highlight confusion, issues, and overlap across LUIS models and QnA Maker knowledge bases before deployment. - -The Dispatcher is used at the core of each project created using the template. The Dispatch model is used within the `MainDialog` class to identify whether the target is a LUIS model or QnA. In the case of LUIS, the secondary LUIS model is invoked returning the intent and entities. Dispatcher is also used for interruption detection. - -![Dispatch Example](./media/enterprise-template/dispatchexample.png) - -## QnA Maker - -[QnA Maker](https://www.qnamaker.ai/) provides the ability for non-developers to curate general knowledge in the format of question and answer pairs. This knowledge can be imported from FAQ data sources, product manuals and interactively within the QnA Maker portal. - -Two example QnA Maker models are provided in the [.lu](https://github.com/Microsoft/botbuilder-tools/blob/master/packages/Ludown/docs/lu-file-format.md) file format within the QnA folder of CognitiveModels, one for FAQ and one for chit-chat. [LUDown](https://github.com/Microsoft/botbuilder-tools/tree/master/packages/Ludown) is then used as part of the deployment script to create a QnA Maker JSON file which the [QnA Maker](https://github.com/Microsoft/botbuilder-tools/tree/master/packages/QnAMaker) CLI (command line) tool then uses to publish items to the QnA Maker knowledge base. - -![QnA ChitChat example](./media/enterprise-template/qnachitchatexample.png) - -## Content Moderator - -Content Moderator is an optional component which enables detection of potential profanity and helps check for personally identifiable information (PII). For example, a Bot can apologise and hand-off to a human in the event of profanity, or not store telemetry records if PII information is detected. - -A middleware component is provided that screens text and surfaces through a ```TextModeratorResult``` on the TurnState object. - -## Next Steps -Refer to the [tutorials](https://aka.ms/bfs-tutorials) to learn how to create and deploy your Virtual Assistant. - -## Additional resources -Full source code for the Virtual Assistant Template can be found on [GitHub](https://aka.ms/bf-solutions). - diff --git a/articles/v4sdk/bot-builder-webchat-customization.md b/articles/v4sdk/bot-builder-webchat-customization.md deleted file mode 100644 index b4ad007d5..000000000 --- a/articles/v4sdk/bot-builder-webchat-customization.md +++ /dev/null @@ -1,364 +0,0 @@ ---- -title: Web Chat customization - Bot Service -description: Learn how to customize the Bot Framework Web Chat. -keywords: bot framework, webchat, chat, samples, react, reference -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 06/07/2019 ---- - -# Web Chat customization - -This article details how to customize the Web Chat samples to fit your bot. - -## Integrate Web Chat into your website - -Follow the instructions on the [overview page](bot-builder-webchat-overview.md) page to integrate the Web Chat control into your website. - -## Customizing styles - -The latest version of Web Chat control provides rich customization options: you can change colors, sizes, placement of elements, add custom elements, and interact with the hosting webpage. Below are several examples of how to customize those elements of the Web Chat UI. - -You can find the full list of all settings that you can easily modify in Web Chat on the [`defaultStyleOptions.js` file](https://github.com/Microsoft/BotFramework-WebChat/blob/master/packages/component/src/Styles/defaultStyleOptions.js). - -These settings will generate a _style set_, which is a set of CSS rules enhanced with [glamor](https://github.com/threepointone/glamor). You can find the full list of CSS styles generated in the style set on the [`createStyleSet.js` file](https://github.com/Microsoft/BotFramework-WebChat/blob/master/packages/component/src/Styles/createStyleSet.js). - -## Set the size of the Web Chat container - -It is now possible to adjust the size of the Web Chat container using `styleSetOptions`. The following example has a `body` background-color of `paleturquoise` to show the Web Chat container (section with white background). - -```js -… - - - - -
- -… -``` - -Here is the result: - -Web Chat with root height and root width set - -## Change font or color - -Instead of using the default background color and the fonts used inside of the chat bubbles, you can customize those to match the style of the target web page. The code snippet below allows you to change the background color of messages from the user and from the bot. - -Screenshot with custom style options - -If you need to do some simple styling, you can set them via `styleOptions`. Style options are set of predefined styles that you can modify directly, and Web Chat will compute the whole stylesheet based on it. - -```html - - - -
- - - - -``` - -## Change the CSS manually - -In addition to colors, you can modify fonts used to render messages: - -Screenshot with custom style set - -For deeper styling, you can also modify the style set manually by setting the CSS rules directly. - -> Since CSS rules are tightly-coupled to the structure of the DOM tree, there is possibility that these rules need to be updated to work with the newer version of Web Chat. - -```html - - - -
- - - - -``` - -## Change the avatar of the bot within the dialog box - -The latest version of Web Chat supports avatars, which you can customize by setting `botAvatarInitials` and `userAvatarInitials` in the `styleOptions` prop. - -Screenshot with avatar initials - -```html - - - -
- - - - -``` - -Inside Web Chat's `styleOptions` prop, we added `botAvatarInitials` and `userAvatarInitials`: - -```js -botAvatarInitials: 'BF', -userAvatarInitials: 'WC' -``` - -`botAvatarInitials` will set the text inside the avatar on the left-hand side. If it is set to falsy value, the avatar on the bot side will be hidden. In contrast, `userAvatarInitials` will set the avatar text on the right-hand side. - -## Custom rendering activity or attachment - -With the latest version of Web Chat, you can also render activities or attachments that Web Chat does not support out-of-the-box. Activities and attachments render are sent thru a customizable pipeline that modeled after [Redux middleware](https://redux.js.org/api/applymiddleware). The pipeline is flexible enough that you can do the following tasks easily: - -- Decorate existing activities/attachments -- Add new activities/attachments -- Replace existing activities/attachments (or remove them) -- Daisy chain middleware together - -### Show GitHub repository as an attachment - -If you want to display a deck of GitHub repository cards, you can create a new React component for the GitHub repository and add it as a middleware for attachment. - -Screenshot with custom GitHub repository attachment - -```jsx -import ReactWebChat from 'botframework-webchat'; -import ReactDOM from 'react-dom'; - -// Create a new React component that accept render a GitHub repository attachment -const GitHubRepositoryAttachment = props => ( - -); - -// Creating a new middleware pipeline that will render for specific type of attachment -const attachmentMiddleware = () => next => card => { - switch (card.attachment.contentType) { - case 'application/vnd.microsoft.botframework.samples.github-repository': - return ( - - ); - - default: - return next(card); - } -}; - -ReactDOM.render( - , - document.getElementById('webchat') -); -``` - -The full sample can be found in [the customization-card-components sample](https://github.com/microsoft/BotFramework-WebChat/tree/master/samples/10.a.customization-card-components). - -In this sample, we are adding a new React component called `GitHubRepositoryAttachment`: - -```jsx -const GitHubRepositoryAttachment = props => ( - -); -``` - -Then, we create a middleware that will render the new React component when the bot sends an attachment of content type `application/vnd.microsoft.botframework.samples.github-repository`. Otherwise, it will continue on the middleware by calling `next(card)`. - -```jsx -const attachmentMiddleware = () => next => card => { - switch (card.attachment.contentType) { - case 'application/vnd.microsoft.botframework.samples.github-repository': - return ( - - ); - - default: - return next(card); - } -}; -``` - -The activity sent from the bot looks like the following: - -```json -{ - "type": "message", - "from": { - "role": "bot" - }, - "attachmentLayout": "carousel", - "attachments": [ - { - "contentType": "application/vnd.microsoft.botframework.samples.github-repository", - "content": { - "owner": "Microsoft", - "repo": "BotFramework-WebChat" - } - }, - { - "contentType": "application/vnd.microsoft.botframework.samples.github-repository", - "content": { - "owner": "Microsoft", - "repo": "BotFramework-Emulator" - } - }, - { - "contentType": "application/vnd.microsoft.botframework.samples.github-repository", - "content": { - "owner": "Microsoft", - "repo": "BotFramework-DirectLineJS" - } - } - ] -} -``` diff --git a/articles/v4sdk/bot-builder-webchat-overview.md b/articles/v4sdk/bot-builder-webchat-overview.md deleted file mode 100644 index def59c5c9..000000000 --- a/articles/v4sdk/bot-builder-webchat-overview.md +++ /dev/null @@ -1,245 +0,0 @@ ---- -title: Web Chat overview - Bot Service -description: Learn how to configure Bot Framework Web Chat. -keywords: bot framework, webchat, chat, samples, react, reference -author: ivorb -ms.author: kamrani -manager: kamrani -ms.topic: article -ms.service: bot-service -ms.date: 06/07/2019 ---- - -# Web Chat overview - -This article contains details of the [Bot Framework Web Chat](https://github.com/microsoft/BotFramework-WebChat) component. The Bot Framework Web Chat component is a highly customizable web-based client for the Bot Framework V4 SDK. The Bot Framework SDK v4 enables developers to model conversation and build sophisticated bot applications. - -If you're looking to migrate from Web Chat v3 to v4, jump ahead to [the migration section](#migrating-from-web-chat-v3-to-v4). - -## How to use - -> [!NOTE] -> For previous versions of Web Chat (v3), visit the [Web Chat v3 branch](https://github.com/Microsoft/BotFramework-WebChat/tree/v3). - -First, create a bot using [Azure Bot Service](https://azure.microsoft.com/services/bot-service/). -Once the bot is created, you will need to [obtain the bot's Web Chat secret](../bot-service-channel-connect-webchat.md#get-your-bot-secret-key) in Azure Portal. Then use the secret to [generate a token](../rest-api/bot-framework-rest-direct-line-3-0-authentication.md) and pass it to your Web Chat. - -Here is how how you can add a Web Chat control to your website: - -```html - - - -
- - - - -``` - -> `userID`, `username`, `locale`, `botAvatarInitials`, and `userAvatarInitials` are all optional parameters to pass into the `renderWebChat` method. To learn more about Web Chat properties, look at the [Web Chat API Reference](#web-chat-api-reference) section of this article. -> ![Screenshot of Web Chat](https://raw.githubusercontent.com/Microsoft/BotFramework-WebChat/master/media/weatherquery.png.jpg) - -### Integrate with JavaScript - -Web Chat is designed to integrate with your existing website using JavaScript or React. Integrating with JavaScript will give you some styling and customizability, for more information see the article [Integrate Web Chat into your website](https://aka.ms/integrate-webchat-into-site). - -You can use the full, typical webchat package that contains the most typically used features. - -```html - - - -
- - - - -``` - -See the working sample of the [full Web Chat bundle](https://github.com/Microsoft/BotFramework-WebChat/tree/master/samples/01.a.getting-started-full-bundle). - -### Integrate with React - -For full customizability, you can use [React](https://reactjs.org/) to recompose components of Web Chat. - -To install the production build from npm, run `npm install botframework-webchat`. - -```jsx -import { DirectLine } from 'botframework-directlinejs'; -import React from 'react'; -import ReactWebChat from 'botframework-webchat'; - -export default class extends React.Component { - constructor(props) { - super(props); - - this.directLine = new DirectLine({ token: 'YOUR_DIRECT_LINE_TOKEN' }); - } - - render() { - return ( - - element - ); - } -} -``` - -> You can also run `npm install botframework-webchat@master` to install a development build that is synced with Web Chat's GitHub `master` branch. - -See a working sample of [Web Chat rendered via React](https://github.com/Microsoft/BotFramework-WebChat/tree/master/samples/03.a.host-with-react/). - -> [!TIP] -> If you are new to React and jsx you can find training on Reacts [Getting Started](https://reactjs.org/docs/getting-started.html) page. - - -## Customize Web Chat UI - -Web Chat is designed to be customizable without forking the source code. The table below outlines what kind of customizations you can achieve when you are importing Web Chat in different ways. This list is not exhaustive. - -| | CDN bundle | React | -| ----------------------------- | ------------------ | ------------------ | -| Change colors | :heavy_check_mark: | :heavy_check_mark: | -| Change sizes | :heavy_check_mark: | :heavy_check_mark: | -| Update/replace CSS styles | :heavy_check_mark: | :heavy_check_mark: | -| Listen to events | :heavy_check_mark: | :heavy_check_mark: | -| Interact with hosting webpage | :heavy_check_mark: | :heavy_check_mark: | -| Custom render activities | | :heavy_check_mark: | -| Custom render attachments | | :heavy_check_mark: | -| Add new UI components | | :heavy_check_mark: | -| Recompose the whole UI | | :heavy_check_mark: | - -See more about [customizing Web Chat](https://github.com/Microsoft/BotFramework-WebChat/blob/master/SAMPLES.md) to learn more on customization. - -> [!NOTE] -> For information on Content Delivery Networks (CDNs) See [Content delivery networks (CDNs)](https://aka.ms/CDN-best-practices) - -## Migrating from Web Chat v3 to v4 - -There are three possible paths that migration might take when migrating from v3 to v4. First, please compare your beginning scenario as described below. - -For a list of related samples, see [Web Chat hosted samples](https://aka.ms/botframework-webchat-samples). - -### My current website integrates Web Chat using an `