LoginSignup
16
12
お題は不問!Qiita Engineer Festa 2023で記事投稿!

Azure Bot × Teams × Azure OpenAIの環境構築① ~オウム返しするまで~

Last updated at Posted at 2023-07-06

まえがき

本記事ではAzure OpenAIはまだ登場しません。次回以降にまとめていきたいと思います。
と言っても、最初の一歩なので「ユーザの入力をAzure OpenAIに対して投げ、そのレスポンスをユーザに表示してあげる。」といった基礎的な処理を組み込むだけになりそう、、

※2023年7月8日:追記
本記事の続きを行い、別の記事にまとめました。

Prerequisites

詳細は下記公式ドキュメントに記載があります。

Teams Toolkitの準備

今回は上記公式ドキュメントを参考に、VSCodeの拡張機能であるTeams Toolkitをインストールします。
VSCodeの拡張機能タブをクリック → 検索バーにteamsと入力 → installをクリックします。
(私の環境では既にinstall済みのためinstallが表示されていません)

image.png

Teamsアプリをローカル環境に構築

VSCode上からログイン作業

  • 開発用アカウント
  • Azureアカウント

それぞれにログインしておきます。

image.png

雛形アプリ作成

Teams Toolkitで雛形アプリを作成します。
Create New App → Bot → Basic Bot → TypeScriptとクリックし、アプリ名を入力します。

image.png

image.png

image.png

image.png

この作業を終えると雛形アプリが作成されます。作成されたディレクトリに移動し、メインのソースコードを少し編集します。
具体的には、teamsBot.tsを編集します。編集箇所は以下の通りです

  • import MessageFactoryを追記
  • onMessage()内に、ユーザの入力をそのまま返すコードを追記
    • await context.sendActivity(MessageFactory.text(txt))
teamsBot.ts
import {
  TeamsActivityHandler,
  CardFactory,
  TurnContext,
  AdaptiveCardInvokeValue,
  AdaptiveCardInvokeResponse,
  MessageFactory, // 【追記】
} from "botbuilder";
import rawWelcomeCard from "./adaptiveCards/welcome.json";
import rawLearnCard from "./adaptiveCards/learn.json";
import { AdaptiveCards } from "@microsoft/adaptivecards-tools";

export interface DataInterface {
  likeCount: number;
}

export class TeamsBot extends TeamsActivityHandler {
  // record the likeCount
  likeCountObj: { likeCount: number };

  constructor() {
    super();

    this.likeCountObj = { likeCount: 0 };

    this.onMessage(async (context, next) => {
      console.log("Running with Message Activity.");

      let txt = context.activity.text;
      const removedMentionText = TurnContext.removeRecipientMention(context.activity);
      if (removedMentionText) {
        // Remove the line break
        txt = removedMentionText.toLowerCase().replace(/\n|\r/g, "").trim();
      }

      // 【追記】ユーザのチャット画面にtxtを表示 → オウム返しとなる
      await context.sendActivity(MessageFactory.text(txt))

      // Trigger command by IM text
      switch (txt) {
        case "welcome": {
          const card = AdaptiveCards.declareWithoutData(rawWelcomeCard).render();
          await context.sendActivity({ attachments: [CardFactory.adaptiveCard(card)] });
          break;
        }
        case "learn": {
          this.likeCountObj.likeCount = 0;
          const card = AdaptiveCards.declare<DataInterface>(rawLearnCard).render(this.likeCountObj);
          await context.sendActivity({ attachments: [CardFactory.adaptiveCard(card)] });
          break;
        }
        /**
         * case "yourCommand": {
         *   await context.sendActivity(`Add your response here!`);
         *   break;
         * }
         */
      }

      // By calling next() you ensure that the next BotHandler is run.
      await next();
    });

    this.onMembersAdded(async (context, next) => {
      const membersAdded = context.activity.membersAdded;
      for (let cnt = 0; cnt < membersAdded.length; cnt++) {
        if (membersAdded[cnt].id) {
          const card = AdaptiveCards.declareWithoutData(rawWelcomeCard).render();
          await context.sendActivity({ attachments: [CardFactory.adaptiveCard(card)] });
          break;
        }
      }
      await next();
    });
  }

  // Invoked when an action is taken on an Adaptive Card. The Adaptive Card sends an event to the Bot and this
  // method handles that event.
  async onAdaptiveCardInvoke(
    context: TurnContext,
    invokeValue: AdaptiveCardInvokeValue
  ): Promise<AdaptiveCardInvokeResponse> {
    // The verb "userlike" is sent from the Adaptive Card defined in adaptiveCards/learn.json
    if (invokeValue.action.verb === "userlike") {
      this.likeCountObj.likeCount++;
      const card = AdaptiveCards.declare<DataInterface>(rawLearnCard).render(this.likeCountObj);
      await context.updateActivity({
        type: "message",
        id: context.activity.replyToId,
        attachments: [CardFactory.adaptiveCard(card)],
      });
      return { statusCode: 200, type: undefined, value: undefined };
    }
  }
}

ローカル環境でアプリを実行

VSCodeのデバッグ機能を使用します。EdgeやChromeでTeamsアプリが立ち上がり、開発中のコードの動作検証などを行うことができます。

image.png

今回私はEdgeで起動したため、Edgeで立ち上がったアプリを確認してみます。

image.png

オウム返しをしてくれるかと思います。

image.png

Azureリソースのプロビジョニング

Teams Toolkitから作成

Teams Toolkitでは、ボットを作成するために必要なリソース群を実質ワンクリックで作成することができます。

image.png

リソースデプロイ先となるサブスクリプションを選択。
image.png

リソースグループを選択。(今回は新規作成)
image.png
image.png

リージョンを選択。
image.png

Provisionをクリック。するとAzure上に必要なリソース群が作成されます。便利ですね。
image.png

作成物の確認

Azure Portalからリソースグループを確認してみます。Azure BotとApp Serviceが作成されています。
image.png

また、Teamsプロジェクトフォルダにあるenv/.env.devを確認すると、作成されたAzureリソースに合わせて必要な情報が追記されています。
Azure Botの認証情報やAppServiceのリソースIDが追記されていることがわかります。
image.png

AppServiceを見ると、Azure Botの認証情報が環境変数として設定されていることがわかります。
image.png

この段階では、AppServiceはただの箱の状態です。そのため、以降の手順で先ほど作成したオウム返しBotをデプロイします。

TeamsアプリをAppServiceにデプロイ

Teams ToolkitからAppServiceへのアプリデプロイを実施します。
image.png

デプロイのログはVSCode、AppService側の両方で確認できます。AppServiceではデプロイセンターから確認可能です。

image.png

デプロイに成功していることを確認します。

image.png

Web ChatとTeams上で動作確認する

Azure Botの画面からWebチャットでテストをクリックすると、Azure Portal上で動作確認を行えます。

image.png

また、Azure Botの画面からチャンネルを選択し、Open in TeamsをクリックするとTeamsから動作確認を行えます。

image.png

ローカル環境で実行した時同様、オウム返しをしてくれるかと思います。

image.png

まとめ・次回

Teams Toolkit × Azureを使用することで10分程度でオウム返しのBotを作成することができました。
次回はこのBotにAzure OpenAIにリクエストを投げる仕組みを追加していきたいと思います。

参考

16
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
12