openfree commited on
Commit
09c3e29
ยท
verified ยท
1 Parent(s): bc9d1cb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +612 -126
app.py CHANGED
@@ -1,8 +1,9 @@
1
  """
2
- Ultimate Brand Theory Generator - Unified Output Version
3
- ========================================================
4
- 2025-05-28 | 15๊ฐœ ์ด๋ก ์„ ํ†ตํ•ฉํ•œ ์ข…ํ•ฉ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ๊ธฐ (ํ†ต์ผ๋œ ์ถœ๋ ฅ ๊ตฌ์กฐ)
5
- ------------------------------------------------------------------------
 
6
  """
7
 
8
  import os
@@ -13,6 +14,7 @@ from openai import OpenAI
13
  from datetime import datetime
14
  from typing import List, Dict, Tuple, Optional
15
  import random
 
16
 
17
  # OpenAI ํด๋ผ์ด์–ธํŠธ
18
  if not os.getenv("OPENAI_API_KEY"):
@@ -20,27 +22,142 @@ if not os.getenv("OPENAI_API_KEY"):
20
 
21
  client = OpenAI()
22
 
23
- # ์ด๋ก ๋ณ„ ์„ค๋ช…
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  THEORY_DESCRIPTIONS = {
25
- "square": "4๊ฐœ์˜ ๋‹จ์–ด๊ฐ€ ์˜๋ฏธ์  ๊ด€๊ณ„๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์‚ฌ๊ฐํ˜•์„ ์ด๋ฃจ๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ๋Œ€๋ณ€์˜ ์ˆจ๊ฒจ์ง„ ์—ฐ๊ฒฐ์ด '์•„ํ•˜!' ๋ชจ๋จผํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.",
26
- "blending": "๋‘ ๊ฐœ ์ด์ƒ์˜ ๊ฐœ๋…์„ ํ˜ผํ•ฉํ•˜์—ฌ ์ƒˆ๋กœ์šด ์˜๋ฏธ๋ฅผ ์ฐฝ์ถœํ•ฉ๋‹ˆ๋‹ค. Netflix(Net+Flix)์ฒ˜๋Ÿผ ํ˜์‹ ์ ์ธ ๊ฐœ๋…์„ ํƒ„์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.",
27
- "sound": "์Œ์†Œ์™€ ์˜๋ฏธ ๊ฐ„์˜ ์—ฐ๊ด€์„ฑ์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. 'i,e'๋Š” ๊ฐ€๋ณ๊ณ  ๋น ๋ฅธ ๋А๋‚Œ, 'o,u'๋Š” ๋ฌด๊ฒ๊ณ  ๋А๋ฆฐ ๋А๋‚Œ์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.",
28
- "linguistic": "์–ธ์–ด๋ณ„ ์‚ฌ๊ณ ๋ฐฉ์‹ ์ฐจ์ด๋ฅผ ๊ณ ๋ คํ•œ ๊ธ€๋กœ๋ฒŒ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋ฌธํ™”์  ๋‰˜์•™์Šค์™€ ํ˜„์ง€ํ™” ์ „๋žต์„ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.",
29
- "archetype": "Jung์˜ 12๊ฐ€์ง€ ๋ณดํŽธ์  ์›ํ˜•์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. Hero(Nike), Creator(Apple)์ฒ˜๋Ÿผ ๋ฌด์˜์‹์  ๊ฐ์ • ์—ฐ๊ฒฐ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.",
30
- "jobs": "๊ณ ๊ฐ์ด ํ•ด๊ฒฐํ•˜๋ ค๋Š” '์ผ'์— ์ดˆ์ ์„ ๋งž์ถฅ๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์ , ๊ฐ์ •์ , ์‚ฌํšŒ์  ์ฐจ์›์˜ ๋‹ˆ์ฆˆ๋ฅผ ํ†ตํ•ฉ์ ์œผ๋กœ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.",
31
- "scamper": "7๊ฐ€์ง€ ์ฐฝ์˜์  ๊ธฐ๋ฒ•(๋Œ€์ฒด, ๊ฒฐํ•ฉ, ์ ์‘, ์ˆ˜์ •, ์šฉ๋„๋ณ€๊ฒฝ, ์ œ๊ฑฐ, ์—ญ์ „)์œผ๋กœ ํ˜์‹ ์ ์ธ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.",
32
- "design": "์ธ๊ฐ„ ์ค‘์‹ฌ ํ˜์‹ ์„ ์ถ”๊ตฌํ•ฉ๋‹ˆ๋‹ค. ๋ฐ”๋žŒ์งํ•จ(์ธ๊ฐ„), ์‹คํ˜„๊ฐ€๋Šฅ์„ฑ(๊ธฐ์ˆ ), ์ƒ์กด๊ฐ€๋Šฅ์„ฑ(๋น„์ฆˆ๋‹ˆ์Šค)์˜ ๊ต์ง‘ํ•ฉ์„ ์ฐพ์Šต๋‹ˆ๋‹ค.",
33
- "biomimicry": "์ž์—ฐ์—์„œ ์˜๊ฐ์„ ๋ฐ›์€ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. 38์–ต๋…„ ์ง„ํ™”์˜ ์ง€ํ˜œ๋ฅผ ๋ธŒ๋žœ๋”ฉ์— ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.",
34
- "cognitive": "์ธ์ง€ ์ฒ˜๋ฆฌ๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. 1-3์Œ์ ˆ์˜ ์‰ฌ์šด ๋ฐœ์Œ์œผ๋กœ ์ฆ‰๊ฐ์  ์ธ์‹๊ณผ ๊ธฐ์–ต์„ ๋•์Šต๋‹ˆ๋‹ค.",
35
- "vonrestorff": "๋…ํŠนํ•˜๊ณ  ๊ธฐ์–ต์— ๋‚จ๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์นดํ…Œ๊ณ ๋ฆฌ ๊ด€์Šต์„ ์˜๋„์ ์œผ๋กœ ์œ„๋ฐ˜ํ•˜์—ฌ 30๋ฐฐ ๋” ์ž˜ ๊ธฐ์–ต๋˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.",
36
- "network": "๋„คํŠธ์›Œํฌ ๊ฐ€์น˜๋ฅผ ๊ทน๋Œ€ํ™”ํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๋งŽ์„์ˆ˜๋ก ๊ฐ€์น˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค.",
37
- "memetics": "๋ฌธํ™”์ ์œผ๋กœ ๋ณต์ œ๋˜๊ณ  ์ง„ํ™”ํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋ฐˆ์ฒ˜๋Ÿผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํผ์ ธ๋‚˜๊ฐ€๋Š” ๋ฐ”์ด๋Ÿด ์š”์†Œ๋ฅผ ๋‚ด์žฌํ™”ํ•ฉ๋‹ˆ๋‹ค.",
38
- "color": "์ƒ‰์ƒ ์—ฐ์ƒ๊ณผ ๊ฐ์ •์„ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋นจ๊ฐ•(์—ด์ •), ํŒŒ๋ž‘(์‹ ๋ขฐ), ์ดˆ๋ก(์ž์—ฐ) ๋“ฑ ์ƒ‰์ƒ ์‹ฌ๋ฆฌ๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.",
39
- "gestalt": "์ง€๊ฐ ์›๋ฆฌ๋ฅผ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ „์ฒด๊ฐ€ ๋ถ€๋ถ„์˜ ํ•ฉ๋ณด๋‹ค ํฌ๋‹ค๋Š” ์›์น™์œผ๋กœ ํ†ตํ•ฉ์  ๋ธŒ๋žœ๋“œ ๊ฒฝํ—˜์„ ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  }
41
 
42
- # ํ†ต์ผ๋œ ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ
43
- UNIFIED_BASE_PROMPT = """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  ๋‹น์‹ ์€ {theory_name} ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. {theory_description}
45
 
46
  ์‚ฌ์šฉ์ž ์ž…๋ ฅ(์—…์ข…/ํ‚ค์›Œ๋“œ)์„ ๋ฐ›์•„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ†ต์ผ๋œ JSON ํ˜•์‹์˜ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜์„ธ์š”:
@@ -88,10 +205,139 @@ UNIFIED_BASE_PROMPT = """
88
 
89
  ๋ฐ˜๋“œ์‹œ ์œ ํšจํ•œ JSON ํ˜•์‹์œผ๋กœ ์‘๋‹ตํ•˜๊ณ , ๋ชจ๋“  ํ•„๋“œ๋ฅผ ์ฑ„์›Œ์ฃผ์„ธ์š”.
90
  ๊ฐ ์ด๋ก ์˜ ํŠน์„ฑ์„ theory_specific ์„น์…˜์— ๋‹ด๋˜, ๋‚˜๋จธ์ง€๋Š” ํ†ต์ผ๋œ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•˜์„ธ์š”.
 
91
  """
92
 
93
- # ์ด๋ก ๋ณ„ ํŠน์ˆ˜ ํ•„๋“œ ์ •์˜
94
- THEORY_SPECIFIC_FIELDS = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  "square": """
96
  "tl": "์™ผ์ชฝ์ƒ๋‹จ",
97
  "tr": "์˜ค๋ฅธ์ชฝ์ƒ๋‹จ",
@@ -218,46 +464,97 @@ THEORY_SPECIFIC_FIELDS = {
218
  """
219
  }
220
 
221
- def create_theory_prompt(theory: str) -> str:
222
  """๊ฐ ์ด๋ก ๋ณ„ ํ†ต์ผ๋œ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ"""
223
  theory_names = {
224
- "square": "Square Theory",
225
- "blending": "Conceptual Blending Theory",
226
- "sound": "Sound Symbolism",
227
- "linguistic": "Linguistic Relativity",
228
- "archetype": "Jung์˜ Archetype Theory",
229
- "jobs": "Jobs-to-be-Done Theory",
230
- "scamper": "SCAMPER Method",
231
- "design": "IDEO์˜ Design Thinking",
232
- "biomimicry": "Biomimicry",
233
- "cognitive": "Cognitive Load Theory",
234
- "vonrestorff": "Von Restorff Effect",
235
- "network": "Network Effects",
236
- "memetics": "Memetics",
237
- "color": "Color Psychology",
238
- "gestalt": "Gestalt Theory"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  }
240
 
241
- return UNIFIED_BASE_PROMPT.format(
242
- theory_name=theory_names[theory],
243
- theory_description=THEORY_DESCRIPTIONS[theory],
244
- theory_specific_fields=THEORY_SPECIFIC_FIELDS[theory]
 
 
 
245
  )
246
 
247
- def generate_by_theory(industry: str, keywords: str, theory: str, count: int = 3) -> Tuple[str, str]:
248
  """ํŠน์ • ์ด๋ก ์œผ๋กœ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ"""
249
 
 
 
250
  if not industry or not keywords:
251
- return "โš ๏ธ ์—…์ข…๊ณผ ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.", ""
 
 
252
 
253
- prompt = create_theory_prompt(theory)
254
- user_input = f"""์—…์ข…: {industry}
 
 
 
 
 
 
255
  ํ‚ค์›Œ๋“œ: {keywords}
256
 
257
  ์œ„ ์ •๋ณด๋กœ {count}๊ฐœ์˜ ๋ธŒ๋žœ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”.
258
  ๊ฐ ๋ธŒ๋žœ๋“œ๋Š” ํ†ต์ผ๋œ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๋˜, theory_specific ์„น์…˜์—๋Š” {theory} ์ด๋ก ์˜ ํŠน์„ฑ์„ ๋ฐ˜์˜ํ•˜์„ธ์š”."""
259
 
260
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  response = client.chat.completions.create(
262
  model="gpt-4o-mini",
263
  messages=[
@@ -282,19 +579,19 @@ def generate_by_theory(industry: str, keywords: str, theory: str, count: int = 3
282
  results = [results]
283
 
284
  # ๋งˆํฌ๋‹ค์šด ์ƒ์„ฑ
285
- markdown = generate_unified_markdown(theory, results, industry, keywords)
286
 
287
  # HTML ์‹œ๊ฐํ™” ์ƒ์„ฑ
288
- html = generate_unified_visualization(theory, results)
289
 
290
- return markdown, html
291
 
292
  except Exception as e:
293
- error_msg = f"โŒ {theory} ์ด๋ก  ์˜ค๋ฅ˜: {str(e)}"
294
  print(error_msg)
295
- return error_msg, ""
296
 
297
- def generate_unified_markdown(theory: str, results: List[Dict], industry: str, keywords: str) -> str:
298
  """ํ†ต์ผ๋œ ๋งˆํฌ๋‹ค์šด ์ƒ์„ฑ"""
299
 
300
  theory_names = {
@@ -322,11 +619,27 @@ def generate_unified_markdown(theory: str, results: List[Dict], industry: str, k
322
  "memetics": "๐Ÿงฌ", "color": "๐ŸŽจ", "gestalt": "๐Ÿ‘๏ธ"
323
  }
324
 
325
- markdown = f"""# {theory_icons[theory]} {theory_names[theory]}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
 
327
  <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 10px; margin-bottom: 20px;">
328
  <h3 style="margin: 0 0 10px 0;">์ด๋ก  ๊ฐœ์š”</h3>
329
- <p style="margin: 0; line-height: 1.6;">{THEORY_DESCRIPTIONS[theory]}</p>
330
  </div>
331
 
332
  **์—…์ข…**: {industry} | **ํ‚ค์›Œ๋“œ**: {keywords}
@@ -347,10 +660,34 @@ def generate_unified_markdown(theory: str, results: List[Dict], industry: str, k
347
  slogan = core.get('slogan', 'N/A')
348
 
349
  markdown += f"\n## {idx}. {brand_name}\n"
350
- markdown += f"**์Šฌ๋กœ๊ฑด**: *\"{slogan}\"*\n\n"
351
 
352
- # ํ•ต์‹ฌ ์ •๋ณด
353
- markdown += f"""### ๐Ÿ“ ํ•ต์‹ฌ ์ •๋ณด
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  - **ํ•ต์‹ฌ ๊ฐ€์น˜**: {core.get('core_value', 'N/A')}
355
  - **๋ชฉํ‘œ ๊ฐ์ •**: {core.get('target_emotion', 'N/A')}
356
  - **๋ธŒ๋žœ๋“œ ์„ฑ๊ฒฉ**: {core.get('brand_personality', 'N/A')}
@@ -373,18 +710,30 @@ def generate_unified_markdown(theory: str, results: List[Dict], industry: str, k
373
 
374
  # ์ด๋ก ๋ณ„ ํŠน์ˆ˜ ์ •๋ณด
375
  if theory_specific:
376
- markdown += f"\n### ๐Ÿ’ก {theory_names[theory]} ํŠน์„ฑ\n"
 
377
  for key, value in theory_specific.items():
378
- # ํ‚ค๋ฅผ ์ฝ๊ธฐ ์‰ฌ์šด ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜
379
  display_key = key.replace('_', ' ').title()
380
  markdown += f"- **{display_key}**: {value}\n"
381
 
382
  # ํ‰๊ฐ€ ์ ์ˆ˜
383
- markdown += f"""
 
 
 
 
 
 
 
 
 
 
 
 
384
  ### ๐Ÿ“Š ํ‰๊ฐ€
385
- - **์ฐฝ์˜์„ฑ**: {'โญ' * int(evaluation.get('creativity_score', 0))} ({evaluation.get('creativity_score', 0)}/10)
386
- - **๊ธฐ์–ต์„ฑ**: {'โญ' * int(evaluation.get('memorability_score', 0))} ({evaluation.get('memorability_score', 0)}/10)
387
- - **๊ด€๋ จ์„ฑ**: {'โญ' * int(evaluation.get('relevance_score', 0))} ({evaluation.get('relevance_score', 0)}/10)
388
 
389
  ๐Ÿ’ฌ **์ „์ฒด ํ‰๊ฐ€**: {evaluation.get('overall_effectiveness', 'N/A')}
390
  """
@@ -393,9 +742,12 @@ def generate_unified_markdown(theory: str, results: List[Dict], industry: str, k
393
 
394
  return markdown
395
 
396
- def generate_unified_visualization(theory: str, results: List[Dict]) -> str:
397
  """ํ†ต์ผ๋œ ์‹œ๊ฐํ™” ์ƒ์„ฑ"""
398
 
 
 
 
399
  html_parts = []
400
 
401
  for idx, result in enumerate(results, 1):
@@ -410,6 +762,22 @@ def generate_unified_visualization(theory: str, results: List[Dict]) -> str:
410
  slogan = core.get('slogan', '')
411
  primary_color = visual.get('primary_color', '#667eea')
412
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
413
  # ํ†ต์ผ๋œ ์นด๋“œ ๋ ˆ์ด์•„์›ƒ
414
  html = f"""
415
  <div style="max-width: 800px; margin: 30px auto; font-family: -apple-system, sans-serif;">
@@ -428,38 +796,38 @@ def generate_unified_visualization(theory: str, results: List[Dict]) -> str:
428
  <div style="font-size: 2em; color: {primary_color}; font-weight: bold;">
429
  {evaluation.get('creativity_score', 0)}/10
430
  </div>
431
- <div style="color: #7f8c8d; margin-top: 5px;">์ฐฝ์˜์„ฑ</div>
432
  </div>
433
  <div style="text-align: center;">
434
  <div style="font-size: 2em; color: {primary_color}; font-weight: bold;">
435
  {evaluation.get('memorability_score', 0)}/10
436
  </div>
437
- <div style="color: #7f8c8d; margin-top: 5px;">๊ธฐ์–ต์„ฑ</div>
438
  </div>
439
  <div style="text-align: center;">
440
  <div style="font-size: 2em; color: {primary_color}; font-weight: bold;">
441
  {evaluation.get('relevance_score', 0)}/10
442
  </div>
443
- <div style="color: #7f8c8d; margin-top: 5px;">๊ด€๋ จ์„ฑ</div>
444
  </div>
445
  </div>
446
 
447
  <!-- ํ•ต์‹ฌ ์ •๋ณด ๊ทธ๋ฆฌ๋“œ -->
448
  <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-bottom: 30px;">
449
  <div style="background: #f8f9fa; padding: 20px; border-radius: 10px;">
450
- <h4 style="margin: 0 0 10px 0; color: {primary_color};">ํ•ต์‹ฌ ๊ฐ€์น˜</h4>
451
  <p style="margin: 0; color: #555;">{core.get('core_value', 'N/A')}</p>
452
  </div>
453
  <div style="background: #f8f9fa; padding: 20px; border-radius: 10px;">
454
- <h4 style="margin: 0 0 10px 0; color: {primary_color};">๋ชฉํ‘œ ๊ฐ์ •</h4>
455
  <p style="margin: 0; color: #555;">{core.get('target_emotion', 'N/A')}</p>
456
  </div>
457
  <div style="background: #f8f9fa; padding: 20px; border-radius: 10px;">
458
- <h4 style="margin: 0 0 10px 0; color: {primary_color};">์ฐจ๋ณ„ํ™” ํฌ์ธํŠธ</h4>
459
  <p style="margin: 0; color: #555;">{strategic.get('differentiation', 'N/A')}</p>
460
  </div>
461
  <div style="background: #f8f9fa; padding: 20px; border-radius: 10px;">
462
- <h4 style="margin: 0 0 10px 0; color: {primary_color};">๋ฐœ์Œ ๊ฐ€์ด๋“œ</h4>
463
  <p style="margin: 0; color: #555;">{linguistic.get('pronunciation', 'N/A')}</p>
464
  </div>
465
  </div>
@@ -474,9 +842,10 @@ def generate_unified_visualization(theory: str, results: List[Dict]) -> str:
474
  html += visualize_color_specific(theory_specific, primary_color)
475
  else:
476
  # ๊ธฐ๋ณธ ์ด๋ก  ํŠน์„ฑ ํ‘œ์‹œ
 
477
  html += f"""
478
  <div style="background: linear-gradient(135deg, {primary_color}15 0%, {primary_color}05 100%); padding: 25px; border-radius: 15px; margin-top: 20px;">
479
- <h4 style="margin: 0 0 15px 0; color: {primary_color};">์ด๋ก  ํŠน์„ฑ</h4>
480
  <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;">
481
  """
482
  for key, value in theory_specific.items():
@@ -493,9 +862,10 @@ def generate_unified_visualization(theory: str, results: List[Dict]) -> str:
493
  """
494
 
495
  # ์ „์ฒด ํ‰๊ฐ€
 
496
  html += f"""
497
  <div style="background: #f8f9fa; padding: 20px; border-radius: 10px; margin-top: 20px;">
498
- <h4 style="margin: 0 0 10px 0; color: {primary_color};">์ „์ฒด ํ‰๊ฐ€</h4>
499
  <p style="margin: 0; color: #555; line-height: 1.6;">{evaluation.get('overall_effectiveness', 'N/A')}</p>
500
  </div>
501
  </div>
@@ -511,7 +881,7 @@ def visualize_square_specific(theory_specific: Dict, primary_color: str) -> str:
511
  """Square Theory ํŠน์ˆ˜ ์‹œ๊ฐํ™”"""
512
  return f"""
513
  <div style="background: #f8f9fa; padding: 30px; border-radius: 15px; margin-top: 20px;">
514
- <h4 style="margin: 0 0 20px 0; color: {primary_color}; text-align: center;">Square ๊ตฌ์กฐ</h4>
515
  <div style="position: relative; width: 100%; max-width: 400px; height: 300px; margin: 0 auto;">
516
  <div style="position: absolute; top: 0; left: 0; background: white; color: {primary_color}; padding: 15px 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); font-weight: bold;">
517
  {theory_specific.get('tl', '?')}
@@ -547,7 +917,7 @@ def visualize_blending_specific(theory_specific: Dict, primary_color: str) -> st
547
  """Conceptual Blending ํŠน์ˆ˜ ์‹œ๊ฐํ™”"""
548
  return f"""
549
  <div style="background: #f8f9fa; padding: 30px; border-radius: 15px; margin-top: 20px;">
550
- <h4 style="margin: 0 0 20px 0; color: {primary_color}; text-align: center;">๊ฐœ๋… ํ˜ผํ•ฉ</h4>
551
  <div style="display: flex; justify-content: center; align-items: center; gap: 20px; flex-wrap: wrap;">
552
  <div style="text-align: center; padding: 20px; background: white; color: {primary_color}; border-radius: 50%; width: 120px; height: 120px; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
553
  <div>
@@ -582,7 +952,7 @@ def visualize_color_specific(theory_specific: Dict, primary_color: str) -> str:
582
 
583
  html = f"""
584
  <div style="background: #f8f9fa; padding: 30px; border-radius: 15px; margin-top: 20px;">
585
- <h4 style="margin: 0 0 20px 0; color: {primary_color}; text-align: center;">์ƒ‰์ƒ ํŒ”๋ ˆํŠธ</h4>
586
  <div style="display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;">
587
  """
588
 
@@ -600,24 +970,61 @@ def visualize_color_specific(theory_specific: Dict, primary_color: str) -> str:
600
 
601
  # Gradio UI
602
  with gr.Blocks(
603
- title="Ultimate Brand Theory Generator - Unified",
604
  theme=gr.themes.Soft(),
605
  css="""
606
  .gradio-container {
607
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
608
  }
609
  .tab-nav button {
610
- font-size: 0.9em !important;
611
- padding: 10px 15px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
612
  }
613
  """
614
  ) as demo:
615
- gr.Markdown("""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
616
  <div style="text-align: center; padding: 30px 0;">
617
- <h1 style="font-size: 2.5em; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 10px;">
618
- ๐ŸŒŸ Ultimate Brand Theory Generator
619
  </h1>
620
- <p style="font-size: 1.2em; color: #7f8c8d;">15๊ฐœ ์ด๋ก ์„ ํ™œ์šฉํ•œ ์ข…ํ•ฉ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ๊ธฐ (ํ†ต์ผ๋œ ์ถœ๋ ฅ ๊ตฌ์กฐ)</p>
 
621
  </div>
622
  """)
623
 
@@ -625,42 +1032,71 @@ with gr.Blocks(
625
  with gr.Column(scale=1, min_width=300):
626
  gr.Markdown("""
627
  <div style="background: #f8f9fa; padding: 20px; border-radius: 10px; margin-bottom: 20px;">
628
- <h3 style="margin-top: 0;">๐Ÿ“ ๋ธŒ๋žœ๋“œ ์ •๋ณด ์ž…๋ ฅ</h3>
629
  </div>
630
  """)
631
 
 
 
 
 
 
 
 
 
632
  industry_input = gr.Textbox(
633
- label="๐Ÿญ ์—…์ข…",
634
- placeholder="์˜ˆ: ์นดํŽ˜, ํ”ผํŠธ๋‹ˆ์Šค, ๊ต์œก, ๋ทฐํ‹ฐ...",
635
- value="์นดํŽ˜/์ปคํ”ผ์ˆ"
636
  )
637
 
638
  keywords_input = gr.Textbox(
639
- label="๐Ÿ”‘ ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ",
640
- placeholder="ํ”„๋ฆฌ๋ฏธ์—„, ํŽธ์•ˆํ•œ, ๋„์‹œ์ ์ธ, ์นœํ™˜๊ฒฝ...",
641
- info="๋ธŒ๋žœ๋“œ๊ฐ€ ๋‹ด์•„์•ผ ํ•  ํ•ต์‹ฌ ๊ฐ€์น˜๋‚˜ ํŠน์ง•๋“ค",
642
  lines=2
643
  )
644
 
 
 
 
 
 
 
 
645
  gr.Markdown("""
646
  <div style="background: #e3f2fd; padding: 15px; border-radius: 8px; margin-top: 20px;">
647
- <h4 style="margin-top: 0; color: #1976d2;">๐Ÿ”„ ํ†ต์ผ๋œ ์ถœ๋ ฅ ๊ตฌ์กฐ</h4>
648
- <p style="margin: 10px 0;">๋ชจ๋“  ์ด๋ก ์—์„œ ๋™์ผํ•œ ๊ตฌ์กฐ๋กœ ๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:</p>
649
- <ul style="margin: 5px 0; padding-left: 20px;">
650
- <li><strong>ํ•ต์‹ฌ ์ •๋ณด</strong>: ๋ธŒ๋žœ๋“œ๋ช…, ์Šฌ๋กœ๊ฑด, ๊ฐ€์น˜, ์„ฑ๊ฒฉ</li>
651
- <li><strong>์‹œ๊ฐ์  ์š”์†Œ</strong>: ์ƒ‰์ƒ, ๋น„์ฃผ์–ผ ์ปจ์…‰</li>
652
- <li><strong>์–ธ์–ด์  ํŠน์„ฑ</strong>: ๋ฐœ์Œ, ๊ธ€๋กœ๋ฒŒ ์ ์‘์„ฑ</li>
653
- <li><strong>์ „๋žต์  ๊ฐ€์น˜</strong>: ์ฐจ๋ณ„ํ™”, ํฌ์ง€์…”๋‹</li>
654
- <li><strong>์ด๋ก ๋ณ„ ํŠน์„ฑ</strong>: ๊ฐ ์ด๋ก ์˜ ๊ณ ์œ  ์š”์†Œ</li>
655
- <li><strong>ํ‰๊ฐ€ ์ ์ˆ˜</strong>: ์ฐฝ์˜์„ฑ, ๊ธฐ์–ต์„ฑ, ๊ด€๋ จ์„ฑ</li>
 
 
 
 
 
 
 
 
656
  </ul>
657
  </div>
658
  """)
659
 
660
  with gr.Column(scale=3):
 
 
 
 
 
 
 
661
  # 15๊ฐœ ํƒญ ์ƒ์„ฑ
662
- with gr.Tabs():
663
- # ๊ฐ ์ด๋ก ๋ณ„ ํƒญ (์˜ˆ์‹œ๋กœ ๋ช‡ ๊ฐœ๋งŒ ํ‘œ์‹œ)
664
  theories = [
665
  ("๐ŸŸฆ Square Theory", "square"),
666
  ("๐Ÿ”€ Conceptual Blending", "blending"),
@@ -681,35 +1117,85 @@ with gr.Blocks(
681
 
682
  for tab_name, theory_key in theories:
683
  with gr.Tab(tab_name):
684
- with gr.Row():
685
- btn = gr.Button(f"{tab_name}๋กœ ์ƒ์„ฑ", variant="primary", size="sm")
686
- output = gr.Markdown()
687
- visual = gr.HTML()
688
-
689
- btn.click(
690
- lambda i, k, t=theory_key: generate_by_theory(i, k, t),
691
- inputs=[industry_input, keywords_input],
692
- outputs=[output, visual]
693
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
694
 
695
  gr.Markdown("""
696
- <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 15px; margin-top: 40px;">
697
- <h3 style="margin-top: 0;">๐Ÿ“Š ํ†ต์ผ๋œ ํ‰๊ฐ€ ์‹œ์Šคํ…œ</h3>
698
- <p style="margin: 15px 0;">๋ชจ๋“  ๋ธŒ๋žœ๋“œ๋Š” ๋‹ค์Œ 3๊ฐ€์ง€ ๊ธฐ์ค€์œผ๋กœ ํ‰๊ฐ€๋ฉ๋‹ˆ๋‹ค:</p>
699
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px;">
700
- <div>
701
- <h4>์ฐฝ์˜์„ฑ (Creativity)</h4>
702
- <p style="margin: 5px 0;">๋…์ฐฝ์„ฑ๊ณผ ํ˜์‹ ์„ฑ์˜ ์ •๋„</p>
 
 
 
703
  </div>
704
- <div>
705
- <h4>๊ธฐ์–ต์„ฑ (Memorability)</h4>
706
- <p style="margin: 5px 0;">์‰ฝ๊ฒŒ ๊ธฐ์–ต๋˜๊ณ  ํšŒ์ƒ๋˜๋Š” ์ •๋„</p>
707
  </div>
708
- <div>
709
- <h4>๊ด€๋ จ์„ฑ (Relevance)</h4>
710
- <p style="margin: 5px 0;">์—…์ข…๊ณผ ํ‚ค์›Œ๋“œ์™€์˜ ์—ฐ๊ด€์„ฑ</p>
711
  </div>
712
  </div>
 
 
 
 
 
 
713
  </div>
714
  """)
715
 
 
1
  """
2
+ THEORIAโ„ข - Theory-driven Naming AI
3
+ ===================================
4
+ ํŠน๋ณ„ํ•œ 15๊ฐœ์˜ ์ด๋ก ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๋„ค์ด๋ฐ AI
5
+ Theory-driven Naming AI with 15 Specialized Theories
6
+ -----------------------------------
7
  """
8
 
9
  import os
 
14
  from datetime import datetime
15
  from typing import List, Dict, Tuple, Optional
16
  import random
17
+ import time
18
 
19
  # OpenAI ํด๋ผ์ด์–ธํŠธ
20
  if not os.getenv("OPENAI_API_KEY"):
 
22
 
23
  client = OpenAI()
24
 
25
+ # ์–ธ์–ด๋ณ„ ํ…์ŠคํŠธ ์ •์˜
26
+ TEXTS = {
27
+ "en": {
28
+ "title": "THEORIAโ„ข",
29
+ "subtitle": "Theory-driven Naming AI with 15 Specialized Theories",
30
+ "description": "Generate innovative brand names using 15 cognitive and creative theories",
31
+ "industry_label": "๐Ÿญ Industry",
32
+ "industry_placeholder": "e.g., cafe, fitness, education, beauty...",
33
+ "keywords_label": "๐Ÿ”‘ Keywords",
34
+ "keywords_placeholder": "premium, comfortable, urban, eco-friendly...",
35
+ "keywords_info": "Core values or characteristics the brand should embody",
36
+ "generate_button": "Generate with {theory}",
37
+ "language_label": "๐ŸŒ Language",
38
+ "progress_message": "Generating innovative names using {theory}...",
39
+ "error_message": "โŒ Error in {theory}: {error}",
40
+ "input_required": "โš ๏ธ Please enter both industry and keywords.",
41
+ "evaluation_labels": {
42
+ "creativity": "Creativity",
43
+ "memorability": "Memorability",
44
+ "relevance": "Relevance"
45
+ }
46
+ },
47
+ "ko": {
48
+ "title": "THEORIAโ„ข",
49
+ "subtitle": "ํŠน๋ณ„ํ•œ 15๊ฐœ์˜ ์ด๋ก ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๋„ค์ด๋ฐ AI",
50
+ "description": "15๊ฐ€์ง€ ์ธ์ง€ ๋ฐ ์ฐฝ์˜ ์ด๋ก ์„ ํ™œ์šฉํ•œ ํ˜์‹ ์ ์ธ ๋ธŒ๋žœ๋“œ๋ช… ์ƒ์„ฑ",
51
+ "industry_label": "๐Ÿญ ์—…์ข…",
52
+ "industry_placeholder": "์˜ˆ: ์นดํŽ˜, ํ”ผํŠธ๋‹ˆ์Šค, ๊ต์œก, ๋ทฐํ‹ฐ...",
53
+ "keywords_label": "๐Ÿ”‘ ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ",
54
+ "keywords_placeholder": "ํ”„๋ฆฌ๋ฏธ์—„, ํŽธ์•ˆํ•œ, ๋„์‹œ์ ์ธ, ์นœํ™˜๊ฒฝ...",
55
+ "keywords_info": "๋ธŒ๋žœ๋“œ๊ฐ€ ๋‹ด์•„์•ผ ํ•  ํ•ต์‹ฌ ๊ฐ€์น˜๋‚˜ ํŠน์ง•๋“ค",
56
+ "generate_button": "{theory}๋กœ ์ƒ์„ฑ",
57
+ "language_label": "๐ŸŒ ์–ธ์–ด",
58
+ "progress_message": "{theory}๋ฅผ ํ™œ์šฉํ•ด ํ˜์‹ ์ ์ธ ์ด๋ฆ„์„ ์ƒ์„ฑํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค...",
59
+ "error_message": "โŒ {theory} ์˜ค๋ฅ˜: {error}",
60
+ "input_required": "โš ๏ธ ์—…์ข…๊ณผ ํ‚ค์›Œ๋“œ๋ฅผ ๋ชจ๋‘ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.",
61
+ "evaluation_labels": {
62
+ "creativity": "์ฐฝ์˜์„ฑ",
63
+ "memorability": "๊ธฐ์–ต์„ฑ",
64
+ "relevance": "๊ด€๋ จ์„ฑ"
65
+ }
66
+ }
67
+ }
68
+
69
+ # ์ด๋ก ๋ณ„ ์„ค๋ช… (์˜์–ด/ํ•œ๊ตญ์–ด)
70
  THEORY_DESCRIPTIONS = {
71
+ "en": {
72
+ "square": "Creates a semantic square structure where 4 words are connected by meaningful relationships. Hidden diagonal connections create 'aha!' moments.",
73
+ "blending": "Blends two or more concepts to create new meaning. Like Netflix (Net+Flix), it births innovative concepts.",
74
+ "sound": "Utilizes associations between phonemes and meaning. 'i,e' convey lightness and speed, 'o,u' convey weight and slowness.",
75
+ "linguistic": "Creates global brands considering linguistic thought differences. Reflects cultural nuances and localization strategies.",
76
+ "archetype": "Leverages Jung's 12 universal archetypes. Creates unconscious emotional connections like Hero (Nike) or Creator (Apple).",
77
+ "jobs": "Focuses on the 'job' customers are trying to get done. Integrates functional, emotional, and social needs.",
78
+ "scamper": "Uses 7 creative techniques (Substitute, Combine, Adapt, Modify, Put to other use, Eliminate, Reverse) for innovation.",
79
+ "design": "Pursues human-centered innovation. Finds the intersection of desirability (human), feasibility (technical), and viability (business).",
80
+ "biomimicry": "Creates nature-inspired brands. Applies 3.8 billion years of evolutionary wisdom to branding.",
81
+ "cognitive": "Creates brands that minimize cognitive processing. Uses 1-3 syllables for instant recognition and recall.",
82
+ "vonrestorff": "Creates unique, memorable brands. Intentionally violates category conventions for 30x better recall.",
83
+ "network": "Creates brands that maximize network value. Designs structures where value increases with more users.",
84
+ "memetics": "Creates culturally replicable and evolving brands. Embeds viral elements that spread naturally like memes.",
85
+ "color": "Creates brands using color associations and emotions. Applies color psychology: red (passion), blue (trust), green (nature).",
86
+ "gestalt": "Creates brands using perception principles. Designs holistic brand experiences where the whole exceeds the sum of parts."
87
+ },
88
+ "ko": {
89
+ "square": "4๊ฐœ์˜ ๋‹จ์–ด๊ฐ€ ์˜๋ฏธ์  ๊ด€๊ณ„๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์‚ฌ๊ฐํ˜•์„ ์ด๋ฃจ๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ๋Œ€๋ณ€์˜ ์ˆจ๊ฒจ์ง„ ์—ฐ๊ฒฐ์ด '์•„ํ•˜!' ๋ชจ๋จผํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.",
90
+ "blending": "๋‘ ๊ฐœ ์ด์ƒ์˜ ๊ฐœ๋…์„ ํ˜ผํ•ฉํ•˜์—ฌ ์ƒˆ๋กœ์šด ์˜๋ฏธ๋ฅผ ์ฐฝ์ถœํ•ฉ๋‹ˆ๋‹ค. Netflix(Net+Flix)์ฒ˜๋Ÿผ ํ˜์‹ ์ ์ธ ๊ฐœ๋…์„ ํƒ„์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.",
91
+ "sound": "์Œ์†Œ์™€ ์˜๋ฏธ ๊ฐ„์˜ ์—ฐ๊ด€์„ฑ์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. 'i,e'๋Š” ๊ฐ€๋ณ๊ณ  ๋น ๋ฅธ ๋А๋‚Œ, 'o,u'๋Š” ๋ฌด๊ฒ๊ณ  ๋А๋ฆฐ ๋А๋‚Œ์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.",
92
+ "linguistic": "์–ธ์–ด๋ณ„ ์‚ฌ๊ณ ๋ฐฉ์‹ ์ฐจ์ด๋ฅผ ๊ณ ๋ คํ•œ ๊ธ€๋กœ๋ฒŒ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋ฌธํ™”์  ๋‰˜์•™์Šค์™€ ํ˜„์ง€ํ™” ์ „๋žต์„ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.",
93
+ "archetype": "Jung์˜ 12๊ฐ€์ง€ ๋ณดํŽธ์  ์›ํ˜•์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. Hero(Nike), Creator(Apple)์ฒ˜๋Ÿผ ๋ฌด์˜์‹์  ๊ฐ์ • ์—ฐ๊ฒฐ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.",
94
+ "jobs": "๊ณ ๊ฐ์ด ํ•ด๊ฒฐํ•˜๋ ค๋Š” '์ผ'์— ์ดˆ์ ์„ ๋งž์ถฅ๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์ , ๊ฐ์ •์ , ์‚ฌํšŒ์  ์ฐจ์›์˜ ๋‹ˆ์ฆˆ๋ฅผ ํ†ตํ•ฉ์ ์œผ๋กœ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.",
95
+ "scamper": "7๊ฐ€์ง€ ์ฐฝ์˜์  ๊ธฐ๋ฒ•(๋Œ€์ฒด, ๊ฒฐํ•ฉ, ์ ์‘, ์ˆ˜์ •, ์šฉ๋„๋ณ€๊ฒฝ, ์ œ๊ฑฐ, ์—ญ์ „)์œผ๋กœ ํ˜์‹ ์ ์ธ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.",
96
+ "design": "์ธ๊ฐ„ ์ค‘์‹ฌ ํ˜์‹ ์„ ์ถ”๊ตฌํ•ฉ๋‹ˆ๋‹ค. ๋ฐ”๋žŒ์งํ•จ(์ธ๊ฐ„), ์‹คํ˜„๊ฐ€๋Šฅ์„ฑ(๊ธฐ์ˆ ), ์ƒ์กด๊ฐ€๋Šฅ์„ฑ(๋น„์ฆˆ๋‹ˆ์Šค)์˜ ๊ต์ง‘ํ•ฉ์„ ์ฐพ์Šต๋‹ˆ๋‹ค.",
97
+ "biomimicry": "์ž์—ฐ์—์„œ ์˜๊ฐ์„ ๋ฐ›์€ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. 38์–ต๋…„ ์ง„ํ™”์˜ ์ง€ํ˜œ๋ฅผ ๋ธŒ๋žœ๋”ฉ์— ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.",
98
+ "cognitive": "์ธ์ง€ ์ฒ˜๋ฆฌ๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. 1-3์Œ์ ˆ์˜ ์‰ฌ์šด ๋ฐœ์Œ์œผ๋กœ ์ฆ‰๊ฐ์  ์ธ์‹๊ณผ ๊ธฐ์–ต์„ ๋•์Šต๋‹ˆ๋‹ค.",
99
+ "vonrestorff": "๋…ํŠนํ•˜๊ณ  ๊ธฐ์–ต์— ๋‚จ๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์นดํ…Œ๊ณ ๋ฆฌ ๊ด€์Šต์„ ์˜๋„์ ์œผ๋กœ ์œ„๋ฐ˜ํ•˜์—ฌ 30๋ฐฐ ๋” ์ž˜ ๊ธฐ์–ต๋˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.",
100
+ "network": "๋„คํŠธ์›Œํฌ ๊ฐ€์น˜๋ฅผ ๊ทน๋Œ€ํ™”ํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๋งŽ์„์ˆ˜๋ก ๊ฐ€์น˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค.",
101
+ "memetics": "๋ฌธํ™”์ ์œผ๋กœ ๋ณต์ œ๋˜๊ณ  ์ง„ํ™”ํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋ฐˆ์ฒ˜๋Ÿผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํผ์ ธ๋‚˜๊ฐ€๋Š” ๋ฐ”์ด๋Ÿด ์š”์†Œ๋ฅผ ๋‚ด์žฌํ™”ํ•ฉ๋‹ˆ๋‹ค.",
102
+ "color": "์ƒ‰์ƒ ์—ฐ์ƒ๊ณผ ๊ฐ์ •์„ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋นจ๊ฐ•(์—ด์ •), ํŒŒ๋ž‘(์‹ ๋ขฐ), ์ดˆ๋ก(์ž์—ฐ) ๋“ฑ ์ƒ‰์ƒ ์‹ฌ๋ฆฌ๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.",
103
+ "gestalt": "์ง€๊ฐ ์›๋ฆฌ๋ฅผ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ „์ฒด๊ฐ€ ๋ถ€๋ถ„์˜ ํ•ฉ๋ณด๋‹ค ํฌ๋‹ค๋Š” ์›์น™์œผ๋กœ ํ†ตํ•ฉ์  ๋ธŒ๋žœ๋“œ ๊ฒฝํ—˜์„ ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค."
104
+ }
105
  }
106
 
107
+ # ํ†ต์ผ๋œ ๊ธฐ๋ณธ ๏ฟฝ๏ฟฝ๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ (์˜์–ด)
108
+ UNIFIED_BASE_PROMPT_EN = """
109
+ You are a {theory_name} expert. {theory_description}
110
+
111
+ Based on the user input (industry/keywords), generate an array in the following unified JSON format:
112
+
113
+ {{
114
+ "brands": [
115
+ {{
116
+ "core": {{
117
+ "brand_name": "Brand Name",
118
+ "slogan": "Slogan",
119
+ "core_value": "Core Value",
120
+ "target_emotion": "Target Emotion",
121
+ "brand_personality": "Brand Personality"
122
+ }},
123
+ "visual": {{
124
+ "primary_color": "#HEX",
125
+ "color_meaning": "Color Meaning",
126
+ "visual_concept": "Visual Concept",
127
+ "typography_style": "Typography Style"
128
+ }},
129
+ "linguistic": {{
130
+ "pronunciation": "Pronunciation Guide",
131
+ "etymology": "Etymology/Structure",
132
+ "global_adaptability": "Global Adaptability",
133
+ "memorable_factor": "Memorability Factor"
134
+ }},
135
+ "strategic": {{
136
+ "differentiation": "Differentiation Point",
137
+ "market_positioning": "Market Positioning",
138
+ "growth_potential": "Growth Potential",
139
+ "implementation_ease": "Implementation Ease"
140
+ }},
141
+ "theory_specific": {{
142
+ {theory_specific_fields}
143
+ }},
144
+ "evaluation": {{
145
+ "creativity_score": 0-10,
146
+ "memorability_score": 0-10,
147
+ "relevance_score": 0-10,
148
+ "overall_effectiveness": "Overall effectiveness description"
149
+ }}
150
+ }}
151
+ ]
152
+ }}
153
+
154
+ Return valid JSON format and fill all fields.
155
+ Include theory-specific characteristics in the theory_specific section while maintaining the unified structure.
156
+ All content should be in English.
157
+ """
158
+
159
+ # ํ†ต์ผ๋œ ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ (ํ•œ๊ตญ์–ด)
160
+ UNIFIED_BASE_PROMPT_KO = """
161
  ๋‹น์‹ ์€ {theory_name} ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. {theory_description}
162
 
163
  ์‚ฌ์šฉ์ž ์ž…๋ ฅ(์—…์ข…/ํ‚ค์›Œ๋“œ)์„ ๋ฐ›์•„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ†ต์ผ๋œ JSON ํ˜•์‹์˜ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜์„ธ์š”:
 
205
 
206
  ๋ฐ˜๋“œ์‹œ ์œ ํšจํ•œ JSON ํ˜•์‹์œผ๋กœ ์‘๋‹ตํ•˜๊ณ , ๋ชจ๋“  ํ•„๋“œ๋ฅผ ์ฑ„์›Œ์ฃผ์„ธ์š”.
207
  ๊ฐ ์ด๋ก ์˜ ํŠน์„ฑ์„ theory_specific ์„น์…˜์— ๋‹ด๋˜, ๋‚˜๋จธ์ง€๋Š” ํ†ต์ผ๋œ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•˜์„ธ์š”.
208
+ ๋ชจ๋“  ๋‚ด์šฉ์€ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•˜์„ธ์š”.
209
  """
210
 
211
+ # ์ด๋ก ๋ณ„ ํŠน์ˆ˜ ํ•„๋“œ ์ •์˜ (์˜์–ด)
212
+ THEORY_SPECIFIC_FIELDS_EN = {
213
+ "square": """
214
+ "tl": "Top Left",
215
+ "tr": "Top Right",
216
+ "bl": "Bottom Left",
217
+ "br": "Bottom Right",
218
+ "top_edge": "Top Relationship",
219
+ "bottom_edge": "Bottom Relationship",
220
+ "left_edge": "Left Relationship",
221
+ "right_edge": "Right Relationship",
222
+ "diagonal_insight": "Diagonal Insight"
223
+ """,
224
+
225
+ "blending": """
226
+ "input_space1": "First Concept",
227
+ "input_space2": "Second Concept",
228
+ "generic_space": "Common Structure",
229
+ "blended_space": "Blended New Meaning",
230
+ "emergent_properties": "Emergent Properties",
231
+ "blend_ratio": "Blend Ratio"
232
+ """,
233
+
234
+ "sound": """
235
+ "phonetic_analysis": "Phonetic Analysis",
236
+ "sound_meaning": "Sound Meaning",
237
+ "vowel_consonant_ratio": "Vowel/Consonant Ratio",
238
+ "phoneme_emotion_map": "Phoneme-Emotion Mapping",
239
+ "cross_linguistic_sound": "Cross-linguistic Sound Consistency"
240
+ """,
241
+
242
+ "linguistic": """
243
+ "korean_adaptation": "Korean Adaptation",
244
+ "english_meaning": "English Meaning",
245
+ "cultural_considerations": "Cultural Considerations",
246
+ "avoid_meanings": "Meanings to Avoid",
247
+ "localization_strategy": "Localization Strategy"
248
+ """,
249
+
250
+ "archetype": """
251
+ "archetype": "Selected Archetype",
252
+ "archetype_traits": "Archetype Traits",
253
+ "shadow_side": "Shadow Side",
254
+ "mythology_reference": "Mythological Reference",
255
+ "customer_journey": "Customer Journey Connection"
256
+ """,
257
+
258
+ "jobs": """
259
+ "functional_job": "Functional Job",
260
+ "emotional_job": "Emotional Job",
261
+ "social_job": "Social Job",
262
+ "job_statement": "Core Job Statement",
263
+ "outcome_metrics": "Outcome Metrics"
264
+ """,
265
+
266
+ "scamper": """
267
+ "scamper_technique": "Technique Used",
268
+ "original_concept": "Original Concept",
269
+ "transformation": "Transformation Process",
270
+ "innovation_type": "Innovation Type",
271
+ "disruption_level": "Disruption Level"
272
+ """,
273
+
274
+ "design": """
275
+ "user_insight": "User Insight",
276
+ "pain_point": "Pain Point Solved",
277
+ "desirability": "Desirability (Human)",
278
+ "feasibility": "Feasibility (Technical)",
279
+ "viability": "Viability (Business)"
280
+ """,
281
+
282
+ "biomimicry": """
283
+ "natural_inspiration": "Natural Inspiration",
284
+ "biomimetic_principle": "Biomimetic Principle",
285
+ "form_function": "Form and Function",
286
+ "sustainability_aspect": "Sustainability Aspect",
287
+ "adaptation_strategy": "Adaptation Strategy"
288
+ """,
289
+
290
+ "cognitive": """
291
+ "syllable_count": "Syllable Count",
292
+ "processing_ease": "Processing Ease Score",
293
+ "memory_hooks": "Memory Hooks",
294
+ "cognitive_fluency": "Cognitive Fluency",
295
+ "attention_span_fit": "Attention Span Fit"
296
+ """,
297
+
298
+ "vonrestorff": """
299
+ "category_norm": "Category Norm",
300
+ "deviation_strategy": "Deviation Strategy",
301
+ "uniqueness_factors": "Uniqueness Factors",
302
+ "attention_triggers": "Attention Triggers",
303
+ "isolation_effect": "Isolation Effect Usage"
304
+ """,
305
+
306
+ "network": """
307
+ "network_type": "Network Type",
308
+ "viral_coefficient": "Viral Coefficient",
309
+ "sharing_ease": "Sharing Ease",
310
+ "community_aspect": "Community Aspect",
311
+ "network_value": "Network Value"
312
+ """,
313
+
314
+ "memetics": """
315
+ "meme_structure": "Meme Structure",
316
+ "replication_ease": "Replication Ease",
317
+ "mutation_potential": "Mutation Potential",
318
+ "cultural_fitness": "Cultural Fitness",
319
+ "transmission_channels": "Transmission Channels"
320
+ """,
321
+
322
+ "color": """
323
+ "color_palette": "Color Palette",
324
+ "emotional_response": "Emotional Response",
325
+ "cultural_associations": "Cultural Associations",
326
+ "industry_alignment": "Industry Alignment",
327
+ "color_accessibility": "Color Accessibility"
328
+ """,
329
+
330
+ "gestalt": """
331
+ "gestalt_principle": "Principle Used",
332
+ "visual_structure": "Visual Structure",
333
+ "perceptual_grouping": "Perceptual Grouping",
334
+ "figure_ground": "Figure-Ground Relationship",
335
+ "closure_effect": "Closure Effect"
336
+ """
337
+ }
338
+
339
+ # ์ด๋ก ๋ณ„ ํŠน์ˆ˜ ํ•„๋“œ ์ •์˜ (ํ•œ๊ตญ์–ด)
340
+ THEORY_SPECIFIC_FIELDS_KO = {
341
  "square": """
342
  "tl": "์™ผ์ชฝ์ƒ๋‹จ",
343
  "tr": "์˜ค๋ฅธ์ชฝ์ƒ๋‹จ",
 
464
  """
465
  }
466
 
467
+ def create_theory_prompt(theory: str, language: str) -> str:
468
  """๊ฐ ์ด๋ก ๋ณ„ ํ†ต์ผ๋œ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ"""
469
  theory_names = {
470
+ "en": {
471
+ "square": "Square Theory",
472
+ "blending": "Conceptual Blending Theory",
473
+ "sound": "Sound Symbolism",
474
+ "linguistic": "Linguistic Relativity",
475
+ "archetype": "Jung's Archetype Theory",
476
+ "jobs": "Jobs-to-be-Done Theory",
477
+ "scamper": "SCAMPER Method",
478
+ "design": "IDEO's Design Thinking",
479
+ "biomimicry": "Biomimicry",
480
+ "cognitive": "Cognitive Load Theory",
481
+ "vonrestorff": "Von Restorff Effect",
482
+ "network": "Network Effects",
483
+ "memetics": "Memetics",
484
+ "color": "Color Psychology",
485
+ "gestalt": "Gestalt Theory"
486
+ },
487
+ "ko": {
488
+ "square": "Square Theory",
489
+ "blending": "Conceptual Blending Theory",
490
+ "sound": "Sound Symbolism",
491
+ "linguistic": "Linguistic Relativity",
492
+ "archetype": "Jung์˜ Archetype Theory",
493
+ "jobs": "Jobs-to-be-Done Theory",
494
+ "scamper": "SCAMPER Method",
495
+ "design": "IDEO์˜ Design Thinking",
496
+ "biomimicry": "Biomimicry",
497
+ "cognitive": "Cognitive Load Theory",
498
+ "vonrestorff": "Von Restorff Effect",
499
+ "network": "Network Effects",
500
+ "memetics": "Memetics",
501
+ "color": "Color Psychology",
502
+ "gestalt": "Gestalt Theory"
503
+ }
504
  }
505
 
506
+ base_prompt = UNIFIED_BASE_PROMPT_EN if language == "en" else UNIFIED_BASE_PROMPT_KO
507
+ theory_specific_fields = THEORY_SPECIFIC_FIELDS_EN if language == "en" else THEORY_SPECIFIC_FIELDS_KO
508
+
509
+ return base_prompt.format(
510
+ theory_name=theory_names[language][theory],
511
+ theory_description=THEORY_DESCRIPTIONS[language][theory],
512
+ theory_specific_fields=theory_specific_fields[theory]
513
  )
514
 
515
+ def generate_by_theory(industry: str, keywords: str, theory: str, language: str, count: int = 3) -> Tuple[str, str, gr.update]:
516
  """ํŠน์ • ์ด๋ก ์œผ๋กœ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ"""
517
 
518
+ texts = TEXTS[language]
519
+
520
  if not industry or not keywords:
521
+ return texts["input_required"], "", gr.update(visible=False)
522
+
523
+ prompt = create_theory_prompt(theory, language)
524
 
525
+ if language == "en":
526
+ user_input = f"""Industry: {industry}
527
+ Keywords: {keywords}
528
+
529
+ Generate {count} brands with the above information.
530
+ Each brand should have a unified structure, with theory-specific characteristics in the theory_specific section."""
531
+ else:
532
+ user_input = f"""์—…์ข…: {industry}
533
  ํ‚ค์›Œ๋“œ: {keywords}
534
 
535
  ์œ„ ์ •๋ณด๋กœ {count}๊ฐœ์˜ ๋ธŒ๋žœ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”.
536
  ๊ฐ ๋ธŒ๋žœ๋“œ๋Š” ํ†ต์ผ๋œ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๋˜, theory_specific ์„น์…˜์—๋Š” {theory} ์ด๋ก ์˜ ํŠน์„ฑ์„ ๋ฐ˜์˜ํ•˜์„ธ์š”."""
537
 
538
  try:
539
+ # ํ”„๋กœ๊ทธ๋ ˆ์Šค๋ฐ” ํ‘œ์‹œ
540
+ theory_names = {
541
+ "square": "Square Theory",
542
+ "blending": "Conceptual Blending",
543
+ "sound": "Sound Symbolism",
544
+ "linguistic": "Linguistic Relativity",
545
+ "archetype": "Archetype Theory",
546
+ "jobs": "Jobs-to-be-Done",
547
+ "scamper": "SCAMPER Method",
548
+ "design": "Design Thinking",
549
+ "biomimicry": "Biomimicry",
550
+ "cognitive": "Cognitive Load Theory",
551
+ "vonrestorff": "Von Restorff Effect",
552
+ "network": "Network Effects",
553
+ "memetics": "Memetics",
554
+ "color": "Color Psychology",
555
+ "gestalt": "Gestalt Principles"
556
+ }
557
+
558
  response = client.chat.completions.create(
559
  model="gpt-4o-mini",
560
  messages=[
 
579
  results = [results]
580
 
581
  # ๋งˆํฌ๋‹ค์šด ์ƒ์„ฑ
582
+ markdown = generate_unified_markdown(theory, results, industry, keywords, language)
583
 
584
  # HTML ์‹œ๊ฐํ™” ์ƒ์„ฑ
585
+ html = generate_unified_visualization(theory, results, language)
586
 
587
+ return markdown, html, gr.update(visible=False)
588
 
589
  except Exception as e:
590
+ error_msg = texts["error_message"].format(theory=theory_names[theory], error=str(e))
591
  print(error_msg)
592
+ return error_msg, "", gr.update(visible=False)
593
 
594
+ def generate_unified_markdown(theory: str, results: List[Dict], industry: str, keywords: str, language: str) -> str:
595
  """ํ†ต์ผ๋œ ๋งˆํฌ๋‹ค์šด ์ƒ์„ฑ"""
596
 
597
  theory_names = {
 
619
  "memetics": "๐Ÿงฌ", "color": "๐ŸŽจ", "gestalt": "๐Ÿ‘๏ธ"
620
  }
621
 
622
+ texts = TEXTS[language]
623
+
624
+ if language == "en":
625
+ markdown = f"""# {theory_icons[theory]} {theory_names[theory]}
626
+
627
+ <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 10px; margin-bottom: 20px;">
628
+ <h3 style="margin: 0 0 10px 0;">Theory Overview</h3>
629
+ <p style="margin: 0; line-height: 1.6;">{THEORY_DESCRIPTIONS[language][theory]}</p>
630
+ </div>
631
+
632
+ **Industry**: {industry} | **Keywords**: {keywords}
633
+ *Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*
634
+
635
+ ---
636
+ """
637
+ else:
638
+ markdown = f"""# {theory_icons[theory]} {theory_names[theory]}
639
 
640
  <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 10px; margin-bottom: 20px;">
641
  <h3 style="margin: 0 0 10px 0;">์ด๋ก  ๊ฐœ์š”</h3>
642
+ <p style="margin: 0; line-height: 1.6;">{THEORY_DESCRIPTIONS[language][theory]}</p>
643
  </div>
644
 
645
  **์—…์ข…**: {industry} | **ํ‚ค์›Œ๋“œ**: {keywords}
 
660
  slogan = core.get('slogan', 'N/A')
661
 
662
  markdown += f"\n## {idx}. {brand_name}\n"
 
663
 
664
+ if language == "en":
665
+ markdown += f"""**Slogan**: *"{slogan}"*
666
+
667
+ ### ๐Ÿ“ Core Information
668
+ - **Core Value**: {core.get('core_value', 'N/A')}
669
+ - **Target Emotion**: {core.get('target_emotion', 'N/A')}
670
+ - **Brand Personality**: {core.get('brand_personality', 'N/A')}
671
+
672
+ ### ๐ŸŽจ Visual Concept
673
+ - **Primary Color**: {visual.get('primary_color', '#000000')} - {visual.get('color_meaning', 'N/A')}
674
+ - **Visual Concept**: {visual.get('visual_concept', 'N/A')}
675
+ - **Typography**: {visual.get('typography_style', 'N/A')}
676
+
677
+ ### ๐Ÿ—ฃ๏ธ Linguistic Features
678
+ - **Pronunciation**: {linguistic.get('pronunciation', 'N/A')}
679
+ - **Etymology**: {linguistic.get('etymology', 'N/A')}
680
+ - **Global Adaptability**: {linguistic.get('global_adaptability', 'N/A')}
681
+
682
+ ### ๐ŸŽฏ Strategic Value
683
+ - **Differentiation**: {strategic.get('differentiation', 'N/A')}
684
+ - **Market Positioning**: {strategic.get('market_positioning', 'N/A')}
685
+ - **Growth Potential**: {strategic.get('growth_potential', 'N/A')}
686
+ """
687
+ else:
688
+ markdown += f"""**์Šฌ๋กœ๊ฑด**: *"{slogan}"*
689
+
690
+ ### ๐Ÿ“ ํ•ต์‹ฌ ์ •๋ณด
691
  - **ํ•ต์‹ฌ ๊ฐ€์น˜**: {core.get('core_value', 'N/A')}
692
  - **๋ชฉํ‘œ ๊ฐ์ •**: {core.get('target_emotion', 'N/A')}
693
  - **๋ธŒ๋žœ๋“œ ์„ฑ๊ฒฉ**: {core.get('brand_personality', 'N/A')}
 
710
 
711
  # ์ด๋ก ๋ณ„ ํŠน์ˆ˜ ์ •๋ณด
712
  if theory_specific:
713
+ theory_header = f"### ๐Ÿ’ก {theory_names[theory]} " + ("Features" if language == "en" else "ํŠน์„ฑ") + "\n"
714
+ markdown += theory_header
715
  for key, value in theory_specific.items():
 
716
  display_key = key.replace('_', ' ').title()
717
  markdown += f"- **{display_key}**: {value}\n"
718
 
719
  # ํ‰๊ฐ€ ์ ์ˆ˜
720
+ eval_labels = texts["evaluation_labels"]
721
+
722
+ if language == "en":
723
+ markdown += f"""
724
+ ### ๐Ÿ“Š Evaluation
725
+ - **{eval_labels['creativity']}**: {'โญ' * int(evaluation.get('creativity_score', 0))} ({evaluation.get('creativity_score', 0)}/10)
726
+ - **{eval_labels['memorability']}**: {'โญ' * int(evaluation.get('memorability_score', 0))} ({evaluation.get('memorability_score', 0)}/10)
727
+ - **{eval_labels['relevance']}**: {'โญ' * int(evaluation.get('relevance_score', 0))} ({evaluation.get('relevance_score', 0)}/10)
728
+
729
+ ๐Ÿ’ฌ **Overall Assessment**: {evaluation.get('overall_effectiveness', 'N/A')}
730
+ """
731
+ else:
732
+ markdown += f"""
733
  ### ๐Ÿ“Š ํ‰๊ฐ€
734
+ - **{eval_labels['creativity']}**: {'โญ' * int(evaluation.get('creativity_score', 0))} ({evaluation.get('creativity_score', 0)}/10)
735
+ - **{eval_labels['memorability']}**: {'โญ' * int(evaluation.get('memorability_score', 0))} ({evaluation.get('memorability_score', 0)}/10)
736
+ - **{eval_labels['relevance']}**: {'โญ' * int(evaluation.get('relevance_score', 0))} ({evaluation.get('relevance_score', 0)}/10)
737
 
738
  ๐Ÿ’ฌ **์ „์ฒด ํ‰๊ฐ€**: {evaluation.get('overall_effectiveness', 'N/A')}
739
  """
 
742
 
743
  return markdown
744
 
745
+ def generate_unified_visualization(theory: str, results: List[Dict], language: str) -> str:
746
  """ํ†ต์ผ๋œ ์‹œ๊ฐํ™” ์ƒ์„ฑ"""
747
 
748
+ texts = TEXTS[language]
749
+ eval_labels = texts["evaluation_labels"]
750
+
751
  html_parts = []
752
 
753
  for idx, result in enumerate(results, 1):
 
762
  slogan = core.get('slogan', '')
763
  primary_color = visual.get('primary_color', '#667eea')
764
 
765
+ # ์–ธ์–ด๋ณ„ ๋ผ๋ฒจ
766
+ if language == "en":
767
+ labels = {
768
+ "core_value": "Core Value",
769
+ "target_emotion": "Target Emotion",
770
+ "differentiation": "Differentiation",
771
+ "pronunciation": "Pronunciation"
772
+ }
773
+ else:
774
+ labels = {
775
+ "core_value": "ํ•ต์‹ฌ ๊ฐ€์น˜",
776
+ "target_emotion": "๋ชฉํ‘œ ๊ฐ์ •",
777
+ "differentiation": "์ฐจ๋ณ„ํ™” ํฌ์ธํŠธ",
778
+ "pronunciation": "๋ฐœ์Œ ๊ฐ€์ด๋“œ"
779
+ }
780
+
781
  # ํ†ต์ผ๋œ ์นด๋“œ ๋ ˆ์ด์•„์›ƒ
782
  html = f"""
783
  <div style="max-width: 800px; margin: 30px auto; font-family: -apple-system, sans-serif;">
 
796
  <div style="font-size: 2em; color: {primary_color}; font-weight: bold;">
797
  {evaluation.get('creativity_score', 0)}/10
798
  </div>
799
+ <div style="color: #7f8c8d; margin-top: 5px;">{eval_labels['creativity']}</div>
800
  </div>
801
  <div style="text-align: center;">
802
  <div style="font-size: 2em; color: {primary_color}; font-weight: bold;">
803
  {evaluation.get('memorability_score', 0)}/10
804
  </div>
805
+ <div style="color: #7f8c8d; margin-top: 5px;">{eval_labels['memorability']}</div>
806
  </div>
807
  <div style="text-align: center;">
808
  <div style="font-size: 2em; color: {primary_color}; font-weight: bold;">
809
  {evaluation.get('relevance_score', 0)}/10
810
  </div>
811
+ <div style="color: #7f8c8d; margin-top: 5px;">{eval_labels['relevance']}</div>
812
  </div>
813
  </div>
814
 
815
  <!-- ํ•ต์‹ฌ ์ •๋ณด ๊ทธ๋ฆฌ๋“œ -->
816
  <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-bottom: 30px;">
817
  <div style="background: #f8f9fa; padding: 20px; border-radius: 10px;">
818
+ <h4 style="margin: 0 0 10px 0; color: {primary_color};">{labels['core_value']}</h4>
819
  <p style="margin: 0; color: #555;">{core.get('core_value', 'N/A')}</p>
820
  </div>
821
  <div style="background: #f8f9fa; padding: 20px; border-radius: 10px;">
822
+ <h4 style="margin: 0 0 10px 0; color: {primary_color};">{labels['target_emotion']}</h4>
823
  <p style="margin: 0; color: #555;">{core.get('target_emotion', 'N/A')}</p>
824
  </div>
825
  <div style="background: #f8f9fa; padding: 20px; border-radius: 10px;">
826
+ <h4 style="margin: 0 0 10px 0; color: {primary_color};">{labels['differentiation']}</h4>
827
  <p style="margin: 0; color: #555;">{strategic.get('differentiation', 'N/A')}</p>
828
  </div>
829
  <div style="background: #f8f9fa; padding: 20px; border-radius: 10px;">
830
+ <h4 style="margin: 0 0 10px 0; color: {primary_color};">{labels['pronunciation']}</h4>
831
  <p style="margin: 0; color: #555;">{linguistic.get('pronunciation', 'N/A')}</p>
832
  </div>
833
  </div>
 
842
  html += visualize_color_specific(theory_specific, primary_color)
843
  else:
844
  # ๊ธฐ๋ณธ ์ด๋ก  ํŠน์„ฑ ํ‘œ์‹œ
845
+ theory_header = "Theory Features" if language == "en" else "์ด๋ก  ํŠน์„ฑ"
846
  html += f"""
847
  <div style="background: linear-gradient(135deg, {primary_color}15 0%, {primary_color}05 100%); padding: 25px; border-radius: 15px; margin-top: 20px;">
848
+ <h4 style="margin: 0 0 15px 0; color: {primary_color};">{theory_header}</h4>
849
  <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;">
850
  """
851
  for key, value in theory_specific.items():
 
862
  """
863
 
864
  # ์ „์ฒด ํ‰๊ฐ€
865
+ overall_header = "Overall Assessment" if language == "en" else "์ „์ฒด ํ‰๊ฐ€"
866
  html += f"""
867
  <div style="background: #f8f9fa; padding: 20px; border-radius: 10px; margin-top: 20px;">
868
+ <h4 style="margin: 0 0 10px 0; color: {primary_color};">{overall_header}</h4>
869
  <p style="margin: 0; color: #555; line-height: 1.6;">{evaluation.get('overall_effectiveness', 'N/A')}</p>
870
  </div>
871
  </div>
 
881
  """Square Theory ํŠน์ˆ˜ ์‹œ๊ฐํ™”"""
882
  return f"""
883
  <div style="background: #f8f9fa; padding: 30px; border-radius: 15px; margin-top: 20px;">
884
+ <h4 style="margin: 0 0 20px 0; color: {primary_color}; text-align: center;">Square Structure</h4>
885
  <div style="position: relative; width: 100%; max-width: 400px; height: 300px; margin: 0 auto;">
886
  <div style="position: absolute; top: 0; left: 0; background: white; color: {primary_color}; padding: 15px 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); font-weight: bold;">
887
  {theory_specific.get('tl', '?')}
 
917
  """Conceptual Blending ํŠน์ˆ˜ ์‹œ๊ฐํ™”"""
918
  return f"""
919
  <div style="background: #f8f9fa; padding: 30px; border-radius: 15px; margin-top: 20px;">
920
+ <h4 style="margin: 0 0 20px 0; color: {primary_color}; text-align: center;">Concept Blending</h4>
921
  <div style="display: flex; justify-content: center; align-items: center; gap: 20px; flex-wrap: wrap;">
922
  <div style="text-align: center; padding: 20px; background: white; color: {primary_color}; border-radius: 50%; width: 120px; height: 120px; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
923
  <div>
 
952
 
953
  html = f"""
954
  <div style="background: #f8f9fa; padding: 30px; border-radius: 15px; margin-top: 20px;">
955
+ <h4 style="margin: 0 0 20px 0; color: {primary_color}; text-align: center;">Color Palette</h4>
956
  <div style="display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;">
957
  """
958
 
 
970
 
971
  # Gradio UI
972
  with gr.Blocks(
973
+ title="THEORIAโ„ข - Theory-driven Naming AI",
974
  theme=gr.themes.Soft(),
975
  css="""
976
  .gradio-container {
977
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
978
  }
979
  .tab-nav button {
980
+ font-size: 0.85em !important;
981
+ padding: 8px 12px !important;
982
+ white-space: nowrap !important;
983
+ }
984
+ .tab-nav {
985
+ flex-wrap: wrap !important;
986
+ gap: 5px !important;
987
+ }
988
+ @keyframes pulse {
989
+ 0% { opacity: 0.6; }
990
+ 50% { opacity: 1; }
991
+ 100% { opacity: 0.6; }
992
+ }
993
+ .progress-bar {
994
+ animation: pulse 1.5s ease-in-out infinite;
995
  }
996
  """
997
  ) as demo:
998
+ # ์–ธ์–ด ์ƒํƒœ ๊ด€๋ฆฌ
999
+ current_language = gr.State(value="en")
1000
+
1001
+ def update_ui_language(language):
1002
+ """UI ์–ธ์–ด ์—…๋ฐ์ดํŠธ"""
1003
+ texts = TEXTS[language]
1004
+ return (
1005
+ language, # current_language state update
1006
+ # Title section update
1007
+ gr.update(value=f"""
1008
+ <div style="text-align: center; padding: 30px 0;">
1009
+ <h1 style="font-size: 3em; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 10px;">
1010
+ {texts['title']}
1011
+ </h1>
1012
+ <p style="font-size: 1.4em; color: #7f8c8d; font-weight: 500;">{texts['subtitle']}</p>
1013
+ <p style="font-size: 1.1em; color: #95a5a6; margin-top: 10px;">{texts['description']}</p>
1014
+ </div>
1015
+ """),
1016
+ gr.update(label=texts['industry_label'], placeholder=texts['industry_placeholder']),
1017
+ gr.update(label=texts['keywords_label'], placeholder=texts['keywords_placeholder'], info=texts['keywords_info']),
1018
+ )
1019
+
1020
+ # ํ—ค๋”
1021
+ title_section = gr.Markdown("""
1022
  <div style="text-align: center; padding: 30px 0;">
1023
+ <h1 style="font-size: 3em; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 10px;">
1024
+ THEORIAโ„ข
1025
  </h1>
1026
+ <p style="font-size: 1.4em; color: #7f8c8d; font-weight: 500;">Theory-driven Naming AI with 15 Specialized Theories</p>
1027
+ <p style="font-size: 1.1em; color: #95a5a6; margin-top: 10px;">Generate innovative brand names using 15 cognitive and creative theories</p>
1028
  </div>
1029
  """)
1030
 
 
1032
  with gr.Column(scale=1, min_width=300):
1033
  gr.Markdown("""
1034
  <div style="background: #f8f9fa; padding: 20px; border-radius: 10px; margin-bottom: 20px;">
1035
+ <h3 style="margin-top: 0; color: #2c3e50;">๐Ÿ“ Brand Information</h3>
1036
  </div>
1037
  """)
1038
 
1039
+ # ์–ธ์–ด ์„ ํƒ
1040
+ language_selector = gr.Radio(
1041
+ choices=[("English", "en"), ("ํ•œ๊ตญ์–ด", "ko")],
1042
+ value="en",
1043
+ label="๐ŸŒ Language",
1044
+ info="Select output language"
1045
+ )
1046
+
1047
  industry_input = gr.Textbox(
1048
+ label="๐Ÿญ Industry",
1049
+ placeholder="e.g., cafe, fitness, education, beauty...",
1050
+ value=""
1051
  )
1052
 
1053
  keywords_input = gr.Textbox(
1054
+ label="๐Ÿ”‘ Keywords",
1055
+ placeholder="premium, comfortable, urban, eco-friendly...",
1056
+ info="Core values or characteristics the brand should embody",
1057
  lines=2
1058
  )
1059
 
1060
+ # ์–ธ์–ด ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ
1061
+ language_selector.change(
1062
+ update_ui_language,
1063
+ inputs=[language_selector],
1064
+ outputs=[current_language, title_section, industry_input, keywords_input]
1065
+ )
1066
+
1067
  gr.Markdown("""
1068
  <div style="background: #e3f2fd; padding: 15px; border-radius: 8px; margin-top: 20px;">
1069
+ <h4 style="margin-top: 0; color: #1976d2;">๐ŸŽฏ 15 Specialized Theories</h4>
1070
+ <p style="margin: 10px 0; font-size: 0.9em;">Each theory offers a unique approach to brand naming:</p>
1071
+ <ul style="margin: 5px 0; padding-left: 20px; font-size: 0.85em;">
1072
+ <li><strong>Cognitive</strong>: Square, Sound, Cognitive Load, Gestalt</li>
1073
+ <li><strong>Creative</strong>: Blending, SCAMPER, Biomimicry</li>
1074
+ <li><strong>Strategic</strong>: Jobs-to-be-Done, Design Thinking</li>
1075
+ <li><strong>Cultural</strong>: Archetype, Linguistic, Memetics</li>
1076
+ <li><strong>Distinctive</strong>: Von Restorff, Color, Network</li>
1077
+ </ul>
1078
+ </div>
1079
+
1080
+ <div style="background: #fff3cd; padding: 15px; border-radius: 8px; margin-top: 15px;">
1081
+ <h4 style="margin-top: 0; color: #856404;">๐Ÿ’ก Pro Tips</h4>
1082
+ <ul style="margin: 5px 0; padding-left: 20px; font-size: 0.85em;">
1083
+ <li>Try multiple theories to find the perfect fit</li>
1084
+ <li>Compare results across different approaches</li>
1085
+ <li>Combine insights from various theories</li>
1086
  </ul>
1087
  </div>
1088
  """)
1089
 
1090
  with gr.Column(scale=3):
1091
+ # 15๊ฐœ ํƒญ์„ 3๊ฐœ ํ–‰์œผ๋กœ ๊ตฌ์„ฑ
1092
+ gr.Markdown("""
1093
+ <div style="background: #f8f9fa; padding: 15px; border-radius: 10px; margin-bottom: 20px;">
1094
+ <h3 style="margin: 0; color: #2c3e50; text-align: center;">Select a Theory to Generate Names</h3>
1095
+ </div>
1096
+ """)
1097
+
1098
  # 15๊ฐœ ํƒญ ์ƒ์„ฑ
1099
+ with gr.Tabs(elem_classes="tab-nav"):
 
1100
  theories = [
1101
  ("๐ŸŸฆ Square Theory", "square"),
1102
  ("๐Ÿ”€ Conceptual Blending", "blending"),
 
1117
 
1118
  for tab_name, theory_key in theories:
1119
  with gr.Tab(tab_name):
1120
+ with gr.Column():
1121
+ # ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฉ”์‹œ์ง€
1122
+ progress_msg = gr.Markdown(
1123
+ visible=False,
1124
+ value=f"""
1125
+ <div style="text-align: center; padding: 20px; background: #f0f8ff; border-radius: 10px; margin: 10px 0;">
1126
+ <div class="progress-bar" style="font-size: 1.2em; color: #1976d2;">
1127
+ Generating innovative names using {tab_name}...
1128
+ </div>
1129
+ <div style="margin-top: 10px;">
1130
+ <div style="width: 100%; background: #e0e0e0; border-radius: 5px; overflow: hidden;">
1131
+ <div style="width: 100%; height: 4px; background: linear-gradient(90deg, #1976d2 0%, #42a5f5 50%, #1976d2 100%); animation: slide 1.5s linear infinite;"></div>
1132
+ </div>
1133
+ </div>
1134
+ </div>
1135
+ <style>
1136
+ @keyframes slide {
1137
+ 0% { transform: translateX(-100%); }
1138
+ 100% { transform: translateX(100%); }
1139
+ }
1140
+ </style>
1141
+ """
1142
+ )
1143
+
1144
+ with gr.Row():
1145
+ btn = gr.Button(
1146
+ f"Generate with {tab_name}",
1147
+ variant="primary",
1148
+ size="lg",
1149
+ elem_id=f"btn_{theory_key}"
1150
+ )
1151
+
1152
+ output = gr.Markdown()
1153
+ visual = gr.HTML()
1154
+
1155
+ def generate_with_progress(industry, keywords, theory, language):
1156
+ """ํ”„๋กœ๊ทธ๋ ˆ์Šค๋ฐ”์™€ ํ•จ๊ป˜ ์ƒ์„ฑ"""
1157
+ # ๋จผ์ € ํ”„๋กœ๊ทธ๋ ˆ์Šค๋ฐ” ํ‘œ์‹œ
1158
+ yield "", "", gr.update(visible=True)
1159
+
1160
+ # ์‹ค์ œ ์ƒ์„ฑ ์ž‘์—…
1161
+ result_md, result_html, _ = generate_by_theory(industry, keywords, theory, language)
1162
+
1163
+ # ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ ๋ฐ ํ”„๋กœ๊ทธ๋ ˆ์Šค๋ฐ” ์ˆจ๊น€
1164
+ yield result_md, result_html, gr.update(visible=False)
1165
+
1166
+ btn.click(
1167
+ lambda i, k, l, t=theory_key: generate_with_progress(i, k, t, l),
1168
+ inputs=[industry_input, keywords_input, current_language],
1169
+ outputs=[output, visual, progress_msg]
1170
+ )
1171
 
1172
  gr.Markdown("""
1173
+ <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 40px; border-radius: 15px; margin-top: 40px;">
1174
+ <h3 style="margin-top: 0; text-align: center;">๐Ÿ† Why THEORIAโ„ข?</h3>
1175
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 25px; margin-top: 25px;">
1176
+ <div style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px;">
1177
+ <h4 style="margin: 0 0 10px 0;">๐Ÿงช Scientific Foundation</h4>
1178
+ <p style="margin: 0; font-size: 0.95em;">Based on proven cognitive and creative theories from psychology, linguistics, and design</p>
1179
+ </div>
1180
+ <div style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px;">
1181
+ <h4 style="margin: 0 0 10px 0;">๐ŸŽฏ Multi-dimensional Approach</h4>
1182
+ <p style="margin: 0; font-size: 0.95em;">15 different perspectives ensure you find the perfect name for your brand</p>
1183
  </div>
1184
+ <div style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px;">
1185
+ <h4 style="margin: 0 0 10px 0;">๐Ÿ“Š Unified Evaluation</h4>
1186
+ <p style="margin: 0; font-size: 0.95em;">Consistent scoring system allows easy comparison across all theories</p>
1187
  </div>
1188
+ <div style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px;">
1189
+ <h4 style="margin: 0 0 10px 0;">๐ŸŒ Global Ready</h4>
1190
+ <p style="margin: 0; font-size: 0.95em;">Multilingual support and cultural considerations built into every theory</p>
1191
  </div>
1192
  </div>
1193
+
1194
+ <div style="text-align: center; margin-top: 30px; padding-top: 20px; border-top: 1px solid rgba(255,255,255,0.2);">
1195
+ <p style="margin: 0; font-size: 0.9em; opacity: 0.8;">
1196
+ THEORIAโ„ข - Where Science Meets Creativity in Brand Naming
1197
+ </p>
1198
+ </div>
1199
  </div>
1200
  """)
1201