撰寫 API 呼叫以進行下列動作:
-
建立應用程式。
-
新增從剖析資料收集而來的意圖和實體。
-
建立 LUIS 應用程式之後,您便可以從所剖析的資料新增範例語句。
您可以在
index.js
檔案的最後一個部分看到此程式流程。 請複製或
下載
此程式碼,並將其儲存成
index.js
。
完成時,請記得從程式碼中移除金鑰,且不要公開張貼金鑰。 在生產環境中,請使用安全的方式來儲存和存取您的認證,例如
Azure Key Vault
。 如需詳細資訊,請參閱 Azure AI 服務
安全性
一文。
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);
剖析 CSV
包含 CSV 中語句的資料行項目必須剖析成 LUIS 可理解的 JSON 格式。 此 JSON 格式必須包含識別語句意圖的
intentName
欄位。 它也必須包含
entityLabels
欄位,如果語句中沒有任何實體,則此欄位可以空白。
例如,"Turn on the lights" 項目會與此 JSON 對應:
"text": "Turn on the lights",
"intentName": "TurnOn",
"entityLabels": [
"entityName": "Operation",
"startCharIndex": 5,
"endCharIndex": 6
"entityName": "Device",
"startCharIndex": 12,
"endCharIndex": 17
在此範例中,
intentName
來自 CSV 檔案中
Request
資料行標題下的使用者要求,而
entityName
則來自其他含有關鍵資訊的資料行。 例如,如果有
Operation
或
Device
的項目,而該字串也出現在實際的要求中,您便可以將它標記為實體。 下列程式碼示範此剖析程序。 您可以複製或
下載
此程式碼,並將其儲存成
_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;
建立 LUIS 應用程式
將資料剖析成 JSON 之後,請將其新增至 LUIS 應用程式。 下列程式碼會建立 LUIS 應用程式。 請複製或
下載
此程式碼,並將其儲存成
_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;
新增對應方式
有了應用程式之後,您必須將意圖新增至應用程式。 下列程式碼會建立 LUIS 應用程式。 請複製或
下載
此程式碼,並將其儲存成
_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;
下列程式碼會將實體新增至 LUIS 應用程式。 請複製或
下載
此程式碼,並將其儲存成
_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;
新增表達方式
在 LUIS 應用程式中定義實體和意圖之後,您可以新增語句。 下列程式碼會使用
Utterances_AddBatch
API,這可讓您一次最多新增 100 個語句。 請複製或
下載
此程式碼,並將其儲存成
_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) => {
// 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) => {
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;
執行程式碼
安裝 Node.js 相依性
在終端機/命令行中安裝Node.js相依性。
> npm install
變更組態設定
若要使用此應用程式,您必須將 index.js 檔案中的值變更成自己的端點金鑰,然後提供想要讓應用程式擁有的名稱。 您也可以設定應用程式的文化特性,或變更版本號碼。
開啟 index.js 檔案,然後變更位於檔案頂端的這些值。
// Change these values
const LUIS_programmaticKey = "YOUR_AUTHORING_KEY";
const LUIS_appName = "Sample App";
const LUIS_appCulture = "en-us";
const LUIS_versionId = "0.1";
執行指令碼
使用 Node.js 從終端機/命令列執行指令碼。
> node index.js
> npm start
當應用程式正在執行時,命令列會顯示進度。 命令列輸出會包含來自 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
開啟 LUIS 應用程式
當指令碼完成之後,您可以登入 LUIS,然後在 [我的應用程式] 底下查看您建立的 LUIS 應用程式。 您應該能夠在 [TurnOn]、[TurnOff] 及 [None] 意圖底下看到您所新增的語句。
在 LUIS 網站中測試及定型您的應用程式。
此範例應用程式會使用下列 LUIS API:
建立應用程式