Een LUIS-app programmatisch bouwen met behulp van Node.js
Belangrijk
LUIS wordt op 1 oktober 2025 buiten gebruik gesteld en vanaf 1 april 2023 kunt u geen nieuwe LUIS-resources maken. We raden u aan uw LUIS-toepassingen te migreren naar gesprekstaalbegrip om te profiteren van continue productondersteuning en meertalige mogelijkheden.
LUIS biedt een programmatische API die alles doet wat de LUIS-website doet. Dit kan tijd besparen wanneer u al bestaande gegevens hebt en het sneller is om programmatisch een LUIS-app te maken dan door gegevens handmatig in te voeren.
Let op
Dit document is niet bijgewerkt met tekst en schermopnamen voor de nieuwste LUIS-portal.
Vereisten
- Meld u aan bij de LUIS-website en zoek uw ontwerpsleutel in Accountinstellingen. U gebruikt deze sleutel om de creatie-API's aan te roepen.
- Als u geen Azure-abonnement hebt, maakt u een gratis account voordat u begint.
- Dit artikel begint met een CSV voor de logboekbestanden van gebruikersaanvragen van een hypothetisch bedrijf. Download het hier.
- Installeer de meest recente Node.js versie. U kunt het hier downloaden.
- [Aanbevolen] Visual Studio Code voor IntelliSense en foutopsporing kunt u deze gratis downloaden.
Alle code in dit artikel is beschikbaar in de GitHub-opslagplaats van Azure-Samples Language Understanding.
Vooraf bestaande gegevens toewijzen aan intenties en entiteiten
Zelfs als u een systeem hebt dat niet met LUIS is gemaakt, kunt u, als het tekstgegevens bevat die zijn toegewezen aan verschillende dingen die gebruikers willen doen, mogelijk een toewijzing maken van de bestaande categorieƫn gebruikersinvoer voor intenties in LUIS. Als u belangrijke woorden of woordgroepen kunt identificeren in wat de gebruikers zeiden, kunnen deze woorden worden toegewezen aan entiteiten.
Open het bestand IoT.csv
. Het bevat een logboek met gebruikersquery's naar een hypothetische service voor huisautomatisering, waaronder hoe ze zijn gecategoriseerd, wat de gebruiker zei en enkele kolommen met nuttige informatie die uit deze service is gehaald.
U ziet dat de kolom RequestType intenties kan zijn en dat in de kolom Aanvraag een voorbeelduiting wordt weergegeven. De andere velden kunnen entiteiten zijn als ze voorkomen in de utterance. Omdat er intenties, entiteiten en voorbeelduitingen zijn, hebt u de vereisten voor een eenvoudige voorbeeld-app.
Stappen voor het genereren van een LUIS-app op basis van niet-LUIS-gegevens
Een nieuwe LUIS-app genereren vanuit het CSV-bestand:
- Parseren van de gegevens uit het CSV-bestand:
- Converteer naar een indeling die u naar LUIS kunt uploaden met behulp van de ontwerp-API.
- Verzamel op basis van de geparseerde gegevens informatie over intenties en entiteiten.
- Schrijf API-aanroepen naar:
- Maak de app.
- Voeg intenties en entiteiten toe die zijn verzameld uit de geparseerde gegevens.
- Zodra u de LUIS-app hebt gemaakt, kunt u de voorbeelduitingen toevoegen op basis van de geparseerde gegevens.
U kunt deze programmastroom zien in het laatste deel van het index.js
bestand. Kopieer of download deze code en sla deze op in index.js
.
Belangrijk
Vergeet niet de sleutel uit uw code te verwijderen wanneer u klaar bent, en maak deze sleutel nooit openbaar. Gebruik voor productie een veilige manier om uw referenties op te slaan en te openen, zoals Azure Key Vault. Zie het beveiligingsartikel over Azure AI-services voor meer informatie.
var path = require('path');
const parse = require('./_parse');
const createApp = require('./_create');
const addEntities = require('./_entities');
const addIntents = require('./_intents');
const upload = require('./_upload');
// Change these values
const LUIS_authoringKey = "YOUR_AUTHORING_KEY";
const LUIS_appName = "Sample App - build from IoT csv file";
const LUIS_appCulture = "en-us";
const LUIS_versionId = "0.1";
// NOTE: final output of add-utterances api named utterances.upload.json
const downloadFile = "./IoT.csv";
const uploadFile = "./utterances.json"
// The app ID is returned from LUIS when your app is created
var LUIS_appId = ""; // default app ID
var intents = [];
var entities = [];
/* add utterances parameters */
var configAddUtterances = {
LUIS_subscriptionKey: LUIS_authoringKey,
LUIS_appId: LUIS_appId,
LUIS_versionId: LUIS_versionId,
inFile: path.join(__dirname, uploadFile),
batchSize: 100,
uri: "https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/examples"
};
/* create app parameters */
var configCreateApp = {
LUIS_subscriptionKey: LUIS_authoringKey,
LUIS_versionId: LUIS_versionId,
appName: LUIS_appName,
culture: LUIS_appCulture,
uri: "https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/"
};
/* add intents parameters */
var configAddIntents = {
LUIS_subscriptionKey: LUIS_authoringKey,
LUIS_appId: LUIS_appId,
LUIS_versionId: LUIS_versionId,
intentList: intents,
uri: "https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/intents"
};
/* add entities parameters */
var configAddEntities = {
LUIS_subscriptionKey: LUIS_authoringKey,
LUIS_appId: LUIS_appId,
LUIS_versionId: LUIS_versionId,
entityList: entities,
uri: "https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/entities"
};
/* input and output files for parsing CSV */
var configParse = {
inFile: path.join(__dirname, downloadFile),
outFile: path.join(__dirname, uploadFile)
};
// Parse CSV
parse(configParse)
.then((model) => {
// Save intent and entity names from parse
intents = model.intents;
entities = model.entities;
// Create the LUIS app
return createApp(configCreateApp);
}).then((appId) => {
// Add intents
LUIS_appId = appId;
configAddIntents.LUIS_appId = appId;
configAddIntents.intentList = intents;
return addIntents(configAddIntents);
}).then(() => {
// Add entities
configAddEntities.LUIS_appId = LUIS_appId;
configAddEntities.entityList = entities;
return addEntities(configAddEntities);
}).then(() => {
// Add example utterances to the intents in the app
configAddUtterances.LUIS_appId = LUIS_appId;
return upload(configAddUtterances);
}).catch(err => {
console.log(err.message);
});
De CSV parseren
De kolomvermeldingen die de uitingen in het CSV-bestand bevatten, moeten worden geparseerd in een JSON-indeling die LUIS kan begrijpen. Deze JSON-indeling moet een intentName
veld bevatten dat de intentie van de uiting identificeert. Het moet ook een entityLabels
veld bevatten, dat leeg kan zijn als er geen entiteiten in de uiting zijn.
De vermelding voor 'De lichten inschakelen' wordt bijvoorbeeld toegewezen aan deze JSON:
{
"text": "Turn on the lights",
"intentName": "TurnOn",
"entityLabels": [
{
"entityName": "Operation",
"startCharIndex": 5,
"endCharIndex": 6
},
{
"entityName": "Device",
"startCharIndex": 12,
"endCharIndex": 17
}
]
}
In dit voorbeeld is de intentName
afkomstig van de gebruikersaanvraag onder de kolomkop Aanvraag in het CSV-bestand en de entityName
gegevens zijn afkomstig uit de andere kolommen met belangrijke informatie. Als er bijvoorbeeld een vermelding is voor Bewerking of Apparaat en die tekenreeks ook voorkomt in de werkelijke aanvraag, kan deze worden gelabeld als een entiteit. De volgende code demonstreert dit parseringsproces. U kunt het kopiƫren of downloaden en opslaan in _parse.js
.
// node 7.x
// built with streams for larger files
const fse = require('fs-extra');
const path = require('path');
const lineReader = require('line-reader');
const babyparse = require('babyparse');
const Promise = require('bluebird');
const intent_column = 0;
const utterance_column = 1;
var entityNames = [];
var eachLine = Promise.promisify(lineReader.eachLine);
function listOfIntents(intents) {
return intents.reduce(function (a, d) {
if (a.indexOf(d.intentName) === -1) {
a.push(d.intentName);
}
return a;
}, []);
}
function listOfEntities(utterances) {
return utterances.reduce(function (a, d) {
d.entityLabels.forEach(function(entityLabel) {
if (a.indexOf(entityLabel.entityName) === -1) {
a.push(entityLabel.entityName);
}
}, this);
return a;
}, []);
}
var utterance = function (rowAsString) {
let json = {
"text": "",
"intentName": "",
"entityLabels": [],
};
if (!rowAsString) return json;
let dataRow = babyparse.parse(rowAsString);
// Get intent name and utterance text
json.intentName = dataRow.data[0][intent_column];
json.text = dataRow.data[0][utterance_column];
// For each column heading that may be an entity, search for the element in this column in the utterance.
entityNames.forEach(function (entityName) {
entityToFind = dataRow.data[0][entityName.column];
if (entityToFind != "") {
strInd = json.text.indexOf(entityToFind);
if (strInd > -1) {
let entityLabel = {
"entityName": entityName.name,
"startCharIndex": strInd,
"endCharIndex": strInd + entityToFind.length - 1
}
json.entityLabels.push(entityLabel);
}
}
}, this);
return json;
};
const convert = async (config) => {
try {
var i = 0;
// get inFile stream
inFileStream = await fse.createReadStream(config.inFile, 'utf-8')
// create out file
var myOutFile = await fse.createWriteStream(config.outFile, 'utf-8');
var utterances = [];
// read 1 line at a time
return eachLine(inFileStream, (line) => {
// skip first line with headers
if (i++ == 0) {
// csv to baby parser object
let dataRow = babyparse.parse(line);
// populate entityType list
var index = 0;
dataRow.data[0].forEach(function (element) {
if ((index != intent_column) && (index != utterance_column)) {
entityNames.push({ name: element, column: index });
}
index++;
}, this);
return;
}
// transform utterance from csv to json
utterances.push(utterance(line));
}).then(() => {
console.log("intents: " + JSON.stringify(listOfIntents(utterances)));
console.log("entities: " + JSON.stringify(listOfEntities(utterances)));
myOutFile.write(JSON.stringify({ "converted_date": new Date().toLocaleString(), "utterances": utterances }));
myOutFile.end();
console.log("parse done");
console.log("JSON file should contain utterances. Next step is to create an app with the intents and entities it found.");
var model =
{
intents: listOfIntents(utterances),
entities: listOfEntities(utterances)
}
return model;
});
} catch (err) {
throw err;
}
}
module.exports = convert;
De LUIS-app maken
Zodra de gegevens zijn geparseerd in JSON, voegt u deze toe aan een LUIS-app. Met de volgende code wordt de LUIS-app gemaakt. Kopieer of download het en sla het op in _create.js
.
// node 7.x
// uses async/await - promises
var rp = require('request-promise');
var fse = require('fs-extra');
var path = require('path');
// main function to call
// Call Apps_Create
var createApp = async (config) => {
try {
// JSON for the request body
// { "name": MyAppName, "culture": "en-us"}
var jsonBody = {
"name": config.appName,
"culture": config.culture
};
// Create a LUIS app
var createAppPromise = callCreateApp({
uri: config.uri,
method: 'POST',
headers: {
'Ocp-Apim-Subscription-Key': config.LUIS_subscriptionKey
},
json: true,
body: jsonBody
});
let results = await createAppPromise;
// Create app returns an app ID
let appId = results.response;
console.log(`Called createApp, created app with ID ${appId}`);
return appId;
} catch (err) {
console.log(`Error creating app: ${err.message} `);
throw err;
}
}
// Send JSON as the body of the POST request to the API
var callCreateApp = async (options) => {
try {
var response;
if (options.method === 'POST') {
response = await rp.post(options);
} else if (options.method === 'GET') { // TODO: There's no GET for create app
response = await rp.get(options);
}
// response from successful create should be the new app ID
return { response };
} catch (err) {
throw err;
}
}
module.exports = createApp;
Intents toevoegen
Zodra u een app hebt, moet u er intenties voor hebben. Met de volgende code wordt de LUIS-app gemaakt. Kopieer of download het en sla het op in _intents.js
.
var rp = require('request-promise');
var fse = require('fs-extra');
var path = require('path');
var request = require('requestretry');
// time delay between requests
const delayMS = 1000;
// retry recount
const maxRetry = 5;
// retry request if error or 429 received
var retryStrategy = function (err, response, body) {
let shouldRetry = err || (response.statusCode === 429);
if (shouldRetry) console.log("retrying add intent...");
return shouldRetry;
}
// Call add-intents
var addIntents = async (config) => {
var intentPromises = [];
config.uri = config.uri.replace("{appId}", config.LUIS_appId).replace("{versionId}", config.LUIS_versionId);
config.intentList.forEach(function (intent) {
config.intentName = intent;
try {
// JSON for the request body
var jsonBody = {
"name": config.intentName,
};
// Create an intent
var addIntentPromise = callAddIntent({
// uri: config.uri,
url: config.uri,
fullResponse: false,
method: 'POST',
headers: {
'Ocp-Apim-Subscription-Key': config.LUIS_subscriptionKey
},
json: true,
body: jsonBody,
maxAttempts: maxRetry,
retryDelay: delayMS,
retryStrategy: retryStrategy
});
intentPromises.push(addIntentPromise);
console.log(`Called addIntents for intent named ${intent}.`);
} catch (err) {
console.log(`Error in addIntents: ${err.message} `);
}
}, this);
let results = await Promise.all(intentPromises);
console.log(`Results of all promises = ${JSON.stringify(results)}`);
let response = results;
}
// Send JSON as the body of the POST request to the API
var callAddIntent = async (options) => {
try {
var response;
response = await request(options);
return { response: response };
} catch (err) {
console.log(`Error in callAddIntent: ${err.message} `);
}
}
module.exports = addIntents;
Entiteiten toevoegen
Met de volgende code worden de entiteiten toegevoegd aan de LUIS-app. Kopieer of download het en sla het op in _entities.js
.
// node 7.x
// uses async/await - promises
const request = require("requestretry");
var rp = require('request-promise');
var fse = require('fs-extra');
var path = require('path');
// time delay between requests
const delayMS = 1000;
// retry recount
const maxRetry = 5;
// retry request if error or 429 received
var retryStrategy = function (err, response, body) {
let shouldRetry = err || (response.statusCode === 429);
if (shouldRetry) console.log("retrying add entity...");
return shouldRetry;
}
// main function to call
// Call add-entities
var addEntities = async (config) => {
var entityPromises = [];
config.uri = config.uri.replace("{appId}", config.LUIS_appId).replace("{versionId}", config.LUIS_versionId);
config.entityList.forEach(function (entity) {
try {
config.entityName = entity;
// JSON for the request body
// { "name": MyEntityName}
var jsonBody = {
"name": config.entityName,
};
// Create an app
var addEntityPromise = callAddEntity({
url: config.uri,
fullResponse: false,
method: 'POST',
headers: {
'Ocp-Apim-Subscription-Key': config.LUIS_subscriptionKey
},
json: true,
body: jsonBody,
maxAttempts: maxRetry,
retryDelay: delayMS,
retryStrategy: retryStrategy
});
entityPromises.push(addEntityPromise);
console.log(`called addEntity for entity named ${entity}.`);
} catch (err) {
console.log(`Error in addEntities: ${err.message} `);
//throw err;
}
}, this);
let results = await Promise.all(entityPromises);
console.log(`Results of all promises = ${JSON.stringify(results)}`);
let response = results;// await fse.writeJson(createResults.json, results);
}
// Send JSON as the body of the POST request to the API
var callAddEntity = async (options) => {
try {
var response;
response = await request(options);
return { response: response };
} catch (err) {
console.log(`error in callAddEntity: ${err.message}`);
}
}
module.exports = addEntities;
Utterances toevoegen
Zodra de entiteiten en intenties zijn gedefinieerd in de LUIS-app, kunt u de uitingen toevoegen. De volgende code maakt gebruik van de Utterances_AddBatch-API , waarmee u maximaal 100 utterances tegelijk kunt toevoegen. Kopieer of download het en sla het op in _upload.js
.
// node 7.x
// uses async/await - promises
var rp = require('request-promise');
var fse = require('fs-extra');
var path = require('path');
var request = require('requestretry');
// time delay between requests
const delayMS = 500;
// retry recount
const maxRetry = 5;
// retry request if error or 429 received
var retryStrategy = function (err, response, body) {
let shouldRetry = err || (response.statusCode === 429);
if (shouldRetry) console.log("retrying add examples...");
return shouldRetry;
}
// main function to call
var upload = async (config) => {
try{
// read in utterances
var entireBatch = await fse.readJson(config.inFile);
// break items into pages to fit max batch size
var pages = getPagesForBatch(entireBatch.utterances, config.batchSize);
var uploadPromises = [];
// load up promise array
pages.forEach(page => {
config.uri = "https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/examples".replace("{appId}", config.LUIS_appId).replace("{versionId}", config.LUIS_versionId)
var pagePromise = sendBatchToApi({
url: config.uri,
fullResponse: false,
method: 'POST',
headers: {
'Ocp-Apim-Subscription-Key': config.LUIS_subscriptionKey
},
json: true,
body: page,
maxAttempts: maxRetry,
retryDelay: delayMS,
retryStrategy: retryStrategy
});
uploadPromises.push(pagePromise);
})
//execute promise array
let results = await Promise.all(uploadPromises)
console.log(`\n\nResults of all promises = ${JSON.stringify(results)}`);
let response = await fse.writeJson(config.inFile.replace('.json','.upload.json'),results);
console.log("upload done");
} catch(err){
throw err;
}
}
// turn whole batch into pages batch
// because API can only deal with N items in batch
var getPagesForBatch = (batch, maxItems) => {
try{
var pages = [];
var currentPage = 0;
var pageCount = (batch.length % maxItems == 0) ? Math.round(batch.length / maxItems) : Math.round((batch.length / maxItems) + 1);
for (let i = 0;i<pageCount;i++){
var currentStart = currentPage * maxItems;
var currentEnd = currentStart + maxItems;
var pagedBatch = batch.slice(currentStart,currentEnd);
var j = 0;
pagedBatch.forEach(item=>{
item.ExampleId = j++;
});
pages.push(pagedBatch);
currentPage++;
}
return pages;
}catch(err){
throw(err);
}
}
// send json batch as post.body to API
var sendBatchToApi = async (options) => {
try {
var response = await request(options);
//return {page: options.body, response:response};
return {response:response};
}catch(err){
throw err;
}
}
module.exports = upload;
De code uitvoeren
Afhankelijkheden van Node.js installeren
Installeer de Node.js afhankelijkheden in de terminal/opdrachtregel.
> npm install
Configuratie-instellingen wijzigen
Als u deze toepassing wilt gebruiken, moet u de waarden in het index.js-bestand wijzigen in uw eigen eindpuntsleutel en de naam opgeven die de app moet hebben. U kunt ook de cultuur van de app instellen of het versienummer wijzigen.
Open het bestand index.js en wijzig deze waarden boven aan het bestand.
// Change these values
const LUIS_programmaticKey = "YOUR_AUTHORING_KEY";
const LUIS_appName = "Sample App";
const LUIS_appCulture = "en-us";
const LUIS_versionId = "0.1";
Het script uitvoeren
Voer het script uit vanaf een terminal/opdrachtregel met Node.js.
> node index.js
Or
> npm start
Aanvraagvoortgang
Terwijl de toepassing wordt uitgevoerd, wordt de voortgang van de opdrachtregel weergegeven. De uitvoer van de opdrachtregel bevat de indeling van de antwoorden van LUIS.
> node index.js
intents: ["TurnOn","TurnOff","Dim","Other"]
entities: ["Operation","Device","Room"]
parse done
JSON file should contain utterances. Next step is to create an app with the intents and entities it found.
Called createApp, created app with ID 314b306c-0033-4e09-92ab-94fe5ed158a2
Called addIntents for intent named TurnOn.
Called addIntents for intent named TurnOff.
Called addIntents for intent named Dim.
Called addIntents for intent named Other.
Results of all calls to addIntent = [{"response":"e7eaf224-8c61-44ed-a6b0-2ab4dc56f1d0"},{"response":"a8a17efd-f01c-488d-ad44-a31a818cf7d7"},{"response":"bc7c32fc-14a0-4b72-bad4-d345d807f965"},{"response":"727a8d73-cd3b-4096-bc8d-d7cfba12eb44"}]
called addEntity for entity named Operation.
called addEntity for entity named Device.
called addEntity for entity named Room.
Results of all calls to addEntity= [{"response":"6a7e914f-911d-4c6c-a5bc-377afdce4390"},{"response":"56c35237-593d-47f6-9d01-2912fa488760"},{"response":"f1dd440c-2ce3-4a20-a817-a57273f169f3"}]
retrying add examples...
Results of add utterances = [{"response":[{"value":{"UtteranceText":"turn on the lights","ExampleId":-67649},"hasError":false},{"value":{"UtteranceText":"turn the heat on","ExampleId":-69067},"hasError":false},{"value":{"UtteranceText":"switch on the kitchen fan","ExampleId":-3395901},"hasError":false},{"value":{"UtteranceText":"turn off bedroom lights","ExampleId":-85402},"hasError":false},{"value":{"UtteranceText":"turn off air conditioning","ExampleId":-8991572},"hasError":false},{"value":{"UtteranceText":"kill the lights","ExampleId":-70124},"hasError":false},{"value":{"UtteranceText":"dim the lights","ExampleId":-174358},"hasError":false},{"value":{"UtteranceText":"hi how are you","ExampleId":-143722},"hasError":false},{"value":{"UtteranceText":"answer the phone","ExampleId":-69939},"hasError":false},{"value":{"UtteranceText":"are you there","ExampleId":-149588},"hasError":false},{"value":{"UtteranceText":"help","ExampleId":-81949},"hasError":false},{"value":{"UtteranceText":"testing the circuit","ExampleId":-11548708},"hasError":false}]}]
upload done
De LUIS-app openen
Zodra het script is voltooid, kunt u zich aanmelden bij LUIS en de LUIS-app zien die u hebt gemaakt onder Mijn apps. U moet de utterances kunnen zien die u hebt toegevoegd onder de intenties TurnOn, TurnOff en None .
Volgende stappen
Test en train uw app op de LUIS-website.
Aanvullende bronnen
In deze voorbeeldtoepassing worden de volgende LUIS-API's gebruikt: