export async function publishLuisToPrediction()

in extensions/azurePublish/src/node/luisAndQnA.ts [82:230]


export async function publishLuisToPrediction(
  name: string,
  environment: string,
  accessToken: string,
  luisSettings: ILuisConfig,
  luisResource: string,
  path: string,
  logger,
  runtime?: RuntimeTemplate
) {
  let {
    // eslint-disable-next-line prefer-const
    authoringKey: luisAuthoringKey,
    authoringEndpoint: authoringEndpoint,
    authoringRegion: luisAuthoringRegion,
  } = luisSettings;

  if (!luisAuthoringRegion) {
    luisAuthoringRegion = luisSettings.region || 'westus';
  }
  if (!authoringEndpoint) {
    authoringEndpoint = `https://${luisAuthoringRegion}.api.cognitive.microsoft.com`;
  }

  // Find any files that contain the name 'luis.settings' in them
  // These are generated by the LuBuild process and placed in the generated folder
  // These contain dialog-to-luis app id mapping
  const luisConfigFiles = (await getFiles(botPath(path, runtime))).filter((filename) =>
    filename.includes('luis.settings')
  );
  const luisAppIds: any = {};

  // Read in all the luis app id mappings
  for (const luisConfigFile of luisConfigFiles) {
    const luisSettings = await fs.readJson(luisConfigFile);
    Object.assign(luisAppIds, luisSettings.luis);
  }

  if (!Object.keys(luisAppIds).length) return luisAppIds;
  logger({
    status: BotProjectDeployLoggerType.DEPLOY_INFO,
    message: 'start publish luis',
  });

  // In order for the bot to use the LUIS models, we need to assign a LUIS key to the endpoint of each app
  // First step is to get a list of all the accounts available based on the given luisAuthoringKey.
  let accountList;

  // Retry twice here
  let retryCount = 0;
  while (retryCount < 2) {
    try {
      // Make a call to the azureaccounts api
      // DOCS HERE: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5be313cec181ae720aa2b26c
      // This returns a list of azure account information objects with AzureSubscriptionID, ResourceGroup, AccountName for each.
      const getAccountUri = `${authoringEndpoint}/luis/api/v2.0/azureaccounts`;
      const options: AxiosRequestConfig = {
        headers: { Authorization: `Bearer ${accessToken}`, 'Ocp-Apim-Subscription-Key': luisAuthoringKey },
      };
      const response = await axios.get(getAccountUri, options);

      // this should include an array of account info objects
      accountList = response?.data ?? [];
      break;
    } catch (err) {
      if (retryCount < 1) {
        logger({
          status: AzurePublishErrors.LUIS_PUBLISH_ERROR,
          message: JSON.stringify(err, Object.getOwnPropertyNames(err)),
        });
        retryCount++;
      } else {
        // handle the token invalid
        const error = JSON.parse(err.error);
        if (error?.error?.message && error?.error?.message.indexOf('access token expiry') > 0) {
          throw new Error(
            `Type: ${error?.error?.code}, Message: ${error?.error?.message}, run az account get-access-token, then replace the accessToken in your configuration`
          );
        } else {
          throw err;
        }
      }
    }
  }

  // Extract the account object that matches the expected resource name.
  // This is the name that would appear in the azure portal associated with the luis endpoint key.
  const account = getAccount(accountList, luisResource ? luisResource : `${name}-${environment}-luis`);

  // Assign the appropriate account to each of the applicable LUIS apps for this bot.
  // DOCS HERE: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5be32228e8473de116325515
  for (const dialogKey in luisAppIds) {
    const luisAppId = luisAppIds[dialogKey].appId;
    logger({
      status: BotProjectDeployLoggerType.DEPLOY_INFO,
      message: `Assigning to luis app id: ${luisAppId}`,
    });

    // Retry at most twice for each api call
    let retryCount = 0;
    while (retryCount < 2) {
      try {
        const luisAssignEndpoint = `${authoringEndpoint}/luis/api/v2.0/apps/${luisAppId}/azureaccounts`;
        const options: AxiosRequestConfig = {
          headers: { Authorization: `Bearer ${accessToken}`, 'Ocp-Apim-Subscription-Key': luisAuthoringKey },
        };
        await axios.post(luisAssignEndpoint, account, options);

        break;
      } catch (err) {
        if (retryCount < 1) {
          logger({
            status: AzurePublishErrors.LUIS_PUBLISH_ERROR,
            message: JSON.stringify(err, Object.getOwnPropertyNames(err), 2),
          });
          retryCount++;
        } else {
          // handle the token invalid
          // handle the token invalid
          if (typeof err.error === 'string') {
            const error = JSON.parse(err.error);
            if (error?.error?.message && error?.error?.message.indexOf('access token expiry') > 0) {
              throw new Error(
                `Type: ${error?.error?.code}, Message: ${error?.error?.message}, run az account get-access-token, then replace the accessToken in your configuration`
              );
            }
          }

          const luisError = extractLuisErrorData(err);
          const luisDebugInfo = `Luis App ID: ${luisAppId}; Luis Authoring Key: ${luisAuthoringKey}; AzureSubscriptionID: ${account.AzureSubscriptionId} ResourceGroup: ${account.ResourceGroup}; AccountName: ${account.AccountName}; Location: ${account.Location}`;
          throw Error(
            `Failed to bind luis prediction resource to luis applications. Please check if your luisResource is set to luis prediction service name in your publish profile.
            ${luisDebugInfo}.
            ${luisError}`
          );
        }
      }
    }
  }

  // The process has now completed.
  logger({
    status: BotProjectDeployLoggerType.DEPLOY_INFO,
    message: 'Luis Publish Success! ...',
  });

  // return the new settings that need to be added to the main settings file.
  return luisAppIds;
}