Minor QnA test issues and formatting (#1016)
* Some tests weren't passing, just on some machines. * Standardized Okhttp3 version across modules * Okhttp3 dependencies in parent pom * Code reformatting (no logic changes) * Corrected a few CompletableFuture exceptional return results.
This commit is contained in:
Родитель
7b2d3a47c1
Коммит
de1867d1a2
|
@ -49,14 +49,20 @@
|
|||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.bot</groupId>
|
||||
<artifactId>bot-builder</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<artifactId>bot-integration-spring</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.bot</groupId>
|
||||
|
@ -69,27 +75,16 @@
|
|||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.bot</groupId>
|
||||
<artifactId>bot-integration-spring</artifactId>
|
||||
<version>4.6.0-preview8</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.9.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>mockwebserver</artifactId>
|
||||
<version>4.9.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.microsoft.bot.ai.qna.utils.TrainUtils;
|
|||
import com.microsoft.bot.builder.BotTelemetryClient;
|
||||
import com.microsoft.bot.builder.NullBotTelemetryClient;
|
||||
import com.microsoft.bot.builder.TurnContext;
|
||||
import com.microsoft.bot.connector.Async;
|
||||
import com.microsoft.bot.restclient.serializer.JacksonAdapter;
|
||||
import com.microsoft.bot.schema.Activity;
|
||||
import com.microsoft.bot.schema.ActivityTypes;
|
||||
|
@ -75,8 +76,12 @@ public class QnAMaker implements QnAMakerClient, TelemetryQnAMaker {
|
|||
* identifiable information in telemetry
|
||||
* events.
|
||||
*/
|
||||
public QnAMaker(QnAMakerEndpoint withEndpoint, QnAMakerOptions options,
|
||||
BotTelemetryClient withTelemetryClient, Boolean withLogPersonalInformation) {
|
||||
public QnAMaker(
|
||||
QnAMakerEndpoint withEndpoint,
|
||||
QnAMakerOptions options,
|
||||
BotTelemetryClient withTelemetryClient,
|
||||
Boolean withLogPersonalInformation
|
||||
) {
|
||||
if (withLogPersonalInformation == null) {
|
||||
withLogPersonalInformation = false;
|
||||
}
|
||||
|
@ -100,7 +105,8 @@ public class QnAMaker implements QnAMakerClient, TelemetryQnAMaker {
|
|||
|
||||
if (this.endpoint.getHost().endsWith("v2.0") || this.endpoint.getHost().endsWith("v3.0")) {
|
||||
throw new UnsupportedOperationException(
|
||||
"v2.0 and v3.0 of QnA Maker service" + " is no longer supported in the QnA Maker.");
|
||||
"v2.0 and v3.0 of QnA Maker service" + " is no longer supported in the QnA Maker."
|
||||
);
|
||||
}
|
||||
|
||||
this.telemetryClient = withTelemetryClient != null ? withTelemetryClient : new NullBotTelemetryClient();
|
||||
|
@ -113,8 +119,8 @@ public class QnAMaker implements QnAMakerClient, TelemetryQnAMaker {
|
|||
/**
|
||||
* Initializes a new instance of the {@link QnAMaker} class.
|
||||
*
|
||||
* @param withEndpoint The endpoint of the knowledge base to query.
|
||||
* @param options The options for the QnA Maker knowledge base.
|
||||
* @param withEndpoint The endpoint of the knowledge base to query.
|
||||
* @param options The options for the QnA Maker knowledge base.
|
||||
*/
|
||||
public QnAMaker(QnAMakerEndpoint withEndpoint, @Nullable QnAMakerOptions options) {
|
||||
this(withEndpoint, options, null, null);
|
||||
|
@ -170,10 +176,14 @@ public class QnAMaker implements QnAMakerClient, TelemetryQnAMaker {
|
|||
* @return A list of answers for the user query, sorted in decreasing order of
|
||||
* ranking score.
|
||||
*/
|
||||
public CompletableFuture<QueryResult[]> getAnswers(TurnContext turnContext, QnAMakerOptions options,
|
||||
Map<String, String> telemetryProperties, @Nullable Map<String, Double> telemetryMetrics) {
|
||||
public CompletableFuture<QueryResult[]> getAnswers(
|
||||
TurnContext turnContext,
|
||||
QnAMakerOptions options,
|
||||
Map<String, String> telemetryProperties,
|
||||
@Nullable Map<String, Double> telemetryMetrics
|
||||
) {
|
||||
return this.getAnswersRaw(turnContext, options, telemetryProperties, telemetryMetrics)
|
||||
.thenApply(result -> result.getAnswers());
|
||||
.thenApply(result -> result.getAnswers());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,22 +201,29 @@ public class QnAMaker implements QnAMakerClient, TelemetryQnAMaker {
|
|||
* @return A list of answers for the user query, sorted in decreasing order of
|
||||
* ranking score.
|
||||
*/
|
||||
public CompletableFuture<QueryResults> getAnswersRaw(TurnContext turnContext, QnAMakerOptions options,
|
||||
@Nullable Map<String, String> telemetryProperties, @Nullable Map<String, Double> telemetryMetrics) {
|
||||
public CompletableFuture<QueryResults> getAnswersRaw(
|
||||
TurnContext turnContext,
|
||||
QnAMakerOptions options,
|
||||
@Nullable Map<String, String> telemetryProperties,
|
||||
@Nullable Map<String, Double> telemetryMetrics
|
||||
) {
|
||||
if (turnContext == null) {
|
||||
throw new IllegalArgumentException("turnContext");
|
||||
return Async.completeExceptionally(new IllegalArgumentException("turnContext"));
|
||||
}
|
||||
if (turnContext.getActivity() == null) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("The %1$s property for %2$s can't be null.", "Activity", "turnContext"));
|
||||
return Async.completeExceptionally(
|
||||
new IllegalArgumentException(
|
||||
String.format("The %1$s property for %2$s can't be null.", "Activity", "turnContext")
|
||||
)
|
||||
);
|
||||
}
|
||||
Activity messageActivity = turnContext.getActivity();
|
||||
if (messageActivity == null || !messageActivity.isType(ActivityTypes.MESSAGE)) {
|
||||
throw new IllegalArgumentException("Activity type is not a message");
|
||||
return Async.completeExceptionally(new IllegalArgumentException("Activity type is not a message"));
|
||||
}
|
||||
|
||||
if (Strings.isNullOrEmpty(turnContext.getActivity().getText())) {
|
||||
throw new IllegalArgumentException("Null or empty text");
|
||||
return Async.completeExceptionally(new IllegalArgumentException("Null or empty text"));
|
||||
}
|
||||
|
||||
return this.generateAnswerHelper.getAnswersRaw(turnContext, messageActivity, options).thenCompose(result -> {
|
||||
|
@ -253,14 +270,19 @@ public class QnAMaker implements QnAMakerClient, TelemetryQnAMaker {
|
|||
* @return A Task representing the work to be executed.
|
||||
* @throws IOException Throws an IOException if there is any.
|
||||
*/
|
||||
protected CompletableFuture<Void> onQnaResults(QueryResult[] queryResults, TurnContext turnContext,
|
||||
@Nullable Map<String, String> telemetryProperties, @Nullable Map<String, Double> telemetryMetrics)
|
||||
throws IOException {
|
||||
return fillQnAEvent(queryResults, turnContext, telemetryProperties, telemetryMetrics).thenAccept(eventData -> {
|
||||
// Track the event
|
||||
this.telemetryClient.trackEvent(QnATelemetryConstants.QNA_MSG_EVENT, eventData.getLeft(),
|
||||
eventData.getRight());
|
||||
});
|
||||
protected CompletableFuture<Void> onQnaResults(
|
||||
QueryResult[] queryResults,
|
||||
TurnContext turnContext,
|
||||
@Nullable Map<String, String> telemetryProperties,
|
||||
@Nullable Map<String, Double> telemetryMetrics
|
||||
) throws IOException {
|
||||
return fillQnAEvent(queryResults, turnContext, telemetryProperties, telemetryMetrics).thenAccept(
|
||||
eventData -> {
|
||||
// Track the event
|
||||
this.telemetryClient
|
||||
.trackEvent(QnATelemetryConstants.QNA_MSG_EVENT, eventData.getLeft(), eventData.getRight());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -279,17 +301,20 @@ public class QnAMaker implements QnAMakerClient, TelemetryQnAMaker {
|
|||
* any properties passed from the GetAnswersAsync method.
|
||||
* @throws IOException Throws an IOException if there is any.
|
||||
*/
|
||||
protected CompletableFuture<Pair<Map<String, String>, Map<String, Double>>> fillQnAEvent(QueryResult[] queryResults,
|
||||
TurnContext turnContext, @Nullable Map<String, String> telemetryProperties,
|
||||
@Nullable Map<String, Double> telemetryMetrics) throws IOException {
|
||||
protected CompletableFuture<Pair<Map<String, String>, Map<String, Double>>> fillQnAEvent(
|
||||
QueryResult[] queryResults,
|
||||
TurnContext turnContext,
|
||||
@Nullable Map<String, String> telemetryProperties,
|
||||
@Nullable Map<String, Double> telemetryMetrics
|
||||
) throws IOException {
|
||||
Map<String, String> properties = new HashMap<String, String>();
|
||||
Map<String, Double> metrics = new HashMap<String, Double>();
|
||||
|
||||
properties.put(QnATelemetryConstants.KNOWLEDGE_BASE_ID_PROPERTY, this.endpoint.getKnowledgeBaseId());
|
||||
|
||||
String text = turnContext.getActivity().getText();
|
||||
String userName = turnContext.getActivity().getFrom() != null
|
||||
? turnContext.getActivity().getFrom().getName() : null;
|
||||
String userName =
|
||||
turnContext.getActivity().getFrom() != null ? turnContext.getActivity().getFrom().getName() : null;
|
||||
|
||||
// Use the LogPersonalInformation flag to toggle logging PII data, text and user
|
||||
// name are common examples
|
||||
|
@ -307,9 +332,14 @@ public class QnAMaker implements QnAMakerClient, TelemetryQnAMaker {
|
|||
if (queryResults.length > 0) {
|
||||
JacksonAdapter jacksonAdapter = new JacksonAdapter();
|
||||
QueryResult queryResult = queryResults[0];
|
||||
properties.put(QnATelemetryConstants.MATCHED_QUESTION_PROPERTY,
|
||||
jacksonAdapter.serialize(queryResult.getQuestions()));
|
||||
properties.put(QnATelemetryConstants.QUESTION_ID_PROPERTY, queryResult.getId().toString());
|
||||
properties.put(
|
||||
QnATelemetryConstants.MATCHED_QUESTION_PROPERTY,
|
||||
jacksonAdapter.serialize(queryResult.getQuestions())
|
||||
);
|
||||
properties.put(
|
||||
QnATelemetryConstants.QUESTION_ID_PROPERTY,
|
||||
queryResult.getId() != null ? queryResult.getId().toString() : ""
|
||||
);
|
||||
properties.put(QnATelemetryConstants.ANSWER_PROPERTY, queryResult.getAnswer());
|
||||
metrics.put(QnATelemetryConstants.SCORE_PROPERTY, queryResult.getScore().doubleValue());
|
||||
properties.put(QnATelemetryConstants.ARTICLE_FOUND_PROPERTY, "true");
|
||||
|
@ -323,13 +353,13 @@ public class QnAMaker implements QnAMakerClient, TelemetryQnAMaker {
|
|||
// Additional Properties can override "stock" properties.
|
||||
if (telemetryProperties != null) {
|
||||
Multimap<String, String> multiMapTelemetryProperties = LinkedListMultimap.create();
|
||||
for (Entry<String, String> entry: telemetryProperties.entrySet()) {
|
||||
for (Entry<String, String> entry : telemetryProperties.entrySet()) {
|
||||
multiMapTelemetryProperties.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (Entry<String, String> entry: properties.entrySet()) {
|
||||
for (Entry<String, String> entry : properties.entrySet()) {
|
||||
multiMapTelemetryProperties.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (Entry<String, Collection<String>> entry: multiMapTelemetryProperties.asMap().entrySet()) {
|
||||
for (Entry<String, Collection<String>> entry : multiMapTelemetryProperties.asMap().entrySet()) {
|
||||
telemetryProperties.put(entry.getKey(), entry.getValue().iterator().next());
|
||||
}
|
||||
}
|
||||
|
@ -337,13 +367,13 @@ public class QnAMaker implements QnAMakerClient, TelemetryQnAMaker {
|
|||
// Additional Metrics can override "stock" metrics.
|
||||
if (telemetryMetrics != null) {
|
||||
Multimap<String, Double> multiMapTelemetryMetrics = LinkedListMultimap.create();
|
||||
for (Entry<String, Double> entry: telemetryMetrics.entrySet()) {
|
||||
for (Entry<String, Double> entry : telemetryMetrics.entrySet()) {
|
||||
multiMapTelemetryMetrics.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (Entry<String, Double> entry: metrics.entrySet()) {
|
||||
for (Entry<String, Double> entry : metrics.entrySet()) {
|
||||
multiMapTelemetryMetrics.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (Entry<String, Collection<Double>> entry: multiMapTelemetryMetrics.asMap().entrySet()) {
|
||||
for (Entry<String, Collection<Double>> entry : multiMapTelemetryMetrics.asMap().entrySet()) {
|
||||
telemetryMetrics.put(entry.getKey(), entry.getValue().iterator().next());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,8 +33,12 @@ public interface QnAMakerClient {
|
|||
* @return A list of answers for the user query, sorted in decreasing order of
|
||||
* ranking score.
|
||||
*/
|
||||
CompletableFuture<QueryResult[]> getAnswers(TurnContext turnContext, QnAMakerOptions options,
|
||||
Map<String, String> telemetryProperties, @Nullable Map<String, Double> telemetryMetrics);
|
||||
CompletableFuture<QueryResult[]> getAnswers(
|
||||
TurnContext turnContext,
|
||||
QnAMakerOptions options,
|
||||
Map<String, String> telemetryProperties,
|
||||
@Nullable Map<String, Double> telemetryMetrics
|
||||
);
|
||||
|
||||
/**
|
||||
* Generates an answer from the knowledge base.
|
||||
|
@ -51,8 +55,12 @@ public interface QnAMakerClient {
|
|||
* @return A list of answers for the user query, sorted in decreasing order of
|
||||
* ranking score.
|
||||
*/
|
||||
CompletableFuture<QueryResults> getAnswersRaw(TurnContext turnContext, QnAMakerOptions options,
|
||||
@Nullable Map<String, String> telemetryProperties, @Nullable Map<String, Double> telemetryMetrics);
|
||||
CompletableFuture<QueryResults> getAnswersRaw(
|
||||
TurnContext turnContext,
|
||||
QnAMakerOptions options,
|
||||
@Nullable Map<String, String> telemetryProperties,
|
||||
@Nullable Map<String, Double> telemetryMetrics
|
||||
);
|
||||
|
||||
/**
|
||||
* Filters the ambiguous question for active learning.
|
||||
|
|
|
@ -197,8 +197,8 @@ public class QnAMakerRecognizer extends Recognizer {
|
|||
* Sets a value indicating whether gets or sets environment of knowledgebase to
|
||||
* be called.
|
||||
*
|
||||
* @param withIsTest A value indicating whether to call test or prod environment of
|
||||
* knowledgebase.
|
||||
* @param withIsTest A value indicating whether to call test or prod environment
|
||||
* of knowledgebase.
|
||||
*/
|
||||
public void setIsTest(Boolean withIsTest) {
|
||||
this.isTest = withIsTest;
|
||||
|
@ -234,8 +234,8 @@ public class QnAMakerRecognizer extends Recognizer {
|
|||
/**
|
||||
* Sets {@link Metadata} join operator.
|
||||
*
|
||||
* @param withStrictFiltersJoinOperator A value used for Join operation of Metadata
|
||||
* {@link Metadata}.
|
||||
* @param withStrictFiltersJoinOperator A value used for Join operation of
|
||||
* Metadata {@link Metadata}.
|
||||
*/
|
||||
public void setStrictFiltersJoinOperator(JoinOperator withStrictFiltersJoinOperator) {
|
||||
this.strictFiltersJoinOperator = withStrictFiltersJoinOperator;
|
||||
|
@ -290,7 +290,7 @@ public class QnAMakerRecognizer extends Recognizer {
|
|||
* Sets an expression to evaluate to set the context.
|
||||
*
|
||||
* @param withContext An expression to evaluate to QnARequestContext to pass as
|
||||
* context.
|
||||
* context.
|
||||
*/
|
||||
public void setContext(QnARequestContext withContext) {
|
||||
this.context = withContext;
|
||||
|
@ -329,8 +329,8 @@ public class QnAMakerRecognizer extends Recognizer {
|
|||
* Sets the flag to determine if personal information should be logged in
|
||||
* telemetry.
|
||||
*
|
||||
* @param withLogPersonalInformation The flag to indicate in personal information
|
||||
* should be logged in telemetry.
|
||||
* @param withLogPersonalInformation The flag to indicate in personal
|
||||
* information should be logged in telemetry.
|
||||
*/
|
||||
public void setLogPersonalInformation(Boolean withLogPersonalInformation) {
|
||||
this.logPersonalInformation = withLogPersonalInformation;
|
||||
|
@ -351,8 +351,12 @@ public class QnAMakerRecognizer extends Recognizer {
|
|||
* @return A {@link RecognizerResult} containing the QnA Maker result.
|
||||
*/
|
||||
@Override
|
||||
public CompletableFuture<RecognizerResult> recognize(DialogContext dialogContext, Activity activity,
|
||||
Map<String, String> telemetryProperties, Map<String, Double> telemetryMetrics) {
|
||||
public CompletableFuture<RecognizerResult> recognize(
|
||||
DialogContext dialogContext,
|
||||
Activity activity,
|
||||
Map<String, String> telemetryProperties,
|
||||
Map<String, Double> telemetryMetrics
|
||||
) {
|
||||
// Identify matched intents
|
||||
RecognizerResult recognizerResult = new RecognizerResult();
|
||||
recognizerResult.setText(activity.getText());
|
||||
|
@ -364,14 +368,11 @@ public class QnAMakerRecognizer extends Recognizer {
|
|||
|
||||
List<Metadata> filters = new ArrayList<Metadata>();
|
||||
// TODO this should be uncommented as soon as Expression is added in Java
|
||||
/* if (this.includeDialogNameInMetadata.getValue(dialogContext.getState())) {
|
||||
filters.add(new Metadata() {
|
||||
{
|
||||
setName("dialogName");
|
||||
setValue(dialogContext.getActiveDialog().getId());
|
||||
}
|
||||
});
|
||||
} */
|
||||
/*
|
||||
* if (this.includeDialogNameInMetadata.getValue(dialogContext.getState())) {
|
||||
* filters.add(new Metadata() { { setName("dialogName");
|
||||
* setValue(dialogContext.getActiveDialog().getId()); } }); }
|
||||
*/
|
||||
|
||||
// if there is $qna.metadata set add to filters
|
||||
Metadata[] externalMetadata = this.metadata;
|
||||
|
@ -402,13 +403,13 @@ public class QnAMakerRecognizer extends Recognizer {
|
|||
}
|
||||
Float internalTopAnswer = topAnswer.getScore();
|
||||
if (topAnswer.getAnswer().trim().toUpperCase().startsWith(intentPrefix.toUpperCase())) {
|
||||
recognizerResult.getIntents().put(
|
||||
topAnswer.getAnswer().trim().substring(intentPrefix.length()).trim(),
|
||||
new IntentScore() {
|
||||
{
|
||||
setScore(internalTopAnswer);
|
||||
}
|
||||
});
|
||||
recognizerResult.getIntents()
|
||||
.put(topAnswer.getAnswer().trim().substring(
|
||||
intentPrefix.length()).trim(),
|
||||
new IntentScore() {{
|
||||
setScore(internalTopAnswer);
|
||||
}}
|
||||
);
|
||||
} else {
|
||||
recognizerResult.getIntents().put(this.qnAMatchIntent, new IntentScore() {
|
||||
{
|
||||
|
@ -440,9 +441,12 @@ public class QnAMakerRecognizer extends Recognizer {
|
|||
});
|
||||
}
|
||||
|
||||
this.trackRecognizerResult(dialogContext, "QnAMakerRecognizerResult", this
|
||||
.fillRecognizerResultTelemetryProperties(recognizerResult, telemetryProperties, dialogContext),
|
||||
telemetryMetrics);
|
||||
this.trackRecognizerResult(
|
||||
dialogContext,
|
||||
"QnAMakerRecognizerResult",
|
||||
this.fillRecognizerResultTelemetryProperties(recognizerResult, telemetryProperties, dialogContext),
|
||||
telemetryMetrics
|
||||
);
|
||||
return recognizerResult;
|
||||
});
|
||||
});
|
||||
|
@ -473,8 +477,8 @@ public class QnAMakerRecognizer extends Recognizer {
|
|||
}
|
||||
};
|
||||
|
||||
return CompletableFuture.completedFuture(
|
||||
new QnAMaker(endpoint, new QnAMakerOptions(), this.getTelemetryClient(), logPersonalInfo));
|
||||
return CompletableFuture
|
||||
.completedFuture(new QnAMaker(endpoint, new QnAMakerOptions(), this.getTelemetryClient(), logPersonalInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -489,37 +493,53 @@ public class QnAMakerRecognizer extends Recognizer {
|
|||
* on the TelemetryClient.
|
||||
*/
|
||||
@Override
|
||||
protected Map<String, String> fillRecognizerResultTelemetryProperties(RecognizerResult recognizerResult,
|
||||
Map<String, String> telemetryProperties, @Nullable DialogContext dialogContext) {
|
||||
protected Map<String, String> fillRecognizerResultTelemetryProperties(
|
||||
RecognizerResult recognizerResult,
|
||||
Map<String, String> telemetryProperties,
|
||||
@Nullable DialogContext dialogContext
|
||||
) {
|
||||
if (dialogContext == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"dialogContext: DialogContext needed for state in "
|
||||
+ "AdaptiveRecognizer.FillRecognizerResultTelemetryProperties method.");
|
||||
"dialogContext: DialogContext needed for state in "
|
||||
+ "AdaptiveRecognizer.FillRecognizerResultTelemetryProperties method."
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, String> properties = new HashMap<String, String>() {
|
||||
{
|
||||
put("TopIntent",
|
||||
!recognizerResult.getIntents().isEmpty()
|
||||
? (String) recognizerResult.getIntents().keySet().toArray()[0]
|
||||
: null);
|
||||
put("TopIntentScore",
|
||||
!recognizerResult.getIntents().isEmpty()
|
||||
? Double.toString(
|
||||
((IntentScore) recognizerResult.getIntents().values().toArray()[0]).getScore())
|
||||
: null);
|
||||
put("Intents",
|
||||
!recognizerResult.getIntents().isEmpty()
|
||||
? Serialization.toStringSilent(recognizerResult.getIntents())
|
||||
: null);
|
||||
put("Entities",
|
||||
recognizerResult.getEntities() != null
|
||||
? Serialization.toStringSilent(recognizerResult.getEntities())
|
||||
: null);
|
||||
put("AdditionalProperties",
|
||||
!recognizerResult.getProperties().isEmpty()
|
||||
? Serialization.toStringSilent(recognizerResult.getProperties())
|
||||
: null);
|
||||
put(
|
||||
"TopIntent",
|
||||
!recognizerResult.getIntents().isEmpty()
|
||||
? (String) recognizerResult.getIntents().keySet().toArray()[0]
|
||||
: null
|
||||
);
|
||||
put(
|
||||
"TopIntentScore",
|
||||
!recognizerResult.getIntents()
|
||||
.isEmpty()
|
||||
? Double.toString(
|
||||
((IntentScore) recognizerResult.getIntents().values().toArray()[0]).getScore()
|
||||
)
|
||||
: null
|
||||
);
|
||||
put(
|
||||
"Intents",
|
||||
!recognizerResult.getIntents().isEmpty()
|
||||
? Serialization.toStringSilent(recognizerResult.getIntents())
|
||||
: null
|
||||
);
|
||||
put(
|
||||
"Entities",
|
||||
recognizerResult.getEntities() != null
|
||||
? Serialization.toStringSilent(recognizerResult.getEntities())
|
||||
: null
|
||||
);
|
||||
put(
|
||||
"AdditionalProperties",
|
||||
!recognizerResult.getProperties().isEmpty()
|
||||
? Serialization.toStringSilent(recognizerResult.getProperties())
|
||||
: null
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -531,10 +551,15 @@ public class QnAMakerRecognizer extends Recognizer {
|
|||
// Additional Properties can override "stock properties".
|
||||
if (telemetryProperties != null) {
|
||||
telemetryProperties.putAll(properties);
|
||||
Map<String, List<String>> telemetryPropertiesMap = telemetryProperties.entrySet().stream().collect(
|
||||
Collectors.groupingBy(Entry::getKey, Collectors.mapping(Entry::getValue, Collectors.toList())));
|
||||
return telemetryPropertiesMap.entrySet().stream()
|
||||
.collect(Collectors.toMap(Entry::getKey, e -> e.getValue().get(0)));
|
||||
Map<String, List<String>> telemetryPropertiesMap =
|
||||
telemetryProperties.entrySet()
|
||||
.stream()
|
||||
.collect(
|
||||
Collectors.groupingBy(Entry::getKey, Collectors.mapping(Entry::getValue, Collectors.toList()))
|
||||
);
|
||||
return telemetryPropertiesMap.entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Entry::getKey, e -> e.getValue().get(0)));
|
||||
}
|
||||
|
||||
return properties;
|
||||
|
|
|
@ -50,6 +50,10 @@ public interface TelemetryQnAMaker {
|
|||
* @return A list of answers for the user query, sorted in decreasing order of
|
||||
* ranking score.
|
||||
*/
|
||||
CompletableFuture<QueryResult[]> getAnswers(TurnContext turnContext, QnAMakerOptions options,
|
||||
Map<String, String> telemetryProperties, @Nullable Map<String, Double> telemetryMetrics);
|
||||
CompletableFuture<QueryResult[]> getAnswers(
|
||||
TurnContext turnContext,
|
||||
QnAMakerOptions options,
|
||||
Map<String, String> telemetryProperties,
|
||||
@Nullable Map<String, Double> telemetryMetrics
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.microsoft.bot.ai.qna.dialogs;
|
||||
|
||||
import com.microsoft.bot.connector.Async;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -81,8 +82,8 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
private String cardNoMatchText;
|
||||
|
||||
@JsonProperty("cardNoMatchResponse")
|
||||
private BindToActivity cardNoMatchResponse = new BindToActivity(
|
||||
MessageFactory.text(DEFAULT_CARD_NO_MATCH_RESPONSE));
|
||||
private BindToActivity cardNoMatchResponse =
|
||||
new BindToActivity(MessageFactory.text(DEFAULT_CARD_NO_MATCH_RESPONSE));
|
||||
|
||||
@JsonProperty("strictFilters")
|
||||
private Metadata[] strictFilters;
|
||||
|
@ -472,10 +473,20 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
* default client.
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:ParameterNumber")
|
||||
public QnAMakerDialog(String dialogId, String withKnowledgeBaseId, String withEndpointKey, String withHostName,
|
||||
@Nullable Activity withNoAnswer, Float withThreshold, String withActiveLearningCardTitle,
|
||||
String withCardNoMatchText, Integer withTop, @Nullable Activity withCardNoMatchResponse,
|
||||
@Nullable Metadata[] withStrictFilters, @Nullable OkHttpClient withHttpClient) {
|
||||
public QnAMakerDialog(
|
||||
String dialogId,
|
||||
String withKnowledgeBaseId,
|
||||
String withEndpointKey,
|
||||
String withHostName,
|
||||
@Nullable Activity withNoAnswer,
|
||||
Float withThreshold,
|
||||
String withActiveLearningCardTitle,
|
||||
String withCardNoMatchText,
|
||||
Integer withTop,
|
||||
@Nullable Activity withCardNoMatchResponse,
|
||||
@Nullable Metadata[] withStrictFilters,
|
||||
@Nullable OkHttpClient withHttpClient
|
||||
) {
|
||||
super(dialogId, null);
|
||||
if (knowledgeBaseId == null) {
|
||||
throw new IllegalArgumentException("knowledgeBaseId");
|
||||
|
@ -491,14 +502,17 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
this.endpointKey = withEndpointKey;
|
||||
this.threshold = withThreshold != null ? withThreshold : DEFAULT_THRESHOLD;
|
||||
this.top = withTop != null ? withTop : DEFAULT_TOP_N;
|
||||
this.activeLearningCardTitle = withActiveLearningCardTitle != null ? withActiveLearningCardTitle
|
||||
: DEFAULT_CARD_TITLE;
|
||||
this.activeLearningCardTitle =
|
||||
withActiveLearningCardTitle != null ? withActiveLearningCardTitle : DEFAULT_CARD_TITLE;
|
||||
this.cardNoMatchText = withCardNoMatchText != null ? withCardNoMatchText : DEFAULT_CARD_NO_MATCH_TEXT;
|
||||
this.strictFilters = withStrictFilters;
|
||||
this.noAnswer = new BindToActivity(
|
||||
withNoAnswer != null ? withNoAnswer : MessageFactory.text(DEFAULT_NO_ANSWER));
|
||||
this.cardNoMatchResponse = new BindToActivity(withCardNoMatchResponse != null ? withCardNoMatchResponse
|
||||
: MessageFactory.text(DEFAULT_CARD_NO_MATCH_RESPONSE));
|
||||
this.noAnswer =
|
||||
new BindToActivity(withNoAnswer != null ? withNoAnswer : MessageFactory.text(DEFAULT_NO_ANSWER));
|
||||
this.cardNoMatchResponse = new BindToActivity(
|
||||
withCardNoMatchResponse != null
|
||||
? withCardNoMatchResponse
|
||||
: MessageFactory.text(DEFAULT_CARD_NO_MATCH_RESPONSE)
|
||||
);
|
||||
this.httpClient = withHttpClient;
|
||||
|
||||
// add waterfall steps
|
||||
|
@ -542,14 +556,33 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
* default client.
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:ParameterNumber")
|
||||
public QnAMakerDialog(String withKnowledgeBaseId, String withEndpointKey, String withHostName,
|
||||
@Nullable Activity withNoAnswer, Float withThreshold, String withActiveLearningCardTitle,
|
||||
String withCardNoMatchText, Integer withTop, @Nullable Activity withCardNoMatchResponse,
|
||||
@Nullable Metadata[] withStrictFilters,
|
||||
@Nullable OkHttpClient withHttpClient) {
|
||||
this(QnAMakerDialog.class.getName(), withKnowledgeBaseId, withEndpointKey, withHostName, withNoAnswer,
|
||||
withThreshold, withActiveLearningCardTitle, withCardNoMatchText, withTop, withCardNoMatchResponse,
|
||||
withStrictFilters, withHttpClient);
|
||||
public QnAMakerDialog(
|
||||
String withKnowledgeBaseId,
|
||||
String withEndpointKey,
|
||||
String withHostName,
|
||||
@Nullable Activity withNoAnswer,
|
||||
Float withThreshold,
|
||||
String withActiveLearningCardTitle,
|
||||
String withCardNoMatchText,
|
||||
Integer withTop,
|
||||
@Nullable Activity withCardNoMatchResponse,
|
||||
@Nullable Metadata[] withStrictFilters,
|
||||
@Nullable OkHttpClient withHttpClient
|
||||
) {
|
||||
this(
|
||||
QnAMakerDialog.class.getName(),
|
||||
withKnowledgeBaseId,
|
||||
withEndpointKey,
|
||||
withHostName,
|
||||
withNoAnswer,
|
||||
withThreshold,
|
||||
withActiveLearningCardTitle,
|
||||
withCardNoMatchText,
|
||||
withTop,
|
||||
withCardNoMatchResponse,
|
||||
withStrictFilters,
|
||||
withHttpClient
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -570,7 +603,7 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
@Override
|
||||
public CompletableFuture<DialogTurnResult> beginDialog(DialogContext dc, @Nullable Object options) {
|
||||
if (dc == null) {
|
||||
throw new IllegalArgumentException("dc");
|
||||
return Async.completeExceptionally(new IllegalArgumentException("dc"));
|
||||
}
|
||||
|
||||
if (!dc.getContext().getActivity().isType(ActivityTypes.MESSAGE)) {
|
||||
|
@ -622,7 +655,7 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
|
||||
String reply = dc.getContext().getActivity().getText();
|
||||
QnAMakerDialogOptions dialogOptions = (QnAMakerDialogOptions) ObjectPath
|
||||
.getPathValue(dc.getActiveDialog().getState(), OPTIONS, QnAMakerDialogOptions.class);
|
||||
.getPathValue(dc.getActiveDialog().getState(), OPTIONS, QnAMakerDialogOptions.class);
|
||||
|
||||
if (reply.equalsIgnoreCase(dialogOptions.getResponseOptions().getCardNoMatchText())) {
|
||||
// it matches nomatch text, we like that.
|
||||
|
@ -630,8 +663,10 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
}
|
||||
|
||||
List<String> suggestedQuestions = (List<String>) dc.getState().get("this.suggestedQuestions");
|
||||
if (suggestedQuestions != null && suggestedQuestions.stream()
|
||||
.anyMatch(question -> question.compareToIgnoreCase(reply.trim()) == 0)) {
|
||||
if (
|
||||
suggestedQuestions != null
|
||||
&& suggestedQuestions.stream().anyMatch(question -> question.compareToIgnoreCase(reply.trim()) == 0)
|
||||
) {
|
||||
// it matches one of the suggested actions, we like that.
|
||||
return CompletableFuture.completedFuture(true);
|
||||
}
|
||||
|
@ -640,16 +675,17 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
return this.getQnAMakerClient(dc).thenCompose(qnaClient -> {
|
||||
QnAMakerDialog.resetOptions(dc, dialogOptions);
|
||||
|
||||
return qnaClient.getAnswersRaw(dc.getContext(), dialogOptions.getQnAMakerOptions(),
|
||||
null, null)
|
||||
.thenApply(response -> {
|
||||
return qnaClient.getAnswersRaw(dc.getContext(), dialogOptions.getQnAMakerOptions(), null, null)
|
||||
.thenApply(
|
||||
response -> {
|
||||
// cache result so step doesn't have to do it again, this is a turn cache and we
|
||||
// use hashcode so we don't conflict with any other qnamakerdialogs out there.
|
||||
dc.getState().setValue(String.format("turn.qnaresult%s", this.hashCode()), response);
|
||||
|
||||
// disable interruption if we have answers.
|
||||
return !(response.getAnswers().length == 0);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
// call base for default behavior.
|
||||
|
@ -657,8 +693,7 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link QnAMakerClient} to use to access the QnA Maker knowledge
|
||||
* base.
|
||||
* Gets an {@link QnAMakerClient} to use to access the QnA Maker knowledge base.
|
||||
*
|
||||
* @param dc The {@link DialogContext} for the current turn of conversation.
|
||||
* @return A Task representing the asynchronous operation. If the task is
|
||||
|
@ -679,8 +714,9 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
}
|
||||
};
|
||||
|
||||
return this.getQnAMakerOptions(dc).thenApply(options -> new QnAMaker(endpoint, options,
|
||||
this.getTelemetryClient(), this.logPersonalInformation));
|
||||
return this.getQnAMakerOptions(
|
||||
dc
|
||||
).thenApply(options -> new QnAMaker(endpoint, options, this.getTelemetryClient(), this.logPersonalInformation));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -717,12 +753,10 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
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);
|
||||
setActiveLearningCardTitle(
|
||||
activeLearningCardTitle != null ? activeLearningCardTitle : DEFAULT_CARD_TITLE
|
||||
);
|
||||
setCardNoMatchText(cardNoMatchText != null ? cardNoMatchText : DEFAULT_CARD_NO_MATCH_TEXT);
|
||||
setCardNoMatchResponse(cardNoMatchResponse.bind(dc, null).join());
|
||||
}
|
||||
});
|
||||
|
@ -736,8 +770,8 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
* @return An object of Task of type {@link DialogTurnResult}.
|
||||
*/
|
||||
protected CompletableFuture<DialogTurnResult> displayQnAResult(WaterfallStepContext stepContext) {
|
||||
QnAMakerDialogOptions dialogOptions = ObjectPath.getPathValue(stepContext.getActiveDialog().getState(),
|
||||
OPTIONS, QnAMakerDialogOptions.class);
|
||||
QnAMakerDialogOptions dialogOptions =
|
||||
ObjectPath.getPathValue(stepContext.getActiveDialog().getState(), OPTIONS, QnAMakerDialogOptions.class);
|
||||
String reply = stepContext.getContext().getActivity().getText();
|
||||
if (reply.compareToIgnoreCase(dialogOptions.getResponseOptions().getCardNoMatchText()) == 0) {
|
||||
Activity activity = dialogOptions.getResponseOptions().getCardNoMatchResponse();
|
||||
|
@ -751,8 +785,8 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
}
|
||||
|
||||
// If previous QnAId is present, replace the dialog
|
||||
Integer previousQnAId = ObjectPath.getPathValue(stepContext.getActiveDialog().getState(), PREVIOUS_QNA_ID,
|
||||
Integer.class, 0);
|
||||
Integer previousQnAId =
|
||||
ObjectPath.getPathValue(stepContext.getActiveDialog().getState(), PREVIOUS_QNA_ID, Integer.class, 0);
|
||||
if (previousQnAId > 0) {
|
||||
// restart the waterfall to step 0
|
||||
return this.runStep(stepContext, 0, DialogReason.BEGIN_CALLED, null);
|
||||
|
@ -781,10 +815,10 @@ 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);
|
||||
Integer previousQnAId = ObjectPath.getPathValue(dc.getActiveDialog().getState(), PREVIOUS_QNA_ID,
|
||||
Integer.class, 0);
|
||||
Map<String, Integer> previousContextData =
|
||||
ObjectPath.getPathValue(dc.getActiveDialog().getState(), QNA_CONTEXT_DATA, Map.class);
|
||||
Integer previousQnAId =
|
||||
ObjectPath.getPathValue(dc.getActiveDialog().getState(), PREVIOUS_QNA_ID, Integer.class, 0);
|
||||
|
||||
if (previousQnAId > 0) {
|
||||
dialogOptions.getQnAMakerOptions().setContext(new QnARequestContext() {
|
||||
|
@ -804,8 +838,8 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
// clear suggestedQuestions between turns.
|
||||
stepContext.getState().removeValue("this.suggestedQuestions");
|
||||
|
||||
QnAMakerDialogOptions dialogOptions = ObjectPath.getPathValue(stepContext.getActiveDialog().getState(),
|
||||
OPTIONS, QnAMakerDialogOptions.class);
|
||||
QnAMakerDialogOptions dialogOptions =
|
||||
ObjectPath.getPathValue(stepContext.getActiveDialog().getState(), OPTIONS, QnAMakerDialogOptions.class);
|
||||
QnAMakerDialog.resetOptions(stepContext, dialogOptions);
|
||||
|
||||
// Storing the context info
|
||||
|
@ -813,12 +847,12 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
|
||||
// Calling QnAMaker to get response.
|
||||
return this.getQnAMakerClient(stepContext).thenApply(qnaMakerClient -> {
|
||||
QueryResults response = (QueryResults) stepContext.getState()
|
||||
.get(String.format("turn.qnaresult%s", this.hashCode()));
|
||||
QueryResults response =
|
||||
(QueryResults) stepContext.getState().get(String.format("turn.qnaresult%s", this.hashCode()));
|
||||
if (response == null) {
|
||||
response = qnaMakerClient.getAnswersRaw(stepContext.getContext(), dialogOptions.getQnAMakerOptions(),
|
||||
null, null)
|
||||
.join();
|
||||
response = qnaMakerClient
|
||||
.getAnswersRaw(stepContext.getContext(), dialogOptions.getQnAMakerOptions(), null, null)
|
||||
.join();
|
||||
}
|
||||
|
||||
// Resetting previous query.
|
||||
|
@ -833,8 +867,10 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
// Check if active learning is enabled.
|
||||
// MaximumScoreForLowScoreVariation is the score above which no need to check
|
||||
// for feedback.
|
||||
if (response.getAnswers().length > 0 && response.getAnswers()[0]
|
||||
.getScore() <= (ActiveLearningUtils.getMaximumScoreForLowScoreVariation() / PERCENTAGE_DIVISOR)) {
|
||||
if (
|
||||
response.getAnswers().length > 0 && response.getAnswers()[0]
|
||||
.getScore() <= (ActiveLearningUtils.getMaximumScoreForLowScoreVariation() / PERCENTAGE_DIVISOR)
|
||||
) {
|
||||
// Get filtered list of the response that support low score variation criteria.
|
||||
response.setAnswers(qnaMakerClient.getLowScoreVariation(response.getAnswers()));
|
||||
|
||||
|
@ -845,9 +881,11 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
}
|
||||
|
||||
// Get active learning suggestion card activity.
|
||||
Activity message = QnACardBuilder.getSuggestionsCard(suggestedQuestions,
|
||||
dialogOptions.getResponseOptions().getActiveLearningCardTitle(),
|
||||
dialogOptions.getResponseOptions().getCardNoMatchText());
|
||||
Activity message = QnACardBuilder.getSuggestionsCard(
|
||||
suggestedQuestions,
|
||||
dialogOptions.getResponseOptions().getActiveLearningCardTitle(),
|
||||
dialogOptions.getResponseOptions().getCardNoMatchText()
|
||||
);
|
||||
stepContext.getContext().sendActivity(message).join();
|
||||
|
||||
ObjectPath.setPathValue(stepContext.getActiveDialog().getState(), OPTIONS, dialogOptions);
|
||||
|
@ -870,33 +908,37 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
}
|
||||
|
||||
private CompletableFuture<DialogTurnResult> callTrain(WaterfallStepContext stepContext) {
|
||||
QnAMakerDialogOptions dialogOptions = ObjectPath.getPathValue(stepContext.getActiveDialog().getState(), OPTIONS,
|
||||
QnAMakerDialogOptions.class);
|
||||
QnAMakerDialogOptions dialogOptions =
|
||||
ObjectPath.getPathValue(stepContext.getActiveDialog().getState(), OPTIONS, QnAMakerDialogOptions.class);
|
||||
List<QueryResult> trainResponses = (List<QueryResult>) stepContext.getValues().get(ValueProperty.QNA_DATA);
|
||||
String currentQuery = (String) stepContext.getValues().get(ValueProperty.CURRENT_QUERY);
|
||||
|
||||
String reply = stepContext.getContext().getActivity().getText();
|
||||
|
||||
if (trainResponses.size() > 1) {
|
||||
QueryResult qnaResult = trainResponses
|
||||
.stream().filter(kvp -> kvp.getQuestions()[0].equals(reply)).findFirst().orElse(null);
|
||||
QueryResult qnaResult =
|
||||
trainResponses.stream().filter(kvp -> kvp.getQuestions()[0].equals(reply)).findFirst().orElse(null);
|
||||
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() {
|
||||
{
|
||||
setUserId(stepContext.getContext().getActivity().getId());
|
||||
setUserQuestion(currentQuery);
|
||||
setQnaId(qnaResult.getId());
|
||||
}
|
||||
};
|
||||
FeedbackRecord[] records = {record};
|
||||
FeedbackRecords feedbackRecords = new FeedbackRecords() {{
|
||||
setRecords(records);
|
||||
}};
|
||||
FeedbackRecords feedbackRecords = new FeedbackRecords() {
|
||||
{
|
||||
setRecords(records);
|
||||
}
|
||||
};
|
||||
// Call Active Learning Train API
|
||||
return this.getQnAMakerClient(stepContext).thenCompose(qnaClient -> {
|
||||
try {
|
||||
return qnaClient.callTrain(feedbackRecords).thenCompose(task ->
|
||||
stepContext.next(new ArrayList<QueryResult>().add(qnaResult)));
|
||||
return qnaClient.callTrain(feedbackRecords)
|
||||
.thenCompose(task -> stepContext.next(new ArrayList<QueryResult>().add(qnaResult)));
|
||||
} catch (IOException e) {
|
||||
LoggerFactory.getLogger(QnAMakerDialog.class).error("callTrain");
|
||||
}
|
||||
|
@ -921,8 +963,8 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
}
|
||||
|
||||
private CompletableFuture<DialogTurnResult> checkForMultiTurnPrompt(WaterfallStepContext stepContext) {
|
||||
QnAMakerDialogOptions dialogOptions = ObjectPath.getPathValue(stepContext.getActiveDialog().getState(),
|
||||
OPTIONS, QnAMakerDialogOptions.class);
|
||||
QnAMakerDialogOptions dialogOptions =
|
||||
ObjectPath.getPathValue(stepContext.getActiveDialog().getState(), OPTIONS, QnAMakerDialogOptions.class);
|
||||
List<QueryResult> response = (List<QueryResult>) stepContext.getResult();
|
||||
if (response != null && response.size() > 0) {
|
||||
// -Check if context is present and prompt exists
|
||||
|
@ -936,21 +978,21 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
QueryResult answer = response.get(0);
|
||||
|
||||
if (answer.getContext() != null && answer.getContext().getPrompts().length > 0) {
|
||||
Map<String, Integer> previousContextData = ObjectPath.getPathValue(
|
||||
stepContext.getActiveDialog().getState(), QNA_CONTEXT_DATA, Map.class);
|
||||
Map<String, Integer> previousContextData =
|
||||
ObjectPath.getPathValue(stepContext.getActiveDialog().getState(), QNA_CONTEXT_DATA, Map.class);
|
||||
|
||||
for (QnAMakerPrompt prompt : answer.getContext().getPrompts()) {
|
||||
previousContextData.put(prompt.getDisplayText(), prompt.getQnaId());
|
||||
}
|
||||
|
||||
ObjectPath.setPathValue(stepContext.getActiveDialog().getState(),
|
||||
QNA_CONTEXT_DATA, previousContextData);
|
||||
ObjectPath
|
||||
.setPathValue(stepContext.getActiveDialog().getState(), QNA_CONTEXT_DATA, previousContextData);
|
||||
ObjectPath.setPathValue(stepContext.getActiveDialog().getState(), PREVIOUS_QNA_ID, answer.getId());
|
||||
ObjectPath.setPathValue(stepContext.getActiveDialog().getState(), OPTIONS, dialogOptions);
|
||||
|
||||
// Get multi-turn prompts card activity.
|
||||
Activity message = QnACardBuilder.getQnAPromptsCard(answer,
|
||||
dialogOptions.getResponseOptions().getCardNoMatchText());
|
||||
Activity message =
|
||||
QnACardBuilder.getQnAPromptsCard(answer, dialogOptions.getResponseOptions().getCardNoMatchText());
|
||||
stepContext.getContext().sendActivity(message).join();
|
||||
|
||||
return CompletableFuture.completedFuture(new DialogTurnResult(DialogTurnStatus.WAITING));
|
||||
|
@ -967,6 +1009,7 @@ public class QnAMakerDialog extends WaterfallDialog {
|
|||
public static final String CURRENT_QUERY = "currentQuery";
|
||||
public static final String QNA_DATA = "qnaData";
|
||||
|
||||
private ValueProperty() { }
|
||||
private ValueProperty() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,5 +22,6 @@ public final class RankerTypes {
|
|||
*/
|
||||
public static final String AUTO_SUGGEST_QUESTION = "AutoSuggestQuestion";
|
||||
|
||||
private RankerTypes() { }
|
||||
private RankerTypes() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@ public final class ActiveLearningUtils {
|
|||
|
||||
private static Float minimumScoreForLowScoreVariation = MINIMUM_SCORE_VARIATION;
|
||||
|
||||
private ActiveLearningUtils() { }
|
||||
private ActiveLearningUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets maximum Score For Low Score Variation.
|
||||
|
@ -47,7 +48,7 @@ public final class ActiveLearningUtils {
|
|||
* Sets maximum Score For Low Score Variation.
|
||||
*
|
||||
* @param withMaximumScoreForLowScoreVariation Maximum Score For Low Score
|
||||
* Variation.
|
||||
* Variation.
|
||||
*/
|
||||
public static void setMaximumScoreForLowScoreVariation(Float withMaximumScoreForLowScoreVariation) {
|
||||
ActiveLearningUtils.maximumScoreForLowScoreVariation = withMaximumScoreForLowScoreVariation;
|
||||
|
@ -66,7 +67,7 @@ public final class ActiveLearningUtils {
|
|||
* Sets minimum Score For Low Score Variation.
|
||||
*
|
||||
* @param withMinimumScoreForLowScoreVariation Minimum Score For Low Score
|
||||
* Variation.
|
||||
* Variation.
|
||||
*/
|
||||
public static void setMinimumScoreForLowScoreVariation(Float withMinimumScoreForLowScoreVariation) {
|
||||
ActiveLearningUtils.minimumScoreForLowScoreVariation = withMinimumScoreForLowScoreVariation;
|
||||
|
@ -101,12 +102,17 @@ public final class ActiveLearningUtils {
|
|||
filteredQnaSearchResult.add(qnaSearchResults.get(0));
|
||||
|
||||
for (int i = 1; i < qnaSearchResults.size(); i++) {
|
||||
if (ActiveLearningUtils
|
||||
.includeForClustering(prevScore, qnaSearchResults.get(i).getScore() * PERCENTAGE_DIVISOR,
|
||||
ActiveLearningUtils.PREVIOUS_LOW_SCORE_VARIATION_MULTIPLIER)
|
||||
&& ActiveLearningUtils.includeForClustering(topAnswerScore,
|
||||
qnaSearchResults.get(i).getScore() * PERCENTAGE_DIVISOR,
|
||||
ActiveLearningUtils.MAX_LOW_SCORE_VARIATION_MULTIPLIER)) {
|
||||
if (
|
||||
ActiveLearningUtils.includeForClustering(
|
||||
prevScore,
|
||||
qnaSearchResults.get(i).getScore() * PERCENTAGE_DIVISOR,
|
||||
ActiveLearningUtils.PREVIOUS_LOW_SCORE_VARIATION_MULTIPLIER
|
||||
) && ActiveLearningUtils.includeForClustering(
|
||||
topAnswerScore,
|
||||
qnaSearchResults.get(i).getScore() * PERCENTAGE_DIVISOR,
|
||||
ActiveLearningUtils.MAX_LOW_SCORE_VARIATION_MULTIPLIER
|
||||
)
|
||||
) {
|
||||
prevScore = qnaSearchResults.get(i).getScore() * PERCENTAGE_DIVISOR;
|
||||
filteredQnaSearchResult.add(qnaSearchResults.get(i));
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ public class BindToActivity {
|
|||
|
||||
/**
|
||||
* Construct to bind an Activity.
|
||||
*
|
||||
* @param withActivity activity to bind.
|
||||
*/
|
||||
public BindToActivity(Activity withActivity) {
|
||||
|
@ -27,7 +28,7 @@ public class BindToActivity {
|
|||
/**
|
||||
*
|
||||
* @param context The context.
|
||||
* @param data The data.
|
||||
* @param data The data.
|
||||
* @return The activity.
|
||||
*/
|
||||
public CompletableFuture<Activity> bind(DialogContext context, @Nullable Object data) {
|
||||
|
@ -36,6 +37,7 @@ public class BindToActivity {
|
|||
|
||||
/**
|
||||
* Get the activity text.
|
||||
*
|
||||
* @return The activity text.
|
||||
*/
|
||||
public String toString() {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
package com.microsoft.bot.ai.qna.utils;
|
||||
|
||||
import com.microsoft.bot.connector.Async;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -39,11 +40,10 @@ public class GenerateAnswerUtils {
|
|||
/**
|
||||
* Initializes a new instance of the {@link GenerateAnswerUtils} class.
|
||||
*
|
||||
* @param withEndpoint QnA Maker endpoint details.
|
||||
* @param withOptions QnA Maker options.
|
||||
* @param withEndpoint QnA Maker endpoint details.
|
||||
* @param withOptions QnA Maker options.
|
||||
*/
|
||||
public GenerateAnswerUtils(QnAMakerEndpoint withEndpoint,
|
||||
QnAMakerOptions withOptions) {
|
||||
public GenerateAnswerUtils(QnAMakerEndpoint withEndpoint, QnAMakerOptions withOptions) {
|
||||
this.endpoint = withEndpoint;
|
||||
|
||||
this.options = withOptions != null ? withOptions : new QnAMakerOptions();
|
||||
|
@ -74,15 +74,18 @@ public class GenerateAnswerUtils {
|
|||
* @param turnContext The Turn Context that contains the user question to be
|
||||
* queried against your knowledge base.
|
||||
* @param messageActivity Message activity of the turn context.
|
||||
* @param withOptions The options for the QnA Maker knowledge base. If null,
|
||||
* @param withOptions The options for the QnA Maker knowledge base. If null,
|
||||
* constructor option is used for this instance.
|
||||
* @return A list of answers for the user query, sorted in decreasing order of
|
||||
* ranking score.
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
@Deprecated
|
||||
public CompletableFuture<QueryResult[]> getAnswers(TurnContext turnContext, Activity messageActivity,
|
||||
QnAMakerOptions withOptions) throws IOException {
|
||||
public CompletableFuture<QueryResult[]> getAnswers(
|
||||
TurnContext turnContext,
|
||||
Activity messageActivity,
|
||||
QnAMakerOptions withOptions
|
||||
) throws IOException {
|
||||
return this.getAnswersRaw(turnContext, messageActivity, withOptions).thenApply(result -> result.getAnswers());
|
||||
}
|
||||
|
||||
|
@ -92,24 +95,34 @@ public class GenerateAnswerUtils {
|
|||
* @param turnContext The Turn Context that contains the user question to be
|
||||
* queried against your knowledge base.
|
||||
* @param messageActivity Message activity of the turn context.
|
||||
* @param withOptions The options for the QnA Maker knowledge base. If null,
|
||||
* @param withOptions The options for the QnA Maker knowledge base. If null,
|
||||
* constructor option is used for this instance.
|
||||
* @return A list of answers for the user query, sorted in decreasing order of
|
||||
* ranking score.
|
||||
*/
|
||||
public CompletableFuture<QueryResults> getAnswersRaw(TurnContext turnContext, Activity messageActivity,
|
||||
QnAMakerOptions withOptions) {
|
||||
public CompletableFuture<QueryResults> getAnswersRaw(
|
||||
TurnContext turnContext,
|
||||
Activity messageActivity,
|
||||
QnAMakerOptions withOptions
|
||||
) {
|
||||
if (turnContext == null) {
|
||||
throw new IllegalArgumentException("turnContext");
|
||||
return Async.completeExceptionally(new IllegalArgumentException("turnContext"));
|
||||
}
|
||||
|
||||
if (turnContext.getActivity() == null) {
|
||||
throw new IllegalArgumentException(String.format("The %1$s property for %2$s can't be null: turnContext",
|
||||
turnContext.getActivity(), "turnContext"));
|
||||
return Async.completeExceptionally(
|
||||
new IllegalArgumentException(
|
||||
String.format(
|
||||
"The %1$s property for %2$s can't be null: turnContext",
|
||||
turnContext.getActivity(),
|
||||
"turnContext"
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (messageActivity == null) {
|
||||
throw new IllegalArgumentException("Activity type is not a message");
|
||||
return Async.completeExceptionally(new IllegalArgumentException("Activity type is not a message"));
|
||||
}
|
||||
|
||||
QnAMakerOptions hydratedOptions = this.hydrateOptions(withOptions);
|
||||
|
@ -126,8 +139,10 @@ public class GenerateAnswerUtils {
|
|||
}
|
||||
}
|
||||
|
||||
private static CompletableFuture<QueryResults> formatQnAResult(JsonNode response, QnAMakerOptions options)
|
||||
throws IOException {
|
||||
private static CompletableFuture<QueryResults> formatQnAResult(
|
||||
JsonNode response,
|
||||
QnAMakerOptions options
|
||||
) throws IOException {
|
||||
String jsonResponse = null;
|
||||
JacksonAdapter jacksonAdapter = new JacksonAdapter();
|
||||
QueryResults results = null;
|
||||
|
@ -137,8 +152,10 @@ public class GenerateAnswerUtils {
|
|||
for (QueryResult answer : results.getAnswers()) {
|
||||
answer.setScore(answer.getScore() / PERCENTAGE_DIVISOR);
|
||||
}
|
||||
List<QueryResult> answerList = Arrays.asList(results.getAnswers()).
|
||||
stream().filter(answer -> answer.getScore() > options.getScoreThreshold()).collect(Collectors.toList());
|
||||
List<QueryResult> answerList = Arrays.asList(results.getAnswers())
|
||||
.stream()
|
||||
.filter(answer -> answer.getScore() > options.getScoreThreshold())
|
||||
.collect(Collectors.toList());
|
||||
results.setAnswers(answerList.toArray(new QueryResult[answerList.size()]));
|
||||
|
||||
return CompletableFuture.completedFuture(results);
|
||||
|
@ -154,8 +171,9 @@ public class GenerateAnswerUtils {
|
|||
}
|
||||
|
||||
if (options.getScoreThreshold() < 0 || options.getScoreThreshold() > 1) {
|
||||
throw new IllegalArgumentException(String
|
||||
.format("options: The %s property should be a value between 0 and 1", options.getScoreThreshold()));
|
||||
throw new IllegalArgumentException(
|
||||
String.format("options: The %s property should be a value between 0 and 1", options.getScoreThreshold())
|
||||
);
|
||||
}
|
||||
|
||||
if (options.getTimeout() == 0.0d) {
|
||||
|
@ -187,15 +205,16 @@ public class GenerateAnswerUtils {
|
|||
QnAMakerOptions hydratedOptions = null;
|
||||
|
||||
try {
|
||||
hydratedOptions = jacksonAdapter.deserialize(jacksonAdapter.serialize(options),
|
||||
QnAMakerOptions.class);
|
||||
hydratedOptions = jacksonAdapter.deserialize(jacksonAdapter.serialize(options), QnAMakerOptions.class);
|
||||
} catch (IOException e) {
|
||||
LoggerFactory.getLogger(GenerateAnswerUtils.class).error("hydrateOptions");
|
||||
}
|
||||
|
||||
if (queryOptions != null) {
|
||||
if (queryOptions.getScoreThreshold() != hydratedOptions.getScoreThreshold()
|
||||
&& queryOptions.getScoreThreshold() != 0) {
|
||||
if (
|
||||
queryOptions.getScoreThreshold() != hydratedOptions.getScoreThreshold()
|
||||
&& queryOptions.getScoreThreshold() != 0
|
||||
) {
|
||||
hydratedOptions.setScoreThreshold(queryOptions.getScoreThreshold());
|
||||
}
|
||||
|
||||
|
@ -210,18 +229,24 @@ public class GenerateAnswerUtils {
|
|||
hydratedOptions.setContext(queryOptions.getContext());
|
||||
hydratedOptions.setQnAId(queryOptions.getQnAId());
|
||||
hydratedOptions.setIsTest(queryOptions.getIsTest());
|
||||
hydratedOptions.setRankerType(queryOptions.getRankerType() != null ? queryOptions.getRankerType()
|
||||
: RankerTypes.DEFAULT_RANKER_TYPE);
|
||||
hydratedOptions.setRankerType(
|
||||
queryOptions.getRankerType() != null ? queryOptions.getRankerType() : RankerTypes.DEFAULT_RANKER_TYPE
|
||||
);
|
||||
hydratedOptions.setStrictFiltersJoinOperator(queryOptions.getStrictFiltersJoinOperator());
|
||||
}
|
||||
|
||||
return hydratedOptions;
|
||||
}
|
||||
|
||||
private CompletableFuture<QueryResults> queryQnaService(Activity messageActivity, QnAMakerOptions withOptions)
|
||||
throws IOException {
|
||||
String requestUrl = String.format("%1$s/knowledgebases/%2$s/generateanswer", this.endpoint.getHost(),
|
||||
this.endpoint.getKnowledgeBaseId());
|
||||
private CompletableFuture<QueryResults> queryQnaService(
|
||||
Activity messageActivity,
|
||||
QnAMakerOptions withOptions
|
||||
) throws IOException {
|
||||
String requestUrl = String.format(
|
||||
"%1$s/knowledgebases/%2$s/generateanswer",
|
||||
this.endpoint.getHost(),
|
||||
this.endpoint.getKnowledgeBaseId()
|
||||
);
|
||||
JacksonAdapter jacksonAdapter = new JacksonAdapter();
|
||||
String jsonRequest = null;
|
||||
|
||||
|
@ -250,8 +275,12 @@ public class GenerateAnswerUtils {
|
|||
});
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> emitTraceInfo(TurnContext turnContext, Activity messageActivity,
|
||||
QueryResult[] result, QnAMakerOptions withOptions) {
|
||||
private CompletableFuture<Void> emitTraceInfo(
|
||||
TurnContext turnContext,
|
||||
Activity messageActivity,
|
||||
QueryResult[] result,
|
||||
QnAMakerOptions withOptions
|
||||
) {
|
||||
String knowledgeBaseId = this.endpoint.getKnowledgeBaseId();
|
||||
QnAMakerTraceInfo traceInfo = new QnAMakerTraceInfo() {
|
||||
{
|
||||
|
@ -267,8 +296,12 @@ public class GenerateAnswerUtils {
|
|||
setRankerType(withOptions.getRankerType());
|
||||
}
|
||||
};
|
||||
Activity traceActivity = Activity.createTraceActivity(QnAMaker.QNA_MAKER_NAME, QnAMaker.QNA_MAKER_TRACE_TYPE,
|
||||
traceInfo, QnAMaker.QNA_MAKER_TRACE_LABEL);
|
||||
Activity traceActivity = Activity.createTraceActivity(
|
||||
QnAMaker.QNA_MAKER_NAME,
|
||||
QnAMaker.QNA_MAKER_TRACE_TYPE,
|
||||
traceInfo,
|
||||
QnAMaker.QNA_MAKER_TRACE_LABEL
|
||||
);
|
||||
return turnContext.sendActivity(traceActivity).thenApply(response -> null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
package com.microsoft.bot.ai.qna.utils;
|
||||
|
||||
import com.microsoft.bot.connector.Async;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory;
|
|||
*/
|
||||
public class HttpRequestUtils {
|
||||
private OkHttpClient httpClient = new OkHttpClient();
|
||||
|
||||
/**
|
||||
* Execute Http request.
|
||||
*
|
||||
|
@ -33,18 +34,23 @@ public class HttpRequestUtils {
|
|||
* @param endpoint QnA Maker endpoint details.
|
||||
* @return Returns http response object.
|
||||
*/
|
||||
public CompletableFuture<JsonNode> executeHttpRequest(String requestUrl, String payloadBody,
|
||||
QnAMakerEndpoint endpoint) {
|
||||
public CompletableFuture<JsonNode> executeHttpRequest(
|
||||
String requestUrl,
|
||||
String payloadBody,
|
||||
QnAMakerEndpoint endpoint
|
||||
) {
|
||||
if (requestUrl == null) {
|
||||
throw new IllegalArgumentException("requestUrl: Request url can not be null.");
|
||||
return Async
|
||||
.completeExceptionally(new IllegalArgumentException("requestUrl: Request url can not be null."));
|
||||
}
|
||||
|
||||
if (payloadBody == null) {
|
||||
throw new IllegalArgumentException("payloadBody: Payload body can not be null.");
|
||||
return Async
|
||||
.completeExceptionally(new IllegalArgumentException("payloadBody: Payload body can not be null."));
|
||||
}
|
||||
|
||||
if (endpoint == null) {
|
||||
throw new IllegalArgumentException("endpoint");
|
||||
return Async.completeExceptionally(new IllegalArgumentException("endpoint"));
|
||||
}
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
@ -57,11 +63,11 @@ public class HttpRequestUtils {
|
|||
qnaResponse = mapper.readTree(response.body().string());
|
||||
if (!response.isSuccessful()) {
|
||||
String message = "Unexpected code " + response.code();
|
||||
throw new Exception(message);
|
||||
return Async.completeExceptionally(new Exception(message));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LoggerFactory.getLogger(HttpRequestUtils.class).error("findPackages", e);
|
||||
throw new CompletionException(e);
|
||||
return Async.completeExceptionally(e);
|
||||
}
|
||||
|
||||
return CompletableFuture.completedFuture(qnaResponse);
|
||||
|
@ -69,15 +75,15 @@ public class HttpRequestUtils {
|
|||
|
||||
private Request buildRequest(String requestUrl, String endpointKey, RequestBody body) {
|
||||
HttpUrl.Builder httpBuilder = HttpUrl.parse(requestUrl).newBuilder();
|
||||
Request.Builder requestBuilder = new Request.Builder()
|
||||
.url(httpBuilder.build())
|
||||
Request.Builder requestBuilder = new Request.Builder().url(httpBuilder.build())
|
||||
.addHeader("Authorization", String.format("EndpointKey %s", endpointKey))
|
||||
.addHeader("Ocp-Apim-Subscription-Key", endpointKey).addHeader("User-Agent", UserAgent.value())
|
||||
.addHeader("Ocp-Apim-Subscription-Key", endpointKey)
|
||||
.addHeader("User-Agent", UserAgent.value())
|
||||
.post(body);
|
||||
return requestBuilder.build();
|
||||
}
|
||||
|
||||
private RequestBody buildRequestBody(String payloadBody) throws JsonProcessingException {
|
||||
return RequestBody.create(payloadBody, MediaType.parse("application/json; charset=utf-8"));
|
||||
return RequestBody.create(MediaType.parse("application/json; charset=utf-8"), payloadBody);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ import com.microsoft.bot.schema.HeroCard;
|
|||
*/
|
||||
public final class QnACardBuilder {
|
||||
|
||||
private QnACardBuilder() { }
|
||||
private QnACardBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get active learning suggestions card.
|
||||
|
|
|
@ -8,7 +8,8 @@ package com.microsoft.bot.ai.qna.utils;
|
|||
*/
|
||||
public final class QnATelemetryConstants {
|
||||
|
||||
private QnATelemetryConstants() { }
|
||||
private QnATelemetryConstants() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The Key used for the custom event type within telemetry.
|
||||
|
|
|
@ -5,6 +5,7 @@ package com.microsoft.bot.ai.qna.utils;
|
|||
|
||||
import com.microsoft.bot.ai.qna.QnAMakerEndpoint;
|
||||
import com.microsoft.bot.ai.qna.models.FeedbackRecords;
|
||||
import com.microsoft.bot.connector.Async;
|
||||
import com.microsoft.bot.restclient.serializer.JacksonAdapter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -34,7 +35,9 @@ public class TrainUtils {
|
|||
*/
|
||||
public CompletableFuture<Void> callTrain(FeedbackRecords feedbackRecords) throws IOException {
|
||||
if (feedbackRecords == null) {
|
||||
throw new IllegalArgumentException("feedbackRecords: Feedback records cannot be null.");
|
||||
return Async.completeExceptionally(
|
||||
new IllegalArgumentException("feedbackRecords: Feedback records cannot be null.")
|
||||
);
|
||||
}
|
||||
|
||||
if (feedbackRecords.getRecords() == null || feedbackRecords.getRecords().length == 0) {
|
||||
|
@ -46,8 +49,8 @@ public class TrainUtils {
|
|||
}
|
||||
|
||||
private CompletableFuture<Void> queryTrain(FeedbackRecords feedbackRecords) throws IOException {
|
||||
String requestUrl = String.format("%1$s/knowledgebases/%2$s/train", this.endpoint.getHost(),
|
||||
this.endpoint.getKnowledgeBaseId());
|
||||
String requestUrl = String
|
||||
.format("%1$s/knowledgebases/%2$s/train", this.endpoint.getHost(), this.endpoint.getKnowledgeBaseId());
|
||||
|
||||
JacksonAdapter jacksonAdapter = new JacksonAdapter();
|
||||
String jsonRequest = jacksonAdapter.serialize(feedbackRecords);
|
||||
|
|
|
@ -98,6 +98,7 @@ public class QnAMakerRecognizerTests {
|
|||
Assert.assertEquals(result.getIntents().get("QnAMatch"), null);
|
||||
Assert.assertNotEquals(result.getIntents().get("None"), null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
} finally {
|
||||
try {
|
||||
|
|
|
@ -197,7 +197,7 @@ public class QnAMakerTests {
|
|||
}
|
||||
};
|
||||
TurnContext context = new TurnContextImpl(adapter, activity);
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> qna.getAnswers(context, null));
|
||||
Assert.assertThrows(CompletionException.class, () -> qna.getAnswers(context, null).join());
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
} finally {
|
||||
|
@ -229,7 +229,7 @@ public class QnAMakerTests {
|
|||
}
|
||||
};
|
||||
TurnContext context = new TurnContextImpl(adapter, activity);
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> qna.getAnswers(context, null));
|
||||
Assert.assertThrows(CompletionException.class, () -> qna.getAnswers(context, null).join());
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
} finally {
|
||||
|
@ -248,7 +248,7 @@ public class QnAMakerTests {
|
|||
// Get basic Qna
|
||||
QnAMaker qna = this.qnaReturnsAnswer(mockWebServer);
|
||||
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> qna.getAnswers(null, null));
|
||||
Assert.assertThrows(CompletionException.class, () -> qna.getAnswers(null, null).join());
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
} finally {
|
||||
|
@ -281,7 +281,7 @@ public class QnAMakerTests {
|
|||
};
|
||||
|
||||
TurnContext context = new TurnContextImpl(adapter, activity);
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> qna.getAnswers(context, null));
|
||||
Assert.assertThrows(CompletionException.class, () -> qna.getAnswers(context, null).join());
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
} finally {
|
||||
|
@ -304,7 +304,7 @@ public class QnAMakerTests {
|
|||
TestAdapter adapter = new TestAdapter(
|
||||
TestAdapter.createConversationReference("QnaMaker_TraceActivity_NullActivity", "User1", "Bot"));
|
||||
TurnContext context = new MyTurnContext(adapter, null);
|
||||
Assert.assertThrows(IllegalArgumentException.class, () -> qna.getAnswers(context, null));
|
||||
Assert.assertThrows(CompletionException.class, () -> qna.getAnswers(context, null).join());
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
} finally {
|
||||
|
@ -1076,7 +1076,7 @@ public class QnAMakerTests {
|
|||
}
|
||||
};
|
||||
QnAMaker qna = new QnAMaker(qnAMakerEndpoint, null);
|
||||
Assert.assertThrows(CompletionException.class, () -> qna.getAnswers(getContext("how do I clean the stove?"), null));
|
||||
Assert.assertThrows(CompletionException.class, () -> qna.getAnswers(getContext("how do I clean the stove?"), null).join());
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
} finally {
|
||||
|
|
|
@ -60,31 +60,31 @@
|
|||
<artifactId>guava</artifactId>
|
||||
<version>30.1-jre</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>retrofit</artifactId>
|
||||
<version>2.5.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>3.12.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>logging-interceptor</artifactId>
|
||||
<version>3.12.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp-urlconnection</artifactId>
|
||||
<version>3.12.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>converter-jackson</artifactId>
|
||||
<version>2.5.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>logging-interceptor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp-urlconnection</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.azure</groupId>
|
||||
<artifactId>azure-annotations</artifactId>
|
||||
|
|
22
pom.xml
22
pom.xml
|
@ -311,6 +311,28 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>3.12.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>logging-interceptor</artifactId>
|
||||
<version>3.12.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp-urlconnection</artifactId>
|
||||
<version>3.12.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>mockwebserver</artifactId>
|
||||
<version>3.12.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.microsoft.bot</groupId>
|
||||
<artifactId>bot-schema</artifactId>
|
||||
|
|
Загрузка…
Ссылка в новой задаче