aiqcamp commited on
Commit
bcd9bb8
·
verified ·
1 Parent(s): 417aa68

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -195
app.py CHANGED
@@ -5,7 +5,7 @@ import time
5
  import logging
6
  import google.generativeai as genai
7
 
8
- # Configure logging
9
  logging.basicConfig(
10
  level=logging.INFO,
11
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
@@ -16,11 +16,11 @@ logging.basicConfig(
16
  )
17
  logger = logging.getLogger("idea_generator")
18
 
19
- # Get Gemini API Key from environment variable
20
  GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
21
  genai.configure(api_key=GEMINI_API_KEY)
22
 
23
- # Helper function to select one option from a transformation string with a slash
24
  def choose_alternative(transformation):
25
  if "/" not in transformation:
26
  return transformation
@@ -42,7 +42,7 @@ def choose_alternative(transformation):
42
  else:
43
  return random.choice([left, right])
44
 
45
- # Physical transformation categories and related changes
46
  physical_transformation_categories = {
47
  "공간적 변화": [
48
  "전진/후진 이동", "좌/우 이동", "상승/하강", "피치 회전", "요 회전", "롤 회전",
@@ -101,103 +101,33 @@ physical_transformation_categories = {
101
  ]
102
  }
103
 
104
- # Marketing transformation categories
105
- marketing_transformation_categories = {
106
- "브랜드/아이덴티티 변화": [
107
- "브랜드명 변경/리브랜딩", "로고 재설계/현대화", "슬로건 업데이트/변경",
108
- "브랜드 컬러 팔레트 변경", "브랜드 보이스/톤 조정", "브랜드 포지셔닝 재정립",
109
- "브랜드 스토리 재구성", "브랜드 아키텍처 재구성", "브랜드 퍼스널리티 진화",
110
- "브랜드 이미지 재정립"
111
- ],
112
- "제품/서비스 변화": [
113
- "기능적 업그레이드/다운그레이드", "포장/패키징 재설계", "제품 사이즈/용량 조정",
114
- "SKU 확장/축소", "맞춤형/개인화 옵션 추가", "프리미엄/베이직 라인 출시",
115
- "한정판/시즌 에디션 출시", "콜라보레이션/크로스오버 제품", "지속가능성 개선",
116
- "번들링/언번들링 전략 변경"
117
- ],
118
- "가격 전략 변화": [
119
- "프리미엄/럭셔리 가격 포지셔닝", "가격 하락/경제적 포지셔닝", "가치 기반 가격 책정",
120
- "동적 가격 정책 도입", "멤버십/구독 모델 전환", "가격 세분화 전략",
121
- "프로모션 가격 전략 변경", "심리적 가격 책정 적용", "번들 가격 전략 도입",
122
- "프리미엄/이코노미 이중 전략"
123
- ],
124
- "프로모션/커뮤니케이션 변화": [
125
- "메시지 프레이밍 변경", "타겟 오디언스 확장/재정의", "감성적/이성적 소구점 전환",
126
- "스토리텔링 방식 변화", "콘텐츠 마케팅 전략 조정", "크리에이티브 방향성 변경",
127
- "광고 캠페인 재설계", "브랜드 앰배서더/인플루언서 교체", "언어/트론 조정",
128
- "비주얼 아이덴티티 업데이트"
129
- ],
130
- "채널/유통 변화": [
131
- "온라인/오프라인 전략 전환", "옴니채널 통합/분리", "유통 파트너십 확장/축소",
132
- "D2C(Direct-to-Consumer) 모델 도입", "리테일 경험 재설계", "서비스 딜리버리 방식 변경",
133
- "팝업/이벤트 기반 유통 전략", "지역적 확장/축소", "파트너 생태계 재구성",
134
- "디지털 마켓플레이스 전략 변화"
135
- ],
136
- "고객 경험 변화": [
137
- "고객 여정 재설계", "퍼스널라이제이션/맞춤화 강화", "서비스 레벨 조정",
138
- "로열티 프로그램 재구성", "고객 참여 메커니즘 변화", "사용자 인터페이스/UX 개선",
139
- "고객 서비스 프로토콜 변경", "피드백 루프 재설계", "자가 서비스 옵션 확장",
140
- "체험형 마케팅 요소 강화"
141
- ],
142
- "디지털 마케팅 변화": [
143
- "검색 최적화(SEO) 전략 변경", "소셜 미디어 플랫폼 포트폴리오 조정", "콘텐츠 타입/포맷 다양화",
144
- "데이터 기반 타겟팅 정교화", "마케팅 자동화 확장/조정", "디지털 광고 알고리즘 최적화",
145
- "이메일 마케팅 전략 변화", "모바일 최적화 전략 강화", "AR/VR 마케팅 요소 통합",
146
- "인공지능 기반 마케팅 도입"
147
- ],
148
- "시장 포지셔닝 변화": [
149
- "시장 세그먼트 재정의", "경쟁사 대비 포지셔닝 변경", "틈새시장/메인스트림 전략 전환",
150
- "산업/카테고리 횡단 재포지셔닝", "지리적 타겟 시장 확장/축소", "글로벌/로컬 포지셔닝 조정",
151
- "문화적 맥락 적응", "주요 시장 메시지 재정의", "특성 차별화 강화/변경",
152
- "가치 제안 재구성"
153
- ],
154
- "혁신/트렌드 반응": [
155
- "첨단 기술 통합", "트렌드 얼리어답터/팔로워 포지셔닝", "지속가능성/친환경 전략 강화",
156
- "사회적 책임 이니셔티브 도입", "디지털 트랜스포메이션 가속화", "헬스/웰빙 요소 강화",
157
- "세대별 트렌드 반응 적용", "미래지향적 혁신 커뮤니케이션", "문화적 현상 연계 마케팅",
158
- "크로스 인더스트리 혁신 적용"
159
- ],
160
- "데이터/분석 기반 변화": [
161
- "고객 데이터 수집 방식 변경", "예측 분석 모델 도입/강화", "A/B 테스팅 체계 구축/확장",
162
- "소비자 인사이트 발굴 방식 변화", "마케팅 ROI 측정 프레임워크 변경", "실시간 데이터 활용 체계 구축",
163
- "프라이버시 중심 데이터 전략", "세그먼테이션 모델 고도화", "디지털 행동 분석 체계 강화",
164
- "통합 마케팅 데이터 대시보드 구축"
165
- ]
166
- }
167
-
168
  def query_gemini_api(prompt):
169
  try:
170
- # Use a stable model
171
  model = genai.GenerativeModel('gemini-2.0-flash-thinking-exp-01-21')
172
 
173
- # Generate content with a simple approach
174
  response = model.generate_content(prompt)
175
-
176
- # Check the response - defensive handling
177
  try:
178
- # First try .text attribute
179
  if hasattr(response, 'text'):
180
  return response.text
181
 
182
- # Try accessing candidates (safely)
183
  if hasattr(response, 'candidates') and response.candidates:
184
  if len(response.candidates) > 0:
185
  candidate = response.candidates[0]
186
-
187
- # Try accessing content and parts
188
  if hasattr(candidate, 'content'):
189
  content = candidate.content
190
-
191
  if hasattr(content, 'parts') and content.parts:
192
  if len(content.parts) > 0:
193
  return content.parts[0].text
194
-
195
- # Direct parts access attempt
196
  if hasattr(response, 'parts') and response.parts:
197
  if len(response.parts) > 0:
198
  return response.parts[0].text
199
-
200
- # Fallback if all attempts fail
201
  return "Unable to generate a response. API response structure is different than expected."
202
 
203
  except Exception as inner_e:
@@ -206,23 +136,29 @@ def query_gemini_api(prompt):
206
 
207
  except Exception as e:
208
  logger.error(f"Error calling Gemini API: {e}")
209
-
210
- # Check for API key validation error
211
  if "API key not valid" in str(e):
212
  return "API key is not valid. Please check your GEMINI_API_KEY environment variable."
213
-
214
  return f"An error occurred while calling the API: {str(e)}"
215
 
216
- # Generate enhanced descriptions without unnecessary questions or explanations
217
- def enhance_with_llm(base_description, obj_name, category, is_marketing=False):
218
- domain = "마케팅" if is_marketing else "물리적"
219
- prompt = f"""다음은 '{obj_name}'의 '{domain} {category}' 관련 간단한 설명입니다:
 
 
220
  "{base_description}"
221
- 해당 설명을 3-4문장의 창의적인 답변으로 확장하여 출력하라."""
 
 
 
 
 
222
  return query_gemini_api(prompt)
223
 
224
- # Generate physical transformations for a single object
225
- def generate_single_object_physical_transformations(obj):
 
 
226
  results = {}
227
  for category, transformations in physical_transformation_categories.items():
228
  transformation = choose_alternative(random.choice(transformations))
@@ -230,17 +166,10 @@ def generate_single_object_physical_transformations(obj):
230
  results[category] = {"base": base_description, "enhanced": None}
231
  return results
232
 
233
- # Generate marketing transformations for a single object
234
- def generate_single_object_marketing_transformations(obj):
235
- results = {}
236
- for category, transformations in marketing_transformation_categories.items():
237
- transformation = choose_alternative(random.choice(transformations))
238
- base_description = f"{obj}이(가) {transformation} 전략을 실행했다"
239
- results[category] = {"base": base_description, "enhanced": None}
240
- return results
241
-
242
- # Generate physical transformations for two objects
243
- def generate_two_objects_physical_interaction(obj1, obj2):
244
  results = {}
245
  for category, transformations in physical_transformation_categories.items():
246
  transformation = choose_alternative(random.choice(transformations))
@@ -252,21 +181,10 @@ def generate_two_objects_physical_interaction(obj1, obj2):
252
  results[category] = {"base": base_description, "enhanced": None}
253
  return results
254
 
255
- # Generate marketing transformations for two objects
256
- def generate_two_objects_marketing_interaction(obj1, obj2):
257
- results = {}
258
- for category, transformations in marketing_transformation_categories.items():
259
- transformation = choose_alternative(random.choice(transformations))
260
- template = random.choice([
261
- "{obj1}이(가) {obj2}의 브랜드 특성을 활용하여 {change}를 진행했다",
262
- "{obj1}과(와) {obj2}의 협업으로 {change}가 시장에 도입되었다"
263
- ])
264
- base_description = template.format(obj1=obj1, obj2=obj2, change=transformation)
265
- results[category] = {"base": base_description, "enhanced": None}
266
- return results
267
-
268
- # Generate physical transformations for three objects
269
- def generate_three_objects_physical_interaction(obj1, obj2, obj3):
270
  results = {}
271
  for category, transformations in physical_transformation_categories.items():
272
  transformation = choose_alternative(random.choice(transformations))
@@ -278,82 +196,43 @@ def generate_three_objects_physical_interaction(obj1, obj2, obj3):
278
  results[category] = {"base": base_description, "enhanced": None}
279
  return results
280
 
281
- # Generate marketing transformations for three objects
282
- def generate_three_objects_marketing_interaction(obj1, obj2, obj3):
283
- results = {}
284
- for category, transformations in marketing_transformation_categories.items():
285
- transformation = choose_alternative(random.choice(transformations))
286
- template = random.choice([
287
- "{obj1}, {obj2}, {obj3}이(가) 공동 마케팅으로 {change}가 시너지를 창출했다",
288
- "{obj1}이(가) {obj2}와(과) {obj3}의 고객층을 통합하여 {change}로 새로운 시장을 창출했다"
289
- ])
290
- base_description = template.format(obj1=obj1, obj2=obj2, obj3=obj3, change=transformation)
291
- results[category] = {"base": base_description, "enhanced": None}
292
- return results
293
-
294
- # Enhance descriptions using the LLM
295
- def enhance_descriptions(results, objects, is_marketing=False):
296
  obj_name = " 및 ".join([obj for obj in objects if obj])
297
  for category, result in results.items():
298
- result["enhanced"] = enhance_with_llm(result["base"], obj_name, category, is_marketing)
299
  return results
300
 
301
- # Generate physical transformations based on number of objects
302
- def generate_physical_transformations(text1, text2=None, text3=None):
303
- if text2 and text3:
304
- results = generate_three_objects_physical_interaction(text1, text2, text3)
305
- objects = [text1, text2, text3]
306
- elif text2:
307
- results = generate_two_objects_physical_interaction(text1, text2)
308
- objects = [text1, text2]
309
- else:
310
- results = generate_single_object_physical_transformations(text1)
311
- objects = [text1]
312
- return enhance_descriptions(results, objects, is_marketing=False)
313
-
314
- # Generate marketing transformations based on number of objects
315
- def generate_marketing_transformations(text1, text2=None, text3=None):
316
  if text2 and text3:
317
- results = generate_three_objects_marketing_interaction(text1, text2, text3)
318
  objects = [text1, text2, text3]
319
  elif text2:
320
- results = generate_two_objects_marketing_interaction(text1, text2)
321
  objects = [text1, text2]
322
  else:
323
- results = generate_single_object_marketing_transformations(text1)
324
  objects = [text1]
325
- return enhance_descriptions(results, objects, is_marketing=True)
326
 
327
- # Format results for display
 
 
328
  def format_results(results):
329
  formatted = ""
330
  for category, result in results.items():
331
- formatted += f"## {category}\n**기본 변화**: {result['base']}\n\n**자세한 설명**: {result['enhanced']}\n\n---\n\n"
332
  return formatted
333
 
334
- # Process physical inputs and generate transformations
335
- def process_physical_inputs(text1, text2, text3):
336
- messages = []
337
- messages.append("입력값 확인 중...")
338
- time.sleep(0.3)
339
- text1 = text1.strip() if text1 else None
340
- text2 = text2.strip() if text2 else None
341
- text3 = text3.strip() if text3 else None
342
- if not text1:
343
- messages.append("오류: 최소 하나의 키워드를 입력해주세요.")
344
- return "\n\n".join(messages)
345
- messages.append("물리적 변화 아이디어 생성 중...")
346
- time.sleep(0.3)
347
- results = generate_physical_transformations(text1, text2, text3)
348
- messages.append("결과 포맷팅 중...")
349
- time.sleep(0.3)
350
- formatted = format_results(results)
351
- messages.append("완료!")
352
- messages.append(formatted)
353
- return "\n\n".join(messages)
354
-
355
- # Process marketing inputs and generate transformations
356
- def process_marketing_inputs(text1, text2, text3):
357
  messages = []
358
  messages.append("입력값 확인 중...")
359
  time.sleep(0.3)
@@ -363,24 +242,34 @@ def process_marketing_inputs(text1, text2, text3):
363
  if not text1:
364
  messages.append("오류: 최소 하나의 키워드를 입력해주세요.")
365
  return "\n\n".join(messages)
366
- messages.append("마케팅 변화 아이디어 생성 중...")
 
367
  time.sleep(0.3)
368
- results = generate_marketing_transformations(text1, text2, text3)
 
369
  messages.append("결과 포맷팅 중...")
370
  time.sleep(0.3)
371
  formatted = format_results(results)
 
372
  messages.append("완료!")
373
  messages.append(formatted)
 
374
  return "\n\n".join(messages)
375
 
376
- # Check for API key and return warning message if needed
 
 
377
  def get_warning_message():
378
  if not GEMINI_API_KEY:
379
  return "⚠️ 환경 변수 GEMINI_API_KEY가 설정되지 않았습니다. Gemini API 키를 설정하세요."
380
  return ""
381
 
382
- # Create the Gradio UI
383
- with gr.Blocks(title="키워드 기반 창의적 아이디어 생성기", theme=gr.themes.Soft(primary_hue="teal", secondary_hue="slate", neutral_hue="neutral")) as demo:
 
 
 
 
384
  gr.HTML("""
385
  <style>
386
  body { background: linear-gradient(135deg, #e0eafc, #cfdef3); font-family: 'Arial', sans-serif; }
@@ -392,23 +281,26 @@ with gr.Blocks(title="키워드 기반 창의적 아이디어 생성기", theme=
392
  .gr-button { background-color: #4CAF50; color: white; border: none; border-radius: 4px; padding: 8px 16px; }
393
  </style>
394
  """)
395
- gr.Markdown("# 🚀 키워드 기반 창의적 아이디어 생성기")
396
- gr.Markdown("입력한 키워드를 바탕으로 창의적인 물리적/마케팅 변화 아이디어를 도출합니다. 최대 3개의 키워드를 입력할 수 있습��다.")
 
 
397
  warning = gr.Markdown(get_warning_message())
 
 
398
  with gr.Row():
399
  with gr.Column(scale=1):
400
  text_input1 = gr.Textbox(label="키워드 1 (필수)", placeholder="예: 스마트폰")
401
  text_input2 = gr.Textbox(label="키워드 2 (선택)", placeholder="예: 인공지능")
402
  text_input3 = gr.Textbox(label="키워드 3 (선택)", placeholder="예: 헬스케어")
403
  submit_button = gr.Button("아이디어 생성하기")
 
 
404
  with gr.Column(scale=2):
405
- with gr.Tabs():
406
- with gr.TabItem("물리적 변화 아이디어", id="physical_tab"):
407
- physical_output = gr.Markdown(label="물리적 변화 아이디어 결과")
408
- with gr.TabItem("마케팅 변화 아이디어", id="marketing_tab"):
409
- marketing_output = gr.Markdown(label="마케팅 변화 아이디어 결과")
410
-
411
- # Add some example combinations
412
  gr.Examples(
413
  examples=[
414
  ["스마트폰", "", ""],
@@ -419,9 +311,10 @@ with gr.Blocks(title="키워드 기반 창의적 아이디어 생성기", theme=
419
  inputs=[text_input1, text_input2, text_input3],
420
  )
421
 
422
- # Connect the button click events to functions
423
- submit_button.click(fn=process_physical_inputs, inputs=[text_input1, text_input2, text_input3], outputs=physical_output)
424
- submit_button.click(fn=process_marketing_inputs, inputs=[text_input1, text_input2, text_input3], outputs=marketing_output)
 
425
 
426
  if __name__ == "__main__":
427
- demo.launch(debug=True)
 
5
  import logging
6
  import google.generativeai as genai
7
 
8
+ # 로깅 설정
9
  logging.basicConfig(
10
  level=logging.INFO,
11
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
 
16
  )
17
  logger = logging.getLogger("idea_generator")
18
 
19
+ # Gemini API 키는 환경 변수 GEMINI_API_KEY에서 가져옵니다.
20
  GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
21
  genai.configure(api_key=GEMINI_API_KEY)
22
 
23
+ # 슬래시("/")가 포함된 변환 문자열에서 옵션 하나만 선택하는 헬퍼 함수
24
  def choose_alternative(transformation):
25
  if "/" not in transformation:
26
  return transformation
 
42
  else:
43
  return random.choice([left, right])
44
 
45
+ # 창의적인 모델/컨셉/형상 변화 아이디어를 위한 카테고리 (기존 '물리적 변화' 사전 유지)
46
  physical_transformation_categories = {
47
  "공간적 변화": [
48
  "전진/후진 이동", "좌/우 이동", "상승/하강", "피치 회전", "요 회전", "롤 회전",
 
101
  ]
102
  }
103
 
104
+ ##############################################################################
105
+ # Gemini API 호출 함수 (예: gemini-2.0-flash-thinking-exp-01-21 -> 다른 모델 사용 시 수정)
106
+ ##############################################################################
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  def query_gemini_api(prompt):
108
  try:
109
+ # 예시: 기존 gemini-2.0... 대신, 다른 모델이 필요하다면 교체하세요.
110
  model = genai.GenerativeModel('gemini-2.0-flash-thinking-exp-01-21')
111
 
 
112
  response = model.generate_content(prompt)
113
+
114
+ # 응답 구조 방어적으로 처리
115
  try:
 
116
  if hasattr(response, 'text'):
117
  return response.text
118
 
 
119
  if hasattr(response, 'candidates') and response.candidates:
120
  if len(response.candidates) > 0:
121
  candidate = response.candidates[0]
 
 
122
  if hasattr(candidate, 'content'):
123
  content = candidate.content
 
124
  if hasattr(content, 'parts') and content.parts:
125
  if len(content.parts) > 0:
126
  return content.parts[0].text
 
 
127
  if hasattr(response, 'parts') and response.parts:
128
  if len(response.parts) > 0:
129
  return response.parts[0].text
130
+
 
131
  return "Unable to generate a response. API response structure is different than expected."
132
 
133
  except Exception as inner_e:
 
136
 
137
  except Exception as e:
138
  logger.error(f"Error calling Gemini API: {e}")
 
 
139
  if "API key not valid" in str(e):
140
  return "API key is not valid. Please check your GEMINI_API_KEY environment variable."
 
141
  return f"An error occurred while calling the API: {str(e)}"
142
 
143
+ ##############################################################################
144
+ # 설명 확장 함수: "모델/컨셉/형상의 변화에 대한 이해와 혁신 포인트, 기능성 등을 중심"으로
145
+ ##############################################################################
146
+ def enhance_with_llm(base_description, obj_name, category):
147
+ prompt = f"""
148
+ 다음은 '{obj_name}'의 '{category}' 관련 간단한 설명입니다:
149
  "{base_description}"
150
+
151
+ 위 내용을 보다 구체화하여,
152
+ 1) 창의적인 모델/컨셉/형상의 변화에 대한 이해,
153
+ 2) 혁신 포인트와 기능성 등을 중심으로
154
+ 3~4문장의 아이디어로 확장해 주세요.
155
+ """
156
  return query_gemini_api(prompt)
157
 
158
+ ##############################################################################
159
+ # 단일 키워드(오브젝트)에 대한 "창의적 변화 아이디어" 생성
160
+ ##############################################################################
161
+ def generate_single_object_transformations(obj):
162
  results = {}
163
  for category, transformations in physical_transformation_categories.items():
164
  transformation = choose_alternative(random.choice(transformations))
 
166
  results[category] = {"base": base_description, "enhanced": None}
167
  return results
168
 
169
+ ##############################################################################
170
+ # 두 키워드에 대한 "창의적 변화 아이디어" 생성
171
+ ##############################################################################
172
+ def generate_two_objects_interaction(obj1, obj2):
 
 
 
 
 
 
 
173
  results = {}
174
  for category, transformations in physical_transformation_categories.items():
175
  transformation = choose_alternative(random.choice(transformations))
 
181
  results[category] = {"base": base_description, "enhanced": None}
182
  return results
183
 
184
+ ##############################################################################
185
+ # 키워드에 대한 "창의적 변화 아이디어" 생성
186
+ ##############################################################################
187
+ def generate_three_objects_interaction(obj1, obj2, obj3):
 
 
 
 
 
 
 
 
 
 
 
188
  results = {}
189
  for category, transformations in physical_transformation_categories.items():
190
  transformation = choose_alternative(random.choice(transformations))
 
196
  results[category] = {"base": base_description, "enhanced": None}
197
  return results
198
 
199
+ ##############################################################################
200
+ # 생성된 기본 설명을 LLM을 통해 확장
201
+ ##############################################################################
202
+ def enhance_descriptions(results, objects):
 
 
 
 
 
 
 
 
 
 
 
203
  obj_name = " 및 ".join([obj for obj in objects if obj])
204
  for category, result in results.items():
205
+ result["enhanced"] = enhance_with_llm(result["base"], obj_name, category)
206
  return results
207
 
208
+ ##############################################################################
209
+ # 사용자 입력(최대 3개 키워드)에 따라 창의적 변화 아이디어 생성
210
+ ##############################################################################
211
+ def generate_transformations(text1, text2=None, text3=None):
 
 
 
 
 
 
 
 
 
 
 
212
  if text2 and text3:
213
+ results = generate_three_objects_interaction(text1, text2, text3)
214
  objects = [text1, text2, text3]
215
  elif text2:
216
+ results = generate_two_objects_interaction(text1, text2)
217
  objects = [text1, text2]
218
  else:
219
+ results = generate_single_object_transformations(text1)
220
  objects = [text1]
221
+ return enhance_descriptions(results, objects)
222
 
223
+ ##############################################################################
224
+ # 결과 포맷팅
225
+ ##############################################################################
226
  def format_results(results):
227
  formatted = ""
228
  for category, result in results.items():
229
+ formatted += f"## {category}\n**기본 아이디어**: {result['base']}\n\n**확장된 아이디어**: {result['enhanced']}\n\n---\n\n"
230
  return formatted
231
 
232
+ ##############################################################################
233
+ # Gradio UI에서 호출할 함수
234
+ ##############################################################################
235
+ def process_inputs(text1, text2, text3):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  messages = []
237
  messages.append("입력값 확인 중...")
238
  time.sleep(0.3)
 
242
  if not text1:
243
  messages.append("오류: 최소 하나의 키워드를 입력해주세요.")
244
  return "\n\n".join(messages)
245
+
246
+ messages.append("창의적인 모델/컨셉/형상 변화 아이디어 생성 중...")
247
  time.sleep(0.3)
248
+ results = generate_transformations(text1, text2, text3)
249
+
250
  messages.append("결과 포맷팅 중...")
251
  time.sleep(0.3)
252
  formatted = format_results(results)
253
+
254
  messages.append("완료!")
255
  messages.append(formatted)
256
+
257
  return "\n\n".join(messages)
258
 
259
+ ##############################################################################
260
+ # API 키 경고 메시지
261
+ ##############################################################################
262
  def get_warning_message():
263
  if not GEMINI_API_KEY:
264
  return "⚠️ 환경 변수 GEMINI_API_KEY가 설정되지 않았습니다. Gemini API 키를 설정하세요."
265
  return ""
266
 
267
+ ##############################################################################
268
+ # Gradio UI
269
+ ##############################################################################
270
+ with gr.Blocks(title="키워드 기반 창의적 변화 아이디어 생성기",
271
+ theme=gr.themes.Soft(primary_hue="teal", secondary_hue="slate", neutral_hue="neutral")) as demo:
272
+
273
  gr.HTML("""
274
  <style>
275
  body { background: linear-gradient(135deg, #e0eafc, #cfdef3); font-family: 'Arial', sans-serif; }
 
281
  .gr-button { background-color: #4CAF50; color: white; border: none; border-radius: 4px; padding: 8px 16px; }
282
  </style>
283
  """)
284
+
285
+ gr.Markdown("# 🚀 키워드 기반 창의적 변화 아이디어 생성기")
286
+ gr.Markdown("입력한 **키워드**(최대 3개)를 바탕으로, **창의적인 모델/컨셉/형상 변화**에 대한 이해와 **혁신 포인트**, **기능성** 등을 중심으로 확장된 아이디어를 제시합니다.")
287
+
288
  warning = gr.Markdown(get_warning_message())
289
+
290
+ # 좌측 입력 영역
291
  with gr.Row():
292
  with gr.Column(scale=1):
293
  text_input1 = gr.Textbox(label="키워드 1 (필수)", placeholder="예: 스마트폰")
294
  text_input2 = gr.Textbox(label="키워드 2 (선택)", placeholder="예: 인공지능")
295
  text_input3 = gr.Textbox(label="키워드 3 (선택)", placeholder="예: 헬스케어")
296
  submit_button = gr.Button("아이디어 생성하기")
297
+
298
+ # 우측 출력 영역 (탭은 하나만 사용)
299
  with gr.Column(scale=2):
300
+ with gr.TabItem("창의적인 모델/컨셉/형상 변화 아이디어", id="creative_tab"):
301
+ idea_output = gr.Markdown(label="아이디어 결과")
302
+
303
+ # 예시 입력
 
 
 
304
  gr.Examples(
305
  examples=[
306
  ["스마트폰", "", ""],
 
311
  inputs=[text_input1, text_input2, text_input3],
312
  )
313
 
314
+ # 버튼 이벤트: 번째 탭에만 연결
315
+ submit_button.click(fn=process_inputs,
316
+ inputs=[text_input1, text_input2, text_input3],
317
+ outputs=idea_output)
318
 
319
  if __name__ == "__main__":
320
+ demo.launch(debug=True)