アプリの進捗状況

アプリへのリンク
(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をブラウザに表示させるところまでコーディングします。

以下のライブラリを使用します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
openai==0.28.0
langchain==0.0.292
python-dotenv==1.0.0
google-api-python-client==2.125.0
openai==0.28.0 langchain==0.0.292 python-dotenv==1.0.0 google-api-python-client==2.125.0
openai==0.28.0
langchain==0.0.292
python-dotenv==1.0.0
google-api-python-client==2.125.0


まずはローカルのJupyterでコーディングです。

retrieval.ipynb

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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)
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)
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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
OPENAI_API_MODEL=gpt-4
OPENAI_API_TEMPERATURE=0.5
GOOGLE_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxx
GOOGLE_CSE_ID=xxxxxxxxxxxxxxx
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx OPENAI_API_MODEL=gpt-4 OPENAI_API_TEMPERATURE=0.5 GOOGLE_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxx GOOGLE_CSE_ID=xxxxxxxxxxxxxxx
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だけ」を返すようになったテンプレです。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
system_template="""
あなたは、与えられた条件をもとにGoogleでレシピ検索を実行して回答を返すことが得意な、忠実なアシスタントです。
"""
human_template="""
以下の「検索条件」をキーワードとしてGoogle検索を実行し、回答は「回答ルール」に従うこと。
検索条件: {site} {material} レシピ
回答ルール: Google検索結果のページのみ表示
[Google Search Result]といったheaderを付けることを禁止する。
Google検索結果ページのURLを""で囲った文字列のみ回答すること。
URL以外の余計な情報は付与してはいけない。
Google検索結果からHumanが選ぶため、AIが勝手に料理を選んでそのURLに飛んではならない。
"""
system_template=""" あなたは、与えられた条件をもとにGoogleでレシピ検索を実行して回答を返すことが得意な、忠実なアシスタントです。 """ human_template=""" 以下の「検索条件」をキーワードとしてGoogle検索を実行し、回答は「回答ルール」に従うこと。 検索条件: {site} {material} レシピ 回答ルール: Google検索結果のページのみ表示 [Google Search Result]といったheaderを付けることを禁止する。 Google検索結果ページのURLを""で囲った文字列のみ回答すること。 URL以外の余計な情報は付与してはいけない。 Google検索結果からHumanが選ぶため、AIが勝手に料理を選んでその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だけ」返してくれています

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# 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"
# 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"
# 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アプリのサイドバーに組み込む

以下のライブラリを追加で使用します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
streamlit==1.26.0
streamlit==1.26.0
streamlit==1.26.0

ソースコード

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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)
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)
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 >>