Bedrockのtitan text modelをpythonで呼び出してみた

## はじめに
流行りのBedrockを僕も使ってみたいと思ったのですが、lambda経由でAmazon Titan Text modelsを使って動かしている方は少ないように見えたので、やってみようと思いました！

## 実装
### 実行している内容
処理としては、今日の日付を投げて、歴史上今日起きたすごいこと3つを教えてもらう
みたいなことを実装しています。

### lmabdaの作成
デフォルトのpythonで作成しました。
![スクリーンショット 2023-12-11 13.50.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3351273/aa4503fd-e187-485e-e01e-93a7b47945c6.png)

### コード部分
今回はサクッと動かしたかったので、lambdaに直書きしました！
![スクリーンショット 2023-12-11 13.52.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3351273/c4b7c336-4a51-7383-17bd-38558b06b971.png)



```python:lambda_function
import boto3
from function_list import *

def lambda_handler(event, context):
    
    today = event.get('today')
    
    output_text = generate_text(today)
    print(output_text)
```
```python:function_list
import boto3
import json

def generate_text(today):

    #bedrockと接続
    bedrock_runtime = boto3.client('bedrock-runtime')

    #bedrockに投げる内容と設定値を設定
    body = json.dumps({
        "inputText": f"In the world history, three great things happend {today}",
        "textGenerationConfig": {
            "temperature": 0.7,
            "topP": 0.9,
            "maxTokenCount": 300
        }
    })

    #モデルなどを指定し、bedrockにリクエスト
    response = bedrock_runtime.invoke_model(
        body = body,
        modelId = "amazon.titan-text-lite-v1",
        accept = 'application/json',
        contentType = 'application/json'
        )

    #レスポンスの受け取り
    response_body = json.loads(response.get('body').read())
    output_text = response_body['results'][0]['outputText']

    return output_text
```
```json:test
{
  "today": "Dec 10th"
}
```
### 実行結果
下記のような結果を受け取ることができました！
```terminal:test
1. The world's first steam-powered locomotive was invented on December 10, 1804, by the Scottish inventor James Watt.
2. The Wright Flyer, the world's first successful powered, heavier-than-air aircraft, was flown on December 17, 1903, by the American inventors Orville Wright and Wilbur Wright.
3. The first light bulb was invented by the German inventor Thomas Edison on December 10, 1879, and it marked the beginning of the modern era of electricity.
```

## tips
### bedrock上での今日
今回はtodayに実日付を入れて投げてみました。
この理由として、redrockに今日は何日？と聞くと、下記のようなお返事が来るからです！（実施日は12/10）
![スクリーンショット 2023-12-10 15.41.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3351273/98fa0266-fd7e-b450-87ec-d927407921c9.png)

### ロールの設定
lambdaに"AmazonBedrockFullAccess"などの、bedrockに許可を持つroleをつける必要があります。
今回はlambdaで実行だったのでIAMからコンソールで付与しました。

### lambdaのレイヤー設定
amazon titanのモデルも、lambdaのデフォルトのboto3-1.27.1では動かなかったので、最新バージョンにする必要がありました。
やり方は色々ありますが、僕はcloudshellでフォルダを作成、zip化してlambdaレイヤーに入れて使用する
という方法を使いました。
こちらの記事を参考にさせていただきました！
（レイヤーの設定と、lambdaとの結び付けのコマンドまで書いてくださっています！）
https://dev.classmethod.jp/articles/use-layers-to-set-the-version-of-boto3/

### 変数をプロンプトに入れる
コードの中に記載がありますが、
f"{}"を使うことで、変数をプロンプトに入れることができました！


### 他のモデルとの書き方の違い
他のモデルは、公式のサンプルコードがあったのでそれを参考にしていたのですが、下記のエラーになりました。。

```terminal:test
[ERROR] ValidationException: An error occurred (ValidationException) when calling the InvokeModel operation: Malformed input request: 5 schema violations found, please reformat your input and try again.
```
amazon titanのモデルは、ちょっと書き方が違うのですね。
outputの形式も微妙に異なるので、modelを変えて実施する際はご注意ください。

```python:anthropic
#anthropicのbody
body = json.dumps({
    "prompt": "\n\nHuman: explain black holes to 8th graders\n\nAssistant:",
    "max_tokens_to_sample": 300,
    "temperature": 0.1,
    "top_p": 0.9,
})

#anthropicのoutput
response_body = json.loads(response.get('body').read())
print(response_body.get('completion'))
```

```python:titan
#titanのbody
body = json.dumps({
    "inputText": f"In the world history, three great things happend {today}",
    "textGenerationConfig": {
        "temperature": 0.7,
        "topP": 0.9,
        "maxTokenCount": 300
    }
})

#titanのoutput
response_body = json.loads(response.get('body').read())
output_text = response_body['results'][0]['outputText']
print(output_text)
```
```python:titan
#titanのレスポンス全文
{'inputTextTokenCount': 15,
 'results': [
     {'tokenCount': 122,
      'outputText': ".\n1. The world's first steam-powered locomotive was invented on December 10, 1804, by the Scottish inventor James Watt.\n2. The Wright Flyer, the world's first successful powered, heavier-than-air aircraft, was flown on December 17, 1903, by the American inventors Orville Wright and Wilbur Wright.\n3. The first light bulb was invented by the German inventor Thomas Edison on December 10, 1879, and it marked the beginning of the modern era of electricity.",
      'completionReason': 'FINISH'}
     ]
 }
```

### 画像
Stability AI Diffusion XLのサンプルコードはあったのですが、titan imageはなく、公式ブログを参考に頑張ってみたのですが、lambdaにpillowがうまく入らず今回は断念しました。。
もしできた方がいたら、絶対読むので記事にしていただきたいです。笑

## 参考
boto3の最新化方法
https://dev.classmethod.jp/articles/use-layers-to-set-the-version-of-boto3/

titan以外のサンプルコード
https://docs.aws.amazon.com/bedrock/latest/userguide/api-methods-run-inference.html

モデル別bodyの書き方
https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-titan-text.html

titan imageの公式ブログ
https://aws.amazon.com/jp/blogs/aws/amazon-titan-image-generator-multimodal-embeddings-and-text-models-are-now-available-in-amazon-bedrock/