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 = [ "salmon", "chicken breast", "broccoli", "lettuce", "mushroom", "bell pepper", "onion", "cherry tomato", "egg", "milk", "cheese", "garlic" ] label_ko = { "salmon": "μ—°μ–΄", "chicken breast": "λ‹­κ°€μŠ΄μ‚΄", "broccoli": "브둜콜리", "lettuce": "상좔", "mushroom": "버섯", "bell pepper": "피망", "onion": "μ–‘νŒŒ", "cherry tomato": "λ°©μšΈν† λ§ˆν† ", "egg": "κ³„λž€", "milk": "우유", "cheese": "치즈", "garlic": "마늘" } # πŸ”Ή μ „μ—­ λ³€μˆ˜ μ €μž₯용 last_ingredients = "" # πŸ”Ή HTML ν˜•μ‹ 좜λ ₯ def format_result_html(result_text): html = "
" lines = result_text.strip().splitlines() for line in lines: if line.startswith("μš”λ¦¬ 이름:"): content = line.replace("μš”λ¦¬ 이름:", "").strip() html += f"

🍽️ {content}


" elif line.startswith("μ„€λͺ…:"): html += f"

μ„€λͺ…: {line.replace('μ„€λͺ…:', '').strip()}

" elif line.startswith("재료:"): html += f"

재료: {line.replace('재료:', '').strip()}

" elif line.startswith("λ§Œλ“œλŠ” 법:"): html += f"

λ§Œλ“œλŠ” 법: {line.replace('λ§Œλ“œλŠ” 법:', '').strip()}

" elif line.startswith("쑰리 μ‹œκ°„:"): html += f"

⏱ 쑰리 μ‹œκ°„: {line.replace('쑰리 μ‹œκ°„:', '').strip()}

" elif line.startswith("λ‚œμ΄λ„:"): html += f"

🎯 λ‚œμ΄λ„: {line.replace('λ‚œμ΄λ„:', '').strip()}

" else: html += f"

{line}

" html += "
" 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 "

이미지λ₯Ό μ—…λ‘œλ“œν•΄μ£Όμ„Έμš”.

" 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 "

재료λ₯Ό μΈμ‹ν•˜μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.

" last_ingredients = ", ".join(translated_labels) return generate_recipe(last_ingredients) # πŸ”Ή 같은 재료둜 λ‹€μ‹œ μΆ”μ²œ def reroll_recipe(): if not last_ingredients: return "

λ¨Όμ € 이미지λ₯Ό μ—…λ‘œλ“œν•΄μ£Όμ„Έμš”.

" 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("""
""") # 이벀트 μ—°κ²° 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()