cook_recommend / test.py
jinu0804's picture
Initialize project without images
dfcc4e2
Raw
History Blame Contribute Delete
6.77 kB
import os
from dotenv import load_dotenv
from transformers import pipeline
from PIL import Image
import gradio as gr
from openai import OpenAI
import torch
import scipy
import numpy
# πŸ”Ή ν™˜κ²½ λ³€μˆ˜ λ‘œλ“œ
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# πŸ”Ή 객체 탐지 λͺ¨λΈ λ‘œλ”©
detector = pipeline(
task="zero-shot-object-detection",
model="google/owlv2-base-patch16-ensemble"
)
# πŸ”Ή 재료 라벨 및 λ²ˆμ—­
candidate_labels = [
"lettuce","cheese","bread","tomato","ham"
]
label_ko = {
"cheese": "치즈", "bread":"λΉ΅", "tomato":"ν† λ§ˆν† ","ham":"ν–„","lettuce":"양상좔"}
# πŸ”Ή μ „μ—­ λ³€μˆ˜ μ €μž₯용
last_ingredients = ""
# πŸ”Ή HTML ν˜•μ‹ 좜λ ₯
def format_result_html(result_text):
html = "<div id='recipe-box' style='font-family: Pretendard, sans-serif; font-size: 17px; line-height: 1.9; background-color: #fefefe; padding: 20px; border-radius: 12px; border: 1px solid #ddd; box-shadow: 0 2px 8px rgba(0,0,0,0.05);'>"
lines = result_text.strip().splitlines()
for line in lines:
if line.startswith("μš”λ¦¬ 이름:"):
content = line.replace("μš”λ¦¬ 이름:", "").strip()
html += f"<h3 style='color:#d84315;'>🍽️ {content}</h3><br>"
elif line.startswith("μ„€λͺ…:"):
html += f"<p><strong>μ„€λͺ…:</strong> {line.replace('μ„€λͺ…:', '').strip()}</p>"
elif line.startswith("재료:"):
html += f"<p><strong>재료:</strong> {line.replace('재료:', '').strip()}</p>"
elif line.startswith("λ§Œλ“œλŠ” 법:"):
html += f"<p><strong>λ§Œλ“œλŠ” 법:</strong> {line.replace('λ§Œλ“œλŠ” 법:', '').strip()}</p>"
elif line.startswith("쑰리 μ‹œκ°„:"):
html += f"<p><strong>⏱ 쑰리 μ‹œκ°„:</strong> {line.replace('쑰리 μ‹œκ°„:', '').strip()}</p>"
elif line.startswith("λ‚œμ΄λ„:"):
html += f"<p><strong>🎯 λ‚œμ΄λ„:</strong> {line.replace('λ‚œμ΄λ„:', '').strip()}</p>"
else:
html += f"<p>{line}</p>"
html += "</div>"
return html
# πŸ”Ή μš”λ¦¬ 생성 ν•¨μˆ˜
def generate_recipe(ingredient_text):
prompt = f"""
냉μž₯고에 μžˆλŠ” 재료: {ingredient_text}
이 μž¬λ£Œλ“€λ§Œ μ‚¬μš©ν•΄μ„œ λ§Œλ“€ 수 μžˆλŠ” μš”λ¦¬ **ν•˜λ‚˜**λ₯Ό μΆ”μ²œν•΄μ€˜.
- **κ³ κΈ°λ‚˜ μƒμ„ μ²˜λŸΌ λΉ„μ‹Έκ³  주재료 같은 μž¬λ£ŒλŠ” μ ˆλŒ€ λ„£μ§€ 마**
- μ†ŒκΈˆ, ν›„μΆ”, κ°„μž₯, μ‹μš©μœ , 섀탕 λ“±μ˜ κΈ°λ³Έ 양념은 μ‚¬μš©ν•΄λ„ 돼
- μ†ŒκΈˆ, ν›„μΆ”, κ°„μž₯, μ‹μš©μœ , 섀탕 λ“±μ˜ κΈ°λ³Έ 양념을 κΌ­ μ¨μ•Όλ˜λŠ”κ±°λŠ” μ•„λ‹ˆκ³  μš”λ¦¬μ— ν•„μš”ν•˜λ©΄ μ‚¬μš©ν•˜λ©΄ 돼
- κ°€λŠ₯ν•˜λ©΄ 집에 μžˆμ„ λ²•ν•œ 재료둜 κ΅¬μ„±ν•΄μ€˜
- **μž¬λ£ŒλŠ” λ°˜λ“œμ‹œ μž…λ ₯된 재료만 μ‚¬μš©ν•˜κ³ , μ‰Όν‘œλ‘œ λ‚˜μ—΄λœ ν•œ 쀄 ν˜•μ‹μœΌλ‘œ 써쀘**
- μ„€λͺ…은 μˆœμ„œλŒ€λ‘œ 번호 λΆ™μ—¬μ„œ 써쀘
- 좜λ ₯은 μ•„λž˜ ν˜•μ‹μ„ κΌ­ μ§€μΌœμ€˜:
μš”λ¦¬ 이름:
μ„€λͺ…:
재료:
λ§Œλ“œλŠ” 법:
쑰리 μ‹œκ°„:
λ‚œμ΄λ„:
"""
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "당신은 μš”λ¦¬ μ „λ¬Έκ°€μž…λ‹ˆλ‹€."},
{"role": "user", "content": prompt}
],
temperature=0.9,
max_tokens=600
)
return format_result_html(response.choices[0].message.content)
# πŸ”Ή 재료 탐지 ν›„ μš”λ¦¬ μΆ”μ²œ
def detect_and_recommend(image):
global last_ingredients
if image is None:
return "<p style='color:red;'>이미지λ₯Ό μ—…λ‘œλ“œν•΄μ£Όμ„Έμš”.</p>"
outputs = detector(image, candidate_labels=candidate_labels, threshold=0.2)
detected_labels = list(set([o["label"] for o in outputs]))
translated_labels = [label_ko.get(label, label) for label in detected_labels]
if not translated_labels:
return "<p style='color:red;'>재료λ₯Ό μΈμ‹ν•˜μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.</p>"
last_ingredients = ", ".join(translated_labels)
return generate_recipe(last_ingredients)
# πŸ”Ή 같은 재료둜 λ‹€μ‹œ μΆ”μ²œ
def reroll_recipe():
if not last_ingredients:
return "<p style='color:red;'>λ¨Όμ € 이미지λ₯Ό μ—…λ‘œλ“œν•΄μ£Όμ„Έμš”.</p>"
return generate_recipe(last_ingredients)
# πŸ”Ή Gradio UI
with gr.Blocks() as demo:
gr.Markdown("## 🧊 냉μž₯κ³  이미지 기반 μš”λ¦¬ μΆ”μ²œ μ‹œμŠ€ν…œ")
gr.Markdown("냉μž₯κ³  λ‚΄λΆ€ 사진을 μ—…λ‘œλ“œν•œ ν›„ λ²„νŠΌμ„ 눌러 μΆ”μ²œ μš”λ¦¬λ₯Ό ν™•μΈν•˜μ„Έμš”.")
with gr.Row():
with gr.Column(scale=5):
image_input = gr.Image(type="pil", label="냉μž₯κ³  이미지 μ—…λ‘œλ“œ", height=300)
recommend_btn = gr.Button("λ ˆμ‹œν”Ό μΆ”μ²œλ°›κΈ°", size="lg")
with gr.Column(scale=7):
recipe_output = gr.HTML(label="πŸ½οΈμΆ”μ²œ μš”λ¦¬ κ²°κ³Ό")
# μˆ¨κ²¨μ§„ Gradio λ²„νŠΌ (μ‹€μ œ reroll 트리거용)
reroll_hidden_btn = gr.Button("", visible=False)
# HTML λ²„νŠΌλ“€ (볡사 + 리둀)
gr.HTML("""
<div style='display: flex; flex-direction: row; gap: 12px; margin-top: 12px;'>
<button onclick="
const el = document.getElementById('recipe-box');
if (el) {
const range = document.createRange();
range.selectNodeContents(el);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
document.execCommand('copy');
alert('λ ˆμ‹œν”Όκ°€ λ³΅μ‚¬λ˜μ—ˆμŠ΅λ‹ˆλ‹€!');
}
" style='padding: 10px 20px; background-color: #4CAF50; color: white; border: none; border-radius: 6px; font-size: 15px; cursor: pointer;'>
πŸ“‹ λ ˆμ‹œν”Ό λ³΅μ‚¬ν•˜κΈ°
</button>
<button onclick="
const buttons = document.getElementsByTagName('button');
for (let i = 0; i < buttons.length; i++) {
if (buttons[i].innerText === '' && buttons[i].style.display === 'none') {
buttons[i].click();
break;
}
}
" style='padding: 10px 20px; background-color: #607D8B; color: white; border: none; border-radius: 6px; font-size: 15px; cursor: pointer;'>
🎲 λ‹€λ₯Έ μš”λ¦¬ μΆ”μ²œλ°›κΈ°
</button>
</div>
""")
# 이벀트 μ—°κ²°
recommend_btn.click(fn=detect_and_recommend, inputs=image_input, outputs=recipe_output)
reroll_hidden_btn.click(fn=reroll_recipe, inputs=None, outputs=recipe_output)
if __name__ == "__main__":
demo.launch()