アプリの進捗状況
アプリへのリンク
(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 >>