$30 off During Our Annual Pro Sale. View Details »

LINEとSlackとBedrock

moritalous
November 13, 2023

 LINEとSlackとBedrock

2023/11/13 JAWS-UG東京 2023 ~Bedrock Night~

LT発表資料

moritalous

November 13, 2023
Tweet

More Decks by moritalous

Other Decks in Technology

Transcript

  1. LINEとSlackとBedrock
    2023/11/13 JAWS-UG東京 2023 ~Bedrock Night~
    森田 和明

    View Slide

  2. お招きありがとうござ
    います。
    JAWS-UG東京とのことですが、鹿 と 大
    仏 の国から参加させて頂いています。
    →Bedrockで生成
    「Illustration of the country of deer and
    the Great Buddha」
    1

    View Slide

  3. 自己紹介
    富士ソフト株式会社
    エリア事業本部 西日本支社
    インテグレーション&ソリューション部
    森田 和明
    2023 Japan AWS Ambassadors
    生息地
    個人ブログ:
    https://moritalous.pages.dev/
    Qiita: https://qiita.com/moritalous
    X: https://x.com/moritalous
    2

    View Slide

  4. アジェンダ
    1. LINEとBedrock(Anthropic Claude)でチャット
    2. SlackとBedrock(Stable Diffusion XL)で画像生成
    3

    View Slide

  5. 1. LINEとBedrock(Anthropic Claude)でチャット

    View Slide

  6. Lambdaで開発する前に...
    まずはローカル環境でやってみましょう。
    boto3とLangChainをインストールします。
    pip install boto3 langchain==0.0.325 openai
    ※LangChainのバージョンは一応固定してみました。
    ※openaiは話の流れ上必要なだけです。
    4

    View Slide

  7. LangChainでチャット(OpenAI版)
    https://python.langchain.com/docs/modules/memory/adding_memory を参考にしました
    from langchain.chains import ConversationChain
    from langchain.chat_models import ChatOpenAI
    from langchain.memory import ConversationBufferMemory
    llm = ChatOpenAI()
    memory = ConversationBufferMemory()
    chain = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=True
    )
    5

    View Slide

  8. chain.predict(input="こんにちは。")
    > Entering new ConversationChain chain...
    Prompt after formatting:
    The following is a friendly conversation between a human and an AI. The AI is talkative and provides
    lots of specific details from its context. If the AI does not know the answer to a question, it
    truthfully says it does not know.
    Current conversation:
    Human: こんにちは。
    AI:
    > Finished chain.
    'こんにちは!元気ですか?どのようにお手伝いできますか?'
    6

    View Slide

  9. chain.predict(input="今日は晴れです。どのようなタスクができますか?")
    > Entering new ConversationChain chain...
    Prompt after formatting:
    The following is a friendly conversation between a human and an AI. The AI is talkative and provides
    lots of specific details from its context. If the AI does not know the answer to a question, it
    truthfully says it does not know.
    Current conversation:
    Human: こんにちは。
    AI: こんにちは!元気ですか?どのようにお手伝いできますか?
    Human: 今日は晴れです。どのようなタスクができますか?
    AI:
    > Finished chain.
    '私はさまざまなタスクをこなすことができます。例えば、日常生活のアドバイスや情報の提供、予定の管理、翻訳、ニュースの読み
    上げ、天気予報の提供などができます。どのようなタスクが必要ですか?'
    チャット履歴も覚えてくれてますね
    7

    View Slide

  10. Bedrockする
    I'm just a Japanese BEDROCKER!
    8

    View Slide

  11. LangChainでチャット(Bedrock版)
    from langchain.chains import ConversationChain
    - from langchain.chat_models import ChatOpenAI
    + from langchain.chat_models import BedrockChat
    from langchain.memory import ConversationBufferMemory
    - llm = ChatOpenAI()
    + llm = BedrockChat(model_id="anthropic.claude-instant-v1")
    memory = ConversationBufferMemory()
    chain = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=True
    )
    これだけ!!東京リージョンで使えるClaude Instantでも、全然行けます!!
    9

    View Slide

  12. chain.predict(input="こんにちは。")
    > Entering new ConversationChain chain...
    Prompt after formatting:
    The following is a friendly conversation between a human and an AI. The AI is talkative and provides
    lots of specific details from its context. If the AI does not know the answer to a question, it
    truthfully says it does not know.
    Current conversation:
    Human: こんにちは。
    AI:
    /home/ubuntu/workspace/2310-line-slack-bedrock/.venv/lib/python3.10/site-
    packages/langchain/llms/bedrock.py:50: UserWarning: Error: Prompt must alternate between '
    Human:' and '
    Assistant:'. Received
    10

    View Slide

  13. Human: The following is a friendly conversation between a human and an AI. The AI is talkative and
    provides lots of specific details from its context. If the AI does not know the answer to a
    question, it truthfully says it does not know.
    Current conversation:
    Human: こんにちは。
    AI:
    Assistant:
    warnings.warn(ALTERNATION_ERROR + f" Received {input_text}")
    > Finished chain.
    ' こんにちは。はじめまして。私は人工知能のアシスタントです。質問があればしっかり答えられるようにベストを尽くしますが、知
    識の範囲は限られています。よろしくお願いします。'
    回答は返ってきましたが、Warningが出てます。。
    11

    View Slide

  14. エラーの意訳
    「 Human: と Assistant: で囲まんかい!」
    無視しても良さそうだけど、気になる
    12

    View Slide

  15. Bedrock村で修行します
    はしもとさんのスーパースライドを確認します。
    https://www.docswell.com/s/s3kzk/58G697-20231027-bedrock-lt
    13

    View Slide

  16. 入村!!
    14

    View Slide

  17. 村のしきたり
    その1:
    合言葉は、 \n\nHuman: \n\nAssistant: P.29
    その2:
    重要な情報は XMLタグで囲う P.36
    その3:
    会話の履歴を使うとき区切り文字に "Human:" 、 "Assistant:" を使わない P.42
    15

    View Slide

  18. ありがとう!村長!!
    16

    View Slide

  19. ところで今のプロンプトは?
    chain.prompt
    PromptTemplate(
    input_variables=['history', 'input'],
    template='The following is a friendly conversation between a human and an AI. The AI is talkative
    and provides lots of specific details from its context. If the AI does not know the answer to a
    question, it truthfully says it does not know.\n\nCurrent conversation:\n{history}\nHuman:
    {input}\nAI:')
    なるほど。
    17

    View Slide

  20. しきたりに従う
    その1:
    合言葉は、 \n\nHuman: \n\nAssistant: P.29
    → これはLangChainが勝手にやってくれます
    その2:
    重要な情報はXMLタグで囲う P.36
    → {hisotry}の前後を と で囲う
    その3:
    会話の履歴を使うとき区切り文字に "Human:"、"Assistant:"を使わない P.42
    → PromptTemplateの中に埋め込まれている Human: と AI を H: と A: にする
    18

    View Slide

  21. from langchain.chains import ConversationChain
    from langchain.chat_models import BedrockChat
    from langchain.memory import ConversationBufferMemory
    from langchain.prompts import PromptTemplate
    prompt_template = PromptTemplate(
    input_variables=['history', 'input'],
    template='''The following is a friendly conversation between a human and an AI. The AI is
    talkative and provides lots of specific details from its context. If the AI does not know the answer
    to a question, it truthfully says it does not know.
    Current conversation:

    {history}

    {input}'''
    )
    19

    View Slide

  22. memory = ConversationBufferMemory(
    human_prefix="H",
    ai_prefix="A")
    llm = BedrockChat(model_id="anthropic.claude-instant-v1")
    chain = ConversationChain(
    llm=llm,
    memory=memory,
    prompt=prompt_template,
    verbose=True,
    )
    20

    View Slide

  23. chain.predict(input="こんにちは。")
    > Entering new ConversationChain chain...
    Prompt after formatting:
    The following is a friendly conversation between a human and an AI. The AI is talkative and provides
    lots of specific details from its context. If the AI does not know the answer to a question, it
    truthfully says it does not know.
    Current conversation:


    こんにちは。
    > Finished chain.
    ' はい、こんにちは。私はAIアシスタントです。名前は何ですか。'
    21

    View Slide

  24. chain.predict(input="今日は晴れです。どのようなタスクができますか?")
    > Entering new ConversationChain chain...
    Prompt after formatting:
    The following is a friendly conversation between a human and an AI. The AI is talkative and provides
    lots of specific details from its context. If the AI does not know the answer to a question, it
    truthfully says it does not know.
    Current conversation:

    H: こんにちは。
    A: はい、こんにちは。私はAIアシスタントです。名前は何ですか。

    今日は晴れです。どのようなタスクができますか?
    > Finished chain.
    ' はい、今日は晴れそうですね。私は Claude という名前の Chatbot です。\n\n私には特定のタスクを実行する能力はありませ
    んが、ユーザーと会話を行うことができます。質問に答えたり、興味のあるトピックについて話したりすることができます。どのよう
    な話題が興味深いか教えてください。私にとって最善の「タスク」は、ユーザーと可能な限り有益な対話を行うことだと思います。'
    22

    View Slide

  25. ワーニングは無事解消!!
    ありがとう!村長!!
    「#村長ありがとう」「#今日から私も村民です」をつけてお礼を投稿しよう!
    23

    View Slide

  26. チャット履歴の永続化
    ConversationBufferMemory(とChatMessageHistory)ではチャット履歴をメモリに保持し
    ている。データベースに永続化したい
    24

    View Slide

  27. DynamoDBに永続化
    LangChainがDynamoDBに対応。DynamoDBに永続化ができます。
    DynamoDBにテーブルを作成
    テーブル名は任意( SessionTable とします)
    パーティションキーを文字列型の SessionId とします。(LangChainのデフォルト値)
    ほかは何でもよし(オンデマンドモードでもOKです)
    25

    View Slide

  28. from langchain.chains import ConversationChain
    from langchain.chat_models import BedrockChat
    from langchain.memory import ConversationBufferMemory
    + from langchain.memory.chat_message_histories import DynamoDBChatMessageHistory
    from langchain.prompts import PromptTemplate
    <<省略>>
    + history = DynamoDBChatMessageHistory(table_name="SessionTable", session_id="0")
    memory = ConversationBufferMemory(
    human_prefix="H",
    ai_prefix="A",
    + chat_memory=history
    )
    <<省略>>
    履歴はsession_idごとに保存されます。
    26

    View Slide

  29. もうひと手間:直近10件の履歴だけを使うようにする
    from langchain.chains import ConversationChain
    from langchain.chat_models import BedrockChat
    - from langchain.memory import ConversationBufferMemory
    + from langchain.memory import ConversationBufferWindowMemory
    from langchain.memory.chat_message_histories import DynamoDBChatMessageHistory
    from langchain.prompts import PromptTemplate
    <<省略>>
    - memory = ConversationBufferMemory(
    + memory = ConversationBufferWindowMemory(
    human_prefix="H",
    ai_prefix="A",
    chat_memory=history,
    + k=10
    )
    <<省略>>
    27

    View Slide

  30. bedrock.py にまとめる
    from langchain.chains import ConversationChain
    from langchain.chat_models import BedrockChat
    from langchain.memory import ConversationBufferWindowMemory
    from langchain.memory.chat_message_histories import DynamoDBChatMessageHistory
    from langchain.prompts import PromptTemplate
    prompt_template = PromptTemplate(
    input_variables=['history', 'input'],
    template='''The following is a friendly conversation between a human and an AI. The AI is
    talkative and provides lots of specific details from its context. If the AI does not know the answer
    to a question, it truthfully says it does not know.
    Current conversation:

    {history}

    {input}'''
    )
    28

    View Slide

  31. llm = BedrockChat(model_id="anthropic.claude-instant-v1")
    def conversation(input: str, session_id: str):
    history = DynamoDBChatMessageHistory(table_name="SessionTable", session_id=str)
    memory = ConversationBufferWindowMemory(
    human_prefix="H",
    ai_prefix="A",
    chat_memory=history,
    k=10)
    chain = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=True
    )
    return chain.predict(input=input)
    29

    View Slide

  32. AWSのアーキテクチャ
    Amazon Bedrock
    Amazon DynamoDB
    AWS Lambda
    AWS Lambdaの関数URLを使うと便利。SAMも良いよ。
    30

    View Slide

  33. さて、そろそろLINE
    31

    View Slide

  34. LINE Messaging APIの設定
    1. LINE Messaging APIのサイトでコンソールにログインをクリックします。
    2. ログイン後の画面でプロバイダーを選択し、新規チャネル作成をクリックします。
    3. Messaging APIを選択します。
    4. チャネル名などを入力してチャネルを作成します。
    5. 作成後のチャネルの画面の下部にあるチャネルシークレットをメモします。
    6. Messaging API設定タブに移動し、画面下部にあるチャネルアクセストークン(長期) の
    発行ボタンをクリックします。表示されるアクセストークンをメモします。
    チャネルシークレットとアクセストークンが必要になります。
    32

    View Slide

  35. 1. LINE Messaging APIのサイトでコンソールにログインをクリックします。
    33

    View Slide

  36. 2. ログイン後の画面でプロバイダーを選択し、新規チャネル作成をクリックします。
    34

    View Slide

  37. 3. Messaging APIを選択します。
    35

    View Slide

  38. 4. チャネル名などを入力してチャネルを作成します。
    5. 作成後のチャネルの画面の下部にあるチャネルシークレットをメモします。
    36

    View Slide

  39. 6. Messaging API設定タブに移動し、画面下部にあるチャネルアクセストークン(長期) の
    発行ボタンをクリックします。表示されるアクセストークンをメモします。
    37

    View Slide

  40. LINE村のしきたり
    1. 署名を検証せよ!
    →SDKを使おう!
    pip install line-bot-sdk
    38

    View Slide

  41. LINE SDKを組み込んだ app.py
    SDKのサンプルソースを参考にしました。
    import os
    from linebot.v3 import (WebhookHandler)
    from linebot.v3.exceptions import (InvalidSignatureError)
    from linebot.v3.messaging import (
    Configuration,
    ApiClient,
    MessagingApi,
    ReplyMessageRequest,
    TextMessage
    )
    from linebot.v3.webhooks import (MessageEvent,TextMessageContent)
    LINE_CHANNEL_ACCESS_TOKEN = os.getenv('LINE_CHANNEL_ACCESS_TOKEN')
    LINE_CHANNEL_SECRET = os.getenv('LINE_CHANNEL_SECRET')
    39

    View Slide

  42. line_configuration = Configuration(access_token=LINE_CHANNEL_ACCESS_TOKEN)
    line_handler = WebhookHandler(channel_secret=LINE_CHANNEL_SECRET)
    @line_handler.add(MessageEvent, message=TextMessageContent)
    def handle_message(event: MessageEvent):
    user_id = event.source.user_id # ユーザーID
    text = event.message.text # ユーザーのメッセージ
    with ApiClient(line_configuration) as api_client:
    line_bot_api = MessagingApi(api_client)
    line_bot_api.reply_message_with_http_info(
    ReplyMessageRequest(
    reply_token=event.reply_token,
    messages=[TextMessage(text='応答文言')]
    )
    )
    40

    View Slide

  43. # Lambdaのエントリーポイント
    def lambda_handler(event, context):
    # get X-Line-Signature header value
    signature = event['headers']['x-line-signature']
    # get request body as text
    body = event['body']
    line_handler.handle(body,signature)
    return {
    'statusCode': 200,
    'body': 'OK'
    }
    41

    View Slide

  44. Bedrock部分を追加 (Let's bedrocking)
    + from bedrock import conversation
    <<略>>
    @line_handler.add(MessageEvent, message=TextMessageContent)
    def handle_message(event: MessageEvent):
    user_id = event.source.user_id # ユーザーID
    text = event.message.text # ユーザーのメッセージ
    with ApiClient(line_configuration) as api_client:
    + response = conversation(input=text, session_id=user_id)
    line_bot_api = MessagingApi(api_client)
    line_bot_api.reply_message_with_http_info(
    ReplyMessageRequest(
    reply_token=event.reply_token,
    - messages=[TextMessage(text='応答文言')]
    + messages=[TextMessage(text=response)]
    )
    )
    42

    View Slide

  45. 完成
    LINEでチャットができました。
    43

    View Slide

  46. 2. SlackとBedrock(Stable Diffusion XL)で画像生成

    View Slide

  47. いきなりですが
    Bedrockする
    I'm just a Japanese BEDROCKER!
    44

    View Slide

  48. Stable Diffusion XLで画像生成
    ※)Stable Diffusion XLはまだ東京リージョンでは使えません
    ライブラリーをインストール
    pip install boto3 pillow
    テキストから画像生成
    from PIL import Image
    import base64
    import boto3
    import io
    import json
    client = boto3.client('bedrock-runtime')
    45

    View Slide

  49. body = {
    'text_prompts': [{'text': 'land of the deer and the great Buddha'}],
    }
    response = client.invoke_model(
    modelId='stability.stable-diffusion-xl-v0',
    body=json.dumps(body)
    )
    response_body = json.loads(response.get('body').read())
    base64_str = response_body['artifacts'][0].get('base64') # Base64でエンコードされた画像
    image_byte = base64.decodebytes(bytes(base64_str, 'utf-8')) # デコード
    image = Image.open(io.BytesIO(image_byte)) # Imageに変換して
    image.save('sdxl.png') # 保存
    46

    View Slide

  50. 47

    View Slide

  51. 画像+プロンプトもできる
    # 画像を読み込んでBase64エンコードする
    init_image = Image.open('sdxl.png')
    buffer = io.BytesIO()
    init_image.save(buffer, format='png')
    init_image_bytes = buffer.getvalue()
    init_image_base64 = base64.b64encode(init_image_bytes).decode('utf-8')
    # init_imageを指定する
    body = {
    'text_prompts': [{'text': 'watercolor'}], # 水彩画風
    'init_image': init_image_base64
    }
    response = client.invoke_model(
    modelId='stability.stable-diffusion-xl-v0',
    body=json.dumps(body)
    )
    48

    View Slide

  52. 49

    View Slide

  53. さて、そろそろSlack
    50

    View Slide

  54. Bolt for Python
    SlackもSDKがあります。
    Bolt 入門ガイドがとてもわかり易いので、まずはこちらを実施しましょう。
    ソケットモードを使ったガイド
    https://slack.dev/bolt-python/ja-jp/tutorial/getting-started
    Webhookを受ける形式のガイド
    https://slack.dev/bolt-python/ja-jp/tutorial/getting-started-http
    51

    View Slide

  55. Slack村のしきたり
    1. リクエストから3秒以内にHTTPレスポンスを返却する必要がある
    時間のかかる処理は別スレッド(や別プロセス)で行うようにし、急いでレスポンスを返
    さないといけない
    ただし、Lambdaの場合、HTTPレスポンスを返すと別スレッド(や別プロセス)を実行し続
    けてくれない
    52

    View Slide

  56. SDKがLambda対応
    内部的に自分自身を非同期呼び出しする仕組みが組み込まれています。(すごい)
    53

    View Slide

  57. Lambdaレイヤーを作成
    1. requirements.txtを作成
    boto3
    pillow
    requests
    slack_bolt
    2. ZIPを作成
    pip install -r requirements.txt -t python
    zip -r slack-bedrock-layer.zip python
    3. マネジメントコンソールでLambdaレイヤーを登録
    54

    View Slide

  58. Lambdaを作成
    1. Lambdaレイヤーを追加
    2. IAMロールに 自分自身のLambdaをInvokeする権限 と、 Bedrockを呼び出す権限 を追加
    3. タイムアウトを1分に延長
    Lambdaプログラム
    import logging
    from slack_bolt import Ack, App, Say
    from slack_bolt.adapter.aws_lambda import SlackRequestHandler
    app = App(process_before_response=True, logger=logging.Logger(name='app'))
    55

    View Slide

  59. def respond_to_slack_within_3_seconds(body: dict, ack: Ack):
    ack("Accepted!")
    import time
    def run_long_process(message: dict, say: Say):
    time.sleep(5) # 3 秒より長い時間を指定します
    say('Hello')
    app.message("hello")(ack=respond_to_slack_within_3_seconds, lazy=[run_long_process])
    def lambda_handler(event, context):
    slack_handler = SlackRequestHandler(app=app)
    return slack_handler.handle(event, context)
    56

    View Slide

  60. Slackアプリを作成して設定
    入門ガイドの通り実行します。
    1. アプリを新規作成
    2. OAuth & Permissions の Bot Token Scopes でスコープを追加
    chat:write 、 files:read 、 files:write
    3. ワークスペースにアプリをインストール
    4. Bot User OAuth Token(xoxb-)を取得
    5. Basic Information の App Credentials にあるSigning Secretを取得
    6. Lambdaの環境変数をセット
    SLACK_BOT_TOKEN に Bot User OAuth Token
    SLACK_SIGNING_SECRET に Signing Secret
    57

    View Slide

  61. 7. Event Subscriptions の Enable Events をオンにし、 Request URL にLambdaの関数URLをセ
    ット
    8. Event Subscriptions の Subscribe to bot events にイベントを追加
    message.channels 、 message.groups 、 message.im 、 message.mpim
    9. Save Changes ボタンをクリック
    10. 権限が追加されたので、アプリを再度インストール
    11. App Homeの Allow users to send Slash commands and messages from the messages tab にチ
    ェック
    手順11. を行わないと、チャットでメッセージが投げられないと思います。
    58

    View Slide

  62. 画像をBedrockするLambda (Let's bedrocking)
    import base64
    import json
    import logging
    import os
    from slack_bolt import Ack, App, Say
    from slack_bolt.adapter.aws_lambda import SlackRequestHandler
    from slack_sdk.web import WebClient
    import boto3
    import requests
    bedrock = boto3.client('bedrock-runtime') # Bedrockアクセス用のクライアントを生成
    app = App(process_before_response=True, logger=logging.Logger(name='app'))
    59

    View Slide

  63. # Ackを返す関数
    def respond_to_slack_within_3_seconds(body: dict, ack: Ack):
    ack("Accepted!")
    # 非同期Lambdaで実行される処理本体
    def run_long_process(message: dict, say: Say, client: WebClient):
    channel_id = message['channel']
    SLACK_BOT_TOKEN=os.environ.get("SLACK_BOT_TOKEN")
    for file in message['files']:
    url_private = file['url_private']
    mimetype = file['mimetype']
    filetype = file['filetype']
    if filetype in ['jpg', 'png']:
    # HTTPヘッダーに認証情報をつけて添付ファイルを取得
    headers={'Authorization': f'Bearer {SLACK_BOT_TOKEN}'}
    image = requests.get(url=url_private, headers=headers)
    60

    View Slide

  64. # 取得した添付ファイルをBase64でエンコード
    init_image = image.content
    init_image = base64.b64encode(init_image).decode('utf-8')
    ##################
    # Bedrocking!!!! #
    ##################
    body = json.dumps({
    'text_prompts': [{'text': 'watercolor'}],
    'init_image': init_image,
    })
    bedrock_response = bedrock.invoke_model(
    modelId='stability.stable-diffusion-xl-v0',
    body=body)
    response_body = json.loads(bedrock_response.get('body').read())
    # Base64エンコードされた画像が取得できる
    response_body_base64 = response_body['artifacts'][0].get('base64')
    # Base64をデコード
    response_image = base64.decodebytes(bytes(response_body_base64, 'utf-8'))
    61

    View Slide

  65. # Bedrockした画像をアップロードしてチャットに返答
    client.files_upload_v2(
    channel=channel_id,
    file=response_image,
    title='Generated by Stable Diffusion (Bedrock Edition)',
    )
    # 添付ファイル付きメッセージの場合のイベント処理
    app.event({'type': 'message', 'subtype': 'file_share'})(ack=respond_to_slack_within_3_seconds, lazy=
    [run_long_process])
    # Lambdaハンドラー
    def lambda_handler(event, context):
    slack_handler = SlackRequestHandler(app=app)
    return slack_handler.handle(event, context)
    (エラー処理とか、添付ファイルが無いときとか、その他諸々はお願いします。)
    62

    View Slide

  66. 完成
    Slackでチャットができました。
    スマホのカメラで撮影した画像を使うと
    解像度が高すぎるかも。
    512 x 512程度に抑えるほうが良さそう
    なので、画像をリサイズする工夫も検討
    しましょう。
    63

    View Slide

  67. まとめ
    とりあえず入村!
    Bedrockでチャットも画像生成も簡単
    IAMとかboto3とか、AWSサービスを使ってる感覚で生成系AIを使えるのが、Bedrock
    の最大のメリット(個人の主観です)
    LINEもSlackもSDKがあるし、Lambdaで動く
    LangChainが対応しているので、OpenAIでできることはBedrockでもできる
    (と、思わせてくれる。ホントのところはわからないけど)
    JAWSで登壇できてとても嬉しいです。みんなもBedrockしてJAWSに参加しよう!
    64

    View Slide

  68. お土産
    GitHubにソースを公開しています。
    bedrock-line-chat
    https://github.com/moritalous/bedrock-line-chat
    bedrock-slack-sdxl
    https://github.com/moritalous/bedrock-slack-sdxl
    Qiitaの記事もよかったらどうぞ。
    祝GA!!Amazon BedrockとチャットができるLINEボットをオープンソースで公開しま
    した - Serverless Application Repositoryから簡単インストール可
    https://qiita.com/moritalous/items/6e0864d724d04d4ecf22
    65

    View Slide