このコア ボット サンプルでは、空港のフライト予約アプリケーションの例を示しています。 これは LUIS サービスを使用してユーザー入力を認識し、認識した最上位の LUIS の意図を返します。
ユーザー入力の処理が完了するたびに、DialogBot
では UserState
と ConversationState
の両方の現在の状態が保存されます。 必要な情報がすべて収集されると、コード サンプルによりデモの航空券予約が作成されます。 この記事では、このサンプルの LUIS 部分について説明します。 ただし、サンプルの一般的なフローは次のようになります。
- 新しいユーザーが接続され、ようこそカードを表示すると、
OnMembersAddedAsync
が呼び出されます。
- ユーザー入力を受け取るたびに、
OnMessageActivityAsync
が呼び出されます。
OnMessageActivityAsync
モジュールは、Run
ダイアログ拡張メソッドによって適切なダイアログを実行します。 そして、メイン ダイアログは、LUIS ヘルパー を呼び出して、最もスコアが高いユーザーの意図を見つけます。 ユーザー入力の最上位の意図によって "BookFlight" が返されると、ヘルパーは LUIS によって返されたユーザー情報を入力します。 その後、メイン ダイアログは BookingDialog
を開始し、これにより、必要に応じて次のような追加情報をユーザーから取得します。
Origin
出発地
TravelDate
航空券の予約日
Destination
到着地
ユーザー入力の処理が完了するたびに、dialogBot
では userState
と conversationState
の両方の現在の状態が保存されます。 必要な情報がすべて収集されると、コード サンプルによりデモの航空券予約が作成されます。 この記事では、このサンプルの LUIS 部分について説明します。 ただし、サンプルの一般的なフローは次のようになります。
- 新しいユーザーが接続され、ようこそカードを表示すると、
onMembersAdded
が呼び出されます。
- ユーザー入力を受け取るたびに、
OnMessage
が呼び出されます。
onMessage
モジュールは、ユーザー入力を収集する mainDialog
を実行します。
そして、メイン ダイアログは、LUIS ヘルパー FlightBookingRecognizer
を呼び出して、最もスコアが高いユーザーの意図を見つけます。 ユーザー入力の最上位の意図によって "BookFlight" が返されると、ヘルパーは LUIS によって返されたユーザー情報を入力します。
この応答が返されると、mainDialog
は LUIS から返されたユーザー情報を保持して、bookingDialog
を開始します。 bookingDialog
は、次のような追加情報を必要に応じてユーザーから取得します
destination
到着地。
origin
出発地。
travelDate
航空券の予約日。
- ユーザー入力の処理が完了するたびに、
DialogBot
では UserState
と ConversationState
の両方の現在の状態が保存されます。
- 必要な情報がすべて収集されると、コード サンプルによりデモの航空券予約が作成されます。
- この記事では、このサンプルの LUIS 部分について説明します。 ただし、サンプルの一般的なフローは次のようになります。
- 新しいユーザーが接続され、ようこそカードを表示すると、
onMembersAdded
が呼び出されます。
- ユーザー入力を受け取るたびに、
onMessageActivity
が呼び出されます。
onMessageActivity
モジュールは、run
ダイアログ拡張メソッドによって適切なダイアログを実行します。 そして、メイン ダイアログは、LUIS ヘルパー を呼び出して、最もスコアが高いユーザーの意図を見つけます。 ユーザー入力の最上位の意図によって "BookFlight" が返されると、ヘルパーは LUIS によって返されたユーザー情報を入力します。 その後、メイン ダイアログは BookingDialog
を開始し、これにより、必要に応じて次のような追加情報をユーザーから取得します。
Origin
出発地
TravelDate
航空券の予約日
Destination
到着地
ユーザー入力の処理が完了するたびに、DialogBot
では user_state
と conversation_state
の両方の現在の状態が保存されます。 必要な情報がすべて収集されると、コード サンプルによりデモの航空券予約が作成されます。 この記事では、このサンプルの LUIS 部分について説明します。 ただし、サンプルの一般的なフローは次のようになります。
- 新しいユーザーが接続され、ようこそカードを表示すると、
on_members_added_activity
が呼び出されます。
- ユーザー入力を受け取るたびに、
on_message_activity
が呼び出されます。
on_message_activity
モジュールは、run_dialog
ダイアログ拡張メソッドによって適切なダイアログを実行します。 その後、メイン ダイアログは LuisHelper
を呼び出して、最もスコアが高いユーザーの意図を見つけます。 ユーザー入力の最上位の意図によって "BookFlight" が返されると、ヘルパー関数は LUIS によって返されたユーザー情報を入力します。 その後、メイン ダイアログは BookingDialog
を開始し、これにより、必要に応じて次のような追加情報をユーザーから取得します。
destination
到着地。
origin
出発地。
travel_date
航空券の予約日。
LUIS エンティティによって、ボットは標準の意図以外のイベントを理解できます。 これにより、ユーザーから追加情報を収集できるため、ボットは質問をしたり、よりインテリジェントに応答したりできます。 FlightBooking.json ファイルには、3 つの LUIS の意図である "Book Flight"、"Cancel"、および "None" の定義と共に、"From.Airport" や "To.Airport" などのエンティティのセットも含まれています。 これらのエンティティにより、ユーザーが新しい旅行の予約を要求したときに、LUIS は、そのユーザーの元の入力に含まれる追加情報を検出し、返すことができます。
LUIS アプリには、その発行後、ボットからアクセスできるようになります。 ボット内から LUIS アプリにアクセスするためには、いくつかの値を記録する必要があります。 その情報は、LUIS ポータルを使用して取得できます。
LUIS アプリにアクセスするために必要な情報 (アプリケーション ID、オーサリング キー、リージョンなど) を appsettings.json
ファイルに追加します。 前の手順では、発行済みの LUIS アプリからこれらの値を取得しました。 API ホスト名は <your region>.api.cognitive.microsoft.com
形式にする必要があります。
appsetting.json
{
"MicrosoftAppType": "",
"MicrosoftAppId": "",
"MicrosoftAppPassword": "",
"MicrosoftAppTenantId": "",
"LuisAppId": "",
"LuisAPIKey": "",
"LuisAPIHostName": ""
}
LUIS アプリにアクセスするために必要な情報 (アプリケーション ID、オーサリング キー、リージョンなど) を .env
ファイルに追加します。 前の手順では、発行済みの LUIS アプリからこれらの値を取得しました。 API ホスト名は <your region>.api.cognitive.microsoft.com
形式にする必要があります。
.env
MicrosoftAppType=
MicrosoftAppId=
MicrosoftAppPassword=
MicrosoftAppTenantId=
LuisAppId=
LuisAPIKey=
LuisAPIHostName=
LUIS アプリにアクセスするために必要な情報 (アプリケーション ID、オーサリング キー、リージョンなど) を application.properties
ファイルに追加します。 前の手順では、発行済みの LUIS アプリからこれらの値を取得しました。 API ホスト名は <your region>.api.cognitive.microsoft.com
形式にする必要があります。
アプリケーション プロパティ:
MicrosoftAppId=
MicrosoftAppPassword=
LuisAppId=
LuisAPIKey=
LuisAPIHostName=
server.port=3978
LUIS アプリにアクセスするために必要な情報 (アプリケーション ID、オーサリング キー、リージョンなど) を config.py
ファイルに追加します。 前の手順では、発行済みの LUIS アプリからこれらの値を取得しました。 API ホスト名は <your region>.api.cognitive.microsoft.com
形式にする必要があります。
config.py
APP_ID = os.environ.get("MicrosoftAppId", "")
APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "")
APP_TYPE = os.environ.get("MicrosoftAppType", "MultiTenant")
APP_TENANTID = os.environ.get("MicrosoftAppTenantId", "")
LUIS_APP_ID = os.environ.get("LuisAppId", "")
LUIS_API_KEY = os.environ.get("LuisAPIKey", "")
NuGet パッケージ Microsoft.Bot.Builder.AI.Luis がプロジェクトにインストールされていることを確認します。
LUIS サービスに接続するために、ボットは appsetting.json ファイルに追加された情報をプルします。 FlightBookingRecognizer
クラスには、appsetting.json ファイルからのユーザーの設定に関するコードが含まれています。このクラスは、RecognizeAsync
メソッドを呼び出すことで LUIS サービスにクエリを実行します。
FlightBookingRecognizer.cs
public class FlightBookingRecognizer : IRecognizer
{
private readonly LuisRecognizer _recognizer;
public FlightBookingRecognizer(IConfiguration configuration)
{
var luisIsConfigured = !string.IsNullOrEmpty(configuration["LuisAppId"]) && !string.IsNullOrEmpty(configuration["LuisAPIKey"]) && !string.IsNullOrEmpty(configuration["LuisAPIHostName"]);
if (luisIsConfigured)
{
var luisApplication = new LuisApplication(
configuration["LuisAppId"],
configuration["LuisAPIKey"],
"https://" + configuration["LuisAPIHostName"]);
// Set the recognizer options depending on which endpoint version you want to use.
// More details can be found in https://docs.microsoft.com/en-gb/azure/cognitive-services/luis/luis-migration-api-v3
var recognizerOptions = new LuisRecognizerOptionsV3(luisApplication)
{
PredictionOptions = new Bot.Builder.AI.LuisV3.LuisPredictionOptions
{
IncludeInstanceData = true,
}
};
_recognizer = new LuisRecognizer(recognizerOptions);
}
}
// Returns true if luis is configured in the appsettings.json and initialized.
public virtual bool IsConfigured => _recognizer != null;
public virtual async Task<RecognizerResult> RecognizeAsync(ITurnContext turnContext, CancellationToken cancellationToken)
=> await _recognizer.RecognizeAsync(turnContext, cancellationToken);
public virtual async Task<T> RecognizeAsync<T>(ITurnContext turnContext, CancellationToken cancellationToken)
where T : IRecognizerConvert, new()
=> await _recognizer.RecognizeAsync<T>(turnContext, cancellationToken);
}
FlightBookingEx.cs
には、From、To、および TravelDate を抽出するロジックが含まれています。これは、MainDialog.cs
から FlightBookingRecognizer.RecognizeAsync<FlightBooking>
を呼び出したときに LUIS の結果を格納するために使用される部分クラス FlightBooking.cs
を拡張します。
CognitiveModels\FlightBookingEx.cs
// Extends the partial FlightBooking class with methods and properties that simplify accessing entities in the luis results
public partial class FlightBooking
{
public (string From, string Airport) FromEntities
{
get
{
var fromValue = Entities?._instance?.From?.FirstOrDefault()?.Text;
var fromAirportValue = Entities?.From?.FirstOrDefault()?.Airport?.FirstOrDefault()?.FirstOrDefault();
return (fromValue, fromAirportValue);
}
}
public (string To, string Airport) ToEntities
{
get
{
var toValue = Entities?._instance?.To?.FirstOrDefault()?.Text;
var toAirportValue = Entities?.To?.FirstOrDefault()?.Airport?.FirstOrDefault()?.FirstOrDefault();
return (toValue, toAirportValue);
}
}
// This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part.
// TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year.
public string TravelDate
=> Entities.datetime?.FirstOrDefault()?.Expressions.FirstOrDefault()?.Split('T')[0];
}
LUIS を使用するには、ご自身のプロジェクトでは、botbuilder ai npm パッケージをインストールする必要があります。
LUIS サービスに接続するために、ボットは、.env
ファイルに追加された情報を使用します。 flightBookingRecognizer.js
クラスには、.env
ファイルからユーザーの設定をインポートするコードが含まれています。また、recognize()
メソッドを呼び出すことで LUIS サービスにクエリを実行します。
dialogs/flightBookingRecognizer.js
class FlightBookingRecognizer {
constructor(config) {
const luisIsConfigured = config && config.applicationId && config.endpointKey && config.endpoint;
if (luisIsConfigured) {
// Set the recognizer options depending on which endpoint version you want to use e.g v2 or v3.
// More details can be found in https://docs.microsoft.com/en-gb/azure/cognitive-services/luis/luis-migration-api-v3
const recognizerOptions = {
apiVersion: 'v3'
};
this.recognizer = new LuisRecognizer(config, recognizerOptions);
}
}
get isConfigured() {
return (this.recognizer !== undefined);
}
/**
* Returns an object with preformatted LUIS results for the bot's dialogs to consume.
* @param {TurnContext} context
*/
async executeLuisQuery(context) {
return await this.recognizer.recognize(context);
}
getFromEntities(result) {
let fromValue, fromAirportValue;
if (result.entities.$instance.From) {
fromValue = result.entities.$instance.From[0].text;
}
if (fromValue && result.entities.From[0].Airport) {
fromAirportValue = result.entities.From[0].Airport[0][0];
}
return { from: fromValue, airport: fromAirportValue };
}
getToEntities(result) {
let toValue, toAirportValue;
if (result.entities.$instance.To) {
toValue = result.entities.$instance.To[0].text;
}
if (toValue && result.entities.To[0].Airport) {
toAirportValue = result.entities.To[0].Airport[0][0];
}
return { to: toValue, airport: toAirportValue };
}
/**
* This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part.
* TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year.
*/
getTravelDate(result) {
const datetimeEntity = result.entities.datetime;
if (!datetimeEntity || !datetimeEntity[0]) return undefined;
const timex = datetimeEntity[0].timex;
if (!timex || !timex[0]) return undefined;
const datetime = timex[0].split('T')[0];
return datetime;
}
}
From、To、および TravelDate を抽出するロジックは、flightBookingRecognizer.js
内のヘルパー メソッドとして実装されています。 これらのメソッドは、mainDialog.js
から flightBookingRecognizer.executeLuisQuery()
を呼び出した後に使用されます
com.microsoft.bot.bot-ai-luis-v3 パッケージが pom.xml ファイルに追加されていることを確認します。
<dependency>
<groupId>com.microsoft.bot</groupId>
<artifactId>bot-ai-luis-v3</artifactId>
<version>4.14.1</version>
</dependency>
LUIS サービスに接続するために、ボットは application.properties ファイルに追加された情報をプルします。 FlightBookingRecognizer
クラスには、application.properties ファイルのユーザーの設定に関するコードが含まれています。このクラスは、recognize
メソッドを呼び出すことで LUIS サービスにクエリを実行します。
FlightBookingRecognizer.java
/**
* The constructor of the FlightBookingRecognizer class.
*
* @param configuration The Configuration object to use.
*/
public FlightBookingRecognizer(Configuration configuration) {
Boolean luisIsConfigured = StringUtils.isNotBlank(configuration.getProperty("LuisAppId"))
&& StringUtils.isNotBlank(configuration.getProperty("LuisAPIKey"))
&& StringUtils.isNotBlank(configuration.getProperty("LuisAPIHostName"));
if (luisIsConfigured) {
LuisApplication luisApplication = new LuisApplication(
configuration.getProperty("LuisAppId"),
configuration.getProperty("LuisAPIKey"),
String.format("https://%s", configuration.getProperty("LuisAPIHostName"))
);
// Set the recognizer options depending on which endpoint version you want to use.
// More details can be found in
// https://docs.microsoft.com/en-gb/azure/cognitive-services/luis/luis-migration-api-v3
LuisRecognizerOptionsV3 recognizerOptions = new LuisRecognizerOptionsV3(luisApplication);
recognizerOptions.setIncludeInstanceData(true);
this.recognizer = new LuisRecognizer(recognizerOptions);
}
}
/**
* Runs an utterance through a recognizer and returns a generic recognizer result.
*
* @param turnContext Turn context.
* @return Analysis of utterance.
*/
@Override
public CompletableFuture<RecognizerResult> recognize(TurnContext turnContext) {
return this.recognizer.recognize(turnContext);
}
FlightBookingRecognizer.cs
には、From、To、TravelDate を抽出するロジックが含まれており、Luis クエリ結果の結果をデコードするために MainDialog.java
から呼び出されます。
FlightBookingRecognizer.java
/**
* Gets the From data from the entities which is part of the result.
*
* @param result The recognizer result.
* @return The object node representing the From data.
*/
public ObjectNode getFromEntities(RecognizerResult result) {
String fromValue = "", fromAirportValue = "";
if (result.getEntities().get("$instance").get("From") != null) {
fromValue = result.getEntities().get("$instance").get("From").get(0).get("text")
.asText();
}
if (!fromValue.isEmpty()
&& result.getEntities().get("From").get(0).get("Airport") != null) {
fromAirportValue = result.getEntities().get("From").get(0).get("Airport").get(0).get(0)
.asText();
}
ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
ObjectNode entitiesNode = mapper.createObjectNode();
entitiesNode.put("from", fromValue);
entitiesNode.put("airport", fromAirportValue);
return entitiesNode;
}
/**
* Gets the To data from the entities which is part of the result.
*
* @param result The recognizer result.
* @return The object node representing the To data.
*/
public ObjectNode getToEntities(RecognizerResult result) {
String toValue = "", toAirportValue = "";
if (result.getEntities().get("$instance").get("To") != null) {
toValue = result.getEntities().get("$instance").get("To").get(0).get("text").asText();
}
if (!toValue.isEmpty() && result.getEntities().get("To").get(0).get("Airport") != null) {
toAirportValue = result.getEntities().get("To").get(0).get("Airport").get(0).get(0)
.asText();
}
ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
ObjectNode entitiesNode = mapper.createObjectNode();
entitiesNode.put("to", toValue);
entitiesNode.put("airport", toAirportValue);
return entitiesNode;
}
/**
* This value will be a TIMEX. And we are only interested in a Date so grab the first result and
* drop the Time part. TIMEX is a format that represents DateTime expressions that include some
* ambiguity. e.g. missing a Year.
*
* @param result A {link RecognizerResult}
* @return The Timex value without the Time model
*/
public String getTravelDate(RecognizerResult result) {
JsonNode datetimeEntity = result.getEntities().get("datetime");
if (datetimeEntity == null || datetimeEntity.get(0) == null) {
return null;
}
JsonNode timex = datetimeEntity.get(0).get("timex");
if (timex == null || timex.get(0) == null) {
return null;
}
String datetime = timex.get(0).asText().split("T")[0];
return datetime;
}
お使いのプロジェクトに対して botbuilder-ai PyPI パッケージがインストールされていることを確認します。
LUIS サービスに接続するために、ボットは、config.py
ファイルに追加された情報を使用します。 FlightBookingRecognizer
クラスには、config.py
ファイルからユーザーの設定をインポートするコードが含まれています。また、recognize()
メソッドを呼び出すことで LUIS サービスにクエリを実行します。
flight_booking_recognizer.py
class FlightBookingRecognizer(Recognizer):
def __init__(self, configuration: DefaultConfig):
self._recognizer = None
luis_is_configured = (
configuration.LUIS_APP_ID
and configuration.LUIS_API_KEY
and configuration.LUIS_API_HOST_NAME
)
if luis_is_configured:
# Set the recognizer options depending on which endpoint version you want to use e.g v2 or v3.
# More details can be found in https://docs.microsoft.com/azure/cognitive-services/luis/luis-migration-api-v3
luis_application = LuisApplication(
configuration.LUIS_APP_ID,
configuration.LUIS_API_KEY,
"https://" + configuration.LUIS_API_HOST_NAME,
)
self._recognizer = LuisRecognizer(luis_application)
@property
def is_configured(self) -> bool:
# Returns true if luis is configured in the config.py and initialized.
return self._recognizer is not None
async def recognize(self, turn_context: TurnContext) -> RecognizerResult:
return await self._recognizer.recognize(turn_context)
From、To、および travel_date を抽出するロジックは、luis_helper.py
内の LuisHelper
クラスのヘルパー メソッドとして実装されています。 これらのメソッドは、main_dialog.py
から LuisHelper.execute_luis_query()
を呼び出した後に使用されます
helpers/luis_helper.py
class LuisHelper:
@staticmethod
async def execute_luis_query(
luis_recognizer: LuisRecognizer, turn_context: TurnContext
) -> (Intent, object):
"""
Returns an object with preformatted LUIS results for the bot's dialogs to consume.
"""
result = None
intent = None
try:
recognizer_result = await luis_recognizer.recognize(turn_context)
intent = (
sorted(
recognizer_result.intents,
key=recognizer_result.intents.get,
reverse=True,
)[:1][0]
if recognizer_result.intents
else None
)
if intent == Intent.BOOK_FLIGHT.value:
result = BookingDetails()
# We need to get the result from the LUIS JSON which at every level returns an array.
to_entities = recognizer_result.entities.get("$instance", {}).get(
"To", []
)
if len(to_entities) > 0:
if recognizer_result.entities.get("To", [{"$instance": {}}])[0][
"$instance"
]:
result.destination = to_entities[0]["text"].capitalize()
else:
result.unsupported_airports.append(
to_entities[0]["text"].capitalize()
)
from_entities = recognizer_result.entities.get("$instance", {}).get(
"From", []
)
if len(from_entities) > 0:
if recognizer_result.entities.get("From", [{"$instance": {}}])[0][
"$instance"
]:
result.origin = from_entities[0]["text"].capitalize()
else:
result.unsupported_airports.append(
from_entities[0]["text"].capitalize()
)
# This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop
# the Time part. TIMEX is a format that represents DateTime expressions that include some ambiguity.
# e.g. missing a Year.
date_entities = recognizer_result.entities.get("datetime", [])
if date_entities:
timex = date_entities[0]["timex"]
if timex:
datetime = timex[0].split("T")[0]
result.travel_date = datetime
else:
result.travel_date = None
except Exception as exception:
print(exception)
return intent, result
LUIS から返された最上位の意図が "Book flight" に解決されると、ボットは、旅行の予約を作成するための情報が十分に保存されるまでさらに質問を続けます。 予約を作成できたら、その予約情報をユーザーに返します。