aiqcamp's picture
Update app.py
bcd9bb8 verified
raw
history blame
15.9 kB
import os
import gradio as gr
import random
import time
import logging
import google.generativeai as genai
# λ‘œκΉ… μ„€μ •
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("api_debug.log"),
logging.StreamHandler()
]
)
logger = logging.getLogger("idea_generator")
# Gemini API ν‚€λŠ” ν™˜κ²½ λ³€μˆ˜ GEMINI_API_KEYμ—μ„œ κ°€μ Έμ˜΅λ‹ˆλ‹€.
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
genai.configure(api_key=GEMINI_API_KEY)
# μŠ¬λž˜μ‹œ("/")κ°€ ν¬ν•¨λœ λ³€ν™˜ λ¬Έμžμ—΄μ—μ„œ 두 μ˜΅μ…˜ 쀑 ν•˜λ‚˜λ§Œ μ„ νƒν•˜λŠ” 헬퍼 ν•¨μˆ˜
def choose_alternative(transformation):
if "/" not in transformation:
return transformation
parts = transformation.split("/")
if len(parts) != 2:
return random.choice([part.strip() for part in parts])
left = parts[0].strip()
right = parts[1].strip()
if " " in left:
tokens = left.split(" ", 1)
prefix = tokens[0]
if not right.startswith(prefix):
option1 = left
option2 = prefix + " " + right
else:
option1 = left
option2 = right
return random.choice([option1, option2])
else:
return random.choice([left, right])
# 창의적인 λͺ¨λΈ/컨셉/ν˜•μƒ λ³€ν™” 아이디어λ₯Ό μœ„ν•œ μΉ΄ν…Œκ³ λ¦¬ (κΈ°μ‘΄ '물리적 λ³€ν™”' 사전 μœ μ§€)
physical_transformation_categories = {
"곡간적 λ³€ν™”": [
"μ „μ§„/ν›„μ§„ 이동", "쒌/우 이동", "μƒμŠΉ/ν•˜κ°•", "ν”ΌμΉ˜ νšŒμ „", "μš” νšŒμ „", "λ‘€ νšŒμ „",
"ꢀ도 μš΄λ™", "λ‚˜μ„ ν˜• 이동", "κ΄€μ„± λ“œλ¦¬ν”„νŠΈ", "μžμ΄λ‘œμŠ€μ½”ν”½ μ„Έμ°¨ μš΄λ™", "λΉ„λŒ€μΉ­ νšŒμ „",
"μ§„μž μš΄λ™", "탄도학적 이동", "무쀑λ ₯ μƒνƒœμ—μ„œμ˜ λΆ€μœ "
],
"물리적 ν˜•μƒ λ³€ν™”": [
"λΆ€ν”Ό 증가/κ°μ†Œ", "길이 μ‹ μž₯/μˆ˜μΆ•", "λ„ˆλΉ„ ν™•μž₯/μΆ•μ†Œ", "높이 증가/κ°μ†Œ",
"밀도 λ³€ν™”", "무게 증가/κ°μ†Œ", "ν˜•νƒœ λ³€ν˜•", "μœ„μƒ λ³€ν™”", "λΉ„λ“±λ°©μ„± λ³€ν˜•",
"λΉ„μ„ ν˜• λ³€ν˜•", "λ’€ν‹€λ¦Ό/λΉ„ν‹€λ¦Ό", "μˆ˜μΆ•/팽창 λΉ„μœ¨ λ³€ν™”", "λͺ¨μ„œλ¦¬ λΌμš΄λ”©/샀프닝",
"νŒŒλ‹¨/κ· μ—΄ μ§„ν–‰", "μ„Έκ·Έλ¨ΌνŠΈν™”"
],
"ν‘œλ©΄/μ™Έκ΄€ λ³€ν™”": [
"색상 λ³€ν™”", "ν…μŠ€μ²˜ λ³€ν™”", "투λͺ…도/뢈투λͺ…도 λ³€ν™”", "광택/무광 λ³€ν™”",
"λ°˜μ‚¬μœ¨ λ³€ν™”", "νŒ¨ν„΄ λ³€ν™”", "이색성 효과", "광변색 효과", "열변색 효과",
"ν™€λ‘œκ·Έλž˜ν”½ νŒ¨ν„΄ λ³€ν™”", "ν”„λ ˆλ„¬ λ°˜μ‚¬", "ν‘œλ©΄ λͺ¨ν•‘", "λ‚˜λ…Έκ΅¬μ‘° νŒ¨ν„΄ λ³€ν™”",
"μžκ°€ μ²­μ†Œ 효과"
],
"물질 μƒνƒœ λ³€ν™”": [
"고체화/μ•‘ν™”/κΈ°ν™”", "κ²°μ •ν™”/μš©ν•΄", "μ‚°ν™”/뢀식", "κ²½ν™”/μ—°ν™”", "μ΄ˆμž„κ³„ μƒνƒœ μ „ν™˜",
"λΉ„μ •μ§ˆν™”/κ²°μ •ν™”", "상뢄리", "μ½œλ‘œμ΄λ“œ ν˜•μ„±/λΆ„ν•΄", "κ²”ν™”/μ‘Έν™”", "μ€€μ•ˆμ • μƒνƒœ 전이",
"자기쑰립/λΆ„ν•΄", "상전이 νžˆμŠ€ν…Œλ¦¬μ‹œμŠ€", "μœ΅ν•΄", "응고"
],
"열역학적 λ³€ν™”": [
"μ˜¨λ„ μƒμŠΉ/냉각", "μ—΄νŒ½μ°½/μˆ˜μΆ•", "μ—΄ 전도/단열", "μ••λ ₯ 증가/κ°μ†Œ", "단열 μžν™”/νƒˆμžν™”",
"μ—”νŠΈλ‘œν”Ό λ³€ν™”", "μ—΄μ „κΈ° 효과", "μžκΈ°μ—΄λŸ‰ 효과", "상변화 μΆ•μ—΄/λ°©μ—΄", "μ—΄ 슀트레슀 λ°œμƒ/μ™„ν™”",
"열좩격 효과", "볡사 냉각/κ°€μ—΄"
],
"μš΄λ™ν•™μ  λ³€ν™”": [
"가속/감속", "등속 μš΄λ™", "진동/진동 감쇠", "좩돌/반발", "νšŒμ „ 속도 증가/κ°μ†Œ",
"각속도 λ³€ν™”", "카였슀적 μš΄λ™", "μŠ€ν‹±-슬립 ν˜„μƒ", "곡진/λ°˜κ³΅μ§„", "μœ μ²΄μ—­ν•™μ  μ–‘λ ₯/ν•­λ ₯ λ³€ν™”",
"λŒν•‘ κ³„μˆ˜ λ³€ν™”", "ν•˜λͺ¨λ‹‰ λͺ¨μ…˜ ν•©μ„±", "비뉴턴 유체 거동", "νšŒμ „-병진 μš΄λ™ μ»€ν”Œλ§"
],
"ꡬ쑰적 λ³€ν™”": [
"λΆ€ν’ˆ μΆ”κ°€/제거", "쑰립/λΆ„ν•΄", "접이/펼침", "λ³€ν˜•/볡원", "μœ„μƒμ΅œμ ν™” ν˜•μƒ λ³€ν™”",
"μžκ°€ μž¬κ΅¬μ„±", "ν”„λž™νƒˆ νŒ¨ν„΄ ν˜•μ„±/μ†Œλ©Έ", "μ„Έν¬μžλ™μž νŒ¨ν„΄ λ³€ν™”", "λͺ¨λ“ˆμ‹ λ³€ν˜•",
"λ°œν˜„μ  ꡬ쑰 ν˜•μ„±", "ν˜•μƒ κΈ°μ–΅ 효과", "4D ν”„λ¦°νŒ… ꡬ쑰 λ³€ν™”", "λΆ€λΆ„ 제거", "λΆ€λΆ„ κ΅ν™˜",
"κ²°ν•©", "뢄리"
],
"μ „κΈ°/자기적 λ³€ν™”": [
"μžν™”/νƒˆμžν™”", "μ „ν•˜ 증가/κ°μ†Œ", "μ „κΈ°μž₯ 생성/μ†Œλ©Έ", "자기μž₯ 생성/μ†Œλ©Έ", "μ΄ˆμ „λ„ μƒνƒœ 전이",
"κ°•μœ μ „/λ°˜κ°•μœ μ „ 전이", "μ–‘μž μŠ€ν•€ μƒνƒœ λ³€ν™”", "ν”ŒλΌμ¦ˆλ§ˆ μƒνƒœ ν˜•μ„±/μ†Œλ©Έ", "μŠ€ν•€νŒŒ μ „νŒŒ",
"κ΄‘μ „ 효과", "μ••μ „ 효과", "홀 효과"
],
"화학적 λ³€ν™”": [
"ν‘œλ©΄ μ½”νŒ… λ³€ν™”", "물질 μ‘°μ„± λ³€ν™”", "ν™”ν•™ λ°˜μ‘μ— μ˜ν•œ λ³€ν™”", "촉맀 ν™œμ„±ν™”/λΉ„ν™œμ„±ν™”",
"κ΄‘ν™”ν•™ λ°˜μ‘", "μ „κΈ°ν™”ν•™ λ°˜μ‘", "자기쑰립 λ‹¨λΆ„μžλ§‰ ν˜•μ„±", "λΆ„μžμ»΄ν“¨νŒ… λ³€ν™”",
"생체λͺ¨λ°© ν‘œλ©΄ λ³€ν™”", "슀마트 폴리머 λ°˜μ‘", "화학적 진동 λ°˜μ‘", "μ‚°ν™”", "ν™˜μ›",
"쀑합", "κ°€μˆ˜λΆ„ν•΄", "μœ΅ν•©", "방사화"
],
"μ‹œκ°„ κ΄€λ ¨ λ³€ν™”": [
"λ…Έν™”/풍화", "마λͺ¨/뢀식", "퇴색/변색", "손상/볡ꡬ", "수λͺ… μ£ΌκΈ° 단계 λ³€ν™”",
"μ‚¬μš©μž μΈν„°λž™μ…˜ 기반 적응", "ν•™μŠ΅κΈ°λ°˜ ν˜•μƒ μ΅œμ ν™”", "μ‹œκ°„μ  λ¬Όμ„± λ³€ν™”", "집단 κΈ°μ–΅ 효과",
"문화적 의미 λ³€ν™”", "μ‹œκ°„ μ§€μ—° 응닡", "이λ ₯ 의쑴적 λ³€ν™”", "퍼지 μ‹œκ°„ 거동", "진화적 λ³€ν™”",
"주기적 μž¬μƒ/μž¬μƒμ„±"
]
}
##############################################################################
# Gemini API 호좜 ν•¨μˆ˜ (예: gemini-2.0-flash-thinking-exp-01-21 -> λ‹€λ₯Έ λͺ¨λΈ μ‚¬μš© μ‹œ μˆ˜μ •)
##############################################################################
def query_gemini_api(prompt):
try:
# μ˜ˆμ‹œ: κΈ°μ‘΄ gemini-2.0... λŒ€μ‹ , λ‹€λ₯Έ λͺ¨λΈμ΄ ν•„μš”ν•˜λ‹€λ©΄ κ΅μ²΄ν•˜μ„Έμš”.
model = genai.GenerativeModel('gemini-2.0-flash-thinking-exp-01-21')
response = model.generate_content(prompt)
# 응닡 ꡬ쑰 λ°©μ–΄μ μœΌλ‘œ 처리
try:
if hasattr(response, 'text'):
return response.text
if hasattr(response, 'candidates') and response.candidates:
if len(response.candidates) > 0:
candidate = response.candidates[0]
if hasattr(candidate, 'content'):
content = candidate.content
if hasattr(content, 'parts') and content.parts:
if len(content.parts) > 0:
return content.parts[0].text
if hasattr(response, 'parts') and response.parts:
if len(response.parts) > 0:
return response.parts[0].text
return "Unable to generate a response. API response structure is different than expected."
except Exception as inner_e:
logger.error(f"Error processing response: {inner_e}")
return f"An error occurred while processing the response: {str(inner_e)}"
except Exception as e:
logger.error(f"Error calling Gemini API: {e}")
if "API key not valid" in str(e):
return "API key is not valid. Please check your GEMINI_API_KEY environment variable."
return f"An error occurred while calling the API: {str(e)}"
##############################################################################
# μ„€λͺ… ν™•μž₯ ν•¨μˆ˜: "λͺ¨λΈ/컨셉/ν˜•μƒμ˜ 변화에 λŒ€ν•œ 이해와 ν˜μ‹  포인트, κΈ°λŠ₯μ„± 등을 쀑심"으둜
##############################################################################
def enhance_with_llm(base_description, obj_name, category):
prompt = f"""
λ‹€μŒμ€ '{obj_name}'의 '{category}' κ΄€λ ¨ κ°„λ‹¨ν•œ μ„€λͺ…μž…λ‹ˆλ‹€:
"{base_description}"
μœ„ λ‚΄μš©μ„ 보닀 κ΅¬μ²΄ν™”ν•˜μ—¬,
1) 창의적인 λͺ¨λΈ/컨셉/ν˜•μƒμ˜ 변화에 λŒ€ν•œ 이해,
2) ν˜μ‹  ν¬μΈνŠΈμ™€ κΈ°λŠ₯μ„± 등을 μ€‘μ‹¬μœΌλ‘œ
3~4λ¬Έμž₯의 μ•„μ΄λ””μ–΄λ‘œ ν™•μž₯ν•΄ μ£Όμ„Έμš”.
"""
return query_gemini_api(prompt)
##############################################################################
# 단일 ν‚€μ›Œλ“œ(였브젝트)에 λŒ€ν•œ "창의적 λ³€ν™” 아이디어" 생성
##############################################################################
def generate_single_object_transformations(obj):
results = {}
for category, transformations in physical_transformation_categories.items():
transformation = choose_alternative(random.choice(transformations))
base_description = f"{obj}이(κ°€) {transformation} ν˜„μƒμ„ 보인닀"
results[category] = {"base": base_description, "enhanced": None}
return results
##############################################################################
# 두 ν‚€μ›Œλ“œμ— λŒ€ν•œ "창의적 λ³€ν™” 아이디어" 생성
##############################################################################
def generate_two_objects_interaction(obj1, obj2):
results = {}
for category, transformations in physical_transformation_categories.items():
transformation = choose_alternative(random.choice(transformations))
template = random.choice([
"{obj1}이(κ°€) {obj2}에 κ²°ν•©ν•˜μ—¬ {change}κ°€ λ°œμƒν–ˆλ‹€",
"{obj1}κ³Ό(와) {obj2}이(κ°€) μΆ©λŒν•˜λ©΄μ„œ {change}κ°€ 일어났닀"
])
base_description = template.format(obj1=obj1, obj2=obj2, change=transformation)
results[category] = {"base": base_description, "enhanced": None}
return results
##############################################################################
# μ„Έ ν‚€μ›Œλ“œμ— λŒ€ν•œ "창의적 λ³€ν™” 아이디어" 생성
##############################################################################
def generate_three_objects_interaction(obj1, obj2, obj3):
results = {}
for category, transformations in physical_transformation_categories.items():
transformation = choose_alternative(random.choice(transformations))
template = random.choice([
"{obj1}, {obj2}, {obj3}이(κ°€) μ‚Όκ°ν˜• ꡬ쑰둜 κ²°ν•©ν•˜μ—¬ {change}κ°€ λ°œμƒν–ˆλ‹€",
"{obj1}이(κ°€) {obj2}와(κ³Ό) {obj3} μ‚¬μ΄μ—μ„œ 맀개체 역할을 ν•˜λ©° {change}λ₯Ό μ΄‰μ§„ν–ˆλ‹€"
])
base_description = template.format(obj1=obj1, obj2=obj2, obj3=obj3, change=transformation)
results[category] = {"base": base_description, "enhanced": None}
return results
##############################################################################
# μƒμ„±λœ κΈ°λ³Έ μ„€λͺ…을 LLM을 톡해 ν™•μž₯
##############################################################################
def enhance_descriptions(results, objects):
obj_name = " 및 ".join([obj for obj in objects if obj])
for category, result in results.items():
result["enhanced"] = enhance_with_llm(result["base"], obj_name, category)
return results
##############################################################################
# μ‚¬μš©μž μž…λ ₯(μ΅œλŒ€ 3개 ν‚€μ›Œλ“œ)에 따라 창의적 λ³€ν™” 아이디어 생성
##############################################################################
def generate_transformations(text1, text2=None, text3=None):
if text2 and text3:
results = generate_three_objects_interaction(text1, text2, text3)
objects = [text1, text2, text3]
elif text2:
results = generate_two_objects_interaction(text1, text2)
objects = [text1, text2]
else:
results = generate_single_object_transformations(text1)
objects = [text1]
return enhance_descriptions(results, objects)
##############################################################################
# κ²°κ³Ό ν¬λ§·νŒ…
##############################################################################
def format_results(results):
formatted = ""
for category, result in results.items():
formatted += f"## {category}\n**κΈ°λ³Έ 아이디어**: {result['base']}\n\n**ν™•μž₯된 아이디어**: {result['enhanced']}\n\n---\n\n"
return formatted
##############################################################################
# Gradio UIμ—μ„œ ν˜ΈμΆœν•  ν•¨μˆ˜
##############################################################################
def process_inputs(text1, text2, text3):
messages = []
messages.append("μž…λ ₯κ°’ 확인 쀑...")
time.sleep(0.3)
text1 = text1.strip() if text1 else None
text2 = text2.strip() if text2 else None
text3 = text3.strip() if text3 else None
if not text1:
messages.append("였λ₯˜: μ΅œμ†Œ ν•˜λ‚˜μ˜ ν‚€μ›Œλ“œλ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”.")
return "\n\n".join(messages)
messages.append("창의적인 λͺ¨λΈ/컨셉/ν˜•μƒ λ³€ν™” 아이디어 생성 쀑...")
time.sleep(0.3)
results = generate_transformations(text1, text2, text3)
messages.append("κ²°κ³Ό ν¬λ§·νŒ… 쀑...")
time.sleep(0.3)
formatted = format_results(results)
messages.append("μ™„λ£Œ!")
messages.append(formatted)
return "\n\n".join(messages)
##############################################################################
# API ν‚€ κ²½κ³  λ©”μ‹œμ§€
##############################################################################
def get_warning_message():
if not GEMINI_API_KEY:
return "⚠️ ν™˜κ²½ λ³€μˆ˜ GEMINI_API_KEYκ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. Gemini API ν‚€λ₯Ό μ„€μ •ν•˜μ„Έμš”."
return ""
##############################################################################
# Gradio UI
##############################################################################
with gr.Blocks(title="ν‚€μ›Œλ“œ 기반 창의적 λ³€ν™” 아이디어 생성기",
theme=gr.themes.Soft(primary_hue="teal", secondary_hue="slate", neutral_hue="neutral")) as demo:
gr.HTML("""
<style>
body { background: linear-gradient(135deg, #e0eafc, #cfdef3); font-family: 'Arial', sans-serif; }
.gradio-container { padding: 20px; }
h1, h2 { text-align: center; }
h1 { color: #333; }
h2 { color: #555; }
.output { background-color: #ffffff; padding: 15px; border-radius: 8px; }
.gr-button { background-color: #4CAF50; color: white; border: none; border-radius: 4px; padding: 8px 16px; }
</style>
""")
gr.Markdown("# πŸš€ ν‚€μ›Œλ“œ 기반 창의적 λ³€ν™” 아이디어 생성기")
gr.Markdown("μž…λ ₯ν•œ **ν‚€μ›Œλ“œ**(μ΅œλŒ€ 3개)λ₯Ό λ°”νƒ•μœΌλ‘œ, **창의적인 λͺ¨λΈ/컨셉/ν˜•μƒ λ³€ν™”**에 λŒ€ν•œ 이해와 **ν˜μ‹  포인트**, **κΈ°λŠ₯μ„±** 등을 μ€‘μ‹¬μœΌλ‘œ ν™•μž₯된 아이디어λ₯Ό μ œμ‹œν•©λ‹ˆλ‹€.")
warning = gr.Markdown(get_warning_message())
# 쒌츑 μž…λ ₯ μ˜μ—­
with gr.Row():
with gr.Column(scale=1):
text_input1 = gr.Textbox(label="ν‚€μ›Œλ“œ 1 (ν•„μˆ˜)", placeholder="예: 슀마트폰")
text_input2 = gr.Textbox(label="ν‚€μ›Œλ“œ 2 (선택)", placeholder="예: 인곡지λŠ₯")
text_input3 = gr.Textbox(label="ν‚€μ›Œλ“œ 3 (선택)", placeholder="예: ν—¬μŠ€μΌ€μ–΄")
submit_button = gr.Button("아이디어 μƒμ„±ν•˜κΈ°")
# 우츑 좜λ ₯ μ˜μ—­ (탭은 ν•˜λ‚˜λ§Œ μ‚¬μš©)
with gr.Column(scale=2):
with gr.TabItem("창의적인 λͺ¨λΈ/컨셉/ν˜•μƒ λ³€ν™” 아이디어", id="creative_tab"):
idea_output = gr.Markdown(label="아이디어 κ²°κ³Ό")
# μ˜ˆμ‹œ μž…λ ₯
gr.Examples(
examples=[
["슀마트폰", "", ""],
["컀피", "μ±…", ""],
["μžλ™μ°¨", "λ‘œλ΄‡", "인곡지λŠ₯"],
["μš΄λ™ν™”", "μ›¨μ–΄λŸ¬λΈ”", "건강"],
],
inputs=[text_input1, text_input2, text_input3],
)
# λ²„νŠΌ 이벀트: 첫 번째 νƒ­μ—λ§Œ μ—°κ²°
submit_button.click(fn=process_inputs,
inputs=[text_input1, text_input2, text_input3],
outputs=idea_output)
if __name__ == "__main__":
demo.launch(debug=True)