Я ответил на это здесь .
По сути, вам нужно создать свой собственный HTTP-вызов к вашей QnA Maker KB вместо использования встроенных методов согласно this :
public async Task<QnAResult[]> QueryQnAServiceAsync(string query, QnABotState qnAcontext)
{
var requestUrl = $"{_endpoint.Host}/knowledgebases/{_endpoint.KnowledgeBaseId}/generateanswer";
var request = new HttpRequestMessage(HttpMethod.Post, requestUrl);
var jsonRequest = JsonConvert.SerializeObject(
new
{
question = query,
top = _options.Top,
context = qnAcontext,
strictFilters = _options.StrictFilters,
metadataBoost = _options.MetadataBoost,
scoreThreshold = _options.ScoreThreshold,
}, Formatting.None);
request.Headers.Add("Authorization", $"EndpointKey {_endpoint.EndpointKey}");
request.Content = new StringContent(jsonRequest, System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var contentString = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<QnAResultList>(contentString);
return result.Answers;
}
Затем проверьте результат на наличие любых подсказок и действуйте соответственно:
var query = inputActivity.Text;
var qnaResult = await _qnaService.QueryQnAServiceAsync(query, new QnABotState());
var qnaAnswer = qnaResult[0].Answer;
var prompts = qnaResult[0].Context?.Prompts;
if (prompts == null || prompts.Length < 1)
{
outputActivity = MessageFactory.Text(qnaAnswer);
}
else
{
outputActivity = CardHelper.GetHeroCard(qnaAnswer, prompts);
}
await turnContext.SendActivityAsync(outputActivity);
Примечание: Приведенный выше код для «действия соответственно» будет работать только для одного уровня подсказок, согласно моему ответу, который я связал сверху. Если вы хотите поддерживать несколько уровней запросов, вам придется реализовать их как систему состояний в соответствии с этим примером - см. Мой другой ответ здесь для получения более подробной информации.
Примечание 2: Как упомянуто в комментарии ниже, использование вышеуказанного подхода (HeroCard) может привести к сокращению заголовка, если текст слишком длинный. Чтобы избежать этого, вы можете использовать Adaptive Dialogs или Adaptive Cards .
EDIT
На основании этого образца
Вы должны быть в состоянии достигнуть одного уровня подсказок примерно с таким:
QnAResult.cs
public class QnAResult
{
public string[] Questions { get; set; }
public string Answer { get; set; }
public double Score { get; set; }
public int Id { get; set; }
public string Source { get; set; }
public QnAMetadata[] Metadata { get; set; }
public QnAContext Context { get; set; }
}
QnAResultList.cs
public class QnAResultList
{
public QnAResult[] Answers { get; set; }
}
IQnAService.cs
public interface IQnAService
{
Task<QnAResult[]> QueryQnAServiceAsync(string query, QnABotState qnAcontext, QnAMakerEndpoint qnAMakerEndpoint);
}
QnAService.cs
public class QnAService : IQnAService
{
private readonly HttpClient _httpClient;
private readonly IConfiguration _configuration;
public QnAService(HttpClient httpClient, IConfiguration configuration)
{
_httpClient = httpClient;
_configuration = configuration;
}
public async Task<QnAResult[]> QueryQnAServiceAsync(string query, QnABotState qnAcontext, QnAMakerEndpoint qnAMakerEndpoint)
{
var options = new QnAMakerOptions
{
Top = 3
};
var hostname = qnAMakerEndpoint.Host;
var endpoint = new QnAMakerEndpoint
{
KnowledgeBaseId = qnAMakerEndpoint.KnowledgeBaseId,
EndpointKey = qnAMakerEndpoint.EndpointKey,
Host = hostname
};
var requestUrl = $"{endpoint.Host}/knowledgebases/{endpoint.KnowledgeBaseId}/generateanswer";
var request = new HttpRequestMessage(HttpMethod.Post, requestUrl);
var jsonRequest = JsonConvert.SerializeObject(
new
{
question = query,
top = options.Top,
context = qnAcontext,
strictFilters = options.StrictFilters,
metadataBoost = options.MetadataBoost,
scoreThreshold = options.ScoreThreshold,
}, Formatting.None);
request.Headers.Add("Authorization", $"EndpointKey {endpoint.EndpointKey}");
request.Content = new StringContent(jsonRequest, System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var contentString = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<QnAResultList>(contentString);
return result.Answers;
}
}
CardHelper.cs
public class CardHelper
{
/// <summary>
/// Get Hero card
/// </summary>
/// <param name="cardTitle">Title of the card</param>
/// <param name="prompts">List of suggested prompts</param>
/// <returns>Message activity</returns>
public static Activity GetHeroCardWithPrompts(string cardTitle, QnAPrompts[] prompts)
{
var chatActivity = Activity.CreateMessageActivity();
var buttons = new List<CardAction>();
var sortedPrompts = prompts.OrderBy(r => r.DisplayOrder);
foreach (var prompt in sortedPrompts)
{
buttons.Add(
new CardAction()
{
Value = prompt.DisplayText,
Type = ActionTypes.ImBack,
Title = prompt.DisplayText
});
}
var plCard = new HeroCard()
{
Title = cardTitle,
Subtitle = string.Empty,
Buttons = buttons
};
var attachment = plCard.ToAttachment();
chatActivity.Attachments.Add(attachment);
return (Activity)chatActivity;
}
}
MyBot.cs HandleQnA ()
QnAResult[] qnaResults = await _qnAService.QueryQnAServiceAsync(context.Activity.Text, new QnABotState(), _qnAMakerEndpoint);
if (qnaResults.Any())
{
// Get result by highest confidence
QnAResult highestRankedResult = qnaResults.OrderByDescending(x => x.Score).First();
string answer = highestRankedResult.Answer;
QnAPrompts[] prompts = highestRankedResult.Context?.Prompts;
if (prompts == null || prompts.Length < 1)
{
await context.SendActivityAsync(answer, cancellationToken: cancellationToken);
}
else
{
await context.SendActivityAsync(CardHelper.GetHeroCardWithPrompts(answer, prompts), cancellationToken: cancellationToken);
}
}
Используемые мной пакеты NuGet: