どんな相手でもメッセージを続けれるようになりたい。メッセージ練習アプリを作成してみた。

# 独り身からの脱却
以前、独り身で寂しいということを記事にしました。
この記事は、寂しさを紛らわすためのものですが、根本の解決にはなっていません。

https://qiita.com/mamoru-ngy/items/52fea227efd5a6cfad6c



となると、この問題を解決するためにはパートナーを見つける他ありません。

パートナーを見つけるために始めることと言えば、__マッチングアプリ__ ですね！
マッチングアプリはメッセージが大事だとよく聞くので、今回はメッセージを練習するためのアプリを作成してみました。

# 作成したアプリ
今回はstreamlitでアプリを作成しました。
会った回数、性格、興味の入力する欄を設けて、エージェントに反映しました。

![スクリーンショット 2024-12-02 18.39.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682615/b56a09c8-a589-ab04-102f-2868190b4974.png)

メッセージを入力して送信ボタンを押すと返事が返ってきます。
また、履歴も残すようにして、会話に反映するようにしました。

![スクリーンショット 2024-12-02 18.47.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3682615/0cf3fc31-9148-869b-c517-58c59cfec472.png)





# 実装
<details>
<summary>コードまとめ</summary>

```python
import streamlit as st
import requests
import json
import os
import openai

# OpenAI APIキーを設定
API_KEY = "YOUR_OPENAI_API_KEY"

# 履歴ファイルのパス
HISTORY_FILE = "conversation_history.json"

# 会話履歴を読み込む関数
def load_history():
    if os.path.exists(HISTORY_FILE):
        with open(HISTORY_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    return []

# 会話履歴を保存する関数
def save_history(history):
    with open(HISTORY_FILE, "w", encoding="utf-8") as f:
        json.dump(history, f, ensure_ascii=False, indent=2)

# 会話履歴を削除する関数
def clear_history():
    if os.path.exists(HISTORY_FILE):
        os.remove(HISTORY_FILE)

# エージェントと会話する関数 (新しいAPIフォーマットを使用)
def chat_with_agent(user_input, history, meet_count, personality, interests):
    # メッセージ履歴をフォーマット
    messages = [
        {"role": "system", "content": f"あなたはメッセージ練習のためのエージェントです。このエージェントの特徴は以下の通りです。\n\n"
                                      f"- ユーザーとは{meet_count}回会ったことがあり、{personality}な性格です。\n"
                                      f"- エージェントは{', '.join(interests)}に興味があります。\n"}
    ]
    
    # 過去の会話をメッセージに追加
    for entry in history:
        messages.append({"role": "user", "content": entry['user']})
        messages.append({"role": "assistant", "content": entry['agent']})
    
    # 新しいユーザー入力を追加
    messages.append({"role": "user", "content": user_input})
    
    # APIリクエストのヘッダーとペイロード
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {API_KEY}"
    }
    payload = {
        "model": "gpt-4o",
        "messages": messages,
        "max_tokens": 150,
        "temperature": 0.7
    }
    
    # APIリクエストを送信
    response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
    if response.status_code == 200:
        return response.json()["choices"][0]["message"]["content"]
    else:
        st.error(f"APIリクエストエラー: {response.status_code}, {response.text}")
        return "エラーが発生しました。"

# StreamlitアプリのUI
st.title("メッセージ練習アプリ")

# ユーザー入力フォーム
st.sidebar.header("エージェント設定")
meet_count = st.sidebar.number_input("会った回数", min_value=0, max_value=100, step=1)
personality = st.sidebar.text_input("性格")
interests = st.sidebar.text_area("興味 (カンマ区切りで入力)").split(",")

# 会話履歴をロード
history = load_history()

# ユーザーの入力
user_input = st.text_area("あなたのメッセージ", "", height=150)


if st.button("送信") and user_input.strip():
    # エージェントの応答を生成
    agent_response = chat_with_agent(user_input, history, meet_count, personality, interests)
    
    # 履歴に追加（最新を先頭にするため挿入）
    history.insert(0, {"user": user_input, "agent": agent_response})
    
    # 履歴を保存
    save_history(history)

    # 応答を表示
    st.success(f"エージェント: {agent_response}")

# 履歴削除ボタン
if st.button("履歴を削除"):
    clear_history()
    history = []  # 履歴をクリア
    st.warning("履歴が削除されました。")

# 履歴を新しい順で表示
st.header("履歴")
for entry in history:
    st.write(f"**あなた:** {entry['user']}")
    st.write(f"**エージェント:** {entry['agent']}")
    st.write("---")
```

</details>

## 初期設定
必要なライブラリをインポートして、基本設定を行っています。

```python
import streamlit as st
import requests
import json
import os
import openai

# OpenAI APIキーを設定
API_KEY = "YOUR_OPENAI_API_KEY "

# 履歴ファイルのパス
HISTORY_FILE = "conversation_history.json"
```




## 会話履歴の管理
会話履歴の読み込み、保存、削除の関数を作成しています。
```python
# 会話履歴を読み込む関数
def load_history():
    if os.path.exists(HISTORY_FILE):
        with open(HISTORY_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    return []

# 会話履歴を保存する関数
def save_history(history):
    with open(HISTORY_FILE, "w", encoding="utf-8") as f:
        json.dump(history, f, ensure_ascii=False, indent=2)

# 会話履歴を削除する関数
def clear_history():
    if os.path.exists(HISTORY_FILE):
        os.remove(HISTORY_FILE)

```


## エージェントとの会話ロジック
ユーザーからの入力情報や会話履歴をエージェントに送信し、応答を生成します。

```python
# エージェントと会話する関数 (新しいAPIフォーマットを使用)
def chat_with_agent(user_input, history, meet_count, personality, interests):
    # メッセージ履歴をフォーマット
    messages = [
        {"role": "system", "content": f"あなたはメッセージ練習のためのエージェントです。このエージェントの特徴は以下の通りです。\n\n"
                                      f"- ユーザーとは{meet_count}回会ったことがあり、{personality}な性格です。\n"
                                      f"- エージェントは{', '.join(interests)}に興味があります。\n"}
    ]
    
    # 過去の会話をメッセージに追加
    for entry in history:
        messages.append({"role": "user", "content": entry['user']})
        messages.append({"role": "assistant", "content": entry['agent']})
    
    # 新しいユーザー入力を追加
    messages.append({"role": "user", "content": user_input})
    
    # APIリクエストのヘッダーとペイロード
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {API_KEY}"
    }
    payload = {
        "model": "gpt-4o",
        "messages": messages,
        "max_tokens": 150,
        "temperature": 0.7
    }
    
    # APIリクエストを送信
    response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
    if response.status_code == 200:
        return response.json()["choices"][0]["message"]["content"]
    else:
        st.error(f"APIリクエストエラー: {response.status_code}, {response.text}")
        return "エラーが発生しました。"
```


## streamlitによるアプリ構築
タイトルやサイドバー、入力欄を作成しています。

```python
# StreamlitアプリのUI
st.title("メッセージ練習アプリ")

# ユーザー入力フォーム
st.sidebar.header("エージェント設定")
meet_count = st.sidebar.number_input("会った回数", min_value=0, max_value=100, step=1)
personality = st.sidebar.text_input("性格")
interests = st.sidebar.text_area("興味 (カンマ区切りで入力)").split(",")

# 会話履歴をロード
history = load_history()

# ユーザーの入力（メッセージ欄を大きくする）
user_input = st.text_area("あなたのメッセージ", "", height=150)


if st.button("送信") and user_input.strip():
    # エージェントの応答を生成
    agent_response = chat_with_agent(user_input, history, meet_count, personality, interests)
    
    # 履歴に追加（最新を先頭にするため挿入）
    history.insert(0, {"user": user_input, "agent": agent_response})
    
    # 履歴を保存
    save_history(history)

    # 応答を表示
    st.success(f"エージェント: {agent_response}")

# 履歴削除ボタン
if st.button("履歴を削除"):
    clear_history()
    history = []  # 履歴をクリア
    st.warning("履歴が削除されました。")

# 履歴を新しい順で表示
st.header("履歴")
for entry in history:
    st.write(f"**あなた:** {entry['user']}")
    st.write(f"**エージェント:** {entry['agent']}")
    st.write("---")
```

# まとめ
アプリを作成して実際に試してみましたが、思っていたよりもエージェントが質問をしてくれます。実際はここまで質問を投げかけてくれないかもしれないので、エージェントがしてる質問をみて話の広げ方を勉強したほうが良いのかもしれません。