recipe_0626 / app.py
shigeru saito
リクエストごとにインスタンス化、出力メッセージをjsonからフリーテキストに変更、functionsにdescription, examplesを追加、テストコード追加
3d9d048
raw
history blame
16.6 kB
import gradio as gr
import openai
import requests
import os
import fileinput
from dotenv import load_dotenv
import io
import sys
import json
from PIL import Image
from stability_sdk import client
import stability_sdk.interfaces.gooseai.generation.generation_pb2 as generation
title="najimino AI recipe generator"
inputs_label="どんな料理か教えてくれれば,新しいレシピを考えます"
outputs_label="najimino AIが返信をします"
visual_outputs_label="料理のイメージ"
description="""
- ※入出力の文字数は最大1000文字程度までを目安に入力してください。回答に20秒くらいかかります.
"""
article = """
"""
load_dotenv()
openai.api_key = os.getenv('OPENAI_API_KEY')
os.environ['STABILITY_HOST'] = 'grpc.stability.ai:443'
stability_api = client.StabilityInference(
key=os.getenv('STABILITY_KEY'),
verbose=True,
engine="stable-diffusion-512-v2-1",
# Available engines: stable-diffusion-v1 stable-diffusion-v1-5 stable-diffusion-512-v2-0 stable-diffusion-768-v2-0
# stable-diffusion-512-v2-1 stable-diffusion-768-v2-1 stable-diffusion-xl-beta-v2-2-2 stable-inpainting-v1-0 stable-inpainting-512-v2-0
)
# MODEL = "gpt-4"
# MODEL = "gpt-3.5-turbo-16k"
MODEL = "gpt-3.5-turbo-0613"
def get_filetext(filename, cache={}):
if filename in cache:
# キャッシュに保存されている場合は、キャッシュからファイル内容を取得する
return cache[filename]
else:
if not os.path.exists(filename):
raise ValueError(f"ファイル '{filename}' が見つかりませんでした")
with open(filename, "r") as f:
text = f.read()
# ファイル内容をキャッシュする
cache[filename] = text
return text
class StabilityAI:
@classmethod
def generate_image(cls, visualize_prompt):
print("visualize_prompt:"+visualize_prompt)
answers = stability_api.generate(
prompt=visualize_prompt,
)
for resp in answers:
for artifact in resp.artifacts:
if artifact.finish_reason == generation.FILTER:
print("NSFW")
if artifact.type == generation.ARTIFACT_IMAGE:
img = Image.open(io.BytesIO(artifact.binary))
return img
class OpenAI:
@classmethod
def chat_completion(cls, prompt, start_with=""):
constraints = get_filetext(filename = "constraints.md")
template = get_filetext(filename = "template.md")
# ChatCompletion APIに渡すデータを定義する
data = {
"model": MODEL,
"messages": [
{"role": "system", "content": constraints}
,{"role": "system", "content": template}
,{"role": "assistant", "content": "Sure!"}
,{"role": "user", "content": prompt}
,{"role": "assistant", "content": start_with}
],
}
# ChatCompletion APIを呼び出す
response = requests.post(
"https://api.openai.com/v1/chat/completions",
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {openai.api_key}"
},
json=data
)
# ChatCompletion APIから返された結果を取得する
result = response.json()
print(result)
content = result["choices"][0]["message"]["content"].strip()
visualize_prompt = content.split("### Prompt for Visual Expression\n\n")[1]
#print("split_content:"+split_content)
#if len(split_content) > 1:
# visualize_prompt = split_content[1]
#else:
# visualize_prompt = "vacant dish"
#print("visualize_prompt:"+visualize_prompt)
answers = stability_api.generate(
prompt=visualize_prompt,
)
@classmethod
def chat_completion_with_function(cls, prompt, messages, functions):
print("prompt:"+prompt)
response = openai.ChatCompletion.create(
model=MODEL,
messages=messages,
functions=functions,
function_call="auto"
)
# ChatCompletion APIから返された結果を取得する
message = response.choices[0].message
print(json.dumps(message, indent=2))
return message
class NajiminoAI:
def __init__(self, user_message):
self.user_message = user_message
def generate_recipe_prompt(self):
template = get_filetext(filename="template.md")
prompt = f"""
{self.user_message}
---
上記を元に、下記テンプレートを埋めてください。
---
{template}
"""
return prompt
def format_recipe(self, lang, title, description, ingredients, instruction, comment_feelings_taste, explanation_to_blind_person, prompt_for_visual_expression_in_en):
debug_message = f"""
lang: {lang}
title: {title}
description: {description}
ingredients: {ingredients}
instruction: {instruction}
comment_feelings_taste: {comment_feelings_taste}
explanation_to_blind_person: {explanation_to_blind_person}
prompt_for_visual_expression_in_en: {prompt_for_visual_expression_in_en}
"""
print(debug_message)
return debug_message
@classmethod
def generate(cls, user_message):
najiminoai = NajiminoAI(user_message)
return najiminoai.generate_recipe()
def generate_recipe(self):
user_message = self.user_message
constraints = get_filetext(filename = "constraints.md")
messages = [
{"role": "system", "content": constraints}
,{"role": "user", "content": user_message}
]
functions = [
{
"name": "format_recipe",
"description": "どんな料理か教えてくれれば,新しいレシピを考えます",
"parameters": {
"type": "object",
"default": {},
"title": "The Schema of new recipe",
"required": [
"lang",
"title",
"description",
"ingredients",
"instruction",
"comment_feelings_taste",
"explanation_to_blind_person",
"prompt_for_visual_expression_in_en"
],
"properties": {
"lang": {
"type": "string",
"default": "ja",
"title": "Language Schema",
"examples": [
"ja"
]
},
"title": {
"type": "string",
"default": "",
"title": "Title of New Recipe.",
"description": "Write your title of new recipe.",
"examples": [
"グルテンフリーサバのお好み焼き"
]
},
"description": {
"type": "string",
"default": "",
"title": "Your New Recipe",
"description": "Write new recipe and brainstorm and work out the details of every aspect of the new recipe.",
"examples": [
"サバを使ったお好み焼きのレシピです。グルテンフリー仕様で作られているので、小麦粉を使わずに作ることができます。"
]
},
"ingredients": {
"type": "string",
"default": "",
"title": "Your Ingredients",
"description": "Brainstorm the ingredients needed to cook a new recipe and come up with all the ingredients for the new recipe.",
"examples": [
"・サバのフィレ 200g\n・卵 2個\n・キャベツ 1/4個\n・もやし 50g\n・紅しょうが(刻んだもの) 2片\n・ネギ(小口切り) 適量\n・酒大さじ2\n・しょうゆ 大さじ2\n・だし汁 100ml\n・片栗粉 大さじ2\n・サラダ油 お好みで"
]
},
"instruction": {
"type": "string",
"default": "",
"title": "Your Instruction",
"description": "Instruct them to cook a new recipe, brainstorming and working out every aspect and detail of the new recipe.",
"examples": [
"1. キャベツは粗みじん切りにし、もやしは石づきを取っておく。\n2. ボウルに卵を割り入れ、よく混ぜる。酒、しょうゆ、だし汁を加えてさらに混ぜる。\n3. キャベツ、もやし、紅しょうが、ネギを卵液に加え、さらに混ぜる。\n4. サバのフィレを食べやすい大きさに切り、片栗粉をまぶす。\n5. フライパンにサラダ油を熱し、サバを並べ入れる。両面をこんがり焼く。\n6. サバの上に卵液を流し入れ、蓋をして約5分ほど蒸し焼きにする。\n7. ひっくり返して、もう片面も蓋をして約5分ほど蒸し焼きにする。\n8. お好み焼きを取り出し、お好みでソースやマヨネーズをかけて完成です。"
]
},
"comment_feelings_taste": {
"type": "string",
"default": "",
"title": "Your Comment and Feelings, taste of new recipe.",
"description": "Review commnet of new recipe and brainstorm every point of new recipe to fill the details.",
"examples": [
"このグルテンフリーサバのお好み焼きは、サバの旨味とキャベツの甘みが絶妙にマッチしています。表面はサクサク、中はもちもちとした食感で、一度食べたらやみつきになる美味しさです。"
]
},
"explanation_to_blind_person": {
"type": "string",
"default": "",
"title": "Your Explanation to Blind Person",
"description": "Review commnet of new recipe here to explain to the blind people more concretely in detail. Please brainstorm every point of new recipe to fill the details.",
"examples": [
"このグルテンフリーサバのお好み焼きは、サバのフィレとキャベツを主な材料としています。まず、キャベツを細かく刻んでおきます。次に、卵をボウルに割り入れ、酒、しょうゆ、だし汁と一緒によく混ぜます。その後、刻んだキャベツ、もやし、紅しょうが、ネギを卵液に加えて混ぜます。サバのフィレは食べやすい大きさに切り、片栗粉をまぶしてから焼きます。フライパンにサラダ油を熱し、サバを焼きます。その上に卵液を流し入れ、蓋をして約5分蒸し焼きにします。ひっくり返して、もう片面も蓋をして約5分蒸し焼きにします。最後にお好み焼きを取り出し、ソースやマヨネーズをかけて完成です。"
]
},
"prompt_for_visual_expression_in_en": {
"type": "string",
"default": "",
"title": "The Schema of prompt for visual expression in English",
"examples": [
"Imagine a delicious gluten-free okonomiyaki with mackerel. The okonomiyaki is crispy on the outside and chewy on the inside. It is topped with savory sauce and creamy mayonnaise, creating a mouthwatering visual. The dish is garnished with finely chopped green onions and red pickled ginger, adding a pop of color. The mackerel fillets are beautifully grilled and placed on top of the okonomiyaki, adding a touch of elegance. The dish is served on a traditional Japanese plate, completing the visual presentation."
]
}
}
}
}
]
message = OpenAI.chat_completion_with_function(prompt=user_message, messages=messages, functions=functions)
# resultからfunction_callを取り出す
# message = result["function_call"]
print(json.dumps(message, indent=2))
if message.get("function_call"):
function_name = message["function_call"]["name"]
args = json.loads(message["function_call"]["arguments"])
lang=args.get("lang")
title=args.get("title")
description=args.get("description")
ingredients=args.get("ingredients")
instruction=args.get("instruction")
comment_feelings_taste=args.get("comment_feelings_taste")
explanation_to_blind_person=args.get("explanation_to_blind_person")
prompt_for_visual_expression_in_en=args.get("prompt_for_visual_expression_in_en")
function_response = self.format_recipe(
lang=lang,
title=title,
description=description,
ingredients=ingredients,
instruction=instruction,
comment_feelings_taste=comment_feelings_taste,
explanation_to_blind_person=explanation_to_blind_person,
prompt_for_visual_expression_in_en=prompt_for_visual_expression_in_en
)
answers = StabilityAI.generate_image(prompt_for_visual_expression_in_en)
return [function_response, answers]
def main():
iface = gr.Interface(fn=NajiminoAI.generate,
inputs=gr.Textbox(label=inputs_label),
outputs=[gr.Textbox(label=inputs_label), gr.Image(label=visual_outputs_label)],
title=title,
description=description,
article=article,
allow_flagging='never'
)
iface.launch()
if __name__ == '__main__':
function = ''
if len(sys.argv) > 1:
function = sys.argv[1]
if function == 'generate':
NajiminoAI.generate("グルテンフリーの香ばしいサバのお好み焼き")
elif function == 'generate_image':
answers = StabilityAI.generate_image("Imagine a delicious gluten-free okonomiyaki with mackerel. The okonomiyaki is crispy on the outside and chewy on the inside. It is topped with savory sauce and creamy mayonnaise, creating a mouthwatering visual. The dish is garnished with finely chopped green onions and red pickled ginger, adding a pop of color. The mackerel fillets are beautifully grilled and placed on top of the okonomiyaki, adding a touch of elegance. The dish is served on a traditional Japanese plate, completing the visual presentation.")
print(answers)
# <PIL.PngImagePlugin.PngImageFile image mode=RGB size=512x512 at 0x139900430>
import PIL
# answersが何のクラス確認する
if type(answers) == PIL.PngImagePlugin.PngImageFile:
#save image
answers.save("image.png")
else:
main()