aiqcamp's picture
Update app.py
417aa68 verified
raw
history blame
22.3 kB
import os
import gradio as gr
import random
import time
import logging
import google.generativeai as genai
# Configure logging
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")
# Get Gemini API Key from environment variable
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
genai.configure(api_key=GEMINI_API_KEY)
# Helper function to select one option from a transformation string with a slash
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 and related changes
physical_transformation_categories = {
"공간적 변화": [
"전진/후진 이동", "좌/우 이동", "상승/하강", "피치 회전", "요 회전", "롤 회전",
"궤도 운동", "나선형 이동", "관성 드리프트", "자이로스코픽 세차 운동", "비대칭 회전",
"진자 운동", "탄도학적 이동", "무중력 상태에서의 부유"
],
"물리적 형상 변화": [
"부피 증가/감소", "길이 신장/수축", "너비 확장/축소", "높이 증가/감소",
"밀도 변화", "무게 증가/감소", "형태 변형", "위상 변화", "비등방성 변형",
"비선형 변형", "뒤틀림/비틀림", "수축/팽창 비율 변화", "모서리 라운딩/샤프닝",
"파단/균열 진행", "세그먼트화"
],
"표면/외관 변화": [
"색상 변화", "텍스처 변화", "투명도/불투명도 변화", "광택/무광 변화",
"반사율 변화", "패턴 변화", "이색성 효과", "광변색 효과", "열변색 효과",
"홀로그래픽 패턴 변화", "프레넬 반사", "표면 모핑", "나노구조 패턴 변화",
"자가 청소 효과"
],
"물질 상태 변화": [
"고체화/액화/기화", "결정화/용해", "산화/부식", "경화/연화", "초임계 상태 전환",
"비정질화/결정화", "상분리", "콜로이드 형성/분해", "겔화/졸화", "준안정 상태 전이",
"자기조립/분해", "상전이 히스테리시스", "융해", "응고"
],
"열역학적 변화": [
"온도 상승/냉각", "열팽창/수축", "열 전도/단열", "압력 증가/감소", "단열 자화/탈자화",
"엔트로피 변화", "열전기 효과", "자기열량 효과", "상변화 축열/방열", "열 스트레스 발생/완화",
"열충격 효과", "복사 냉각/가열"
],
"운동학적 변화": [
"가속/감속", "등속 운동", "진동/진동 감쇠", "충돌/반발", "회전 속도 증가/감소",
"각속도 변화", "카오스적 운동", "스틱-슬립 현상", "공진/반공진", "유체역학적 양력/항력 변화",
"댐핑 계수 변화", "하모닉 모션 합성", "비뉴턴 유체 거동", "회전-병진 운동 커플링"
],
"구조적 변화": [
"부품 추가/제거", "조립/분해", "접이/펼침", "변형/복원", "위상최적화 형상 변화",
"자가 재구성", "프랙탈 패턴 형성/소멸", "세포자동자 패턴 변화", "모듈식 변형",
"발현적 구조 형성", "형상 기억 효과", "4D 프린팅 구조 변화", "부분 제거", "부분 교환",
"결합", "분리"
],
"전기/자기적 변화": [
"자화/탈자화", "전하 증가/감소", "전기장 생성/소멸", "자기장 생성/소멸", "초전도 상태 전이",
"강유전/반강유전 전이", "양자 스핀 상태 변화", "플라즈마 상태 형성/소멸", "스핀파 전파",
"광전 효과", "압전 효과", "홀 효과"
],
"화학적 변화": [
"표면 코팅 변화", "물질 조성 변화", "화학 반응에 의한 변화", "촉매 활성화/비활성화",
"광화학 반응", "전기화학 반응", "자기조립 단분자막 형성", "분자컴퓨팅 변화",
"생체모방 표면 변화", "스마트 폴리머 반응", "화학적 진동 반응", "산화", "환원",
"중합", "가수분해", "융합", "방사화"
],
"시간 관련 변화": [
"노화/풍화", "마모/부식", "퇴색/변색", "손상/복구", "수명 주기 단계 변화",
"사용자 인터랙션 기반 적응", "학습기반 형상 최적화", "시간적 물성 변화", "집단 기억 효과",
"문화적 의미 변화", "시간 지연 응답", "이력 의존적 변화", "퍼지 시간 거동", "진화적 변화",
"주기적 재생/재생성"
]
}
# Marketing transformation categories
marketing_transformation_categories = {
"브랜드/아이덴티티 변화": [
"브랜드명 변경/리브랜딩", "로고 재설계/현대화", "슬로건 업데이트/변경",
"브랜드 컬러 팔레트 변경", "브랜드 보이스/톤 조정", "브랜드 포지셔닝 재정립",
"브랜드 스토리 재구성", "브랜드 아키텍처 재구성", "브랜드 퍼스널리티 진화",
"브랜드 이미지 재정립"
],
"제품/서비스 변화": [
"기능적 업그레이드/다운그레이드", "포장/패키징 재설계", "제품 사이즈/용량 조정",
"SKU 확장/축소", "맞춤형/개인화 옵션 추가", "프리미엄/베이직 라인 출시",
"한정판/시즌 에디션 출시", "콜라보레이션/크로스오버 제품", "지속가능성 개선",
"번들링/언번들링 전략 변경"
],
"가격 전략 변화": [
"프리미엄/럭셔리 가격 포지셔닝", "가격 하락/경제적 포지셔닝", "가치 기반 가격 책정",
"동적 가격 정책 도입", "멤버십/구독 모델 전환", "가격 세분화 전략",
"프로모션 가격 전략 변경", "심리적 가격 책정 적용", "번들 가격 전략 도입",
"프리미엄/이코노미 이중 전략"
],
"프로모션/커뮤니케이션 변화": [
"메시지 프레이밍 변경", "타겟 오디언스 확장/재정의", "감성적/이성적 소구점 전환",
"스토리텔링 방식 변화", "콘텐츠 마케팅 전략 조정", "크리에이티브 방향성 변경",
"광고 캠페인 재설계", "브랜드 앰배서더/인플루언서 교체", "언어/트론 조정",
"비주얼 아이덴티티 업데이트"
],
"채널/유통 변화": [
"온라인/오프라인 전략 전환", "옴니채널 통합/분리", "유통 파트너십 확장/축소",
"D2C(Direct-to-Consumer) 모델 도입", "리테일 경험 재설계", "서비스 딜리버리 방식 변경",
"팝업/이벤트 기반 유통 전략", "지역적 확장/축소", "파트너 생태계 재구성",
"디지털 마켓플레이스 전략 변화"
],
"고객 경험 변화": [
"고객 여정 재설계", "퍼스널라이제이션/맞춤화 강화", "서비스 레벨 조정",
"로열티 프로그램 재구성", "고객 참여 메커니즘 변화", "사용자 인터페이스/UX 개선",
"고객 서비스 프로토콜 변경", "피드백 루프 재설계", "자가 서비스 옵션 확장",
"체험형 마케팅 요소 강화"
],
"디지털 마케팅 변화": [
"검색 최적화(SEO) 전략 변경", "소셜 미디어 플랫폼 포트폴리오 조정", "콘텐츠 타입/포맷 다양화",
"데이터 기반 타겟팅 정교화", "마케팅 자동화 확장/조정", "디지털 광고 알고리즘 최적화",
"이메일 마케팅 전략 변화", "모바일 최적화 전략 강화", "AR/VR 마케팅 요소 통합",
"인공지능 기반 마케팅 도입"
],
"시장 포지셔닝 변화": [
"시장 세그먼트 재정의", "경쟁사 대비 포지셔닝 변경", "틈새시장/메인스트림 전략 전환",
"산업/카테고리 횡단 재포지셔닝", "지리적 타겟 시장 확장/축소", "글로벌/로컬 포지셔닝 조정",
"문화적 맥락 적응", "주요 시장 메시지 재정의", "특성 차별화 강화/변경",
"가치 제안 재구성"
],
"혁신/트렌드 반응": [
"첨단 기술 통합", "트렌드 얼리어답터/팔로워 포지셔닝", "지속가능성/친환경 전략 강화",
"사회적 책임 이니셔티브 도입", "디지털 트랜스포메이션 가속화", "헬스/웰빙 요소 강화",
"세대별 트렌드 반응 적용", "미래지향적 혁신 커뮤니케이션", "문화적 현상 연계 마케팅",
"크로스 인더스트리 혁신 적용"
],
"데이터/분석 기반 변화": [
"고객 데이터 수집 방식 변경", "예측 분석 모델 도입/강화", "A/B 테스팅 체계 구축/확장",
"소비자 인사이트 발굴 방식 변화", "마케팅 ROI 측정 프레임워크 변경", "실시간 데이터 활용 체계 구축",
"프라이버시 중심 데이터 전략", "세그먼테이션 모델 고도화", "디지털 행동 분석 체계 강화",
"통합 마케팅 데이터 대시보드 구축"
]
}
def query_gemini_api(prompt):
try:
# Use a stable model
model = genai.GenerativeModel('gemini-2.0-flash-thinking-exp-01-21')
# Generate content with a simple approach
response = model.generate_content(prompt)
# Check the response - defensive handling
try:
# First try .text attribute
if hasattr(response, 'text'):
return response.text
# Try accessing candidates (safely)
if hasattr(response, 'candidates') and response.candidates:
if len(response.candidates) > 0:
candidate = response.candidates[0]
# Try accessing content and parts
if hasattr(candidate, 'content'):
content = candidate.content
if hasattr(content, 'parts') and content.parts:
if len(content.parts) > 0:
return content.parts[0].text
# Direct parts access attempt
if hasattr(response, 'parts') and response.parts:
if len(response.parts) > 0:
return response.parts[0].text
# Fallback if all attempts fail
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}")
# Check for API key validation error
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)}"
# Generate enhanced descriptions without unnecessary questions or explanations
def enhance_with_llm(base_description, obj_name, category, is_marketing=False):
domain = "마케팅" if is_marketing else "물리적"
prompt = f"""다음은 '{obj_name}'의 '{domain} {category}' 관련 간단한 설명입니다:
"{base_description}"
해당 설명을 3-4문장의 창의적인 답변으로 확장하여 출력하라."""
return query_gemini_api(prompt)
# Generate physical transformations for a single object
def generate_single_object_physical_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
# Generate marketing transformations for a single object
def generate_single_object_marketing_transformations(obj):
results = {}
for category, transformations in marketing_transformation_categories.items():
transformation = choose_alternative(random.choice(transformations))
base_description = f"{obj}이(가) {transformation} 전략을 실행했다"
results[category] = {"base": base_description, "enhanced": None}
return results
# Generate physical transformations for two objects
def generate_two_objects_physical_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
# Generate marketing transformations for two objects
def generate_two_objects_marketing_interaction(obj1, obj2):
results = {}
for category, transformations in marketing_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
# Generate physical transformations for three objects
def generate_three_objects_physical_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
# Generate marketing transformations for three objects
def generate_three_objects_marketing_interaction(obj1, obj2, obj3):
results = {}
for category, transformations in marketing_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
# Enhance descriptions using the LLM
def enhance_descriptions(results, objects, is_marketing=False):
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, is_marketing)
return results
# Generate physical transformations based on number of objects
def generate_physical_transformations(text1, text2=None, text3=None):
if text2 and text3:
results = generate_three_objects_physical_interaction(text1, text2, text3)
objects = [text1, text2, text3]
elif text2:
results = generate_two_objects_physical_interaction(text1, text2)
objects = [text1, text2]
else:
results = generate_single_object_physical_transformations(text1)
objects = [text1]
return enhance_descriptions(results, objects, is_marketing=False)
# Generate marketing transformations based on number of objects
def generate_marketing_transformations(text1, text2=None, text3=None):
if text2 and text3:
results = generate_three_objects_marketing_interaction(text1, text2, text3)
objects = [text1, text2, text3]
elif text2:
results = generate_two_objects_marketing_interaction(text1, text2)
objects = [text1, text2]
else:
results = generate_single_object_marketing_transformations(text1)
objects = [text1]
return enhance_descriptions(results, objects, is_marketing=True)
# Format results for display
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
# Process physical inputs and generate transformations
def process_physical_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_physical_transformations(text1, text2, text3)
messages.append("결과 포맷팅 중...")
time.sleep(0.3)
formatted = format_results(results)
messages.append("완료!")
messages.append(formatted)
return "\n\n".join(messages)
# Process marketing inputs and generate transformations
def process_marketing_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_marketing_transformations(text1, text2, text3)
messages.append("결과 포맷팅 중...")
time.sleep(0.3)
formatted = format_results(results)
messages.append("완료!")
messages.append(formatted)
return "\n\n".join(messages)
# Check for API key and return warning message if needed
def get_warning_message():
if not GEMINI_API_KEY:
return "⚠️ 환경 변수 GEMINI_API_KEY가 설정되지 않았습니다. Gemini API 키를 설정하세요."
return ""
# Create the 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.Tabs():
with gr.TabItem("물리적 변화 아이디어", id="physical_tab"):
physical_output = gr.Markdown(label="물리적 변화 아이디어 결과")
with gr.TabItem("마케팅 변화 아이디어", id="marketing_tab"):
marketing_output = gr.Markdown(label="마케팅 변화 아이디어 결과")
# Add some example combinations
gr.Examples(
examples=[
["스마트폰", "", ""],
["커피", "책", ""],
["자동차", "로봇", "인공지능"],
["운동화", "웨어러블", "건강"],
],
inputs=[text_input1, text_input2, text_input3],
)
# Connect the button click events to functions
submit_button.click(fn=process_physical_inputs, inputs=[text_input1, text_input2, text_input3], outputs=physical_output)
submit_button.click(fn=process_marketing_inputs, inputs=[text_input1, text_input2, text_input3], outputs=marketing_output)
if __name__ == "__main__":
demo.launch(debug=True)