streamlitとlangchainでチャットAIを作る

# はじめに
今さらですが、最近の学習で**streamlit**を知りました、
爆速で**ChatGPT**のようなサービスを作れるとのことで、その過程を記録していきます。

:::note info
Streamlit
Pythonで簡単にデータアプリケーションを作成できるフレームワークです。データサイエンスや機械学習の結果を、簡単にインタラクティブなウェブアプリケーションとして表示するためのツールとして人気があります。[公式ドキュメント](https://streamlit.io/)
:::

:::note info
langchain
LangChainは、LLMを使ったアプリケーションを簡単に作成・統合するためのフレームワークです。 [公式ドキュメント](https://www.langchain.com/)
:::


## 成果物
![画面収録 2024-08-02 14.37.42.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/334570db-ff7f-abe0-d9cb-219705a26a06.gif)

### 依存リソース

:::note info
**pythonライブラリ**
- streamlit
- langchain-aws
- langchain-community
- langchain
:::

:::note info
**AWSリソース**
- Cloud9
- DynamoDB
:::

便宜上、Cloud9 を使用していますが、SageMaker Studio のコードエディタや Colab でも代替可能です。

SageMaker Studio使用する際に、下記の記事を参考にしてください。

https://qiita.com/minorun365/items/f5289163795d5d7b21e2

また、履歴を保存するためのデータベースが必要です。今回は DynamoDB を使用しますが、他のデータベースでも基本的には代用可能です。

DynamoDB の設定は以下の通りです。
![5662CAE0-1768-46FA-9791-7285732DF2BE.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/af875985-a114-97c5-bca4-8fba53dc8e7c.jpeg)
![0C0237BE-9D5F-4578-99D3-6C585D0F7B32.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/44e12083-cadb-f589-5092-13708c85e444.jpeg)

サンプルコードは下記の通りです。

```python: index.py
import streamlit as st
from langchain_aws import ChatBedrock
from langchain_community.chat_message_histories import DynamoDBChatMessageHistory
from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

st.title("Bedrock チャット")

if "session_id" not in st.session_state:
    st.session_state.session_id = "session_id"

if "history" not in st.session_state:
    st.session_state.history = DynamoDBChatMessageHistory(
    table_name="ai-chat", session_id=st.session_state.session_id
    )

if "chain" not in st.session_state:
    prompt = ChatPromptTemplate.from_messages(
        [
          ("system", "あなたのタスクはユーザーの質問に明確に答えることです。"),
          MessagesPlaceholder(variable_name="messages"),
          MessagesPlaceholder(variable_name="human_message"),
        ]
    )
    
    # ChatBedrock
    chat = ChatBedrock(
      model_id="anthropic.claude-3-sonnet-20240229-v1:0",
      region_name="us-east-1",
      model_kwargs={"max_tokens": 1000},
      streaming=True,
    )
    
    chain = prompt | chat
    st.session_state.chain = chain

if st.button("履歴クリア"):
    st.session_state.history.clear()

for message in st.session_state.history.messages:
    with st.chat_message(message.type):
        st.markdown(message.content)

if prompt := st.chat_input("なんでも聞いて.."):
    with st.chat_message("user"):
        st.markdown(prompt)

    with st.chat_message("assistant"):
        response = st.write_stream(
          st.session_state.chain.stream(
            {
                "messages": st.session_state.history.messages,
                "human_message": [HumanMessage(content=prompt)]
            },
            config={"configurable": {"session_id": st.session_state.session_id}},
          )
        )
    st.session_state.history.add_user_message(prompt)
    st.session_state.history.add_ai_message(response)
```

```
streamlit run index.py --server.port 8080.
```

## 参考文献

https://www.amazon.co.jp/Amazon-Bedrock-%E7%94%9F%E6%88%90AI%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA%E5%85%A5%E9%96%80-AWS%E6%B7%B1%E6%8E%98%E3%82%8A%E3%82%AC%E3%82%A4%E3%83%89-%E5%BE%A1%E7%94%B0/dp/4815626448

https://qiita.com/papasim824/items/b6aef456644321af0010