ChatGPT x Teams ボット x AWS(Python) x Bot Frameworkを使用しない簡単構築

# はじめに
ChatGPTの利用が一気に加速して、様々なサービスや業務に取り入れる人・企業も増えてきました。  
ChatGPTはSlackやLineなどで利用されている方も多いと思いますが、業務でTeamsを利用していて、そこにもChatGPTを利用したいニーズがあり、できるだけ簡単な環境構築(できるだけMicrosoftのサービスを利用しない)をやってみました。  
エンドユーザーの要望は翻訳の多言語化で、日本語、英語、中国語、韓国語の中からだいたい2ヶ国語を話人たちのグループですが、Teamsの翻訳機能は設定で1ヶ国語にしかできない＆ゲストは利用できないなど不便でした。  
そこで、日本語で入力するとボットが英語、中国語、韓国語にChatGPTが翻訳した文章を返すといった機能になります。  
今回のボットは多言語翻訳に機能を限定していますが、様々な用途に変更できると思います。

# 該当する環境
- AWS等からの通知を受け取りたい　→　Incoming Webhookを利用してください。
- 5秒以内に返答できるBot　→　Outgoing Webhookを利用してください。
- Bot Frameworkとか利用しないでシンプルにしたい　→　ぜひこちらを利用してください。
- ChatGPTの細かい設定はまた別途書きたいと思います。今回は環境構築を目的としています。
- AWSのLambdaとAPI Gatewayを利用しています。他のアプリなどでも利用できると思います。


# アーキテクチャ
![Architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/57a9e007-fb5b-50e3-2d6e-17d83bc367c4.png)

# 環境構築の流れ
1. [Azure botの作成](#1-Azure-botの作成)
2. [Lambda関数の作成](#2-Lambdaの作成)
3. [API Gatewayの作成](#3-API-Gatewayの作成)
4. [各種設定](#4-各種設定)
5. [Lambda関数の修正](#5-Lambda関数の修正)
6. [Teamsへの登録](#6-Teamsへの登録)
7. [使ってみた](#7-使ってみた)

## 1. Azure botの作成
- Azureアカウント作成(作成方法は他サイトを参考に。無料で作成できます。)
- Azure portal[https://portal.azure.com/](https://portal.azure.com/)にログインしてください。

1. botの作成
- Applied AI Services > ボットサービス > 作成
![1-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/ca121224-18ca-5132-6918-aa34a8a14deb.png)
![1-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/9c8f12bc-29e7-0d0f-e1a1-071ae530bc82.png)
  <img width="400" alt="1-3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/876bb744-1b9e-0460-d2ea-cad441c14d1c.png">

- リソースグループ名、場所などは適時自分の環境に合わせてください。
  <img width="500" alt="1-4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/c6397a05-f06a-d0ea-251b-5db0259f1187.png">

- プランの変更から価格はFreeを選択
![1-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/9cec624c-9570-c362-a085-6099221c5a9b.png)
  <img width="500" alt="1-6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/26f30a91-e036-0103-a7d7-0f14a5ef1961.png">

- アプリの種類は「シングルテナント」を選択しています。マルチテナントなど他の選択が必要な方はそちらのドキュメントを参照してください。
  <img width="500" alt="1-7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/95d4afec-e191-870f-e4c6-8810383cef13.png">
  <img width="500" alt="1-8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/a8832c89-3894-9c34-d558-decae0a5c4bc.png">


- Microsoft アプリIDの新規作成後、画面の手順に従って完了してください。
  <img width="500" alt="1-9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/21669bb9-04d3-a844-80ca-7cdd20ecd223.png">
  <img width="500" alt="1-10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/a1bade4b-d69b-3f48-1db8-da99fd0e1a94.png">
  <img width="500" alt="1-11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/6b1e4a21-e608-2aea-46bf-08c0510abe84.png">


## 2. Lambdaの作成
- Lambda > 関数の作成
![2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/1712fe2a-cb8f-74a3-c467-3f5a2049def4.png)
  <img width="600" alt="2-2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/f2691524-f0f6-9a6b-8330-251ea8f89c46.png">
  <img width="600" alt="2-3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/e022ca97-d558-f2e6-c74e-3a729f14d8b6.png">
  <img width="600" alt="2-4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/b9751360-459a-0fcf-87a3-5b0a86bdc2aa.png">


- タイムアウトのデフォルトが3秒になっていますが、タイムアウトしやすいので必要に応じて延長しておきましょう。
設定　> 一般設定 > 編集
![2-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/d928a118-d581-7b27-4330-19e66c0c4355.png)
![2-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/86188b38-e7e1-b81d-3283-e86974f16084.png)

- 必要なライブラリrequestsの準備  
一度ローカルに作業ディレクトリを作成し、そこにライブラリを落としてzip化します。

    ```
    $ mkdir workspace
    $ cd workspace
    $ pip3 install requests -t .
    $ zip -r upload.zip *
    ```

- ライブラリをLambdaへアップロード
![2-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/2a45c09c-f9c1-55f5-60e4-ad5f94b6435d.png)
![2-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/935630ac-dd68-3c66-c69a-11f546df84e8.png)


- pyファイル作成
以下の3つのファイルを作成してください。
ファイルは[こちら](https://github.com/derek-wkwk/teams-bot-chatgpt.git)に置いておきます。詳細は後半に記載しています。  
lambda_function.py  
get_message.py  
azure_bot.py


## 3. API Gatewayの作成
- API Gateway > APIを作成 > REST API > APIの作成
![3-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/74c5cfcc-a9c5-4795-9236-9efc0948a599.png)
![3-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/c27eb777-a2b4-f515-1db2-a10e5ce83cc1.png)
![3-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/18ca5ef5-9131-0e37-1fcf-11c034010d77.png)

- リソース > アクション > メソッドの作成 > POST
関数名は先程作成したLambdaの関数名をセットして保存
![3-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/f46db85d-bb86-816e-e32a-ee3e6a715682.png)
  <img width="500" alt="3-5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/65fc05b7-f4a5-dbcb-ce43-1c3af7d6cf6b.png"> 
  <img width="500" alt="3-6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/86b9a36f-862e-6967-0844-53d620fba9e4.png"> 
 ![3-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/68185de9-8ca5-a374-1095-0466a0b3d731.png)

  作成後のリソース図
![3-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/f1cfab1a-8fc9-3499-b8f4-b5c3335c54fd.png)

- マッピングテンプレートの追加
総合リクエスト > マッピングテンプレートの追加
  <img width="500" alt="3-9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/9c6acc8e-5a3f-7450-a9e2-c6454107b1cb.png"> 
  <img width="500" alt="3-10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/f8b22670-a700-95f3-65c5-918adf0d03e4.png"> 

  application/x-www-form-urlencoded
    
  ```
    ## convert HTML POST data or HTTP GET query string to JSON
    
    ## get the raw post data from the AWS built-in variable and give it a nicer name
    #if ($context.httpMethod == "POST")
    #set($rawAPIData = $input.path('$'))
    #elseif ($context.httpMethod == "GET")
    #set($rawAPIData = $input.params().querystring)
    #set($rawAPIData = $rawAPIData.toString())
    #set($rawAPIDataLength = $rawAPIData.length() - 1)
    #set($rawAPIData = $rawAPIData.substring(1, $rawAPIDataLength))
    #set($rawAPIData = $rawAPIData.replace(", ", "&"))
    #else
    #set($rawAPIData = "")
    #end
    
    ## first we get the number of "&" in the string, this tells us if there is more than one key value pair
    #set($countAmpersands = $rawAPIData.length() - $rawAPIData.replace("&", "").length())
    
    ## if there are no "&" at all then we have only one key value pair.
    ## we append an ampersand to the string so that we can tokenise it the same way as multiple kv pairs.
    ## the "empty" kv pair to the right of the ampersand will be ignored anyway.
    #if ($countAmpersands == 0)
    #set($rawPostData = $rawAPIData + "&")
    #end
    
    ## now we tokenise using the ampersand(s)
    #set($tokenisedAmpersand = $rawAPIData.split("&"))
    
    ## we set up a variable to hold the valid key value pairs
    #set($tokenisedEquals = [])
    
    ## now we set up a loop to find the valid key value pairs, which must contain only one "="
    #foreach( $kvPair in $tokenisedAmpersand )
    #set($countEquals = $kvPair.length() - $kvPair.replace("=", "").length())
    #if ($countEquals == 1)
    #set($kvTokenised = $kvPair.split("="))
    #if ($kvTokenised[0].length() > 0)
    ## we found a valid key value pair. add it to the list.
    #set($devNull = $tokenisedEquals.add($kvPair))
    #end
    #end
    #end
    
    ## next we set up our loop inside the output structure "{" and "}"
    {
    #foreach( $kvPair in $tokenisedEquals )
    ## finally we output the JSON for this pair and append a comma if this isn't the last pair
    #set($kvTokenised = $kvPair.split("="))
    "$util.urlDecode($kvTokenised[0])" : #if($kvTokenised[1].length() > 0)"$util.urlDecode($kvTokenised[1])"#{else}""#end#if( $foreach.hasNext ),#end
    #end
    }
  ```
    
  こちらの内容については理解できていない部分があります。詳しくは参照元を御覧ください。  


- アクション > APIのデプロイ
![3-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/661a5f44-f5b6-f010-e8a3-3bb1fa781fcd.png)
  <img width="500" alt="3-12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/ee51c738-43fb-ca12-2ecf-8c9014939bf2.png"> 

- APIを呼び出すurlが記載されています。
![3-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/cc563086-75c4-d5ed-24ff-8e94dd747f8c.png)

- ログの設定をします。
ステージ > ログ/トレース > CloudWatchメトリクスを有効化にチェックして保存
![3-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/17df0f24-cbb2-eeff-6840-24b507d390b2.png)

## 4. 各種設定
ざっと作成だけしてきましたが、詳細の設定をしていきましょう。
1. Azureの設定
 - エンドポイント  
    API Gatewayを作成したときのAPIのurlを入力します。
    ![4-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/8d607537-2e2b-55aa-a1ed-e9d971a71758.png)

  - Teamsの追加  
    Teamsで使用できるようにします。  
    チャネル > Microsoft Teamsを追加
  ![4-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/9b52ecfc-9c9c-c0a1-9a63-57ef26c791cd.png)

  - リクエストログの取得  
    webチャットでテスト > 適当なメッセージを送信
    <img width="500" alt="4-3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/d426199e-8170-4585-b00d-1ffcffba7139.png">

2.CloudWatchのログを確認
- ログに記載されている情報を確認しましょう。  
    CloudWatch > ロググループ >  
![4-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/20be855f-e7f5-194a-5fa6-d45b26b1d6e2.png)

    ロググループが作成されているはずなので、ログリストから先程のテストメッセージを送った際のログを確認します。  
![4-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/de85f5e6-bfac-8366-5ed4-93191dcba23b.png)

 - 以下のような情報が含まれています。
      ```
        (ffd456b5-b5e8-4660-b745-2e6045b6a2a3) Method request body before transformations: {
        "type": "message",
        "id": "Kfag***************0000",
        "timestamp": "2023-03-28T09:55:25.6099948Z",
        "localTimestamp": "2023-03-28T18:55:25.35+09:00",
        "localTimezone": "Asia/Tokyo",
        "serviceUrl": "https://webchat.botframework.com/",
        "channelId": "webchat",
        "from": {
            "id": "1a07***-*********109f",
            "name": ""
        },
        "conversation": {
            "id": "Kfag*************9-as"
        },
        "recipient": {
            "id": "ChatGPTtran@*******TE",
            "name": "ChatGPTtran"
        },
        "textFormat": "plain",
        "locale": "ja",
        "text": "テストメッセージです",
        "attachments": [],
        "entities": [
            {
                "type": "ClientCapabilities",
                "requiresBotState": true,
                "supportsListening": true,
                "supportsTts": true
            }
        ],
        "channelData": {
            "clientActivityID": "1679997325338d317w4yr9p"
        }
        }
      ```

## 5. Lambda関数の修正
ここで改めて関数を確認していきましょう。

1. APIを呼び出した際に実行される関数です。
　　　　<details><summary>lambda_function.py  </summary><div>

    ```python
    import logging
    import traceback
    import os
    import get_message
    import azure_bot
    import json

    logger = logging.getLogger(__name__)
    logger.setLevel(logging.ERROR)


    def lambda_handler(event, context):
        try:
            logger.debug(event)
            bot_name = os.environ.get('BOT_NAME', '')
            text = event['text'].replace(bot_name, '').replace('@', '').strip()
            # ChatGPTへの指示文
            order_text = '以下の文章を日本語、英語、中国語、韓国語に翻訳してください。それぞれの言語の間は改行をいれてください。\n'
            msg = order_text + text 
            msg = get_message.chatgpt_response(msg)

            azure_bot.response_azure(event, msg)

            response = {
                'statusCode': 200,
                'body': json.dumps('Hello from Lambda!')
            }

            return response

        except:
            logger.error(traceback.format_exc())
            return traceback.format_exc()
    ```

    </div></details>　　

   翻訳機能だけに限定したBotにしているので、シンプルにユーザーからの文章の先頭に翻訳する指示文を追加しています。


2. 文章をChatGPTへ送信して、翻訳文を受け取っています。

   <details><summary>get_message.py</summary><div>

   ```python
    import logging
    import requests
    import traceback
    import json
    import os
    from datetime import datetime

    logger = logging.getLogger(__name__)
    logger.setLevel(logging.ERROR)


    def chatgpt_response(text):
         apikey = os.environ.get('CHATGPT_API_KEY', 'sk-Hl*****************************BbBo')
         openai_endpoint = 'https://api.openai.com/v1/chat/completions'
        
         system_content = '\
         あなたはChatbotとして、翻訳をします。\
         以下の制約条件を厳密に守って翻訳をしてください。\
         \
         制約条件: \
         * Chatbotの自身を示す一人称は、Chattranです。\
         * Chattranは日本語、英語、韓国語、中国語を話します。\
         * Chattranは翻訳文だけを返答します。\
         \
         Chattranの行動指針:\
         * Userが日本語で話しかけてきた場合、文章を中国語と英語と韓国語に翻訳して各言語の間に改行を入れ返答します。\
         * Userが英語で話しかけてきた場合、文章を日本語と中国語と韓国語に翻訳して各言語の間に改行を入れ返答します。\
         '
     
         payload = {
             'model': 'gpt-3.5-turbo',
             'messages': [
                 {'role': 'system', 'content': system_content},
                 {'role': 'user', 'content': text}
             ]
         }
        
         headers = {
             'Content-type': 'application/json',
             'Authorization': 'Bearer '+ apikey
         }

         try:
             response = requests.post(
                 openai_endpoint,
                 data=json.dumps(payload),
                 headers=headers
             )
             data = response.json()
             logger.debug(data)
             return_text = data['choices'][0]['message']['content']

                return return_text

            except:
                logger.error(traceback.format_exc())
                return traceback.format_exc()
   ```

   </div></details>　

   API keyはChatGPTからAPI keyを取得してください。  
   system_contentは、機能やコンプラなどに合わせて適時修正が必要です。  
   また、アウトプットのフォーマットなどもここで指定てきますが、なかなか思うようなアウトプットにするには内容を工夫する必要があります。  
   シンプルな内容にしていますので、必要に応じて修正してください。

3. 認証アプリからのJTWトークンの取得及び、Bot Connectorへのレスポンスの送信を行います。  
[Create a bot with the Bot Connector service with the Bot Connector API](https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-quickstart?view=azure-bot-service-4.0#request)
[Authentication with the Bot Connector API](https://learn.microsoft.com/en-us/previous-versions/azure/bot-service/rest-api/bot-framework-rest-connector-authentication?view=azure-bot-service-3.0)
[API reference for the Bot Framework Connector service](https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-connector-api-reference?view=azure-bot-service-4.0#base-uri)
   <details><summary>azure_bot.py</summary><div>

   ```
    import requests
    import json
    import logging

    logger = logging.getLogger(__name__)
    logger.setLevel(logging.ERROR)


    def response_azure(event, message):
        access_token = fetch_access_token()

        id = event['id']
        recipient_id = event['recipient']['id']
        recipient_name = event['recipient']['name']
        conversatoin_id = event['conversation']['id']
        base_url = event['serviceUrl']
        # conversatoin_name = event['conversation']['name']

        data = {
            "type": "message",
            "from": {
                "id": recipient_id,
                "name": recipient_name
            },
            "conversation": {
                "id": conversatoin_id        
            },
            "recipient": {
                "id": recipient_id,
                "name": recipient_name
            },
            "text": message,
            "replyToId" : id
            }
        json_data = json.dumps(data)

        headers = {
            'Authorization': f'Bearer {access_token}',
            'Content-type': 'application/json'
        }

        url = f'{base_url}v3/conversations/{conversatoin_id}/activities/{id}'
        response = requests.post(url, data=json_data, headers=headers)
        logger.debug(response)

        print(response)

    def fetch_access_token():
        tenant_id = '7d25*************************f325'
        params = {
            'grant_type': 'client_credentials',
            'client_id': '142f*****************************89b3',
            'client_secret': 'JMN8********************************ecgP',
            'scope': 'https://api.botframework.com/.default'
        }
        url = f'https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token'
        response = requests.post(url, data=params)

        access_token = json.loads(response.text)['access_token']
        return access_token
   ```

   </div></details>
    
   公式のドキュメントではevent['conversation']['name']があるのですが、何故かリクエストには含まれていませんでした。  

   JTWトークンを取得する際に必要になるのが  
   - tenant_id  
    こちらはMicrosft 365の管理センターで確認できます。

     ![4-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/0c1c3bac-c397-520b-8c70-c1fa79b40a40.png)


   - client_id
    Azure bot > 構成 > Microsoft App IDのことです。  
    ![4-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/8d607537-2e2b-55aa-a1ed-e9d971a71758.png)

   - client_secret  
    こちらが意味不明だったのですが、こちらの値のことでした。  
    ![4-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/97917226-108b-0beb-0a22-e6a6f338ff22.png)

        しかし、Botを作成したときにこの値を取得できていません。  
    ということで、新しくIDを作成して値を取得することにします。  
    Microsoft App ID > パスワードの管理 > クライアントシークレット > 新しいシークレット  
     <img width="500" alt="4-8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/ba7a8f2e-e056-6e99-55ff-e5888741129e.png"> 

        作成時に表示された値を記録してください。(こちら期限があるので、継続して利用していくためには更新が必要ですね。)  
  
       ![4-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/42b179ba-0d3e-2891-d2c5-7798838fb4da.png)

    注）これらの変数はセキュリティの必要性に応じてAWSの環境変数を設定して利用してください。  


## 6. Teamsへの登録
ようやくTeams側で使う最終段階に入ってきました。  
Teamsで使うには、まずアプリ登録が必要ですが、そう簡単にいかないのが仕様です。
[Create Teams app package](https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/build-and-test/apps-package)

ドキュメントを見ると、必要なのがマニュフェストの作成とアイコン画像を32pxと192pxの２つのサイズです。  
- マニュフェストに関してはこちら。  
[App manifest schema for Teams](https://learn.microsoft.com/en-us/microsoftteams/platform/resources/schema/manifest-schema)
   ```
    {
        "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.15/MicrosoftTeams.schema.json",
        "manifestVersion": "1.15",
        "version": "0.1.0",
        "id": "142f*************************89b3",
        "developer": {
            "name": "DeveloperName",
            "websiteUrl": "https://github.com/derek-wkwk/teams-bot-chatgpt.git",
            "privacyUrl": "https://github.com/derek-wkwk/teams-bot-chatgpt.git",
            "termsOfUseUrl": "https://github.com/derek-wkwk/teams-bot-chatgpt.git"
        },
        "name": {
            "short": "ChatTran"
        },
        "description": {
            "short": "Translation bot",
            "full": "Translation chat bot for teams."
        },
        "icons": {
            "outline": "32.png",
            "color": "192.png"
        },
        "accentColor": "#FF4749",
        "bots": [
            {
                "botId": "142f*************************89b3",
                "scopes": [
                    "team",
                    "personal",
                    "groupchat"
                ],
                "needsChannelSelector": false,
                "isNotificationOnly": false,
                "supportsFiles": false,
                "supportsCalling": false,
                "supportsVideo": false
            }
        ],
        "permissions": [
            "identity",
            "messageTeamMembers"
        ],
        "devicePermissions": [
            "notifications"
        ],
        "validDomains": [
            "crediai.com"
        ],
        "defaultInstallScope": "team",
        "defaultGroupCapability": {
            "team": "bot",
            "groupchat": "bot"
        }
    }
   ```

   idとbotIdには上記のclient_id(App ID) をセットしています。  
ドキュメントを見たのですが、別々のIDのようですがどれのことかわかっていないため、両方同じにしています。とりあえずこれで動作しています。。

   ようやくファイルの準備ができました。これらをまとめてzip化します。(upload.zip)  

- Teamsへ登録
今度はTeamsアプリなどから  
アプリ管理 > アプリをアップロード   
![6-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/a99847e1-90df-1f35-f689-b222df65fb7a.png)


  管理者ではない場合、手順が異なるかもしれません。管理者にお願いしましょう。  
  <img width="500" alt="6-2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/0d360617-3d23-1ba2-4787-387718adb792.png">

　アップロード後、多少時間かかりますがこちらのように登録されます。 
 　<img width="500" alt="6-4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/769c3695-355e-0e79-8f7e-4095d37780db.png"> 


　必要なチームやチャットに追加してください。
　![6-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/f33f2ab3-c160-6400-25be-16d2e14553ac.png)



## 7. 使ってみた
追加したチーム内で、ボットにメンションすると、その文が翻訳されて返されてきました。
![7-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280192/12e965e1-43ff-358d-779a-8a254d31a6c0.png)


# 最後に  
　ChatGPTの利用が急速に進んでいて、様々なサービスが始まっています。私も業務で取り入れたりしながらその進化に驚いている毎日です。  
　今回は、どちらかというとChatGPTの要素が少ないですが、いざTeamsで利用しようとした時に、公式ドキュメントがあれだし、サービスのつながりが不明瞭だしでかなり苦労しました。
　取り急ぎ仕上げたため、後ほど細部は修正していく予定ですが、間違いがあればすぐに修正しますのでよろしくお願いいたします。

## 参考サイト
[Microsoft Teamsで(Bot frameworkを使わずに)ボットを作るには](https://zenn.dev/yusukeiwaki/articles/b6ae7bf77a81eb)
[slackのbotをAWS Lambda(Python)+API Gatewayで構築](https://www.yamamanx.com/slack-bot-aws-lambda-python-api-gateway/)