[Samples] Add 49.qnamaker-all-features sample (#1063)

* Add main README and pom

* Add deploymentTemplates

* Add resources folder

* Add webapp folder

* Add empty test

* Add botservices

* Add Startup

* Add dialogs

* Add bot

* Add package-info file

* Fix issues of QnAMakerDialog, add default constructor and remove double braces

* Fix issues in sample, update document and set initialDialog name for WaterfallDialog

* Fix disparities between samples

* Fix issues in migrated README
This commit is contained in:
Martin Battaglino 2021-03-18 13:03:29 -03:00 коммит произвёл GitHub
Родитель c24b0e4046
Коммит 8399a7f3aa
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
20 изменённых файлов: 1905 добавлений и 54 удалений

Просмотреть файл

@ -9,6 +9,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.CompletableFuture;
import javax.annotation.Nullable;
@ -438,6 +439,19 @@ public class QnAMakerDialog extends WaterfallDialog {
this.rankerType = withRankerType;
}
/**
* Initializes a new instance of the @{link QnAMakerDialog} class.
*/
public QnAMakerDialog() {
super("QnAMakerDialog", null);
// add waterfall steps
this.addStep(this::callGenerateAnswer);
this.addStep(this::callTrain);
this.addStep(this::checkForMultiTurnPrompt);
this.addStep(this::displayQnAResult);
}
/**
* Initializes a new instance of the @{link QnAMakerDialog} class.
*
@ -570,7 +584,7 @@ public class QnAMakerDialog extends WaterfallDialog {
@Nullable OkHttpClient withHttpClient
) {
this(
QnAMakerDialog.class.getName(),
"QnAMakerDialog",
withKnowledgeBaseId,
withEndpointKey,
withHostName,
@ -613,15 +627,12 @@ public class QnAMakerDialog extends WaterfallDialog {
QnAMakerOptions qnAMakerOptions = this.getQnAMakerOptions(dc).join();
QnADialogResponseOptions qnADialogResponseOptions = this.getQnAResponseOptions(dc).join();
QnAMakerDialogOptions dialogOptions = new QnAMakerDialogOptions() {
{
setQnAMakerOptions(qnAMakerOptions);
setResponseOptions(qnADialogResponseOptions);
}
};
QnAMakerDialogOptions dialogOptions = new QnAMakerDialogOptions();
dialogOptions.setQnAMakerOptions(qnAMakerOptions);
dialogOptions.setResponseOptions(qnADialogResponseOptions);
if (options != null) {
dialogOptions = (QnAMakerDialogOptions) ObjectPath.assign(dialogOptions, options);
dialogOptions = ObjectPath.assign(dialogOptions, options);
}
ObjectPath.setPathValue(dc.getActiveDialog().getState(), OPTIONS, dialogOptions);
@ -706,13 +717,10 @@ public class QnAMakerDialog extends WaterfallDialog {
return CompletableFuture.completedFuture(qnaClient);
}
QnAMakerEndpoint endpoint = new QnAMakerEndpoint() {
{
setEndpointKey(endpointKey);
setHost(hostName);
setKnowledgeBaseId(knowledgeBaseId);
}
};
QnAMakerEndpoint endpoint = new QnAMakerEndpoint();
endpoint.setEndpointKey(endpointKey);
endpoint.setHost(hostName);
endpoint.setKnowledgeBaseId(knowledgeBaseId);
return this.getQnAMakerOptions(
dc
@ -729,17 +737,15 @@ public class QnAMakerDialog extends WaterfallDialog {
* task is successful, the result contains the QnA Maker options to use.
*/
protected CompletableFuture<QnAMakerOptions> getQnAMakerOptions(DialogContext dc) {
return CompletableFuture.completedFuture(new QnAMakerOptions() {
{
setScoreThreshold(threshold);
setStrictFilters(strictFilters);
setTop(top);
setContext(new QnARequestContext());
setQnAId(0);
setRankerType(rankerType);
setIsTest(isTest);
}
});
QnAMakerOptions options = new QnAMakerOptions();
options.setScoreThreshold(threshold);
options.setStrictFilters(strictFilters);
options.setTop(top);
options.setContext(new QnARequestContext());
options.setQnAId(0);
options.setRankerType(rankerType);
options.setIsTest(isTest);
return CompletableFuture.completedFuture(options);
}
/**
@ -750,16 +756,15 @@ public class QnAMakerDialog extends WaterfallDialog {
* successful, the result contains the response options to use.
*/
protected CompletableFuture<QnADialogResponseOptions> getQnAResponseOptions(DialogContext dc) {
return CompletableFuture.completedFuture(new QnADialogResponseOptions() {
{
setNoAnswer(noAnswer.bind(dc, dc.getState()).join());
setActiveLearningCardTitle(
activeLearningCardTitle != null ? activeLearningCardTitle : DEFAULT_CARD_TITLE
);
setCardNoMatchText(cardNoMatchText != null ? cardNoMatchText : DEFAULT_CARD_NO_MATCH_TEXT);
setCardNoMatchResponse(cardNoMatchResponse.bind(dc, null).join());
}
});
QnADialogResponseOptions options = new QnADialogResponseOptions();
options.setNoAnswer(noAnswer.bind(dc, dc.getState()).join());
options.setActiveLearningCardTitle(
activeLearningCardTitle != null ? activeLearningCardTitle : DEFAULT_CARD_TITLE
);
options.setCardNoMatchText(cardNoMatchText != null ? cardNoMatchText : DEFAULT_CARD_NO_MATCH_TEXT);
options.setCardNoMatchResponse(cardNoMatchResponse.bind(dc, null).join());
return CompletableFuture.completedFuture(options);
}
/**
@ -816,16 +821,18 @@ public class QnAMakerDialog extends WaterfallDialog {
// -Check if previous context is present, if yes then put it with the query
// -Check for id if query is present in reverse index.
Map<String, Integer> previousContextData =
ObjectPath.getPathValue(dc.getActiveDialog().getState(), QNA_CONTEXT_DATA, Map.class);
ObjectPath.getPathValue(
dc.getActiveDialog().getState(),
QNA_CONTEXT_DATA,
Map.class,
new HashMap<String, Integer>());
Integer previousQnAId =
ObjectPath.getPathValue(dc.getActiveDialog().getState(), PREVIOUS_QNA_ID, Integer.class, 0);
if (previousQnAId > 0) {
dialogOptions.getQnAMakerOptions().setContext(new QnARequestContext() {
{
setPreviousQnAId(previousQnAId);
}
});
QnARequestContext context = new QnARequestContext();
context.setPreviousQnAId(previousQnAId);
dialogOptions.getQnAMakerOptions().setContext(context);
Integer currentQnAId = previousContextData.get(dc.getContext().getActivity().getText());
if (currentQnAId != null) {
@ -921,19 +928,13 @@ public class QnAMakerDialog extends WaterfallDialog {
if (qnaResult != null) {
List<QueryResult> queryResultArr = new ArrayList<QueryResult>();
stepContext.getValues().put(ValueProperty.QNA_DATA, queryResultArr.add(qnaResult));
FeedbackRecord record = new FeedbackRecord() {
{
setUserId(stepContext.getContext().getActivity().getId());
setUserQuestion(currentQuery);
setQnaId(qnaResult.getId());
}
};
FeedbackRecord record = new FeedbackRecord();
record.setUserId(stepContext.getContext().getActivity().getId());
record.setUserQuestion(currentQuery);
record.setQnaId(qnaResult.getId());
FeedbackRecord[] records = {record};
FeedbackRecords feedbackRecords = new FeedbackRecords() {
{
setRecords(records);
}
};
FeedbackRecords feedbackRecords = new FeedbackRecords();
feedbackRecords.setRecords(records);
// Call Active Learning Train API
return this.getQnAMakerClient(stepContext).thenCompose(qnaClient -> {
try {

Просмотреть файл

@ -0,0 +1,21 @@
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
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 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

Просмотреть файл

@ -0,0 +1,126 @@
# QnA Maker
Bot Framework v4 QnA Maker bot sample. This sample shows how to integrate Multiturn and Active learning in a QnA Maker bot with Java. Click [here][72] to know more about using follow-up prompts to create multiturn conversation. To know more about how to enable and use active learning, click [here][71].
This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to create a bot that uses the [QnA Maker Cognitive AI](https://www.qnamaker.ai) service.
The [QnA Maker Service](https://www.qnamaker.ai) enables you to build, train and publish a simple question and answer bot based on FAQ URLs, structured documents or editorial content in minutes. In this sample, we demonstrate how to use the QnA Maker service to answer questions based on a FAQ text file used as input.
## Concepts introduced in this sample
The [QnA Maker Service][7] enables you to build, train and publish a simple question and answer bot based on FAQ URLs, structured documents or editorial content in minutes.
In this sample, we demonstrate
- how to use the Active Learning to generate suggestions for knowledge base.
- how to use the Multiturn experience for the knowledge base.
# Prerequisites
- Follow instructions [here](https://docs.microsoft.com/en-us/azure/cognitive-services/qnamaker/how-to/set-up-qnamaker-service-azure) to create a QnA Maker service.
- Follow instructions [here](https://docs.microsoft.com/en-us/azure/cognitive-services/qnamaker/how-to/multiturn-conversation) to create multiturn experience.
- Follow instructions [here](https://docs.microsoft.com/en-us/azure/cognitive-services/qnamaker/quickstarts/create-publish-knowledge-base) to import and publish your newly created QnA Maker service.
- Update [application.properties](src/main/resources/application.properties) with your kbid (KnowledgeBase Id), endpointKey and endpointHost. You may also change the default answer by updating `DefaultAnswer` (optional) field. QnA knowledge base setup and application configuration steps can be found [here](https://aka.ms/qna-instructions).
- (Optional) Follow instructions [here](https://github.com/microsoft/botframework-cli/tree/main/packages/qnamaker) to set up the
QnA Maker CLI to deploy the model.
### Create a QnAMaker Application to enable QnA Knowledge Bases
QnA knowledge base setup and application configuration steps can be found [here](https://aka.ms/qna-instructions).
# Configure Cognitive Service Model
- Create a Knowledge Base in QnAMaker Portal.
- Import "smartLightFAQ.tsv" file, in QnAMaker Portal.
- Save and Train the model.
- Create Bot from Publish page.
- Test bot with Web Chat.
- Capture values of settings like "QnAAuthKey" from "Configuration" page of created bot, in Azure Portal.
- Updated application.properties with values as needed.
- Use value of "QnAAuthKey" for setting "QnAEndpointKey".
- Capture KnowledgeBase Id, HostName and EndpointKey current published app
# Try Active Learning
- Once your QnA Maker service is up and you have published the sample KB, try the following queries to trigger the Train API on the bot.
- Sample query: "light"
- You can observe that, Multiple answers are returned with high score.
# Try Multi-turn prompt
- Once your QnA Maker service is up and you have published the sample KB, try the following queries to trigger the Train API on the bot.
- Sample query: "won't turn on"
- You can notice a prompt, included as part of answer to query.
## To try this sample
- From the root of this project folder:
- Build the sample using `mvn package`
- Run it by using `java -jar .\target\bot-qnamaker-all-features-sample.jar`
##### Microsoft Teams channel group chat fix
- Goto `QnABot.java`
- Add References
- Modify `onTurn` function as:
```java
@Override
public CompletableFuture<Void> onTurn(TurnContext turnContext) {
// Teams group chat
if (turnContext.getActivity().getChannelId().equals(Channels.MSTEAMS)) {
turnContext.getActivity().setText(turnContext.getActivity().removeRecipientMention());
}
return super.onTurn(turnContext)
// Save any state changes that might have occurred during the turn.
.thenCompose(turnResult -> conversationState.saveChanges(turnContext, false))
.thenCompose(saveResult -> userState.saveChanges(turnContext, false));
}
```
## Testing the bot using Bot Framework Emulator
[Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
- Install the Bot Framework Emulator version 4.3.0 or greater from [here](https://github.com/Microsoft/BotFramework-Emulator/releases)
### Connect to the bot using Bot Framework Emulator
- Launch Bot Framework Emulator
- File -> Open Bot
- Enter a Bot URL of `http://localhost:3978/api/messages`
# Deploy the bot to Azure
See [Deploy your Java bot to Azure][50] for instructions.
The deployment process assumes you have an account on Microsoft Azure and are able to log into the [Microsoft Azure Portal][60].
If you are new to Microsoft Azure, please refer to [Getting started with Azure][70] for guidance on how to get started on Azure.
# Further reading
- [Active learning Documentation][40]
- [Bot Framework Documentation][80]
- [Bot Basics][90]
- [Azure Bot Service Introduction][100]
- [Azure Bot Service Documentation][110]
- [QnA Maker CLI][170]
- [BF-CLI][130]
- [Azure Portal][140]
- [Spring Boot][160]
[1]: https://dev.botframework.com
[4]: https://docs.microsoft.com/en-us/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0
[5]: https://github.com/microsoft/botframework-emulator
[6]: https://aka.ms/botframeworkemulator
[7]: https://www.qnamaker.ai
[40]: https://docs.microsoft.com/en-us/azure/cognitive-services/qnamaker/how-to/improve-knowledge-base
[50]: https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-deploy-azure?view=azure-bot-service-4.0
[60]: https://portal.azure.com
[70]: https://azure.microsoft.com/get-started/
[80]: https://docs.botframework.com
[90]: https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0
[100]: https://docs.microsoft.com/en-us/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0
[110]: https://docs.microsoft.com/en-us/azure/bot-service/?view=azure-bot-service-4.0
[120]: https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest
[130]: https://github.com/microsoft/botframework-cli
[140]: https://portal.azure.com
[150]: https://www.luis.ai
[160]: https://spring.io/projects/spring-boot
[170]: https://github.com/microsoft/botframework-cli/tree/main/packages/qnamaker
[71]: https://docs.microsoft.com/en-us/azure/cognitive-services/qnamaker/how-to/improve-knowledge-base
[72]: https://docs.microsoft.com/en-us/azure/cognitive-services/qnamaker/how-to/multiturn-conversation

Просмотреть файл

@ -0,0 +1,291 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"groupLocation": {
"defaultValue": "",
"type": "string",
"metadata": {
"description": "Specifies the location of the Resource Group."
}
},
"groupName": {
"type": "string",
"metadata": {
"description": "Specifies the name of the Resource Group."
}
},
"appId": {
"type": "string",
"metadata": {
"description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
}
},
"appSecret": {
"type": "string",
"metadata": {
"description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings."
}
},
"botId": {
"type": "string",
"metadata": {
"description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
}
},
"botSku": {
"defaultValue": "S1",
"type": "string",
"metadata": {
"description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
}
},
"newAppServicePlanName": {
"defaultValue": "",
"type": "string",
"metadata": {
"description": "The name of the App Service Plan."
}
},
"newAppServicePlanSku": {
"type": "object",
"defaultValue": {
"name": "P1v2",
"tier": "PremiumV2",
"size": "P1v2",
"family": "Pv2",
"capacity": 1
},
"metadata": {
"description": "The SKU of the App Service Plan. Defaults to Standard values."
}
},
"newAppServicePlanLocation": {
"defaultValue": "",
"type": "string",
"metadata": {
"description": "The location of the App Service Plan. Defaults to \"westus\"."
}
},
"newWebAppName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
}
}
},
"variables": {
"appServicePlanName": "[parameters('newAppServicePlanName')]",
"resourcesLocation": "[parameters('newAppServicePlanLocation')]",
"webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
"siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
"botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]",
"publishingUsername": "[concat('$', parameters('newWebAppName'))]",
"resourceGroupId": "[concat(subscription().id, '/resourceGroups/', parameters('groupName'))]"
},
"resources": [
{
"name": "[parameters('groupName')]",
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[parameters('groupLocation')]",
"properties": {}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"name": "storageDeployment",
"resourceGroup": "[parameters('groupName')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups/', parameters('groupName'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"comments": "Create a new Linux App Service Plan if no existing App Service Plan name was passed in.",
"type": "Microsoft.Web/serverfarms",
"name": "[variables('appServicePlanName')]",
"apiVersion": "2018-02-01",
"location": "[variables('resourcesLocation')]",
"sku": "[parameters('newAppServicePlanSku')]",
"kind": "linux",
"properties": {
"perSiteScaling": false,
"maximumElasticWorkerCount": 1,
"isSpot": false,
"reserved": true,
"isXenon": false,
"hyperV": false,
"targetWorkerCount": 0,
"targetWorkerSizeId": 0
}
},
{
"comments": "Create a Web App using a Linux App Service Plan",
"type": "Microsoft.Web/sites",
"apiVersion": "2018-11-01",
"location": "[variables('resourcesLocation')]",
"kind": "app,linux",
"dependsOn": [
"[concat(variables('resourceGroupId'), '/providers/Microsoft.Web/serverfarms/', variables('appServicePlanName'))]"
],
"name": "[variables('webAppName')]",
"properties": {
"name": "[variables('webAppName')]",
"hostNameSslStates": [
{
"name": "[concat(parameters('newWebAppName'), '.azurewebsites.net')]",
"sslState": "Disabled",
"hostType": "Standard"
},
{
"name": "[concat(parameters('newWebAppName'), '.scm.azurewebsites.net')]",
"sslState": "Disabled",
"hostType": "Repository"
}
],
"serverFarmId": "[variables('appServicePlanName')]",
"reserved": true,
"isXenon": false,
"hyperV": false,
"scmSiteAlsoStopped": false,
"clientAffinityEnabled": true,
"clientCertEnabled": false,
"hostNamesDisabled": false,
"containerSize": 0,
"dailyMemoryTimeQuota": 0,
"httpsOnly": false,
"redundancyMode": "None",
"siteConfig": {
"appSettings": [
{
"name": "JAVA_OPTS",
"value": "-Dserver.port=80"
},
{
"name": "MicrosoftAppId",
"value": "[parameters('appId')]"
},
{
"name": "MicrosoftAppPassword",
"value": "[parameters('appSecret')]"
}
],
"cors": {
"allowedOrigins": [
"https://botservice.hosting.portal.azure.net",
"https://hosting.onecloud.azure-test.net/"
]
}
}
}
},
{
"type": "Microsoft.Web/sites/config",
"apiVersion": "2018-11-01",
"name": "[concat(variables('webAppName'), '/web')]",
"location": "[variables('resourcesLocation')]",
"dependsOn": [
"[concat(variables('resourceGroupId'), '/providers/Microsoft.Web/sites/', variables('webAppName'))]"
],
"properties": {
"numberOfWorkers": 1,
"defaultDocuments": [
"Default.htm",
"Default.html",
"Default.asp",
"index.htm",
"index.html",
"iisstart.htm",
"default.aspx",
"index.php",
"hostingstart.html"
],
"netFrameworkVersion": "v4.0",
"linuxFxVersion": "JAVA|8-jre8",
"requestTracingEnabled": false,
"remoteDebuggingEnabled": false,
"httpLoggingEnabled": false,
"logsDirectorySizeLimit": 35,
"detailedErrorLoggingEnabled": false,
"publishingUsername": "[variables('publishingUsername')]",
"scmType": "None",
"use32BitWorkerProcess": true,
"webSocketsEnabled": false,
"alwaysOn": true,
"managedPipelineMode": "Integrated",
"virtualApplications": [
{
"virtualPath": "/",
"physicalPath": "site\\wwwroot",
"preloadEnabled": true
}
],
"loadBalancing": "LeastRequests",
"experiments": {
"rampUpRules": []
},
"autoHealEnabled": false,
"localMySqlEnabled": false,
"ipSecurityRestrictions": [
{
"ipAddress": "Any",
"action": "Allow",
"priority": 1,
"name": "Allow all",
"description": "Allow all access"
}
],
"scmIpSecurityRestrictions": [
{
"ipAddress": "Any",
"action": "Allow",
"priority": 1,
"name": "Allow all",
"description": "Allow all access"
}
],
"scmIpSecurityRestrictionsUseMain": false,
"http20Enabled": false,
"minTlsVersion": "1.2",
"ftpsState": "AllAllowed",
"reservedInstanceCount": 0
}
},
{
"apiVersion": "2017-12-01",
"type": "Microsoft.BotService/botServices",
"name": "[parameters('botId')]",
"location": "global",
"kind": "bot",
"sku": {
"name": "[parameters('botSku')]"
},
"properties": {
"name": "[parameters('botId')]",
"displayName": "[parameters('botId')]",
"endpoint": "[variables('botEndpoint')]",
"msaAppId": "[parameters('appId')]",
"developerAppInsightsApplicationId": null,
"developerAppInsightKey": null,
"publishingCredentials": null,
"storageResourceId": null
},
"dependsOn": [
"[concat(variables('resourceGroupId'), '/providers/Microsoft.Web/sites/', variables('webAppName'))]"
]
}
],
"outputs": {}
}
}
}
]
}

Просмотреть файл

@ -0,0 +1,259 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appId": {
"type": "string",
"metadata": {
"description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
}
},
"appSecret": {
"type": "string",
"metadata": {
"description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. Defaults to \"\"."
}
},
"botId": {
"type": "string",
"metadata": {
"description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
}
},
"botSku": {
"defaultValue": "S1",
"type": "string",
"metadata": {
"description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
}
},
"newAppServicePlanName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The name of the new App Service Plan."
}
},
"newAppServicePlanSku": {
"type": "object",
"defaultValue": {
"name": "P1v2",
"tier": "PremiumV2",
"size": "P1v2",
"family": "Pv2",
"capacity": 1
},
"metadata": {
"description": "The SKU of the App Service Plan. Defaults to Standard values."
}
},
"appServicePlanLocation": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The location of the App Service Plan."
}
},
"existingAppServicePlan": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Name of the existing App Service Plan used to create the Web App for the bot."
}
},
"newWebAppName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
}
}
},
"variables": {
"defaultAppServicePlanName": "[if(empty(parameters('existingAppServicePlan')), 'createNewAppServicePlan', parameters('existingAppServicePlan'))]",
"useExistingAppServicePlan": "[not(equals(variables('defaultAppServicePlanName'), 'createNewAppServicePlan'))]",
"servicePlanName": "[if(variables('useExistingAppServicePlan'), parameters('existingAppServicePlan'), parameters('newAppServicePlanName'))]",
"publishingUsername": "[concat('$', parameters('newWebAppName'))]",
"resourcesLocation": "[parameters('appServicePlanLocation')]",
"webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
"siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
"botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
},
"resources": [
{
"comments": "Create a new Linux App Service Plan if no existing App Service Plan name was passed in.",
"type": "Microsoft.Web/serverfarms",
"condition": "[not(variables('useExistingAppServicePlan'))]",
"name": "[variables('servicePlanName')]",
"apiVersion": "2018-02-01",
"location": "[variables('resourcesLocation')]",
"sku": "[parameters('newAppServicePlanSku')]",
"kind": "linux",
"properties": {
"perSiteScaling": false,
"maximumElasticWorkerCount": 1,
"isSpot": false,
"reserved": true,
"isXenon": false,
"hyperV": false,
"targetWorkerCount": 0,
"targetWorkerSizeId": 0
}
},
{
"comments": "Create a Web App using a Linux App Service Plan",
"type": "Microsoft.Web/sites",
"apiVersion": "2018-11-01",
"location": "[variables('resourcesLocation')]",
"kind": "app,linux",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]"
],
"name": "[variables('webAppName')]",
"properties": {
"name": "[variables('webAppName')]",
"hostNameSslStates": [
{
"name": "[concat(parameters('newWebAppName'), '.azurewebsites.net')]",
"sslState": "Disabled",
"hostType": "Standard"
},
{
"name": "[concat(parameters('newWebAppName'), '.scm.azurewebsites.net')]",
"sslState": "Disabled",
"hostType": "Repository"
}
],
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]",
"reserved": true,
"isXenon": false,
"hyperV": false,
"scmSiteAlsoStopped": false,
"clientAffinityEnabled": true,
"clientCertEnabled": false,
"hostNamesDisabled": false,
"containerSize": 0,
"dailyMemoryTimeQuota": 0,
"httpsOnly": false,
"redundancyMode": "None",
"siteConfig": {
"appSettings": [
{
"name": "JAVA_OPTS",
"value": "-Dserver.port=80"
},
{
"name": "MicrosoftAppId",
"value": "[parameters('appId')]"
},
{
"name": "MicrosoftAppPassword",
"value": "[parameters('appSecret')]"
}
],
"cors": {
"allowedOrigins": [
"https://botservice.hosting.portal.azure.net",
"https://hosting.onecloud.azure-test.net/"
]
}
}
}
},
{
"type": "Microsoft.Web/sites/config",
"apiVersion": "2018-11-01",
"name": "[concat(variables('webAppName'), '/web')]",
"location": "[variables('resourcesLocation')]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
],
"properties": {
"numberOfWorkers": 1,
"defaultDocuments": [
"Default.htm",
"Default.html",
"Default.asp",
"index.htm",
"index.html",
"iisstart.htm",
"default.aspx",
"index.php",
"hostingstart.html"
],
"netFrameworkVersion": "v4.0",
"linuxFxVersion": "JAVA|8-jre8",
"requestTracingEnabled": false,
"remoteDebuggingEnabled": false,
"httpLoggingEnabled": false,
"logsDirectorySizeLimit": 35,
"detailedErrorLoggingEnabled": false,
"publishingUsername": "[variables('publishingUsername')]",
"scmType": "None",
"use32BitWorkerProcess": true,
"webSocketsEnabled": false,
"alwaysOn": true,
"managedPipelineMode": "Integrated",
"virtualApplications": [
{
"virtualPath": "/",
"physicalPath": "site\\wwwroot",
"preloadEnabled": true
}
],
"loadBalancing": "LeastRequests",
"experiments": {
"rampUpRules": []
},
"autoHealEnabled": false,
"localMySqlEnabled": false,
"ipSecurityRestrictions": [
{
"ipAddress": "Any",
"action": "Allow",
"priority": 1,
"name": "Allow all",
"description": "Allow all access"
}
],
"scmIpSecurityRestrictions": [
{
"ipAddress": "Any",
"action": "Allow",
"priority": 1,
"name": "Allow all",
"description": "Allow all access"
}
],
"scmIpSecurityRestrictionsUseMain": false,
"http20Enabled": false,
"minTlsVersion": "1.2",
"ftpsState": "AllAllowed",
"reservedInstanceCount": 0
}
},
{
"apiVersion": "2017-12-01",
"type": "Microsoft.BotService/botServices",
"name": "[parameters('botId')]",
"location": "global",
"kind": "bot",
"sku": {
"name": "[parameters('botSku')]"
},
"properties": {
"name": "[parameters('botId')]",
"displayName": "[parameters('botId')]",
"endpoint": "[variables('botEndpoint')]",
"msaAppId": "[parameters('appId')]",
"developerAppInsightsApplicationId": null,
"developerAppInsightKey": null,
"publishingCredentials": null,
"storageResourceId": null
},
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
]
}
]
}

Просмотреть файл

@ -0,0 +1,244 @@
<?xml version="1.0" encoding="UTF-8" ?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.bot.sample</groupId>
<artifactId>bot-qnamaker-all-features</artifactId>
<version>sample</version>
<packaging>jar</packaging>
<name>${project.groupId}:${project.artifactId}</name>
<description>This package contains a Java QnAMaker Bot sample using Spring Boot.</description>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/>
</parent>
<licenses>
<license>
<name>MIT License</name>
<url>http://www.opensource.org/licenses/mit-license.php</url>
</license>
</licenses>
<developers>
<developer>
<name>Bot Framework Development</name>
<email></email>
<organization>Microsoft</organization>
<organizationUrl>https://dev.botframework.com/</organizationUrl>
</developer>
</developers>
<properties>
<java.version>1.8</java.version>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<start-class>com.microsoft.bot.sample.qnamaker.all.features.Application</start-class>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.microsoft.bot</groupId>
<artifactId>bot-ai-qna</artifactId>
<version>4.6.0-preview9</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.2</version>
</dependency>
<dependency>
<groupId>com.microsoft.bot</groupId>
<artifactId>bot-integration-spring</artifactId>
<version>4.6.0-preview9</version>
<scope>compile</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>build</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
<configuration>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<mainClass>com.microsoft.bot.sample.qnamaker.all.features.Application</mainClass>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-webapp-maven-plugin</artifactId>
<version>1.12.0</version>
<configuration>
<schemaVersion>V2</schemaVersion>
<resourceGroup>${groupname}</resourceGroup>
<appName>${botname}</appName>
<appSettings>
<property>
<name>JAVA_OPTS</name>
<value>-Dserver.port=80</value>
</property>
</appSettings>
<runtime>
<os>linux</os>
<javaVersion>Java 8</javaVersion>
<webContainer>Java SE</webContainer>
</runtime>
<deployment>
<resources>
<resource>
<directory>${project.basedir}/target</directory>
<includes>
<include>*.jar</include>
</includes>
</resource>
</resources>
</deployment>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>publish</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
<configuration>
<warSourceDirectory>src/main/webapp</warSourceDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<skipRemoteStaging>true</skipRemoteStaging>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<source>8</source>
<failOnError>false</failOnError>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

Просмотреть файл

@ -0,0 +1,78 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.bot.sample.qnamaker.all.features;
import com.microsoft.bot.builder.Bot;
import com.microsoft.bot.builder.ConversationState;
import com.microsoft.bot.builder.UserState;
import com.microsoft.bot.integration.AdapterWithErrorHandler;
import com.microsoft.bot.integration.BotFrameworkHttpAdapter;
import com.microsoft.bot.integration.Configuration;
import com.microsoft.bot.integration.spring.BotController;
import com.microsoft.bot.integration.spring.BotDependencyConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
/**
* This is the starting point of the Sprint Boot Bot application.
*/
@SpringBootApplication
// Use the default BotController to receive incoming Channel messages. A custom
// controller could be used by eliminating this import and creating a new
// org.springframework.web.bind.annotation.RestController.
// The default controller is created by the Spring Boot container using
// dependency injection. The default route is /api/messages.
@Import({BotController.class})
/**
* This class extends the BotDependencyConfiguration which provides the default
* implementations for a Bot application. The Application class should
* override methods in order to provide custom implementations.
*/
public class Application extends BotDependencyConfiguration {
/**
* The start method.
*
* @param args The args.
*/
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
/**
* Returns the Bot for this application.
*
* <p>
* The @Component annotation could be used on the Bot class instead of this method
* with the @Bean annotation.
* </p>
*
* @return The Bot implementation for this application.
*/
@Bean
public Bot getBot(
Configuration configuration,
UserState userState,
ConversationState conversationState
) {
BotServices services = new BotServicesImpl(configuration);
RootDialog dialog = new RootDialog(services, configuration);
return new QnABot<>(conversationState, userState, dialog);
}
/**
* Returns a custom Adapter that provides error handling.
*
* @param configuration The Configuration object to use.
* @return An error handling BotFrameworkHttpAdapter.
*/
@Override
public BotFrameworkHttpAdapter getBotFrameworkHttpAdaptor(Configuration configuration) {
return new AdapterWithErrorHandler(configuration);
}
}

Просмотреть файл

@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.bot.sample.qnamaker.all.features;
import com.microsoft.bot.ai.qna.QnAMaker;
/**
* Interface which contains the QnAMaker application.
*/
public interface BotServices {
/**
* Get QnAMaker application.
*
* @return QnAMaker application
*/
QnAMaker getQnAMakerService();
}

Просмотреть файл

@ -0,0 +1,81 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.bot.sample.qnamaker.all.features;
import com.microsoft.bot.ai.qna.QnAMaker;
import com.microsoft.bot.ai.qna.QnAMakerEndpoint;
import com.microsoft.bot.integration.Configuration;
import org.apache.commons.lang3.StringUtils;
/**
* Class which implements the BotService interface to handle
* the services attached to the bot.
*/
public class BotServicesImpl implements BotServices {
private QnAMaker qnAMakerService;
/**
* Initializes a new instance of the {@link BotServicesImpl} class.
*
* @param configuration A {@link Configuration} which contains the properties of the application.properties
*/
public BotServicesImpl(Configuration configuration) {
QnAMakerEndpoint qnAMakerEndpoint = new QnAMakerEndpoint();
qnAMakerEndpoint.setKnowledgeBaseId(configuration.getProperty("QnAKnowledgebaseId"));
qnAMakerEndpoint.setHost(getHostname(configuration.getProperty("QnAEndpointHostName")));
qnAMakerEndpoint.setEndpointKey(getEndpointKey(configuration));
QnAMaker qnAMaker = new QnAMaker(qnAMakerEndpoint, null);
this.qnAMakerService = qnAMaker;
}
/**
* {@inheritDoc}
*/
@Override
public QnAMaker getQnAMakerService() {
return qnAMakerService;
}
/**
* Get the URL with the hostname value.
*
* @param hostname The hostname value
* @return The URL with the hostname value
*/
private static String getHostname(String hostname) {
if (!hostname.startsWith("https://")) {
hostname = "https://".concat(hostname);
}
if (!hostname.contains("/v5.0") && !hostname.endsWith("/qnamaker")) {
hostname = hostname.concat("/qnamaker");
}
return hostname;
}
/**
* Get the endpointKey.
*
* @param configuration A {@link Configuration} populated with the application.properties file
* @return The endpointKey
*/
private static String getEndpointKey(Configuration configuration) {
String endpointKey = configuration.getProperty("QnAEndpointKey");
if (StringUtils.isBlank(endpointKey)) {
// This features sample is copied as is for "azure bot service" default "createbot" template.
// Post this sample change merged into "azure bot service" template repo, "Azure Bot Service"
// will make the web app config change to use "QnAEndpointKey".But, the the old "QnAAuthkey"
// required for backward compact. This is a requirement from docs to keep app setting name
// consistent with "QnAEndpointKey". This is tracked in Github issue:
// https://github.com/microsoft/BotBuilder-Samples/issues/2532
endpointKey = configuration.getProperty("QnAAuthKey");
}
return endpointKey;
}
}

Просмотреть файл

@ -0,0 +1,79 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.bot.sample.qnamaker.all.features;
import com.microsoft.bot.builder.ActivityHandler;
import com.microsoft.bot.builder.BotState;
import com.microsoft.bot.builder.ConversationState;
import com.microsoft.bot.builder.MessageFactory;
import com.microsoft.bot.builder.TurnContext;
import com.microsoft.bot.builder.UserState;
import com.microsoft.bot.dialogs.Dialog;
import com.microsoft.bot.schema.ChannelAccount;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* A simple bot that responds to utterances with answers from QnA Maker.
* If an answer is not found for an utterance, the bot responds with help.
*
* @param <T> A {@link Dialog}
*/
public class QnABot<T extends Dialog> extends ActivityHandler {
private final BotState conversationState;
private final Dialog dialog;
private final BotState userState;
/**
* Initializes a new instance of the {@link QnABot} class.
*
* @param withConversationState A {@link ConversationState}
* @param withUserState A {@link UserState}
* @param withDialog A {@link Dialog}
*/
public QnABot(ConversationState withConversationState, UserState withUserState, T withDialog) {
this.conversationState = withConversationState;
this.userState = withUserState;
this.dialog = withDialog;
}
/**
* {@inheritDoc}
*/
@Override
public CompletableFuture<Void> onTurn(TurnContext turnContext) {
return super.onTurn(turnContext)
// Save any state changes that might have occurred during the turn.
.thenCompose(turnResult -> conversationState.saveChanges(turnContext, false))
.thenCompose(saveResult -> userState.saveChanges(turnContext, false));
}
/**
* {@inheritDoc}
*/
@Override
protected CompletableFuture<Void> onMessageActivity(TurnContext turnContext) {
// Run the Dialog with the new message Activity.
return Dialog.run(
this.dialog,
turnContext,
this.conversationState.createProperty("DialogState"));
}
/**
* {@inheritDoc}
*/
@Override
protected CompletableFuture<Void> onMembersAdded(List<ChannelAccount> membersAdded, TurnContext turnContext) {
for (ChannelAccount member: membersAdded) {
if (!member.getId().equals(turnContext.getActivity().getRecipient().getId())) {
turnContext.sendActivity(MessageFactory.text("Hello and welcome!")).thenApply(result -> null);
}
}
return CompletableFuture.completedFuture(null);
}
}

Просмотреть файл

@ -0,0 +1,85 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.bot.sample.qnamaker.all.features;
import com.microsoft.bot.ai.qna.QnADialogResponseOptions;
import com.microsoft.bot.ai.qna.QnAMakerClient;
import com.microsoft.bot.ai.qna.QnAMakerOptions;
import com.microsoft.bot.ai.qna.dialogs.QnAMakerDialog;
import com.microsoft.bot.builder.MessageFactory;
import com.microsoft.bot.dialogs.DialogContext;
import com.microsoft.bot.integration.Configuration;
import com.microsoft.bot.schema.Activity;
import org.apache.commons.lang3.StringUtils;
import java.util.concurrent.CompletableFuture;
/**
* QnAMaker action builder class.
*/
public class QnAMakerBaseDialog extends QnAMakerDialog {
// Dialog Options parameters
private final String defaultCardTitle = "Did you mean:";
private final String defaultCardNoMatchText = "None of the above.";
private final String defaultCardNoMatchResponse = "Thanks for the feedback.";
private final BotServices services;
private String defaultAnswer = "No QnAMaker answer found.";
/**
* Initializes a new instance of the {@link QnAMakerBaseDialog} class.
* Dialog helper to generate dialogs.
*
* @param withServices Bot Services
* @param configuration A {@link Configuration} which contains the properties of the application.properties
*/
public QnAMakerBaseDialog(BotServices withServices, Configuration configuration) {
super();
this.services = withServices;
if (StringUtils.isNotBlank(configuration.getProperty("DefaultAnswer"))) {
this.defaultAnswer = configuration.getProperty("DefaultAnswer");
}
}
/**
* {@inheritDoc}
*/
@Override
protected CompletableFuture<QnAMakerClient> getQnAMakerClient(DialogContext dc) {
return CompletableFuture.completedFuture(this.services.getQnAMakerService());
}
/**
* {@inheritDoc}
*/
@Override
protected CompletableFuture<QnAMakerOptions> getQnAMakerOptions(DialogContext dc) {
QnAMakerOptions options = new QnAMakerOptions();
options.setScoreThreshold(DEFAULT_THRESHOLD);
options.setTop(DEFAULT_TOP_N);
options.setQnAId(0);
options.setRankerType("Default");
options.setIsTest(false);
return CompletableFuture.completedFuture(options);
}
/**
* {@inheritDoc}
*/
@Override
protected CompletableFuture<QnADialogResponseOptions> getQnAResponseOptions(DialogContext dc) {
Activity defaultAnswerActivity = MessageFactory.text(this.defaultAnswer);
Activity cardNoMatchResponse = MessageFactory.text(this.defaultCardNoMatchResponse);
QnADialogResponseOptions responseOptions = new QnADialogResponseOptions();
responseOptions.setActiveLearningCardTitle(this.defaultCardTitle);
responseOptions.setCardNoMatchText(this.defaultCardNoMatchText);
responseOptions.setNoAnswer(defaultAnswerActivity);
responseOptions.setCardNoMatchResponse(cardNoMatchResponse);
return CompletableFuture.completedFuture(responseOptions);
}
}

Просмотреть файл

@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.bot.sample.qnamaker.all.features;
import com.microsoft.bot.dialogs.ComponentDialog;
import com.microsoft.bot.dialogs.DialogTurnResult;
import com.microsoft.bot.dialogs.WaterfallDialog;
import com.microsoft.bot.dialogs.WaterfallStep;
import com.microsoft.bot.dialogs.WaterfallStepContext;
import com.microsoft.bot.integration.Configuration;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
/**
* This is an example root dialog. Replace this with your applications.
*/
public class RootDialog extends ComponentDialog {
/**
* QnA Maker initial dialog.
*/
private final String initialDialog = "initial-dialog";
/**
* Root dialog for this bot. Creates a QnAMakerDialog.
*
* @param services A {@link BotServices} which contains the applications
* @param configuration A {@link Configuration} populated with the application.properties file
*/
public RootDialog(BotServices services, Configuration configuration) {
super("root");
this.addDialog(new QnAMakerBaseDialog(services, configuration));
WaterfallStep[] waterfallSteps = {
this::initialStep
};
WaterfallDialog waterfallDialog = new WaterfallDialog(initialDialog, Arrays.asList(waterfallSteps));
this.addDialog(waterfallDialog);
// The initial child Dialog to run.
this.setInitialDialogId(initialDialog);
}
/**
* This is the first step of the WaterfallDialog.
* It kicks off the dialog with the QnA Maker with provided options.
*
* @param stepContext A {@link WaterfallStepContext}
* @return A {@link DialogTurnResult}
*/
private CompletableFuture<DialogTurnResult> initialStep(WaterfallStepContext stepContext) {
return stepContext.beginDialog("QnAMakerDialog", null);
}
}

Просмотреть файл

@ -0,0 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for
// license information.
/**
* This package contains the classes for the qnamaker-all-features sample.
*/
package com.microsoft.bot.sample.qnamaker.all.features;

Просмотреть файл

@ -0,0 +1,7 @@
MicrosoftAppId=
MicrosoftAppPassword=
QnAKnowledgebaseId=
QnAEndpointKey=
QnAEndpointHostName=
DefaultAnswer=
server.port=3978

Просмотреть файл

@ -0,0 +1,18 @@
{
"configuration": {
"name": "Default",
"appenders": {
"Console": {
"name": "Console-Appender",
"target": "SYSTEM_OUT",
"PatternLayout": {"pattern": "[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"}
}
},
"loggers": {
"root": {
"level": "debug",
"appender-ref": {"ref": "Console-Appender","level": "debug"}
}
}
}
}

Просмотреть файл

@ -0,0 +1,23 @@
Question Answer Source Metadata SuggestedQuestions IsContextOnly Prompts QnaId
My Contoso smart light won't turn on. 1. The simplest way to troubleshoot your smart light is to turn it off and on.\n2. Check the connection to the wall outlet to make sure it's plugged in properly. dina-kb-9.tsv [] false [{"displayOrder":0,"qnaId":91,"displayText":"Stopped"}] 90
Light won't turn on. 1. The simplest way to troubleshoot your smart light is to turn it off and on.\n2. Check the connection to the wall outlet to make sure it's plugged in properly. dina-kb-9.tsv [] false [{"displayOrder":0,"qnaId":91,"displayText":"Stopped"}] 90
Doesn't work 1. The simplest way to troubleshoot your smart light is to turn it off and on.\n2. Check the connection to the wall outlet to make sure it's plugged in properly. dina-kb-9.tsv [] false [{"displayOrder":0,"qnaId":91,"displayText":"Stopped"}] 90
My smart light app stopped responding. 1. Restart the app. \n2. If the problem persists, contact support. dina-kb-9.tsv [] false [{"displayOrder":0,"qnaId":95,"displayText":"support"}] 91
I upgraded the app and it doesn't work anymore. When you upgrade, you need to:\n\n1. Disable Bluetooth, then re-enable it\n2. After reenable, repair your light with the app. dina-kb-9.tsv [] false [] 92
Light doesn't work after upgrade. When you upgrade, you need to:\n\n1. Disable Bluetooth, then re-enable it\n2. After reenable, repair your light with the app. dina-kb-9.tsv [] false [] 92
light When you upgrade, you need to:\n\n1. Disable Bluetooth, then re-enable it\n2. After reenable, repair your light with the app. dina-kb-9.tsv [] false [] 92
How long does the light's battery last for? The battery will last approximately 10 - 12 weeks with regular use. dina-kb-9.tsv [] false [] 93
What type of light bulb do I need? A 26-Watt compact fluorescent light bulb that features both energy savings and long-life performance. dina-kb-9.tsv [] false [] 94
Contact customer support Email us at service@contoso.com or call us at (202) 555-0164 dina-kb-9.tsv [] false [] 95
I need help Email us at service@contoso.com or call us at (202) 555-0164 dina-kb-9.tsv [] false [] 95
Help! Email us at service@contoso.com or call us at (202) 555-0164 dina-kb-9.tsv [] false [] 95
How do I contact support? Email us at service@contoso.com or call us at (202) 555-0164 dina-kb-9.tsv [] false [] 95
Who should I contact for customer service? Email us at service@contoso.com or call us at (202) 555-0164 dina-kb-9.tsv [] false [] 95
Troubleshooting Enter a question to search the knowledge base. dina-kb-9.tsv category:troubleshooting [] false [] 96
Hi Welcome to the **Smart lightbulb** bot. 😎 dina-kb-9.tsv category:chitchat [] false [] 97
Hello Welcome to the **Smart lightbulb** bot. 😎 dina-kb-9.tsv category:chitchat [] false [] 97
Start Welcome to the **Smart lightbulb** bot. 😎 dina-kb-9.tsv category:chitchat [] false [] 97
Begin Welcome to the **Smart lightbulb** bot. 😎 dina-kb-9.tsv category:chitchat [] false [] 97
Bye 😎 dina-kb-9.tsv category:chitchat [] false [] 98
End 😎 dina-kb-9.tsv category:chitchat [] false [] 98
Good bye 😎 dina-kb-9.tsv category:chitchat [] false [] 98
Не удается отобразить этот файл, потому что он содержит неожиданный символ в строке 2 и столбце 229.

Просмотреть файл

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Class-Path:

Просмотреть файл

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/dispatcher-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

Просмотреть файл

@ -0,0 +1,420 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>QnAMakerBot</title>
<style>
body {
margin: 0px;
padding: 0px;
font-family: Segoe UI;
}
html,
body {
height: 100%;
}
header {
background-image: url("data:image/svg+xml,%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 4638.9 651.6' style='enable-background:new 0 0 4638.9 651.6;' xml:space='preserve'%3E%3Cstyle type='text/css'%3E .st0%7Bfill:%2355A0E0;%7D .st1%7Bfill:none;%7D .st2%7Bfill:%230058A8;%7D .st3%7Bfill:%23328BD8;%7D .st4%7Bfill:%23B6DCF1;%7D .st5%7Bopacity:0.2;fill:url(%23SVGID_1_);enable-background:new ;%7D%0A%3C/style%3E%3Crect y='1.1' class='st0' width='4640' height='646.3'/%3E%3Cpath class='st1' d='M3987.8,323.6L4310.3,1.1h-65.6l-460.1,460.1c-17.5,17.5-46.1,17.5-63.6,0L3260.9,1.1H0v646.3h3660.3 L3889,418.7c17.5-17.5,46.1-17.5,63.6,0l228.7,228.7h66.6l-260.2-260.2C3970.3,369.8,3970.3,341.1,3987.8,323.6z'/%3E%3Cpath class='st2' d='M3784.6,461.2L4244.7,1.1h-983.9l460.1,460.1C3738.4,478.7,3767.1,478.7,3784.6,461.2z'/%3E%3Cpath class='st3' d='M4640,1.1h-329.8l-322.5,322.5c-17.5,17.5-17.5,46.1,0,63.6l260.2,260.2H4640L4640,1.1L4640,1.1z'/%3E%3Cpath class='st4' d='M3889,418.8l-228.7,228.7h521.1l-228.7-228.7C3935.2,401.3,3906.5,401.3,3889,418.8z'/%3E%3ClinearGradient id='SVGID_1_' gradientUnits='userSpaceOnUse' x1='3713.7576' y1='438.1175' x2='3911.4084' y2='14.2535' gradientTransform='matrix(1 0 0 -1 0 641.3969)'%3E%3Cstop offset='0' style='stop-color:%23FFFFFF;stop-opacity:0.5'/%3E%3Cstop offset='1' style='stop-color:%23FFFFFF'/%3E%3C/linearGradient%3E%3Cpath class='st5' d='M3952.7,124.5c-17.5-17.5-46.1-17.5-63.6,0l-523,523h1109.6L3952.7,124.5z'/%3E%3C/svg%3E%0A");
background-repeat: no-repeat;
background-size: 100%;
background-position: right;
background-color: #55A0E0;
width: 100%;
font-size: 44px;
height: 120px;
color: white;
padding: 30px 0 40px 0px;
display: inline-block;
}
.header-icon {
background-image: url("data:image/svg+xml;utf8,%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20xmlns%3Axlink%3D%22http%3A//www.w3.org/1999/xlink%22%20x%3D%220px%22%20y%3D%220px%22%0A%09%20viewBox%3D%220%200%20150.2%20125%22%20style%3D%22enable-background%3Anew%200%200%20150.2%20125%3B%22%20xml%3Aspace%3D%22preserve%22%3E%0A%3Cstyle%20type%3D%22text/css%22%3E%0A%09.st0%7Bfill%3Anone%3B%7D%0A%09.st1%7Bfill%3A%23FFFFFF%3B%7D%0A%3C/style%3E%0A%3Crect%20x%3D%220.5%22%20class%3D%22st0%22%20width%3D%22149.7%22%20height%3D%22125%22/%3E%0A%3Cg%3E%0A%09%3Cpath%20class%3D%22st1%22%20d%3D%22M59%2C102.9L21.8%2C66c-3.5-3.5-3.5-9.1%2C0-12.5l37-36.5l2.9%2C3l-37%2C36.4c-1.8%2C1.8-1.8%2C4.7%2C0%2C6.6l37.2%2C37L59%2C102.9z%22%0A%09%09/%3E%0A%3C/g%3E%0A%3Cg%3E%0A%09%3Cpath%20class%3D%22st1%22%20d%3D%22M92.5%2C102.9l-3-3l37.2-37c0.9-0.9%2C1.4-2%2C1.4-3.3c0-1.2-0.5-2.4-1.4-3.3L89.5%2C20l2.9-3l37.2%2C36.4%0A%09%09c1.7%2C1.7%2C2.6%2C3.9%2C2.6%2C6.3s-0.9%2C4.6-2.6%2C6.3L92.5%2C102.9z%22/%3E%0A%3C/g%3E%0A%3Cg%3E%0A%09%3Cpath%20class%3D%22st1%22%20d%3D%22M90.1%2C68.4c-4.5%2C0-8-3.5-8-8.1c0-4.5%2C3.5-8.1%2C8-8.1c4.4%2C0%2C8%2C3.7%2C8%2C8.1C98.1%2C64.7%2C94.4%2C68.4%2C90.1%2C68.4z%0A%09%09%20M90.1%2C56.5c-2.2%2C0-3.8%2C1.7-3.8%2C3.9c0%2C2.2%2C1.7%2C3.9%2C3.8%2C3.9c1.9%2C0%2C3.8-1.6%2C3.8-3.9S91.9%2C56.5%2C90.1%2C56.5z%22/%3E%0A%3C/g%3E%0A%3Cg%3E%0A%09%3Cpath%20class%3D%22st1%22%20d%3D%22M61.4%2C68.4c-4.5%2C0-8-3.5-8-8.1c0-4.5%2C3.5-8.1%2C8-8.1c4.4%2C0%2C8%2C3.7%2C8%2C8.1C69.5%2C64.7%2C65.8%2C68.4%2C61.4%2C68.4z%0A%09%09%20M61.4%2C56.5c-2.2%2C0-3.8%2C1.7-3.8%2C3.9c0%2C2.2%2C1.7%2C3.9%2C3.8%2C3.9c1.9%2C0%2C3.8-1.6%2C3.8-3.9S63.3%2C56.5%2C61.4%2C56.5z%22/%3E%0A%3C/g%3E%0A%3C/svg%3E%0A");
background-repeat: no-repeat;
float: left;
height: 140px;
width: 140px;
display: inline-block;
vertical-align: middle;
}
.header-text {
padding-left: 1%;
color: #FFFFFF;
font-family: "Segoe UI";
font-size: 72px;
font-weight: 300;
letter-spacing: 0.35px;
line-height: 96px;
display: inline-block;
vertical-align: middle;
}
.header-inner-container {
min-width: 480px;
max-width: 1366px;
margin-left: auto;
margin-right: auto;
vertical-align: middle;
}
.header-inner-container::after {
content: "";
clear: both;
display: table;
}
.main-content-area {
padding-left: 30px;
}
.content-title {
color: #000000;
font-family: "Segoe UI";
font-size: 46px;
font-weight: 300;
line-height: 62px;
}
.main-text {
color: #808080;
font-size: 24px;
font-family: "Segoe UI";
font-size: 24px;
font-weight: 200;
line-height: 32px;
}
.main-text-p1 {
padding-top: 48px;
padding-bottom: 28px;
}
.endpoint {
height: 32px;
width: 571px;
color: #808080;
font-family: "Segoe UI";
font-size: 24px;
font-weight: 200;
line-height: 32px;
padding-top: 28px;
}
.how-to-build-section {
padding-top: 20px;
padding-left: 30px;
}
.how-to-build-section>h3 {
font-size: 16px;
font-weight: 600;
letter-spacing: 0.35px;
line-height: 22px;
margin: 0 0 24px 0;
text-transform: uppercase;
}
.step-container {
display: flex;
align-items: stretch;
position: relative;
}
.step-container dl {
border-left: 1px solid #A0A0A0;
display: block;
padding: 0 24px;
margin: 0;
}
.step-container dl>dt::before {
background-color: white;
border: 1px solid #A0A0A0;
border-radius: 100%;
content: '';
left: 47px;
height: 11px;
position: absolute;
width: 11px;
}
.step-container dl>.test-bullet::before {
background-color: blue;
}
.step-container dl>dt {
display: block;
font-size: inherit;
font-weight: bold;
line-height: 20px;
}
.step-container dl>dd {
font-size: inherit;
line-height: 20px;
margin-left: 0;
padding-bottom: 32px;
}
.step-container:last-child dl {
border-left: 1px solid transparent;
}
.ctaLink {
background-color: transparent;
border: 1px solid transparent;
color: #006AB1;
cursor: pointer;
font-weight: 600;
padding: 0;
white-space: normal;
}
.ctaLink:focus {
outline: 1px solid #00bcf2;
}
.ctaLink:hover {
text-decoration: underline;
}
.step-icon {
display: flex;
height: 38px;
margin-right: 15px;
width: 38px;
}
.step-icon>div {
height: 30px;
width: 30px;
background-repeat: no-repeat;
}
.ms-logo-container {
min-width: 580px;
max-width: 980px;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
transition: bottom 400ms;
}
.ms-logo {
float: right;
background-image: url("data:image/svg+xml;utf8,%0A%3Csvg%20version%3D%221.1%22%20id%3D%22MS-symbol%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20xmlns%3Axlink%3D%22http%3A//www.w3.org/1999/xlink%22%20x%3D%220px%22%20y%3D%220px%22%0A%09%20viewBox%3D%220%200%20400%20120%22%20style%3D%22enable-background%3Anew%200%200%20400%20120%3B%22%20xml%3Aspace%3D%22preserve%22%3E%0A%3Cstyle%20type%3D%22text/css%22%3E%0A%09.st0%7Bfill%3Anone%3B%7D%0A%09.st1%7Bfill%3A%23737474%3B%7D%0A%09.st2%7Bfill%3A%23D63F26%3B%7D%0A%09.st3%7Bfill%3A%23167D3E%3B%7D%0A%09.st4%7Bfill%3A%232E76BC%3B%7D%0A%09.st5%7Bfill%3A%23FDB813%3B%7D%0A%3C/style%3E%0A%3Crect%20x%3D%220.6%22%20class%3D%22st0%22%20width%3D%22398.7%22%20height%3D%22119%22/%3E%0A%3Cpath%20class%3D%22st1%22%20d%3D%22M171.3%2C38.4v43.2h-7.5V47.7h-0.1l-13.4%2C33.9h-5l-13.7-33.9h-0.1v33.9h-6.9V38.4h10.8l12.4%2C32h0.2l13.1-32H171.3%0A%09z%20M177.6%2C41.7c0-1.2%2C0.4-2.2%2C1.3-3c0.9-0.8%2C1.9-1.2%2C3.1-1.2c1.3%2C0%2C2.4%2C0.4%2C3.2%2C1.3c0.8%2C0.8%2C1.3%2C1.8%2C1.3%2C3c0%2C1.2-0.4%2C2.2-1.3%2C3%0A%09c-0.9%2C0.8-1.9%2C1.2-3.2%2C1.2s-2.3-0.4-3.1-1.2C178%2C43.8%2C177.6%2C42.8%2C177.6%2C41.7z%20M185.7%2C50.6v31h-7.3v-31H185.7z%20M207.8%2C76.3%0A%09c1.1%2C0%2C2.3-0.3%2C3.6-0.8c1.3-0.5%2C2.5-1.2%2C3.6-2v6.8c-1.2%2C0.7-2.5%2C1.2-4%2C1.5c-1.5%2C0.3-3.1%2C0.5-4.9%2C0.5c-4.6%2C0-8.3-1.4-11.1-4.3%0A%09c-2.9-2.9-4.3-6.6-4.3-11c0-5%2C1.5-9.1%2C4.4-12.3c2.9-3.2%2C7-4.8%2C12.4-4.8c1.4%2C0%2C2.7%2C0.2%2C4.1%2C0.5c1.4%2C0.4%2C2.5%2C0.8%2C3.3%2C1.2v7%0A%09c-1.1-0.8-2.3-1.5-3.4-1.9c-1.2-0.5-2.4-0.7-3.6-0.7c-2.9%2C0-5.2%2C0.9-7%2C2.8c-1.8%2C1.9-2.7%2C4.4-2.7%2C7.6c0%2C3.1%2C0.8%2C5.6%2C2.5%2C7.3%0A%09C202.6%2C75.4%2C204.9%2C76.3%2C207.8%2C76.3z%20M235.7%2C50.1c0.6%2C0%2C1.1%2C0%2C1.6%2C0.1s0.9%2C0.2%2C1.2%2C0.3v7.4c-0.4-0.3-0.9-0.5-1.7-0.8%0A%09c-0.7-0.3-1.6-0.4-2.7-0.4c-1.8%2C0-3.3%2C0.8-4.5%2C2.3c-1.2%2C1.5-1.9%2C3.8-1.9%2C7v15.6h-7.3v-31h7.3v4.9h0.1c0.7-1.7%2C1.7-3%2C3-4%0A%09C232.2%2C50.6%2C233.8%2C50.1%2C235.7%2C50.1z%20M238.9%2C66.6c0-5.1%2C1.4-9.2%2C4.3-12.2c2.9-3%2C6.9-4.5%2C12.1-4.5c4.8%2C0%2C8.6%2C1.4%2C11.3%2C4.3%0A%09c2.7%2C2.9%2C4.1%2C6.8%2C4.1%2C11.7c0%2C5-1.4%2C9-4.3%2C12c-2.9%2C3-6.8%2C4.5-11.8%2C4.5c-4.8%2C0-8.6-1.4-11.4-4.2C240.3%2C75.3%2C238.9%2C71.4%2C238.9%2C66.6z%0A%09%20M246.5%2C66.3c0%2C3.2%2C0.7%2C5.7%2C2.2%2C7.4c1.5%2C1.7%2C3.6%2C2.6%2C6.3%2C2.6c2.7%2C0%2C4.7-0.9%2C6.1-2.6c1.4-1.7%2C2.1-4.2%2C2.1-7.6c0-3.3-0.7-5.8-2.2-7.5%0A%09c-1.4-1.7-3.4-2.5-6-2.5c-2.7%2C0-4.7%2C0.9-6.2%2C2.7C247.2%2C60.5%2C246.5%2C63%2C246.5%2C66.3z%20M281.5%2C58.8c0%2C1%2C0.3%2C1.9%2C1%2C2.5%0A%09c0.7%2C0.6%2C2.1%2C1.3%2C4.4%2C2.2c2.9%2C1.2%2C5%2C2.5%2C6.1%2C3.9c1.2%2C1.5%2C1.8%2C3.2%2C1.8%2C5.3c0%2C2.9-1.1%2C5.3-3.4%2C7c-2.2%2C1.8-5.3%2C2.7-9.1%2C2.7%0A%09c-1.3%2C0-2.7-0.2-4.3-0.5c-1.6-0.3-2.9-0.7-4-1.2v-7.2c1.3%2C0.9%2C2.8%2C1.7%2C4.3%2C2.2c1.5%2C0.5%2C2.9%2C0.8%2C4.2%2C0.8c1.6%2C0%2C2.9-0.2%2C3.6-0.7%0A%09c0.8-0.5%2C1.2-1.2%2C1.2-2.3c0-1-0.4-1.9-1.2-2.5c-0.8-0.7-2.4-1.5-4.6-2.4c-2.7-1.1-4.6-2.4-5.7-3.8c-1.1-1.4-1.7-3.2-1.7-5.4%0A%09c0-2.8%2C1.1-5.1%2C3.3-6.9c2.2-1.8%2C5.1-2.7%2C8.6-2.7c1.1%2C0%2C2.3%2C0.1%2C3.6%2C0.4c1.3%2C0.2%2C2.5%2C0.6%2C3.4%2C0.9v6.9c-1-0.6-2.1-1.2-3.4-1.7%0A%09c-1.3-0.5-2.6-0.7-3.8-0.7c-1.4%2C0-2.5%2C0.3-3.2%2C0.8C281.9%2C57.1%2C281.5%2C57.8%2C281.5%2C58.8z%20M297.9%2C66.6c0-5.1%2C1.4-9.2%2C4.3-12.2%0A%09c2.9-3%2C6.9-4.5%2C12.1-4.5c4.8%2C0%2C8.6%2C1.4%2C11.3%2C4.3c2.7%2C2.9%2C4.1%2C6.8%2C4.1%2C11.7c0%2C5-1.4%2C9-4.3%2C12c-2.9%2C3-6.8%2C4.5-11.8%2C4.5%0A%09c-4.8%2C0-8.6-1.4-11.4-4.2C299.4%2C75.3%2C297.9%2C71.4%2C297.9%2C66.6z%20M305.5%2C66.3c0%2C3.2%2C0.7%2C5.7%2C2.2%2C7.4c1.5%2C1.7%2C3.6%2C2.6%2C6.3%2C2.6%0A%09c2.7%2C0%2C4.7-0.9%2C6.1-2.6c1.4-1.7%2C2.1-4.2%2C2.1-7.6c0-3.3-0.7-5.8-2.2-7.5c-1.4-1.7-3.4-2.5-6-2.5c-2.7%2C0-4.7%2C0.9-6.2%2C2.7%0A%09C306.3%2C60.5%2C305.5%2C63%2C305.5%2C66.3z%20M353.9%2C56.6h-10.9v25h-7.4v-25h-5.2v-6h5.2v-4.3c0-3.3%2C1.1-5.9%2C3.2-8c2.1-2.1%2C4.8-3.1%2C8.1-3.1%0A%09c0.9%2C0%2C1.7%2C0%2C2.4%2C0.1c0.7%2C0.1%2C1.3%2C0.2%2C1.8%2C0.4V42c-0.2-0.1-0.7-0.3-1.3-0.5c-0.6-0.2-1.3-0.3-2.1-0.3c-1.5%2C0-2.7%2C0.5-3.5%2C1.4%0A%09s-1.2%2C2.4-1.2%2C4.2v3.7h10.9v-7l7.3-2.2v9.2h7.4v6h-7.4v14.5c0%2C1.9%2C0.3%2C3.3%2C1%2C4c0.7%2C0.8%2C1.8%2C1.2%2C3.3%2C1.2c0.4%2C0%2C0.9-0.1%2C1.5-0.3%0A%09c0.6-0.2%2C1.1-0.4%2C1.6-0.7v6c-0.5%2C0.3-1.2%2C0.5-2.3%2C0.7c-1.1%2C0.2-2.1%2C0.3-3.2%2C0.3c-3.1%2C0-5.4-0.8-6.9-2.5c-1.5-1.6-2.3-4.1-2.3-7.4%0A%09V56.6z%22/%3E%0A%3Cg%3E%0A%09%3Crect%20x%3D%2231%22%20y%3D%2224%22%20class%3D%22st2%22%20width%3D%2234.2%22%20height%3D%2234.2%22/%3E%0A%09%3Crect%20x%3D%2268.8%22%20y%3D%2224%22%20class%3D%22st3%22%20width%3D%2234.2%22%20height%3D%2234.2%22/%3E%0A%09%3Crect%20x%3D%2231%22%20y%3D%2261.8%22%20class%3D%22st4%22%20width%3D%2234.2%22%20height%3D%2234.2%22/%3E%0A%09%3Crect%20x%3D%2268.8%22%20y%3D%2261.8%22%20class%3D%22st5%22%20width%3D%2234.2%22%20height%3D%2234.2%22/%3E%0A%3C/g%3E%0A%3C/svg%3E%0A");
}
.ms-logo-container>div {
min-height: 60px;
width: 150px;
background-repeat: no-repeat;
}
.row {
padding: 90px 0px 0 20px;
min-width: 480px;
max-width: 1366px;
margin-left: auto;
margin-right: auto;
}
.column {
float: left;
width: 45%;
padding-right: 20px;
}
.row:after {
content: "";
display: table;
clear: both;
}
a {
text-decoration: none;
}
.download-the-emulator {
height: 20px;
color: #0063B1;
font-size: 15px;
line-height: 20px;
padding-bottom: 70px;
}
.how-to-iframe {
max-width: 700px !important;
min-width: 650px !important;
height: 700px !important;
}
.remove-frame-height {
height: 10px;
}
@media only screen and (max-width: 1300px) {
.ms-logo {
padding-top: 30px;
}
.header-text {
font-size: 40px;
}
.column {
float: none;
padding-top: 30px;
width: 100%;
}
.ms-logo-container {
padding-top: 30px;
min-width: 480px;
max-width: 650px;
margin-left: auto;
margin-right: auto;
}
.row {
padding: 20px 0px 0 20px;
min-width: 480px;
max-width: 650px;
margin-left: auto;
margin-right: auto;
}
}
@media only screen and (max-width: 1370px) {
header {
background-color: #55A0E0;
background-size: auto 200px;
}
}
@media only screen and (max-width: 1230px) {
header {
background-color: #55A0E0;
background-size: auto 200px;
}
.header-text {
font-size: 44px;
}
.header-icon {
height: 120px;
width: 120px;
}
}
@media only screen and (max-width: 1000px) {
header {
background-color: #55A0E0;
background-image: none;
}
}
@media only screen and (max-width: 632px) {
.header-text {
font-size: 32px;
}
.row {
padding: 10px 0px 0 10px;
max-width: 490px !important;
min-width: 410px !important;
}
.endpoint {
font-size: 25px;
}
.main-text {
font-size: 20px;
}
.step-container dl>dd {
font-size: 14px;
}
.column {
padding-right: 5px;
}
.header-icon {
height: 110px;
width: 110px;
}
.how-to-iframe {
max-width: 480px !important;
min-width: 400px !important;
height: 650px !important;
overflow: hidden;
}
}
.remove-frame-height {
max-height: 10px;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
loadFrame();
});
var loadFrame = function () {
var iframe = document.createElement('iframe');
iframe.setAttribute("id", "iframe");
var offLineHTMLContent = "";
var frameElement = document.getElementById("how-to-iframe");
if (window.navigator.onLine) {
iframe.src = 'https://docs.botframework.com/static/abs/pages/f5.htm';
iframe.setAttribute("scrolling", "no");
iframe.setAttribute("frameborder", "0");
iframe.setAttribute("width", "100%");
iframe.setAttribute("height", "100%");
var frameDiv = document.getElementById("how-to-iframe");
frameDiv.appendChild(iframe);
} else {
frameElement.classList.add("remove-frame-height");
}
};
</script>
</head>
<body>
<header class="header">
<div class="header-inner-container">
<div class="header-icon" style="display: inline-block"></div>
<div class="header-text" style="display: inline-block">QnAMakerBot Bot</div>
</div>
</header>
<div class="row">
<div class="column" class="main-content-area">
<div class="content-title">Your bot is ready!</div>
<div class="main-text main-text-p1">You can test your bot in the Bot Framework Emulator<br />
by connecting to http://localhost:3978/api/messages.</div>
<div class="main-text download-the-emulator"><a class="ctaLink"
href="https://aka.ms/bot-framework-F5-download-emulator" target="_blank">Download the Emulator</a>
</div>
<div class="main-text">Visit <a class="ctaLink" href="https://aka.ms/bot-framework-F5-abs-home"
target="_blank">Azure
Bot Service</a> to register your bot and add it to<br />
various channels. The bot's endpoint URL typically looks
like this:</div>
<div class="endpoint">https://<i>your_bots_hostname</i>/api/messages</div>
</div>
<div class="column how-to-iframe" id="how-to-iframe"></div>
</div>
<div class="ms-logo-container">
<div class="ms-logo"></div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.bot.sample.qnamaker.all.features;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTest {
@Test
public void contextLoads() {
}
}