初めてのアプリ開発

<img width="100" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535635/bd311aa5-b28d-d410-518e-2f279c964cba.png"> <img width="100" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535635/f05b6dac-afd3-8cff-8d73-8ba861e57426.png">       <img width="80" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535635/7fe1a1f1-b48a-4acc-e3e7-ed5c36ea9514.png">     <img width="83" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535635/c0266a4f-2e9f-1cd4-0ce3-da6c5dbc6635.png"> <img width="100" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535635/79f91f53-1108-2155-bdbd-c8ee0588bf4c.png">  <img width="100" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535635/15e2359f-c467-3f2b-c23e-cbf4d6fa13ac.png">




# 1.　はじめに
# 1.1　:strawberry:自己紹介:strawberry:
（株）Aidemyのデータ分析講座を受講し、成果物の1つとして今回アプリを作成しました。

受講のきっかけは、株価の精度を上げたい、新しいことに取り組みたいと思い始めました。いざ初めてみると仕事と子育てと勉強は想像以上にハードでした:sweat_drops:
やると決めたからには完璧じゃなくても今の目標を達成するまではやり遂げていきたいと思います。

そんな私ですが数々の挫折と失敗を繰り返し、経理事務→インストラクター兼営業→総務（現在就業8年目）と経験してきました。ITは未経験ですので、この講座は基本的な事なのかもしれませんが覚えるの大変です。昨日より今日が少しでも成長していければと思います。
チューターの皆様には日々感謝してます！

# 1.2 :apple:アプリ開発に至る経緯:apple:

業務の1つとして技能実習生の生活指導員として手続き関係や生活面のフォローをしておりますので翻訳ツールがあったらコミュニケーションをとるのに便利かなと思い、チューターさんに話を持ち掛けました。講座外でしたが教えて頂けることになったので早速取り掛かりました！「翻訳アプリ」を参考に「本日の献立」を作成しました。

# 2.1  :candy:実行環境:candy:
OS　Windows11
GitHub
anaconda
Python 3.9
Visual Studio Code 
　バージョン：1.83.1

# 2.2:grapes:作成手順（本日の献立アプリ）:grapes:
1.anacondaを使用して環境構築する。
環境構築の仕方は下記のリンクを参考にして下さい。
https://www.python.jp/install/anaconda/windows/install.html
https://qiita.com/ozaki_physics/items/985188feb92570e5b82d
2.Streamlitでアプリの見た目を作る
3.ChatGPTとの通信
Open AI API(ChatGPT)との通信の手法について(バックエンド)
Streamlitを使用したユーザーが触れる画面(フロントエンド)
→https://docs.streamlit.io/library/api-reference
VSCodeの使用
GitHubアップロード

# 3. :hamburger:ディレクトリ構成図:hamburger:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535635/572466d8-b575-1ad3-ea8d-5b5da28cdbe8.png)


# :cherries:ディレクトリ構成図の説明:cherries:
data: 通常、このフォルダはデータを保存するために使用されます。CSVファイルを格納

src: ソースコードを保存する主要なディレクトリです。プログラムの主要なコードがここに格納される。

llm_template: このサブディレクトリの名前から判断すると、特定のテンプレート関連のコードやファイルが格納されている

template.yaml: YAML形式のテンプレートファイルです。設定や構造の情報が含まれている

utils: ユーティリティやヘルパー関数を格納するためのディレクトリと思われます。これは一般的にプロジェクト全体で使用される共通のコードや関数を保存するために使われます。

__pycache__: Pythonがコンパイルされたバイトコードをキャッシュとして保存するディレクトリです。これにより、再実行時のパフォーマンスが向上します。

__init__.py: Pythonのパッケージを示すための空のファイルです。これが存在することで、そのディレクトリはPythonのモジュールとして扱われます。

chatgpt.py: ChatGPTに関連する機能やコードを含むPythonファイルと思われます。

load_yaml.py: YAMLファイルを読み込むためのユーティリティ関数が含まれているPythonファイルです。

main.py: プログラムのエントリポイントやメインの実行コードが含まれているファイル

.env: 環境変数や設定値を格納するためのファイル。このファイルは通常、公開しない情報やシークレットキーなどを保持。

requirements.txt: Pythonのプロジェクトにおいて、使用している外部ライブラリやそのバージョンをリストアップするためのファイルです。このファイルを使用して、同じ環境を他のマシンで再現することができます。

# ①:fried_shrimp:main.pyの作成:fried_shrimp:
このコードはStreamlitを用いたウェブアプリの一部です。StreamlitはPythonでウェブアプリを作成するためのフレームワークです。

```python:main.py
import os
from dotenv import load_dotenv
import csv
from pathlib import Path

import streamlit as st
import openai

from utils import chatgpt

load_dotenv()

# APIキーの設定
openai.api_key = os.environ["OPENAI_API_KEY"]

if "chat_history" not in st.session_state:  # session_stateに"chat_history"がない場合の条件
    st.session_state["chat_history"] = []  # session_stateに空のリストとして"chat_history"を作成

if "submit_flg" not in st.session_state:  # session_stateに"submit_flg"がない場合の条件
    st.session_state["submit_flg"] = False  # session_stateにFalseとして"submit_flg"を作成

def on_submit():  # on_submit関数の定義
    st.session_state["submit_flg"] = True  # submit_flgをTrueに設定

def main():  # main関数の定義

    st.title("本日の献立")  # ウェブページのタイトルを設定
    
    message = st.chat_input("メッセージを入力してください", on_submit=on_submit)  # チャット入力を受け取る
    
    if st.session_state["submit_flg"]:  # submit_flgがTrueの場合の条件
        st.session_state["submit_flg"] = False  # submit_flgをFalseに戻す
        result = chatgpt.execute(text=message) # chatgptで入力メッセージを実行し、結果を取得
        st.session_state["chat_history"].append({"user":message}) # ユーザーのメッセージをchat_historyに追加
        st.session_state["chat_history"].append({"ai":result})# AIの応答をchat_historyに追加
     
     
    for chat in st.session_state["chat_history"]:  # chat_historyの各メッセージに対して
        if 'user' in chat:  # メッセージがユーザーからのものであれば
            with st.chat_message("user"):  # ユーザーとしてメッセージを表示
                st.write(chat['user'])  
        elif 'ai' in chat:  # メッセージがAIからのものであれば
            with st.chat_message("ai"):  # AIとしてメッセージを表示
                st.write(chat['ai'])  
     
if __name__ == "__main__":  # このスクリプトが直接実行された場合に以下のコードを実行
main()  # main関数を呼び出す

```
このコードは、ユーザーとAI（chatgpt）とのチャットの履歴をウェブページに表示するためのものです。ユーザーがメッセージを入力し送信すると、そのメッセージとAIの応答が履歴に追加され、ウェブページに表示されます。


# ②:spaghetti:chatgpt.pyの作成:spaghetti:
外部からのテキスト入力を受け取り、そのテキストに基づいてChatOpenAIのGPT-3.5モデルを使ってチャットの応答を生成し返すための関数を定義

```python:chatgpt.py
from langchain.prompts import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
)  # langchain.promptsから必要なクラスをインポート

from langchain.chat_models import ChatOpenAI  # ChatOpenAIクラスをインポート
from utils import load_yaml  # utilsからload_yaml関数をインポート
from pathlib import Path  # pathlibからPathクラスをインポート

def make_template(template):  # make_template関数の定義
    # templateからシステムメッセージのテンプレートを作成
    system_message_prompt = SystemMessagePromptTemplate.from_template(template['messages_template']['system_message_prompt'])
    # templateから人のメッセージのテンプレートを作成
    human_message_prompt = HumanMessagePromptTemplate.from_template(template['messages_template']['human_message_prompt'])
    # 上記二つのメッセージテンプレートからチャットプロンプトを作成
    chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
    return chat_prompt  # チャットプロンプトを返す

def execute(text):  # execute関数の定義
    
    # YAMLファイルからテンプレートをロード
    template = load_yaml.load(Path('./src/llm_template/template.yaml'))
    chat_prompt = make_template(template)  # チャットプロンプトを作成
    llm = ChatOpenAI(model_name="gpt-3.5-turbo")  # ChatOpenAIインスタンスを作成
    # チャットメッセージをフォーマットしてメッセージリストを作成
    chat_messages = chat_prompt.format_prompt(text=text).to_messages()
    response = llm(chat_messages)  # メッセージリストをChatOpenAIに渡し、レスポンスを取得
    response = response.dict()['content']  # レスポンスから必要な内容を抽出
    return response  # 応答を返す
```
chat.pyは、次のYAMLファイルからテンプレートを読み込み、それを基にプロンプトを動的に生成するPythonのスクリプトです。

#  ＊:wine_glass:template.yaml:wine_glass: 
YAMLファイルは設定やテンプレートを保存するのに使われるファイル形式です。

```python:template.yaml
messages_template:    
   
    menu: |
      あなたは献立を作るプロです。本日のメニューを考案して下さい。

    system_message_prompt: |
      You are a professional menu planner. Devise today's menu.

    human_message_prompt: |
      {text}
```
# ③ :fries:load_yaml.pyの作成:fries:
load関数の定義
```python:load_yaml.py
import yaml  # yamlモジュールをインポート。yamlは、YAML形式のデータを読み書きするためのモジュールです。
from yaml.loader import SafeLoader  # yaml.loaderからSafeLoaderをインポート。SafeLoaderは、YAMLファイルを安全にロードするためのローダーです。

def load(path):  # load関数の定義。引数にはYAMLファイルのパスが渡される。
        with open(path,encoding='utf-8') as file:  # 指定されたパスのYAMLファイルをutf-8エンコーディングで開く。
                config = yaml.load(file, Loader=SafeLoader)  # ファイルの内容をSafeLoaderを使ってロードし、configに保存。
        return config  # config（ロードされたYAMLデータ）を返す。
```
このload関数は、指定されたパスのYAMLファイルを開き、その内容をPythonのデータ構造（例：辞書やリスト）としてロード（読み込み）する役割があります。YAMLファイルはテキストファイルの一種で、データのシリアライズ（保存）に使われるフォーマットです。

# ④:curry:__init__.pyについて:curry:

Pythonパッケージがインポートされるときに最初に実行されるファイル
```python:__init__.py
from . import *
```
ここではutilsフォルダからchatgpt.py、load_yaml.pyをインポート

# ⑤:dango:.envについて:dango:
OPENAI_API_KEYの情報を入力します。

# ⑥:ice_cream:requirements.txtについて:ice_cream:

python-dotenv
openai
streamlit
langchain
プロジェクトで必要なPythonパッケージ（ライブラリやモジュール）とそのバージョンをリストアップするためのものです。このファイルを使うことで、開発者はプロジェクトの依存関係を簡単に管理することができます。

# 4.1   :peach:実行方法について:peach:

vscodeを開いて、menu_appフォルダを開きます。
ターミナルから新しいターミナルを開きpowershellからcommandpromptに切り替えます。
conda activate py39と打ち込み実行します。
streamlit run src/main.pyと実行することで、アプリが起動

# 4.2 :watermelon:デプロイについて:watermelon:
手順としてはテキストベースで記載すると下記になります。
githubのリポジトリを作成する
設定はここではprivateにする
vscodeのターミナルで下記のコマンドを打ち込む
git init
git remote add origin {gitのリポジトリのリンク}
git branch -M main
git add .
git commit -m "first commit"
git push origin main

streamlit shareでデプロイを行う
githubアカウントでログインする
newボタンからgithubのリポジトリを選択
立ち上げたいファイルを記載(src/main.py)


# 5. :alarm_clock:アプリを起動して入力:alarm_clock:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535635/6b66e15e-4e2e-97b1-1f36-4fd6ebed1c93.png)

何を作っていいのか悩んだらチャットボットに聞いてみます！！

# 6.:cherry_blossom:終わりに:cherry_blossom:
以上、初めてのアプリを作成してみました。
今後も引き続きアプリ開発の勉強をしていきたいと思います。

「このブログはAidemy Premiumのカリキュラムの一環で、受講修了条件を満たすために公開しています」