アプリの進捗状況
アプリへのリンク
(Streamlit Community Cloud)
webbrowserの出力設定がデフォルトブラウザになってしまっているので、streamlit上ではブラウザオープンが失敗しています。修正します。
開発環境
Windows11, anaconda, python3.10.12,
VScode, Chrome,
Github, Streamlit Community Cloud
使用ライブラリ
streamlit, langchain, openAI,
google-api-python-client, wikipedia,
python-dotenv, GitPython
「料理検索」部分のコーディング
まずはサイドバーのコア機能となる「料理検索」部分を作成します。
使いたい食材をinputすると、プロンプティングによって外部検索(Google検索)が走り、それを基にLLMから回答を得て、検索結果ページのURLをブラウザに表示させるところまでコーディングします。
以下のライブラリを使用します。
openai==0.28.0 langchain==0.0.292 python-dotenv==1.0.0 google-api-python-client==2.125.0
まずはローカルのJupyterでコーディングです。
retrieval.ipynb
import os from dotenv import load_dotenv load_dotenv() import webbrowser from langchain.chat_models import ChatOpenAI from langchain.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate from langchain.agents import load_tools, initialize_agent, AgentType # ChatPromptTemplateの定義 system_template=""" あなたは、与えられた条件をもとにGoogleでレシピ検索を実行して回答を返すことが得意な、忠実なアシスタントです。 """ human_template=""" 以下の「検索条件」をキーワードとしてGoogle検索を実行し、回答は「回答ルール」に従うこと。 検索条件: {site} {material} レシピ 回答ルール: Google検索結果のページのみ表示 [Google Search Result]といったheaderを付けることを禁止する。 Google検索結果ページのURLを""で囲った文字列のみ回答すること。 URL以外の余計な情報は付与してはいけない。 Google検索結果からHumanが選ぶため、AIが勝手に料理を選んでそのURLに飛んではならない。 """ # 最終的にAgentに渡す messages を作成する → Streamlit上では関数化するか chat_prompt = ChatPromptTemplate.from_messages([ SystemMessagePromptTemplate.from_template(system_template), HumanMessagePromptTemplate.from_template(human_template) ]) # {site}の定義 # それぞれ特徴を持たせてクックパッド検索、マカロニ検索ができるよう # ここにも特徴的なキーワードを忍ばせる # streamlitでselectboxを意識して選択肢を考えておく # site_list = ["クックパッド 殿堂入り", "マカロニ Youtube"] messages = chat_prompt.format_prompt(site="クックパッド 殿堂入り", material=input("材料:")).to_messages() # LangChain Agent の振る舞い方を決める # OpenAI Chat Completion API の定義 # 外部検索が目的なので、LangChainのAgentを使用する # gpt-4モデルを使いたいので、.envにOPENAI_API_KEYを記述 # ツールは google-search を採用するため、.envにGOOGLE_API_KEY, GOOGLE_CSE_IDを追記 # 練習の為、.envからAPIモデル名とtemperatureを読み込む実験。他に流用できる箇所があれば取り入れよう。 chat = ChatOpenAI( model_name=os.environ["OPENAI_API_MODEL"], temperature=os.environ["OPENAI_API_TEMPERATURE"], ) tools = load_tools(["google-search"]) # Agentを初期化して変数に入れる # AgentTypeはOPENAI_FUNCTIONSを採用 agent_chain = initialize_agent( tools, chat, agent=AgentType.OPENAI_FUNCTIONS, ) result = agent_chain.run(messages) # デフォルトブラウザでURLを開く url = result webbrowser.open_new(url)
.env
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx OPENAI_API_MODEL=gpt-4 OPENAI_API_TEMPERATURE=0.5 GOOGLE_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxx GOOGLE_CSE_ID=xxxxxxxxxxxxxxx
いつもレシピ検索で利用している「cookpad」と「macaro-ni」どちらかで検索したいので、Streamlit上では st.selectbox() で選択できるようにする予定です。
余っている食材を入力したいので、messages 変数を定義する中に material=input(“食材:”) を忍ばせています。これはStreamlit上で st.text_input() になる予定です。
Agentの振る舞いに遊びを持たせてしまうと、検索結果にばらつきが出てしまいます。
(勝手にヘッダを振ったり、書き方に変化を持たせてくる)
最終的に戻り値のURLを使ってブラウザを開きたいので、「URLだけ」返させるプロンプトでないとなりません。意外とこの調整に時間がかかりました。
HumanMessagePromptTemplateの記述は試行錯誤を重ねて、やっと何とか安定的に「URLだけ」を返すようになったテンプレです。
system_template=""" あなたは、与えられた条件をもとにGoogleでレシピ検索を実行して回答を返すことが得意な、忠実なアシスタントです。 """ human_template=""" 以下の「検索条件」をキーワードとしてGoogle検索を実行し、回答は「回答ルール」に従うこと。 検索条件: {site} {material} レシピ 回答ルール: Google検索結果のページのみ表示 [Google Search Result]といったheaderを付けることを禁止する。 Google検索結果ページのURLを""で囲った文字列のみ回答すること。 URL以外の余計な情報は付与してはいけない。 Google検索結果からHumanが選ぶため、AIが勝手に料理を選んでそのURLに飛んではならない。 """
※ChatOpenAI() は temperature=0.5(.env)に設定していますが、今のところ結果に影響せず、きっちり「URLだけ」返してくれています
# print(result)の結果 "https://www.google.com/search?q=%E3%82%AF%E3%83%83%E3%82%AF%E3%83%91%E3%83%83%E3%83%89+%E6%AE%BF%E5%A0%82%E5%85%A5%E3%82%8A+%E3%81%AA%E3%81%99+%E3%83%AC%E3%82%B7%E3%83%94&rlz=1C1GCEU_enUS832US832&oq=%E3%82%AF%E3%83%83%E3%82%AF%E3%83%91%E3%83%83%E3%83%89+%E6%AE%BF%E5%A0%82%E5%85%A5%E3%82%8A+%E3%81%AA%E3%81%99+%E3%83%AC%E3%82%B7%E3%83%94&aqs=chrome.0.0i512l10.6128j0j7&sourceid=chrome&ie=UTF-8"
ブラウザに、意図したとおりの検索結果ページが立ち上がりました。
Webアプリのサイドバーに組み込む
以下のライブラリを追加で使用します。
streamlit==1.26.0
ソースコード
import os from dotenv import load_dotenv load_dotenv() import webbrowser from langchain.chat_models import ChatOpenAI from langchain.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate from langchain.agents import load_tools, initialize_agent, AgentType import streamlit as st ## ★メインエリア ## # 横幅いっぱいに表示 st.set_page_config(layout="wide") # タブ分け tab1, tab2, tab3 = st.tabs(["履歴管理","今週の献立","買い物リスト"]) with tab1: st.header("前週の献立を履歴に移動して保存") col1, col2 = st.columns((1,1)) with col1: st.text_area("履歴") with col2: st.text_area("前週食べたもの") st.button("履歴に移動して消去") with tab2: st.header("向こう一週間の献立を考える") col1, col2 = st.columns((1,1)) with col1: st.text_area("お気に入りレシピ") st.button("お気に入り 再読込") with col2: st.text_area("今週の献立を考える") st.button("今週の献立 更新") st.button("今週の献立 再読込") with tab3: st.header("買い物リストを作る") col1, col2 = st.columns((1,1)) with col1: st.text_area("今週の献立") with col2: st.text_area("買い物リスト") st.button("買い物リスト 更新") ## ★サイドバーの料理検索チャットボット部分 ## # {site}の定義 select_site = st.sidebar.selectbox("検索したいサイト:",("クックパッド", "マカロニ")) if select_site == "クックパッド": site = "クックパッド 殿堂入り" elif select_site == "マカロニ": site = "マカロニ Youtube" # {material}の定義 material = st.sidebar.text_input("食材:") retrieve = st.sidebar.button("検索") def retrieve_recipe(site, material): # ChatPromptTemplateの定義 system_template=""" あなたは、与えられた条件をもとにGoogleでレシピ検索を実行して回答を返すことが得意な、忠実なアシスタントです。 """ human_template=""" 以下の「検索条件」をキーワードとしてGoogle検索を実行し、回答は「回答ルール」に従うこと。 検索条件: {site} {material} レシピ 回答ルール: Google検索結果のページのみ表示 [Google Search Result]といったheaderを付けることを禁止する。 Google検索結果ページのURLを""で囲った文字列のみ回答すること。 URL以外の余計な情報は付与してはいけない。 Google検索結果からHumanが選ぶため、AIが勝手に料理を選んでそのURLに飛んではならない。 必ず検索結果ページに留まること。Youtubeの動画ページに移動することを禁止する。 """ # promptの定義 chat_prompt = ChatPromptTemplate.from_messages([ SystemMessagePromptTemplate.from_template(system_template), HumanMessagePromptTemplate.from_template(human_template) ]) # {site}の定義 # それぞれ特徴を持たせてクックパッド検索、マカロニ検索ができるよう # ここにも特徴的なキーワードを忍ばせる # streamlitでselectboxを意識して選択肢を考えておく messages = chat_prompt.format_prompt(site=site, material=material).to_messages() # OpenAI Chat Completion API の定義 # 外部検索が目的なので、LangChainのAgentを使用する # gpt-4モデルを使いたいので、.envにOPENAI_API_KEYを記述 # ツールは google-search を採用するため、.envにGOOGLE_API_KEY, GOOGLE_CSE_IDを追記 # 練習の為、.envからAPIモデル名とtemperatureを読み込む実験。他に流用できる箇所があれば取り入れよう。 chat = ChatOpenAI( model_name=os.environ["OPENAI_API_MODEL"], temperature=os.environ["OPENAI_API_TEMPERATURE"], ) tools = load_tools(["google-search"]) # Agentを初期化して変数に入れる # AgentTypeはOPENAI_FUNCTIONSを採用 agent_chain = initialize_agent( tools, chat, agent=AgentType.OPENAI_FUNCTIONS, ) return agent_chain.run(messages) # 初期設定 if material == "": exit() if retrieve: result = retrieve_recipe(site, material) material = "" else: exit() # result = retrieve_recipe(site, material) # デフォルトブラウザでURLを開く url = result webbrowser.open_new(url)
<< Prev Next >>