openfree commited on
Commit
838b990
ยท
verified ยท
1 Parent(s): 56acaac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +731 -307
app.py CHANGED
@@ -1,11 +1,25 @@
1
  """
2
- Square Theory Brand Generator
3
- =============================
4
- 2025-05-28 | Square Theory๋ฅผ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ ๋„ค์ด๋ฐ & ์Šฌ๋กœ๊ฑด ์ƒ์„ฑ๊ธฐ
5
- ----------------------------------------------------------
6
 
7
- Square Theory๋ฅผ ๋ธŒ๋žœ๋”ฉ์— ์ ์šฉ: ๋ธŒ๋žœ๋“œ๋ช…์ด Square๋ฅผ ์™„์„ฑํ•˜๋Š” ๊ตฌ์กฐ
8
- ์˜ˆ: GRUBHUB = GRUB(์Œ์‹) + HUB(์ค‘์‹ฌ) โ†’ ์Œ์‹ ๋ฐฐ๋‹ฌ์˜ ์ค‘์‹ฌ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  """
10
 
11
  import os
@@ -15,6 +29,7 @@ import openai
15
  from openai import OpenAI
16
  from datetime import datetime
17
  from typing import List, Dict, Tuple, Optional
 
18
 
19
  # OpenAI ํด๋ผ์ด์–ธํŠธ
20
  if not os.getenv("OPENAI_API_KEY"):
@@ -22,82 +37,304 @@ if not os.getenv("OPENAI_API_KEY"):
22
 
23
  client = OpenAI()
24
 
25
- # Square Theory ๋ธŒ๋žœ๋”ฉ ์ „์šฉ ํ”„๋กฌํ”„ํŠธ
26
- BRANDING_SQUARE_PROMPT = """
27
- ๋‹น์‹ ์€ Square Theory๋ฅผ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ ๋„ค์ด๋ฐ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
 
28
 
29
- Square Theory๋Š” 4๊ฐœ์˜ ๋‹จ์–ด๊ฐ€ ์˜๋ฏธ์  ๊ด€๊ณ„๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์‚ฌ๊ฐํ˜•์„ ์ด๋ฃจ๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
30
- ์ด๋ฅผ ๋ธŒ๋žœ๋”ฉ์— ์ ์šฉํ•˜๋ฉด, ๋ธŒ๋žœ๋“œ๋ช…์ด Square๋ฅผ ์™„์„ฑํ•˜๋ฉฐ "์•„ํ•˜!" ๋ชจ๋จผํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
- ์„ฑ๊ณต์ ์ธ ๋ธŒ๋žœ๋“œ Square ์˜ˆ์‹œ:
33
- 1. GRUBHUB: GRUB(์Œ์‹) + HUB(์ค‘์‹ฌ) = ์Œ์‹ ๋ฐฐ๋‹ฌ์˜ ์ค‘์‹ฌ์ง€
34
- 2. Brand New (๋ฆฌ๋ธŒ๋žœ๋”ฉ ๋ธ”๋กœ๊ทธ): BRAND + NEW = ์ƒˆ๋กœ์šด ๋ธŒ๋žœ๋“œ = ์—…๋ฐ์ดํŠธ๋œ ๋ธŒ๋žœ๋“œ
35
- 3. Crosscord: CROSSWORD + DISCORD = ํฌ๋กœ์Šค์›Œ๋“œ ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋ฒ„
36
 
37
- ๋ธŒ๋žœ๋“œ Square ์ƒ์„ฑ ์›์น™:
38
- 1. ๋ธŒ๋žœ๋“œ๋ช…์€ ๋‘ ๋‹จ์–ด์˜ ์กฐํ•ฉ (ํ•ฉ์„ฑ์–ด, ํฌํŠธ๋งจํ† , ๋˜๋Š” ๊ตฌ๋ฌธ)
39
- 2. ๊ฐ ๋‹จ์–ด๋Š” ๋น„์ฆˆ๋‹ˆ์Šค์˜ ํ•ต์‹ฌ ์†์„ฑ๊ณผ ์—ฐ๊ฒฐ
40
- 3. ์ „์ฒด Square๊ฐ€ ๋ธŒ๋žœ๋“œ์˜ ์ •์ฒด์„ฑ์„ ๊ฐ•ํ™”
41
- 4. ์Šฌ๋กœ๊ฑด์€ Square์˜ ์˜๋ฏธ๋ฅผ ํ™•์žฅ
42
 
43
- ์‚ฌ์šฉ์ž ์ž…๋ ฅ(์—…์ข…/ํ‚ค์›Œ๋“œ)์„ ๋ฐ›์•„ ๋‹ค์Œ ํ˜•์‹์˜ JSON ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜์„ธ์š”:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  {
45
  "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
46
- "brand_type": "compound/portmanteau/phrase",
47
- "tl": "์™ผ์ชฝ์ƒ๋‹จ ๋‹จ์–ด",
48
- "tr": "์˜ค๋ฅธ์ชฝ์ƒ๋‹จ ๋‹จ์–ด",
49
- "bl": "์™ผ์ชฝํ•˜๋‹จ ๋‹จ์–ด",
50
- "br": "์˜ค๋ฅธ์ชฝํ•˜๋‹จ ๋‹จ์–ด",
51
- "top_edge": "์ƒ๋‹จ ๊ด€๊ณ„",
52
- "bottom_edge": "ํ•˜๋‹จ ๊ด€๊ณ„",
53
- "left_edge": "์™ผ์ชฝ ๊ด€๊ณ„",
54
- "right_edge": "์˜ค๋ฅธ์ชฝ ๊ด€๊ณ„",
55
- "slogan": "๋ธŒ๋žœ๋“œ ์Šฌ๋กœ๊ฑด",
56
- "tagline": "์งง์€ ํƒœ๊ทธ๋ผ์ธ",
57
- "business_description": "๋น„์ฆˆ๋‹ˆ์Šค ์„ค๋ช…",
58
- "why_it_works": "์™œ ์ด Square๊ฐ€ ํšจ๊ณผ์ ์ธ์ง€",
59
- "target_audience": "ํƒ€๊ฒŸ ๊ณ ๊ฐ",
60
- "brand_personality": "๋ธŒ๋žœ๋“œ ๊ฐœ์„ฑ",
61
- "impact_score": 1-10
62
  }
 
 
 
 
 
63
 
64
- ์ฐฝ์˜์ ์ด๋ฉด์„œ๋„ ๊ธฐ์–ตํ•˜๊ธฐ ์‰ฝ๊ณ , ๋น„์ฆˆ๋‹ˆ์Šค ๋ณธ์งˆ์„ ๋‹ด์€ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“œ์„ธ์š”.
 
 
 
 
 
 
 
 
 
65
  """
66
 
67
- # ์—…์ข…๋ณ„ ์˜ˆ์‹œ
68
- INDUSTRY_EXAMPLES = [
69
- "์นดํŽ˜/์ปคํ”ผ์ˆ",
70
- "ํ”ผํŠธ๋‹ˆ์Šค/ํ—ฌ์Šค์žฅ",
71
- "๊ต์œก/์—๋“€ํ…Œํฌ",
72
- "๋ทฐํ‹ฐ/ํ™”์žฅํ’ˆ",
73
- "์Œ์‹ ๋ฐฐ๋‹ฌ",
74
- "์—ฌํ–‰/๊ด€๊ด‘",
75
- "๊ธˆ์œต/ํ•€ํ…Œํฌ",
76
- "ํŒจ์…˜/์˜๋ฅ˜",
77
- "๋ฐ˜๋ ค๋™๋ฌผ",
78
- "์นœํ™˜๊ฒฝ/์ง€์†๊ฐ€๋Šฅ"
79
- ]
80
-
81
- def generate_brand_squares(industry: str, keywords: str, count: int = 5) -> List[Dict]:
82
- """Square Theory ๊ธฐ๋ฐ˜ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ"""
83
-
84
- user_prompt = f"""
85
- ์—…์ข…: {industry}
86
- ํ‚ค์›Œ๋“œ: {keywords}
87
-
88
- ์œ„ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ Square Theory๋ฅผ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ {count}๊ฐœ๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”.
89
- ๊ฐ ๋ธŒ๋žœ๋“œ๋Š” ์™„์ „ํ•œ Square๋ฅผ ํ˜•์„ฑํ•ด์•ผ ํ•˜๋ฉฐ, ๋ธŒ๋žœ๋“œ๋ช…์ด Square์˜ ํ•ต์‹ฌ์ด ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
90
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
  try:
93
  response = client.chat.completions.create(
94
- model="gpt-4o",
95
  messages=[
96
- {"role": "system", "content": BRANDING_SQUARE_PROMPT},
97
- {"role": "user", "content": user_prompt}
98
  ],
99
- temperature=0.85,
100
- max_tokens=4000,
101
  response_format={"type": "json_object"}
102
  )
103
 
@@ -106,216 +343,314 @@ def generate_brand_squares(industry: str, keywords: str, count: int = 5) -> List
106
 
107
  # ์‘๋‹ต ์ •๊ทœํ™”
108
  if isinstance(data, dict):
109
- if "brands" in data:
110
- results = data["brands"]
111
- elif "results" in data:
112
- results = data["results"]
113
- else:
114
- results = [data]
115
  else:
116
  results = data
117
 
118
- # ์ ์ˆ˜์ˆœ ์ •๋ ฌ
119
- results.sort(key=lambda x: x.get("impact_score", 0), reverse=True)
 
 
 
120
 
121
- return results[:count]
 
 
 
122
 
123
  except Exception as e:
124
- raise RuntimeError(f"๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ์‹คํŒจ: {e}")
125
-
126
- def visualize_brand_square(brand: Dict) -> str:
127
- """๋ธŒ๋žœ๋“œ Square ์‹œ๊ฐํ™”"""
128
-
129
- brand_name = brand.get('brand_name', 'BRAND')
130
- tl, tr = brand.get('tl', '?'), brand.get('tr', '?')
131
- bl, br = brand.get('bl', '?'), brand.get('br', '?')
132
-
133
- # ๋ธŒ๋žœ๋“œ๋ช… ๋ถ„ํ•ด (compound/portmanteau์ธ ๊ฒฝ์šฐ)
134
- if brand.get('brand_type') == 'compound':
135
- parts = brand_name.split()
136
- brand_part1 = parts[0] if len(parts) > 0 else brand_name[:len(brand_name)//2]
137
- brand_part2 = parts[1] if len(parts) > 1 else brand_name[len(brand_name)//2:]
138
- else:
139
- # ํฌํŠธ๋งจํ† ์˜ ๊ฒฝ์šฐ ๋Œ€๋žต์ ์œผ๋กœ ๋ถ„ํ• 
140
- mid = len(brand_name) // 2
141
- brand_part1 = brand_name[:mid+1]
142
- brand_part2 = brand_name[mid-1:]
143
 
144
- return f"""
145
- <div style="max-width: 700px; margin: 20px auto; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
- <!-- ๋ธŒ๋žœ๋“œ๋ช… ํ—ค๋” -->
148
- <div style="text-align: center; margin-bottom: 30px;">
149
- <h2 style="font-size: 2.5em; margin: 0; color: #2c3e50; letter-spacing: -1px;">{brand_name}</h2>
150
- <p style="font-size: 1.2em; color: #7f8c8d; margin: 10px 0; font-style: italic;">"{brand.get('slogan', '')}"</p>
151
- <p style="font-size: 0.9em; color: #95a5a6; margin: 5px 0;">{brand.get('tagline', '')}</p>
152
- </div>
153
 
154
- <!-- Square ๋‹ค์ด์–ด๊ทธ๋žจ -->
155
- <div style="position: relative; width: 100%; height: 350px; background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); border-radius: 12px; padding: 30px; box-shadow: 0 10px 30px rgba(0,0,0,0.1);">
 
156
 
157
- <!-- ์ค‘์•™ ๋ธŒ๋žœ๋“œ๋ช… -->
158
- <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px 40px; border-radius: 12px; box-shadow: 0 5px 20px rgba(0,0,0,0.15); z-index: 10;">
159
- <div style="font-size: 1.8em; font-weight: bold; color: #2c3e50; text-align: center;">{brand_name}</div>
160
- <div style="font-size: 0.9em; color: #7f8c8d; text-align: center; margin-top: 5px;">{brand.get('brand_type', 'compound')}</div>
161
- </div>
162
 
163
- <!-- ๊ผญ์ง“์  -->
164
- <div style="position: absolute; top: 30px; left: 30px; background: #3498db; color: white; padding: 12px 20px; border-radius: 8px; font-weight: 600; box-shadow: 0 3px 10px rgba(52, 152, 219, 0.3);">
165
- {tl}
166
- </div>
167
- <div style="position: absolute; top: 30px; right: 30px; background: #e74c3c; color: white; padding: 12px 20px; border-radius: 8px; font-weight: 600; box-shadow: 0 3px 10px rgba(231, 76, 60, 0.3);">
168
- {tr}
169
- </div>
170
- <div style="position: absolute; bottom: 30px; left: 30px; background: #f39c12; color: white; padding: 12px 20px; border-radius: 8px; font-weight: 600; box-shadow: 0 3px 10px rgba(243, 156, 18, 0.3);">
171
- {bl}
172
- </div>
173
- <div style="position: absolute; bottom: 30px; right: 30px; background: #27ae60; color: white; padding: 12px 20px; border-radius: 8px; font-weight: 600; box-shadow: 0 3px 10px rgba(39, 174, 96, 0.3);">
174
- {br}
175
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
- <!-- ๊ด€๊ณ„ ๋ ˆ์ด๋ธ” -->
178
- <div style="position: absolute; top: 45px; left: 50%; transform: translateX(-50%); background: rgba(44, 62, 80, 0.9); color: white; padding: 4px 12px; border-radius: 4px; font-size: 0.8em;">
179
- {brand.get('top_edge', '๊ด€๊ณ„')}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  </div>
181
- <div style="position: absolute; bottom: 45px; left: 50%; transform: translateX(-50%); background: rgba(44, 62, 80, 0.9); color: white; padding: 4px 12px; border-radius: 4px; font-size: 0.8em;">
182
- {brand.get('bottom_edge', '๊ด€๊ณ„')}
183
  </div>
184
- <div style="position: absolute; top: 50%; left: 45px; transform: translateY(-50%) rotate(-90deg); background: rgba(44, 62, 80, 0.9); color: white; padding: 4px 12px; border-radius: 4px; font-size: 0.8em;">
185
- {brand.get('left_edge', '๊ด€๊ณ„')}
186
  </div>
187
- <div style="position: absolute; top: 50%; right: 45px; transform: translateY(-50%) rotate(90deg); background: rgba(44, 62, 80, 0.9); color: white; padding: 4px 12px; border-radius: 4px; font-size: 0.8em;">
188
- {brand.get('right_edge', '๊ด€๊ณ„')}
189
  </div>
190
 
191
- <!-- ์—ฐ๊ฒฐ์„  -->
192
- <svg style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none;">
193
- <defs>
194
- <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
195
- <stop offset="0%" style="stop-color:#3498db;stop-opacity:0.5" />
196
- <stop offset="100%" style="stop-color:#e74c3c;stop-opacity:0.5" />
197
- </linearGradient>
198
- <linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="0%">
199
- <stop offset="0%" style="stop-color:#f39c12;stop-opacity:0.5" />
200
- <stop offset="100%" style="stop-color:#27ae60;stop-opacity:0.5" />
201
- </linearGradient>
202
- </defs>
203
- <!-- ์ƒ๋‹จ -->
204
- <line x1="100" y1="45" x2="600" y2="45" stroke="url(#grad1)" stroke-width="3"/>
205
- <!-- ํ•˜๋‹จ -->
206
- <line x1="100" y1="305" x2="600" y2="305" stroke="url(#grad2)" stroke-width="3"/>
207
- <!-- ์™ผ์ชฝ -->
208
- <line x1="50" y1="80" x2="50" y2="270" stroke="#7f8c8d" stroke-width="3" opacity="0.5"/>
209
- <!-- ์˜ค๋ฅธ์ชฝ -->
210
- <line x1="650" y1="80" x2="650" y2="270" stroke="#7f8c8d" stroke-width="3" opacity="0.5"/>
211
- </svg>
212
  </div>
 
 
 
 
 
 
 
 
213
 
214
- <!-- ๋ธŒ๋žœ๋“œ ์ •๋ณด -->
215
- <div style="margin-top: 30px; display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
216
- <div style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.05);">
217
- <h4 style="margin: 0 0 10px 0; color: #2c3e50;">๐ŸŽฏ ํƒ€๊ฒŸ ๊ณ ๊ฐ</h4>
218
- <p style="margin: 0; color: #7f8c8d;">{brand.get('target_audience', 'N/A')}</p>
 
219
  </div>
220
- <div style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.05);">
221
- <h4 style="margin: 0 0 10px 0; color: #2c3e50;">โœจ ๋ธŒ๋žœ๋“œ ๊ฐœ์„ฑ</h4>
222
- <p style="margin: 0; color: #7f8c8d;">{brand.get('brand_personality', 'N/A')}</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  </div>
224
  </div>
225
 
226
- <div style="margin-top: 20px; background: #ecf0f1; padding: 20px; border-radius: 8px;">
227
- <h4 style="margin: 0 0 10px 0; color: #2c3e50;">๐Ÿ’ก ์™œ ํšจ๊ณผ์ ์ธ๊ฐ€?</h4>
228
- <p style="margin: 0; color: #34495e;">{brand.get('why_it_works', '')}</p>
229
- </div>
230
  </div>
231
  """
232
 
233
- def generate_brands(industry: str, keywords: str, count: int) -> Tuple[str, str, List[Dict]]:
234
- """๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ๋ฐ ํ‘œ์‹œ"""
235
-
236
- if not industry or not keywords:
237
- return "โš ๏ธ ์—…์ข…๊ณผ ํ‚ค์›Œ๋“œ๋ฅผ ๋ชจ๋‘ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.", "", []
238
 
239
- try:
240
- brands = generate_brand_squares(industry, keywords, count)
 
 
241
 
242
- # ๋งˆํฌ๋‹ค์šด ๊ฒฐ๊ณผ
243
- markdown_parts = [
244
- f"# ๐Ÿข Square Theory ๋ธŒ๋žœ๋“œ ์ œ์•ˆ",
245
- f"**์—…์ข…**: {industry} | **ํ‚ค์›Œ๋“œ**: {keywords}",
246
- f"*์ƒ์„ฑ ์‹œ๊ฐ: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*\n"
247
- ]
248
 
249
- # HTML ์‹œ๊ฐํ™”
250
- html_parts = []
 
 
251
 
252
- for idx, brand in enumerate(brands, 1):
253
- score = brand.get('impact_score', 0)
254
-
255
- markdown_parts.append(f"""
256
- ## {idx}. {brand.get('brand_name', 'N/A')} {'โญ' * min(score, 5)}
257
-
258
- **์Šฌ๋กœ๊ฑด**: *"{brand.get('slogan', 'N/A')}"*
259
- **ํƒœ๊ทธ๋ผ์ธ**: {brand.get('tagline', 'N/A')}
260
-
261
- ### ๐Ÿ“ Square ๊ตฌ์กฐ
262
- ```
263
- [{brand.get('tl', '?')}] โ”€({brand.get('top_edge', '?')})โ”€ [{brand.get('tr', '?')}]
264
- โ”‚ โ”‚
265
- ({brand.get('left_edge', '?')}) ({brand.get('right_edge', '?')})
266
- โ”‚ โ”‚
267
- [{brand.get('bl', '?')}] โ”€({brand.get('bottom_edge', '?')})โ”€ [{brand.get('br', '?')}]
268
- ```
269
-
270
- **๋น„์ฆˆ๋‹ˆ์Šค**: {brand.get('business_description', 'N/A')}
271
- **ํƒ€๊ฒŸ**: {brand.get('target_audience', 'N/A')}
272
- **๊ฐœ์„ฑ**: {brand.get('brand_personality', 'N/A')}
273
 
274
- ๐Ÿ’ก **ํšจ๊ณผ**: {brand.get('why_it_works', 'N/A')}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
 
276
- ---
277
- """)
278
-
279
- # ๋ชจ๋“  ๋ธŒ๋žœ๋“œ ์‹œ๊ฐํ™”
280
- html_parts.append(f"<h3 style='text-align: center; color: #7f8c8d; margin: 40px 0 20px 0;'>#{idx}</h3>")
281
- html_parts.append(visualize_brand_square(brand))
282
-
283
- return "\n".join(markdown_parts), "\n".join(html_parts), brands
284
-
285
- except Exception as e:
286
- return f"โŒ ์˜ค๋ฅ˜: {str(e)}", "", []
 
 
 
 
 
 
 
 
 
 
 
287
 
288
- def export_brands(brands: List[Dict]) -> str:
289
- """๋ธŒ๋žœ๋“œ ์ •๋ณด JSON ๋‚ด๋ณด๋‚ด๊ธฐ"""
290
- if not brands:
291
- return None
292
-
293
- export_data = {
294
- "generated_at": datetime.now().isoformat(),
295
- "total_brands": len(brands),
296
- "brands": brands
297
- }
298
 
299
- return json.dumps(export_data, ensure_ascii=False, indent=2)
 
 
 
 
300
 
301
  # Gradio UI
302
- with gr.Blocks(title="Square Theory Brand Generator", theme=gr.themes.Soft()) as demo:
303
  gr.Markdown("""
304
- # ๐Ÿข Square Theory Brand Generator
305
- ### ์˜๋ฏธ์  Square๋ฅผ ์™„์„ฑํ•˜๋Š” ๋ธŒ๋žœ๋“œ ๋„ค์ด๋ฐ & ์Šฌ๋กœ๊ฑด ์ƒ์„ฑ๊ธฐ
306
-
307
- Square Theory๋ฅผ ํ™œ์šฉํ•ด ๋ธŒ๋žœ๋“œ๋ช…์ด ์˜๋ฏธ์  ์‚ฌ๊ฐํ˜•์„ ์™„์„ฑํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์„ธ์š”.
308
- ์ข‹์€ ๋ธŒ๋žœ๋“œ๋ช…์€ ๋‹จ์ˆœํ•œ ์ด๋ฆ„์ด ์•„๋‹Œ, ๋น„์ฆˆ๋‹ˆ์Šค์˜ ๋ณธ์งˆ์„ ๋‹ด์€ Square๋ฅผ ํ˜•์„ฑํ•ฉ๋‹ˆ๋‹ค.
309
 
310
- **์„ฑ๊ณต ์‚ฌ๋ก€**: GRUBHUB (GRUB+HUB), Brand New, Crosscord
 
311
  """)
312
 
313
  with gr.Row():
314
  with gr.Column(scale=2):
315
- industry_input = gr.Dropdown(
316
- choices=INDUSTRY_EXAMPLES,
317
  label="๐Ÿญ ์—…์ข…",
318
- allow_custom_value=True,
319
  value="์นดํŽ˜/์ปคํ”ผ์ˆ"
320
  )
321
 
@@ -325,51 +660,167 @@ with gr.Blocks(title="Square Theory Brand Generator", theme=gr.themes.Soft()) as
325
  info="๋ธŒ๋žœ๋“œ๊ฐ€ ๋‹ด์•„์•ผ ํ•  ํ•ต์‹ฌ ๊ฐ€์น˜๋‚˜ ํŠน์ง•๋“ค"
326
  )
327
 
328
- count_slider = gr.Slider(
329
- minimum=3,
330
- maximum=10,
331
- value=5,
332
- step=1,
333
- label="์ƒ์„ฑ ๊ฐœ์ˆ˜"
334
- )
335
-
336
- generate_btn = gr.Button("๐Ÿš€ ๋ธŒ๋žœ๋“œ Square ์ƒ์„ฑ", variant="primary", size="lg")
337
 
338
  with gr.Column(scale=1):
339
  gr.Markdown("""
340
- ### ๐Ÿ’ก Square Theory ๋ธŒ๋žœ๋”ฉ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
 
342
- **์ข‹์€ ๋ธŒ๋žœ๋“œ Square์˜ ์กฐ๊ฑด:**
343
- 1. ๋ธŒ๋žœ๋“œ๋ช…์˜ ๊ฐ ๋ถ€๋ถ„์ด ์˜๋ฏธ๋ฅผ ๊ฐ€์ง
344
- 2. ๋น„์ฆˆ๋‹ˆ์Šค ๋ณธ์งˆ๊ณผ ์—ฐ๊ฒฐ
345
- 3. ๊ธฐ์–ตํ•˜๊ธฐ ์‰ฝ๊ณ  ๋ฐœ์Œ ๊ฐ€๋Šฅ
346
- 4. Square๊ฐ€ "์•„ํ•˜!" ๋ชจ๋จผํŠธ ์ƒ์„ฑ
347
 
348
- **Square ๊ตฌ์กฐ ์˜ˆ์‹œ:**
349
- ```
350
- GRUB โ”€(์Œ์‹)โ”€ FOOD
351
- โ”‚ โ”‚
352
- (์ค‘์‹ฌ) (๋ฐฐ๋‹ฌ)
353
- โ”‚ โ”‚
354
- HUB โ”€(์„œ๋น„์Šค)โ”€ DELIVERY
355
- ```
356
  """)
357
 
358
- # ์ „์—ญ ๋ณ€์ˆ˜
359
- current_brands = gr.State([])
360
-
361
  with gr.Tabs():
362
- with gr.Tab("๐Ÿ“Š ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ"):
363
- output_markdown = gr.Markdown()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
 
365
- with gr.Tab("๐ŸŽจ ๋ธŒ๋žœ๋“œ ์‹œ๊ฐํ™”"):
366
- output_visual = gr.HTML()
 
 
367
 
368
- with gr.Tab("๐Ÿ’พ ๋‚ด๋ณด๋‚ด๊ธฐ"):
369
- export_btn = gr.Button("JSON ํŒŒ์ผ ์ƒ์„ฑ")
370
- download_file = gr.File(label="๋‹ค์šด๋กœ๋“œ", visible=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
371
 
372
- # ์˜ˆ์‹œ
373
  gr.Examples(
374
  examples=[
375
  ["์นดํŽ˜/์ปคํ”ผ์ˆ", "ํ”„๋ฆฌ๋ฏธ์—„, ์•„๋Š‘ํ•œ, ๋„์‹œ"],
@@ -381,51 +832,24 @@ with gr.Blocks(title="Square Theory Brand Generator", theme=gr.themes.Soft()) as
381
  inputs=[industry_input, keywords_input]
382
  )
383
 
384
- # ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
385
- def generate_and_store(industry, keywords, count):
386
- markdown, html, brands = generate_brands(industry, keywords, count)
387
- return markdown, html, brands
388
-
389
- generate_btn.click(
390
- fn=generate_and_store,
391
- inputs=[industry_input, keywords_input, count_slider],
392
- outputs=[output_markdown, output_visual, current_brands]
393
- )
394
-
395
- def create_export_file(brands):
396
- if not brands:
397
- return None
398
-
399
- content = export_brands(brands)
400
- filename = f"square_theory_brands_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
401
-
402
- with open(filename, 'w', encoding='utf-8') as f:
403
- f.write(content)
404
-
405
- return gr.File(value=filename, visible=True)
406
-
407
- export_btn.click(
408
- fn=create_export_file,
409
- inputs=[current_brands],
410
- outputs=[download_file]
411
- )
412
-
413
  gr.Markdown("""
414
  ---
415
- ### ๐ŸŽฏ ํ™œ์šฉ ๋ฐฉ๋ฒ•
416
 
417
- 1. **๋ธŒ๋žœ๋“œ ๊ฐœ๋ฐœ**: ์ƒ์„ฑ๋œ Square ์ค‘ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ฒƒ ์„ ํƒ
418
- 2. **๋งˆ์ผ€ํŒ… ์ „๋žต**: Square์˜ ๊ฐ ์š”์†Œ๋ฅผ ์บ ํŽ˜์ธ์— ํ™œ์šฉ
419
- 3. **์Šคํ† ๋ฆฌํ…”๋ง**: Square๊ฐ€ ๋งŒ๋“œ๋Š” ๋‚ด๋Ÿฌํ‹ฐ๋ธŒ ํ™œ์šฉ
420
- 4. **ํ™•์žฅ ๊ฐ€๋Šฅ์„ฑ**: Square์˜ ๊ฐ ๋ชจ์„œ๋ฆฌ์—์„œ ์„œ๋ธŒ๋ธŒ๋žœ๋“œ ํŒŒ์ƒ
421
 
422
- ### ๐Ÿ“š Square Theory ๋ธŒ๋žœ๋”ฉ์˜ ํž˜
423
 
424
- Square๋ฅผ ์™„์„ฑํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋Š”:
425
- - **๊ธฐ์–ตํ•˜๊ธฐ ์‰ฌ์›€**: ์˜๋ฏธ์  ์—ฐ๊ฒฐ์ด ๊ธฐ์–ต์„ ๊ฐ•ํ™”
426
- - **์Šคํ† ๋ฆฌ๊ฐ€ ์žˆ์Œ**: Square ์ž์ฒด๊ฐ€ ๋ธŒ๋žœ๋“œ ์Šคํ† ๋ฆฌ
427
- - **ํ™•์žฅ ๊ฐ€๋Šฅ**: ๊ฐ ์š”์†Œ์—์„œ ์ƒˆ๋กœ์šด ์˜๋ฏธ ํŒŒ์ƒ
428
- - **์ฐจ๋ณ„ํ™”๋จ**: ๋…ํŠนํ•œ ์˜๋ฏธ ๊ตฌ์กฐ๋กœ ๊ฒฝ์Ÿ์‚ฌ์™€ ๊ตฌ๋ณ„
 
 
429
  """)
430
 
431
  if __name__ == "__main__":
 
1
  """
2
+ Ultimate Brand Theory Generator
3
+ ===============================
4
+ 2025-05-28 | 15๊ฐœ ์ด๋ก ์„ ํ†ตํ•ฉํ•œ ์ข…ํ•ฉ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ๊ธฐ
5
+ -----------------------------------------------------
6
 
7
+ ํ†ตํ•ฉ๋œ ์ด๋ก ๋“ค:
8
+ 1. Square Theory - ์˜๋ฏธ์  ์‚ฌ๊ฐํ˜• ๊ตฌ์กฐ
9
+ 2. Conceptual Blending - ๊ฐœ๋… ํ˜ผํ•ฉ
10
+ 3. Sound Symbolism - ์Œํ–ฅ ์ƒ์ง•์ฃผ์˜
11
+ 4. Linguistic Relativity - ์–ธ์–ด ์ƒ๋Œ€์„ฑ
12
+ 5. Archetype Theory - ์›ํ˜• ์ด๋ก 
13
+ 6. Jobs-to-be-Done - ํ•  ์ผ ์ด๋ก 
14
+ 7. SCAMPER Method - ์ฐฝ์˜์  ๋ณ€ํ˜•
15
+ 8. Design Thinking - ๋””์ž์ธ ์‚ฌ๊ณ 
16
+ 9. Biomimicry - ์ƒ์ฒด๋ชจ๋ฐฉ
17
+ 10. Cognitive Load - ์ธ์ง€ ๋ถ€ํ•˜
18
+ 11. Von Restorff Effect - ๊ณ ๋ฆฝ ํšจ๊ณผ
19
+ 12. Network Effects - ๋„คํŠธ์›Œํฌ ํšจ๊ณผ
20
+ 13. Memetics - ๋ฐˆ ์ด๋ก 
21
+ 14. Color Psychology - ์ƒ‰์ƒ ์‹ฌ๋ฆฌํ•™
22
+ 15. Gestalt Principles - ๊ฒŒ์ŠˆํƒˆํŠธ ์›์น™
23
  """
24
 
25
  import os
 
29
  from openai import OpenAI
30
  from datetime import datetime
31
  from typing import List, Dict, Tuple, Optional
32
+ import random
33
 
34
  # OpenAI ํด๋ผ์ด์–ธํŠธ
35
  if not os.getenv("OPENAI_API_KEY"):
 
37
 
38
  client = OpenAI()
39
 
40
+ # ===== 1. SQUARE THEORY =====
41
+ SQUARE_THEORY_PROMPT = """
42
+ ๋‹น์‹ ์€ Square Theory ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. Square Theory๋Š” 4๊ฐœ์˜ ๋‹จ์–ด๊ฐ€ ์˜๋ฏธ์  ๊ด€๊ณ„๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์‚ฌ๊ฐํ˜•์„ ์ด๋ฃจ๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
43
+ ๋ธŒ๋žœ๋“œ๋ช…์ด Square๋ฅผ ์™„์„ฑํ•˜๋ฉฐ "์•„ํ•˜!" ๋ชจ๋จผํŠธ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
44
 
45
+ ์‚ฌ์šฉ์ž ์ž…๋ ฅ(์—…์ข…/ํ‚ค์›Œ๋“œ)์„ ๋ฐ›์•„ ๋‹ค์Œ ํ˜•์‹์˜ JSON ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜์„ธ์š”:
46
+ {
47
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
48
+ "tl": "์™ผ์ชฝ์ƒ๋‹จ", "tr": "์˜ค๋ฅธ์ชฝ์ƒ๋‹จ", "bl": "์™ผ์ชฝํ•˜๋‹จ", "br": "์˜ค๋ฅธ์ชฝํ•˜๋‹จ",
49
+ "top_edge": "์ƒ๋‹จ ๊ด€๊ณ„", "bottom_edge": "ํ•˜๋‹จ ๊ด€๊ณ„",
50
+ "left_edge": "์™ผ์ชฝ ๊ด€๊ณ„", "right_edge": "์˜ค๋ฅธ์ชฝ ๊ด€๊ณ„",
51
+ "slogan": "์Šฌ๋กœ๊ฑด",
52
+ "explanation": "์™œ ํšจ๊ณผ์ ์ธ์ง€"
53
+ }
54
+ """
55
+
56
+ # ===== 2. CONCEPTUAL BLENDING =====
57
+ CONCEPTUAL_BLENDING_PROMPT = """
58
+ ๋‹น์‹ ์€ Conceptual Blending Theory ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ๋‘ ๊ฐœ ์ด์ƒ์˜ ๊ฐœ๋…์„ ํ˜ผํ•ฉํ•˜์—ฌ ์ƒˆ๋กœ์šด ์˜๋ฏธ๋ฅผ ์ฐฝ์ถœํ•ฉ๋‹ˆ๋‹ค.
59
+
60
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
61
+ {
62
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
63
+ "input_space1": "์ฒซ ๋ฒˆ์งธ ๊ฐœ๋…",
64
+ "input_space2": "๋‘ ๋ฒˆ์งธ ๊ฐœ๋…",
65
+ "generic_space": "๊ณตํ†ต ๊ตฌ์กฐ",
66
+ "blended_space": "ํ˜ผํ•ฉ๋œ ์ƒˆ๋กœ์šด ์˜๋ฏธ",
67
+ "emergent_properties": "์ฐฝ๋ฐœ์  ์†์„ฑ๋“ค",
68
+ "slogan": "์Šฌ๋กœ๊ฑด",
69
+ "explanation": "ํ˜ผํ•ฉ์ด ํšจ๊ณผ์ ์ธ ์ด์œ "
70
+ }
71
 
72
+ ์˜ˆ์‹œ: Netflix = Net(์ธํ„ฐ๋„ท) + Flix(์˜ํ™”) โ†’ ์˜จ๋ผ์ธ ์ŠคํŠธ๋ฆฌ๋ฐ์˜ ์ƒˆ๋กœ์šด ๊ฐœ๋…
73
+ """
 
 
74
 
75
+ # ===== 3. SOUND SYMBOLISM =====
76
+ SOUND_SYMBOLISM_PROMPT = """
77
+ ๋‹น์‹ ์€ Sound Symbolism ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์Œ์†Œ์™€ ์˜๋ฏธ ๊ฐ„์˜ ์—ฐ๊ด€์„ฑ์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.
 
 
78
 
79
+ ์Œํ–ฅ ์›์น™:
80
+ - ์ „์„ค๋ชจ์Œ(i,e): ์ž‘๊ณ , ๋น ๋ฅด๊ณ , ๊ฐ€๋ฒผ์›€
81
+ - ํ›„์„ค๋ชจ์Œ(o,u): ํฌ๊ณ , ๋А๋ฆฌ๊ณ , ๋ฌด๊ฑฐ์›€
82
+ - ์œ ์Œ(l,r,m,n): ๋ถ€๋“œ๋Ÿฝ๊ณ  ์œ ์—ฐํ•จ
83
+ - ํŒŒ์—ด์Œ(p,t,k,b,d,g): ๊ฐ•ํ•˜๊ณ  ์—ญ๋™์ 
84
+
85
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
86
+ {
87
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
88
+ "phonetic_analysis": "์Œ์„ฑ ๋ถ„์„",
89
+ "sound_meaning": "์Œํ–ฅ์ด ์ „๋‹ฌํ•˜๋Š” ์˜๋ฏธ",
90
+ "target_emotion": "๋ชฉํ‘œ ๊ฐ์ •",
91
+ "industry_fit": "์—…์ข… ์ ํ•ฉ์„ฑ",
92
+ "pronunciation_guide": "๋ฐœ์Œ ๊ฐ€์ด๋“œ",
93
+ "slogan": "์Šฌ๋กœ๊ฑด"
94
+ }
95
+ """
96
+
97
+ # ===== 4. LINGUISTIC RELATIVITY =====
98
+ LINGUISTIC_RELATIVITY_PROMPT = """
99
+ ๋‹น์‹ ์€ Linguistic Relativity ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์–ธ์–ด๋ณ„ ์‚ฌ๊ณ ๋ฐฉ์‹ ์ฐจ์ด๋ฅผ ๊ณ ๋ คํ•ฉ๋‹ˆ๋‹ค.
100
+
101
+ ๋‹ค์–ธ์–ด ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
102
+ {
103
+ "brand_name": "๊ธ€๋กœ๋ฒŒ ๋ธŒ๋žœ๋“œ๋ช…",
104
+ "korean_adaptation": "ํ•œ๊ตญ์–ด ์ ์‘",
105
+ "english_meaning": "์˜์–ด ์˜๋ฏธ",
106
+ "cultural_considerations": "๋ฌธํ™”์  ๊ณ ๋ ค์‚ฌํ•ญ",
107
+ "avoid_meanings": "ํ”ผํ•ด์•ผ ํ•  ์˜๋ฏธ๋“ค",
108
+ "localization_strategy": "ํ˜„์ง€ํ™” ์ „๏ฟฝ๏ฟฝ",
109
+ "slogan": "์Šฌ๋กœ๊ฑด"
110
+ }
111
+ """
112
+
113
+ # ===== 5. ARCHETYPE THEORY =====
114
+ ARCHETYPE_THEORY_PROMPT = """
115
+ ๋‹น์‹ ์€ Jung์˜ Archetype Theory ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. 12๊ฐ€์ง€ ์›ํ˜• ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•˜์—ฌ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
116
+
117
+ 12 ์›ํ˜•: Innocent, Hero, Outlaw, Explorer, Creator, Ruler, Magician, Lover, Caregiver, Jester, Sage, Regular Guy
118
+
119
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
120
+ {
121
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
122
+ "archetype": "์„ ํƒ๋œ ์›ํ˜•",
123
+ "archetype_traits": "์›ํ˜•์˜ ํŠน์ง•๋“ค",
124
+ "brand_personality": "๋ธŒ๋žœ๋“œ ์„ฑ๊ฒฉ",
125
+ "visual_direction": "์‹œ๊ฐ์  ๋ฐฉํ–ฅ",
126
+ "voice_tone": "๋ชฉ์†Œ๋ฆฌ ํ†ค",
127
+ "slogan": "์Šฌ๋กœ๊ฑด",
128
+ "mythology_reference": "์‹ ํ™”์  ์ฐธ์กฐ"
129
+ }
130
+ """
131
+
132
+ # ===== 6. JOBS-TO-BE-DONE =====
133
+ JOBS_TO_BE_DONE_PROMPT = """
134
+ ๋‹น์‹ ์€ Jobs-to-be-Done Theory ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ๊ณ ๊ฐ์ด ํ•ด๊ฒฐํ•˜๋ ค๋Š” '์ผ'์— ์ดˆ์ ์„ ๋งž์ถฅ๋‹ˆ๋‹ค.
135
+
136
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
137
+ {
138
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
139
+ "functional_job": "๊ธฐ๋Šฅ์  ์ผ",
140
+ "emotional_job": "๊ฐ์ •์  ์ผ",
141
+ "social_job": "์‚ฌํšŒ์  ์ผ",
142
+ "job_statement": "ํ•ต์‹ฌ Job ๋ฌธ์žฅ",
143
+ "outcome_metrics": "์„ฑ๊ณผ ์ง€ํ‘œ",
144
+ "slogan": "์Šฌ๋กœ๊ฑด",
145
+ "value_proposition": "๊ฐ€์น˜ ์ œ์•ˆ"
146
+ }
147
+ """
148
+
149
+ # ===== 7. SCAMPER METHOD =====
150
+ SCAMPER_PROMPT = """
151
+ ๋‹น์‹ ์€ SCAMPER Method ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. 7๊ฐ€์ง€ ์ฐฝ์˜์  ๊ธฐ๋ฒ•์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
152
+
153
+ S - Substitute (๋Œ€์ฒด)
154
+ C - Combine (๊ฒฐํ•ฉ)
155
+ A - Adapt (์ ์‘)
156
+ M - Modify/Magnify (์ˆ˜์ •/ํ™•๋Œ€)
157
+ P - Put to another use (๋‹ค๋ฅธ ์šฉ๋„)
158
+ E - Eliminate (์ œ๊ฑฐ)
159
+ R - Reverse (์—ญ์ „)
160
+
161
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
162
+ {
163
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
164
+ "scamper_technique": "์‚ฌ์šฉ๋œ ๊ธฐ๋ฒ•",
165
+ "original_concept": "์›๋ž˜ ๊ฐœ๋…",
166
+ "transformation": "๋ณ€ํ˜• ๊ณผ์ •",
167
+ "innovative_aspect": "ํ˜์‹ ์  ์ธก๋ฉด",
168
+ "slogan": "์Šฌ๋กœ๊ฑด"
169
+ }
170
+ """
171
+
172
+ # ===== 8. DESIGN THINKING =====
173
+ DESIGN_THINKING_PROMPT = """
174
+ ๋‹น์‹ ์€ IDEO์˜ Design Thinking ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์ธ๊ฐ„ ์ค‘์‹ฌ ํ˜์‹ ์„ ์ถ”๊ตฌํ•ฉ๋‹ˆ๋‹ค.
175
+
176
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
177
+ {
178
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
179
+ "user_insight": "์‚ฌ์šฉ์ž ํ†ต์ฐฐ",
180
+ "pain_point": "ํ•ด๊ฒฐํ•˜๋Š” ๋ฌธ์ œ์ ",
181
+ "desirability": "๋ฐ”๋žŒ์งํ•จ (์ธ๊ฐ„)",
182
+ "feasibility": "์‹คํ˜„๊ฐ€๋Šฅ์„ฑ (๊ธฐ์ˆ )",
183
+ "viability": "์ƒ์กด๊ฐ€๋Šฅ์„ฑ (๋น„์ฆˆ๋‹ˆ์Šค)",
184
+ "prototype_concept": "ํ”„๋กœํ† ํƒ€์ž… ์ปจ์…‰",
185
+ "slogan": "์Šฌ๋กœ๊ฑด"
186
+ }
187
+ """
188
+
189
+ # ===== 9. BIOMIMICRY =====
190
+ BIOMIMICRY_PROMPT = """
191
+ ๋‹น์‹ ์€ Biomimicry ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์ž์—ฐ์—์„œ ์˜๊ฐ์„ ๋ฐ›์€ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
192
+
193
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
194
+ {
195
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
196
+ "natural_inspiration": "์ž์—ฐ์  ์˜๊ฐ์›",
197
+ "biomimetic_principle": "์ƒ์ฒด๋ชจ๋ฐฉ ์›๋ฆฌ",
198
+ "form_function": "ํ˜•ํƒœ์™€ ๊ธฐ๋Šฅ",
199
+ "sustainability_aspect": "์ง€์†๊ฐ€๋Šฅ์„ฑ ์ธก๋ฉด",
200
+ "adaptation_strategy": "์ ์‘ ์ „๋žต",
201
+ "slogan": "์Šฌ๋กœ๊ฑด"
202
+ }
203
+ """
204
+
205
+ # ===== 10. COGNITIVE LOAD =====
206
+ COGNITIVE_LOAD_PROMPT = """
207
+ ๋‹น์‹ ์€ Cognitive Load Theory ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์ธ์ง€ ์ฒ˜๋ฆฌ๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
208
+
209
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
210
+ {
211
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
212
+ "syllable_count": "์Œ์ ˆ ์ˆ˜",
213
+ "processing_ease": "์ฒ˜๋ฆฌ ์šฉ์ด์„ฑ ์ ์ˆ˜",
214
+ "memory_hooks": "๊ธฐ์–ต ๊ณ ๋ฆฌ",
215
+ "pronunciation_simplicity": "๋ฐœ์Œ ๋‹จ์ˆœ์„ฑ",
216
+ "cognitive_fluency": "์ธ์ง€์  ์œ ์ฐฝ์„ฑ",
217
+ "slogan": "์Šฌ๋กœ๊ฑด"
218
+ }
219
+ """
220
+
221
+ # ===== 11. VON RESTORFF EFFECT =====
222
+ VON_RESTORFF_PROMPT = """
223
+ ๋‹น์‹ ์€ Von Restorff Effect ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ๋…ํŠนํ•˜๊ณ  ๊ธฐ์–ต์— ๋‚จ๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
224
+
225
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
226
+ {
227
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
228
+ "category_norm": "์นดํ…Œ๊ณ ๋ฆฌ ํ‘œ์ค€",
229
+ "deviation_strategy": "์ผํƒˆ ์ „๋žต",
230
+ "uniqueness_factors": "๋…ํŠน์„ฑ ์š”์†Œ๋“ค",
231
+ "memorability_score": "๊ธฐ์–ต์„ฑ ์ ์ˆ˜",
232
+ "attention_triggers": "์ฃผ์˜ ํŠธ๋ฆฌ๊ฑฐ",
233
+ "slogan": "์Šฌ๋กœ๊ฑด"
234
+ }
235
+ """
236
+
237
+ # ===== 12. NETWORK EFFECTS =====
238
+ NETWORK_EFFECTS_PROMPT = """
239
+ ๋‹น์‹ ์€ Network Effects ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ๋„คํŠธ์›Œํฌ ๊ฐ€์น˜๋ฅผ ๊ทน๋Œ€ํ™”ํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
240
+
241
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
242
+ {
243
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
244
+ "network_type": "๋„คํŠธ์›Œํฌ ์œ ํ˜•",
245
+ "viral_coefficient": "๋ฐ”์ด๋Ÿด ๊ณ„์ˆ˜",
246
+ "sharing_ease": "๊ณต์œ  ์šฉ์ด์„ฑ",
247
+ "community_aspect": "์ปค๋ฎค๋‹ˆํ‹ฐ ์ธก๋ฉด",
248
+ "network_value": "๋„คํŠธ์›Œํฌ ๊ฐ€์น˜",
249
+ "slogan": "์Šฌ๋กœ๊ฑด"
250
+ }
251
+ """
252
+
253
+ # ===== 13. MEMETICS =====
254
+ MEMETICS_PROMPT = """
255
+ ๋‹น์‹ ์€ Memetics ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ๋ฌธํ™”์ ์œผ๋กœ ๋ณต์ œ๋˜๊ณ  ์ง„ํ™”ํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
256
+
257
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
258
  {
259
  "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
260
+ "meme_structure": "๋ฐˆ ๊ตฌ์กฐ",
261
+ "replication_ease": "๋ณต์ œ ์šฉ์ด์„ฑ",
262
+ "mutation_potential": "๋ณ€์ด ์ž ์žฌ๋ ฅ",
263
+ "cultural_fitness": "๋ฌธํ™”์  ์ ํ•ฉ๋„",
264
+ "transmission_channels": "์ „๋‹ฌ ์ฑ„๋„",
265
+ "slogan": "์Šฌ๋กœ๊ฑด"
 
 
 
 
 
 
 
 
 
 
266
  }
267
+ """
268
+
269
+ # ===== 14. COLOR PSYCHOLOGY =====
270
+ COLOR_PSYCHOLOGY_PROMPT = """
271
+ ๋‹น์‹ ์€ Color Psychology ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์ƒ‰์ƒ ์—ฐ์ƒ๊ณผ ๊ฐ์ •์„ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
272
 
273
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
274
+ {
275
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
276
+ "primary_color": "์ฃผ ์ƒ‰์ƒ",
277
+ "color_meaning": "์ƒ‰์ƒ ์˜๋ฏธ",
278
+ "emotional_response": "๊ฐ์ •์  ๋ฐ˜์‘",
279
+ "cultural_associations": "๋ฌธํ™”์  ์—ฐ์ƒ",
280
+ "industry_alignment": "์—…์ข… ์ •๋ ฌ",
281
+ "slogan": "์Šฌ๋กœ๊ฑด"
282
+ }
283
  """
284
 
285
+ # ===== 15. GESTALT PRINCIPLES =====
286
+ GESTALT_PROMPT = """
287
+ ๋‹น์‹ ์€ Gestalt Theory ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. ์ง€๊ฐ ์›๋ฆฌ๋ฅผ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
288
+
289
+ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ํ˜•์‹:
290
+ {
291
+ "brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
292
+ "gestalt_principle": "ํ™œ์šฉ ์›์น™",
293
+ "visual_structure": "์‹œ๊ฐ์  ๊ตฌ์กฐ",
294
+ "perceptual_grouping": "์ง€๊ฐ์  ๊ทธ๋ฃนํ™”",
295
+ "figure_ground": "์ „๊ฒฝ-๋ฐฐ๊ฒฝ ๊ด€๊ณ„",
296
+ "closure_effect": "ํ์‡„ ํšจ๊ณผ",
297
+ "slogan": "์Šฌ๋กœ๊ฑด"
298
+ }
 
 
 
 
 
 
 
 
 
299
  """
300
+
301
+ # ์ด๋ก ๋ณ„ ํ”„๋กฌํ”„ํŠธ ๋งคํ•‘
302
+ THEORY_PROMPTS = {
303
+ "square": SQUARE_THEORY_PROMPT,
304
+ "blending": CONCEPTUAL_BLENDING_PROMPT,
305
+ "sound": SOUND_SYMBOLISM_PROMPT,
306
+ "linguistic": LINGUISTIC_RELATIVITY_PROMPT,
307
+ "archetype": ARCHETYPE_THEORY_PROMPT,
308
+ "jobs": JOBS_TO_BE_DONE_PROMPT,
309
+ "scamper": SCAMPER_PROMPT,
310
+ "design": DESIGN_THINKING_PROMPT,
311
+ "biomimicry": BIOMIMICRY_PROMPT,
312
+ "cognitive": COGNITIVE_LOAD_PROMPT,
313
+ "vonrestorff": VON_RESTORFF_PROMPT,
314
+ "network": NETWORK_EFFECTS_PROMPT,
315
+ "memetics": MEMETICS_PROMPT,
316
+ "color": COLOR_PSYCHOLOGY_PROMPT,
317
+ "gestalt": GESTALT_PROMPT
318
+ }
319
+
320
+ def generate_by_theory(industry: str, keywords: str, theory: str, count: int = 3) -> Tuple[str, str]:
321
+ """ํŠน์ • ์ด๋ก ์œผ๋กœ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ"""
322
+
323
+ if not industry or not keywords:
324
+ return "โš ๏ธ ์—…์ข…๊ณผ ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.", ""
325
+
326
+ prompt = THEORY_PROMPTS.get(theory, SQUARE_THEORY_PROMPT)
327
+ user_input = f"์—…์ข…: {industry}\nํ‚ค์›Œ๋“œ: {keywords}\n\n์œ„ ์ •๋ณด๋กœ {count}๊ฐœ์˜ ๋ธŒ๋žœ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”."
328
 
329
  try:
330
  response = client.chat.completions.create(
331
+ model="gpt-4o-mini",
332
  messages=[
333
+ {"role": "system", "content": prompt},
334
+ {"role": "user", "content": user_input}
335
  ],
336
+ temperature=0.8,
337
+ max_tokens=2000,
338
  response_format={"type": "json_object"}
339
  )
340
 
 
343
 
344
  # ์‘๋‹ต ์ •๊ทœํ™”
345
  if isinstance(data, dict):
346
+ results = data.get("results", data.get("brands", [data]))
 
 
 
 
 
347
  else:
348
  results = data
349
 
350
+ if not isinstance(results, list):
351
+ results = [results]
352
+
353
+ # ๋งˆํฌ๋‹ค์šด ์ƒ์„ฑ
354
+ markdown = generate_theory_markdown(theory, results, industry, keywords)
355
 
356
+ # HTML ์‹œ๊ฐํ™” ์ƒ์„ฑ
357
+ html = generate_theory_visualization(theory, results)
358
+
359
+ return markdown, html
360
 
361
  except Exception as e:
362
+ return f"โŒ ์˜ค๋ฅ˜: {str(e)}", ""
363
+
364
+ def generate_theory_markdown(theory: str, results: List[Dict], industry: str, keywords: str) -> str:
365
+ """์ด๋ก ๋ณ„ ๋งž์ถค ๋งˆํฌ๋‹ค์šด ์ƒ์„ฑ"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
366
 
367
+ theory_names = {
368
+ "square": "Square Theory",
369
+ "blending": "Conceptual Blending",
370
+ "sound": "Sound Symbolism",
371
+ "linguistic": "Linguistic Relativity",
372
+ "archetype": "Archetype Theory",
373
+ "jobs": "Jobs-to-be-Done",
374
+ "scamper": "SCAMPER Method",
375
+ "design": "Design Thinking",
376
+ "biomimicry": "Biomimicry",
377
+ "cognitive": "Cognitive Load Theory",
378
+ "vonrestorff": "Von Restorff Effect",
379
+ "network": "Network Effects",
380
+ "memetics": "Memetics",
381
+ "color": "Color Psychology",
382
+ "gestalt": "Gestalt Principles"
383
+ }
384
 
385
+ markdown = f"""# ๐ŸŽฏ {theory_names[theory]} ๊ฒฐ๊ณผ
386
+ **์—…์ข…**: {industry} | **ํ‚ค์›Œ๋“œ**: {keywords}
387
+ *์ƒ์„ฑ ์‹œ๊ฐ: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*
388
+
389
+ ---
390
+ """
391
 
392
+ for idx, result in enumerate(results, 1):
393
+ brand_name = result.get('brand_name', 'N/A')
394
+ slogan = result.get('slogan', 'N/A')
395
 
396
+ markdown += f"\n## {idx}. {brand_name}\n"
397
+ markdown += f"**์Šฌ๋กœ๊ฑด**: *\"{slogan}\"*\n\n"
 
 
 
398
 
399
+ # ์ด๋ก ๋ณ„ ํŠน์ˆ˜ ํ•„๋“œ ํ‘œ์‹œ
400
+ if theory == "square":
401
+ markdown += f"""
402
+ ### Square ๊ตฌ์กฐ
403
+ ```
404
+ [{result.get('tl')}] โ”€({result.get('top_edge')})โ”€ [{result.get('tr')}]
405
+ โ”‚ โ”‚
406
+ ({result.get('left_edge')}) ({result.get('right_edge')})
407
+ โ”‚ โ”‚
408
+ [{result.get('bl')}] โ”€({result.get('bottom_edge')})โ”€ [{result.get('br')}]
409
+ ```
410
+ """
411
+ elif theory == "blending":
412
+ markdown += f"""
413
+ ### ๊ฐœ๋… ํ˜ผํ•ฉ
414
+ - **์ž…๋ ฅ ๊ณต๊ฐ„ 1**: {result.get('input_space1')}
415
+ - **์ž…๋ ฅ ๊ณต๊ฐ„ 2**: {result.get('input_space2')}
416
+ - **์ผ๋ฐ˜ ๊ณต๊ฐ„**: {result.get('generic_space')}
417
+ - **ํ˜ผํ•ฉ ๊ณต๊ฐ„**: {result.get('blended_space')}
418
+ - **์ฐฝ๋ฐœ์  ์†์„ฑ**: {result.get('emergent_properties')}
419
+ """
420
+ elif theory == "sound":
421
+ markdown += f"""
422
+ ### ์Œํ–ฅ ๋ถ„์„
423
+ - **์Œ์„ฑ ๋ถ„์„**: {result.get('phonetic_analysis')}
424
+ - **์Œํ–ฅ ์˜๋ฏธ**: {result.get('sound_meaning')}
425
+ - **๋ชฉํ‘œ ๊ฐ์ •**: {result.get('target_emotion')}
426
+ - **๋ฐœ์Œ ๊ฐ€์ด๋“œ**: {result.get('pronunciation_guide')}
427
+ """
428
+ elif theory == "archetype":
429
+ markdown += f"""
430
+ ### ์›ํ˜• ๋ถ„์„
431
+ - **์›ํ˜•**: {result.get('archetype')}
432
+ - **์›ํ˜• ํŠน์ง•**: {result.get('archetype_traits')}
433
+ - **๋ธŒ๋žœ๋“œ ์„ฑ๊ฒฉ**: {result.get('brand_personality')}
434
+ - **๋ชฉ์†Œ๋ฆฌ ํ†ค**: {result.get('voice_tone')}
435
+ """
436
+
437
+ # ์„ค๋ช… ์ถ”๊ฐ€
438
+ explanation = result.get('explanation', result.get('value_proposition', ''))
439
+ if explanation:
440
+ markdown += f"\n๐Ÿ’ก **ํ•ต์‹ฌ ๊ฐ€์น˜**: {explanation}\n"
441
 
442
+ markdown += "\n---\n"
443
+
444
+ return markdown
445
+
446
+ def generate_theory_visualization(theory: str, results: List[Dict]) -> str:
447
+ """์ด๋ก ๋ณ„ ๋งž์ถค ์‹œ๊ฐํ™” ์ƒ์„ฑ"""
448
+
449
+ html_parts = []
450
+
451
+ for idx, result in enumerate(results, 1):
452
+ if theory == "square":
453
+ html_parts.append(visualize_square_brand(result))
454
+ elif theory == "blending":
455
+ html_parts.append(visualize_conceptual_blend(result))
456
+ elif theory == "sound":
457
+ html_parts.append(visualize_sound_symbolism(result))
458
+ elif theory == "archetype":
459
+ html_parts.append(visualize_archetype(result))
460
+ elif theory == "color":
461
+ html_parts.append(visualize_color_psychology(result))
462
+ else:
463
+ html_parts.append(visualize_generic_brand(result, theory))
464
+
465
+ return "\n".join(html_parts)
466
+
467
+ # ์‹œ๊ฐํ™” ํ•จ์ˆ˜๋“ค (์ผ๋ถ€๋งŒ ์˜ˆ์‹œ)
468
+ def visualize_square_brand(brand: Dict) -> str:
469
+ """Square Theory ์‹œ๊ฐํ™”"""
470
+ return f"""
471
+ <div style="max-width: 700px; margin: 20px auto; font-family: -apple-system, sans-serif;">
472
+ <h2 style="text-align: center; color: #2c3e50;">{brand.get('brand_name', 'Brand')}</h2>
473
+ <p style="text-align: center; font-style: italic; color: #7f8c8d;">"{brand.get('slogan', '')}"</p>
474
+
475
+ <div style="position: relative; width: 100%; height: 300px; background: #f5f7fa; border-radius: 12px; padding: 30px;">
476
+ <!-- Square ๊ตฌ์กฐ ์‹œ๊ฐํ™” -->
477
+ <div style="position: absolute; top: 30px; left: 30px; background: #3498db; color: white; padding: 15px; border-radius: 8px;">
478
+ {brand.get('tl', '?')}
479
  </div>
480
+ <div style="position: absolute; top: 30px; right: 30px; background: #e74c3c; color: white; padding: 15px; border-radius: 8px;">
481
+ {brand.get('tr', '?')}
482
  </div>
483
+ <div style="position: absolute; bottom: 30px; left: 30px; background: #f39c12; color: white; padding: 15px; border-radius: 8px;">
484
+ {brand.get('bl', '?')}
485
  </div>
486
+ <div style="position: absolute; bottom: 30px; right: 30px; background: #27ae60; color: white; padding: 15px; border-radius: 8px;">
487
+ {brand.get('br', '?')}
488
  </div>
489
 
490
+ <!-- ๋ธŒ๋žœ๋“œ๋ช… ์ค‘์•™ -->
491
+ <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px 40px; border-radius: 12px; box-shadow: 0 5px 20px rgba(0,0,0,0.15);">
492
+ <div style="font-size: 1.8em; font-weight: bold; color: #2c3e50;">{brand.get('brand_name', 'Brand')}</div>
493
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
494
  </div>
495
+ </div>
496
+ """
497
+
498
+ def visualize_conceptual_blend(brand: Dict) -> str:
499
+ """Conceptual Blending ์‹œ๊ฐํ™”"""
500
+ return f"""
501
+ <div style="max-width: 700px; margin: 20px auto; font-family: -apple-system, sans-serif;">
502
+ <h2 style="text-align: center; color: #2c3e50;">{brand.get('brand_name', 'Brand')}</h2>
503
 
504
+ <div style="display: flex; justify-content: space-around; align-items: center; margin: 30px 0;">
505
+ <div style="text-align: center; padding: 20px; background: #3498db; color: white; border-radius: 50%; width: 120px; height: 120px; display: flex; align-items: center; justify-content: center;">
506
+ <div>
507
+ <strong>Input 1</strong><br>
508
+ {brand.get('input_space1', '')}
509
+ </div>
510
  </div>
511
+
512
+ <div style="font-size: 2em;">+</div>
513
+
514
+ <div style="text-align: center; padding: 20px; background: #e74c3c; color: white; border-radius: 50%; width: 120px; height: 120px; display: flex; align-items: center; justify-content: center;">
515
+ <div>
516
+ <strong>Input 2</strong><br>
517
+ {brand.get('input_space2', '')}
518
+ </div>
519
+ </div>
520
+
521
+ <div style="font-size: 2em;">=</div>
522
+
523
+ <div style="text-align: center; padding: 20px; background: #27ae60; color: white; border-radius: 50%; width: 150px; height: 150px; display: flex; align-items: center; justify-content: center;">
524
+ <div>
525
+ <strong>Blend</strong><br>
526
+ {brand.get('blended_space', '')}
527
+ </div>
528
  </div>
529
  </div>
530
 
531
+ <p style="text-align: center; font-style: italic;">"{brand.get('slogan', '')}"</p>
 
 
 
532
  </div>
533
  """
534
 
535
+ def visualize_sound_symbolism(brand: Dict) -> str:
536
+ """Sound Symbolism ์‹œ๊ฐํ™”"""
537
+ return f"""
538
+ <div style="max-width: 700px; margin: 20px auto; font-family: -apple-system, sans-serif;">
539
+ <h2 style="text-align: center; color: #2c3e50;">{brand.get('brand_name', 'Brand')}</h2>
540
 
541
+ <div style="background: #f8f9fa; padding: 30px; border-radius: 12px; text-align: center;">
542
+ <div style="font-size: 3em; letter-spacing: 0.2em; margin: 20px 0; color: #3498db;">
543
+ {brand.get('brand_name', 'BRAND')}
544
+ </div>
545
 
546
+ <div style="margin: 20px 0; padding: 15px; background: white; border-radius: 8px;">
547
+ <strong>์Œ์„ฑ ๋ถ„์„</strong><br>
548
+ {brand.get('phonetic_analysis', '')}
549
+ </div>
 
 
550
 
551
+ <div style="margin: 20px 0; padding: 15px; background: white; border-radius: 8px;">
552
+ <strong>์Œํ–ฅ์ด ์ „๋‹ฌํ•˜๋Š” ๊ฐ์ •</strong><br>
553
+ {brand.get('sound_meaning', '')}
554
+ </div>
555
 
556
+ <div style="margin: 20px 0; font-style: italic; color: #7f8c8d;">
557
+ ๋ฐœ์Œ: {brand.get('pronunciation_guide', '')}
558
+ </div>
559
+ </div>
560
+ </div>
561
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
562
 
563
+ def visualize_archetype(brand: Dict) -> str:
564
+ """Archetype Theory ์‹œ๊ฐํ™”"""
565
+ archetype_colors = {
566
+ "Hero": "#e74c3c",
567
+ "Creator": "#9b59b6",
568
+ "Sage": "#3498db",
569
+ "Explorer": "#1abc9c",
570
+ "Innocent": "#f1c40f",
571
+ "Jester": "#e67e22",
572
+ "Lover": "#e91e63",
573
+ "Caregiver": "#00bcd4",
574
+ "Ruler": "#795548",
575
+ "Magician": "#673ab7",
576
+ "Outlaw": "#212121",
577
+ "Regular Guy": "#607d8b"
578
+ }
579
+
580
+ archetype = brand.get('archetype', 'Hero')
581
+ color = archetype_colors.get(archetype, "#3498db")
582
+
583
+ return f"""
584
+ <div style="max-width: 700px; margin: 20px auto; font-family: -apple-system, sans-serif;">
585
+ <h2 style="text-align: center; color: {color};">{brand.get('brand_name', 'Brand')}</h2>
586
+
587
+ <div style="text-align: center; margin: 30px 0;">
588
+ <div style="display: inline-block; padding: 40px; background: {color}; color: white; border-radius: 50%; width: 200px; height: 200px;">
589
+ <h3 style="margin: 0;">{archetype}</h3>
590
+ <p style="margin: 10px 0; font-size: 0.9em;">{brand.get('archetype_traits', '')}</p>
591
+ </div>
592
+ </div>
593
+
594
+ <div style="background: #f8f9fa; padding: 20px; border-radius: 8px; margin: 20px 0;">
595
+ <p><strong>๋ธŒ๋žœ๋“œ ์„ฑ๊ฒฉ</strong>: {brand.get('brand_personality', '')}</p>
596
+ <p><strong>๋ชฉ์†Œ๋ฆฌ ํ†ค</strong>: {brand.get('voice_tone', '')}</p>
597
+ </div>
598
+
599
+ <p style="text-align: center; font-style: italic; font-size: 1.2em;">"{brand.get('slogan', '')}"</p>
600
+ </div>
601
+ """
602
 
603
+ def visualize_color_psychology(brand: Dict) -> str:
604
+ """Color Psychology ์‹œ๊ฐํ™”"""
605
+ color = brand.get('primary_color', '#3498db')
606
+
607
+ return f"""
608
+ <div style="max-width: 700px; margin: 20px auto; font-family: -apple-system, sans-serif;">
609
+ <h2 style="text-align: center; color: #2c3e50;">{brand.get('brand_name', 'Brand')}</h2>
610
+
611
+ <div style="text-align: center; margin: 30px 0;">
612
+ <div style="display: inline-block; width: 200px; height: 200px; background: {color}; border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.2);"></div>
613
+ </div>
614
+
615
+ <div style="background: #f8f9fa; padding: 20px; border-radius: 8px;">
616
+ <p><strong>์ฃผ ์ƒ‰์ƒ</strong>: {brand.get('primary_color', '')}</p>
617
+ <p><strong>์ƒ‰์ƒ ์˜๋ฏธ</strong>: {brand.get('color_meaning', '')}</p>
618
+ <p><strong>๊ฐ์ •์  ๋ฐ˜์‘</strong>: {brand.get('emotional_response', '')}</p>
619
+ <p><strong>๋ฌธํ™”์  ์—ฐ์ƒ</strong>: {brand.get('cultural_associations', '')}</p>
620
+ </div>
621
+
622
+ <p style="text-align: center; font-style: italic; margin-top: 20px;">"{brand.get('slogan', '')}"</p>
623
+ </div>
624
+ """
625
 
626
+ def visualize_generic_brand(brand: Dict, theory: str) -> str:
627
+ """์ผ๋ฐ˜์ ์ธ ๋ธŒ๋žœ๋“œ ์‹œ๊ฐํ™”"""
628
+ return f"""
629
+ <div style="max-width: 700px; margin: 20px auto; padding: 30px; background: #f8f9fa; border-radius: 12px; font-family: -apple-system, sans-serif;">
630
+ <h2 style="text-align: center; color: #2c3e50; margin-bottom: 10px;">{brand.get('brand_name', 'Brand')}</h2>
631
+ <p style="text-align: center; font-style: italic; color: #7f8c8d; margin-bottom: 30px;">"{brand.get('slogan', '')}"</p>
 
 
 
 
632
 
633
+ <div style="background: white; padding: 20px; border-radius: 8px;">
634
+ {json.dumps(brand, ensure_ascii=False, indent=2).replace('\\n', '<br>').replace(' ', '&nbsp;')}
635
+ </div>
636
+ </div>
637
+ """
638
 
639
  # Gradio UI
640
+ with gr.Blocks(title="Ultimate Brand Theory Generator", theme=gr.themes.Soft()) as demo:
641
  gr.Markdown("""
642
+ # ๐ŸŒŸ Ultimate Brand Theory Generator
643
+ ### 15๊ฐœ ์ด๋ก ์„ ํ™œ์šฉํ•œ ์ข…ํ•ฉ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ๊ธฐ
 
 
 
644
 
645
+ ํ•˜๋‚˜์˜ ์ž…๋ ฅ์œผ๋กœ 15๊ฐ€์ง€ ๋‹ค๋ฅธ ์ด๋ก ์— ๊ธฐ๋ฐ˜ํ•œ ๋ธŒ๋žœ๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
646
+ ๊ฐ ํƒญ์—์„œ ๊ฐ ์ด๋ก ์˜ ๊ณ ์œ ํ•œ ๊ด€์ ์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ๋ธŒ๋žœ๋“œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”!
647
  """)
648
 
649
  with gr.Row():
650
  with gr.Column(scale=2):
651
+ industry_input = gr.Textbox(
 
652
  label="๐Ÿญ ์—…์ข…",
653
+ placeholder="์˜ˆ: ์นดํŽ˜, ํ”ผํŠธ๋‹ˆ์Šค, ๊ต์œก, ๋ทฐํ‹ฐ...",
654
  value="์นดํŽ˜/์ปคํ”ผ์ˆ"
655
  )
656
 
 
660
  info="๋ธŒ๋žœ๋“œ๊ฐ€ ๋‹ด์•„์•ผ ํ•  ํ•ต์‹ฌ ๊ฐ€์น˜๋‚˜ ํŠน์ง•๋“ค"
661
  )
662
 
663
+ generate_btn = gr.Button("๐Ÿš€ ๋ชจ๋“  ์ด๋ก ์œผ๋กœ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ", variant="primary", size="lg")
 
 
 
 
 
 
 
 
664
 
665
  with gr.Column(scale=1):
666
  gr.Markdown("""
667
+ ### ๐Ÿ’ก 15๊ฐ€์ง€ ์ด๋ก  ๊ฐœ์š”
668
+
669
+ **๊ตฌ์กฐ์  ์ ‘๊ทผ**
670
+ - Square Theory: 4์š”์†Œ ์™„์„ฑ
671
+ - Conceptual Blending: ๊ฐœ๋… ํ˜ผํ•ฉ
672
+ - Gestalt: ์ง€๊ฐ ์›๋ฆฌ
673
+
674
+ **์–ธ์–ดํ•™์  ์ ‘๊ทผ**
675
+ - Sound Symbolism: ์Œํ–ฅ ์˜๋ฏธ
676
+ - Linguistic Relativity: ๋ฌธํ™” ์ ์‘
677
+ - Cognitive Load: ์ธ์ง€ ์ตœ์ ํ™”
678
+
679
+ **์‹ฌ๋ฆฌํ•™์  ์ ‘๊ทผ**
680
+ - Archetype: ์›ํ˜• ํ™œ์šฉ
681
+ - Color Psychology: ์ƒ‰์ƒ ์‹ฌ๋ฆฌ
682
+ - Von Restorff: ๋…ํŠน์„ฑ
683
 
684
+ **์ „๋žต์  ์ ‘๊ทผ**
685
+ - Jobs-to-be-Done: ๊ณ ๊ฐ ๊ณผ์—…
686
+ - SCAMPER: ์ฐฝ์˜์  ๋ณ€ํ˜•
687
+ - Design Thinking: ์ธ๊ฐ„์ค‘์‹ฌ
 
688
 
689
+ **์‹œ์Šคํ…œ์  ์ ‘๊ทผ**
690
+ - Network Effects: ๋„คํŠธ์›Œํฌ
691
+ - Memetics: ๋ฌธํ™” ์ „ํŒŒ
692
+ - Biomimicry: ์ž์—ฐ ๋ชจ๋ฐฉ
 
 
 
 
693
  """)
694
 
695
+ # 15๊ฐœ ํƒญ ์ƒ์„ฑ
 
 
696
  with gr.Tabs():
697
+ # 1. Square Theory
698
+ with gr.Tab("๐ŸŸฆ Square Theory"):
699
+ square_output = gr.Markdown()
700
+ square_visual = gr.HTML()
701
+
702
+ # 2. Conceptual Blending
703
+ with gr.Tab("๐Ÿ”€ Conceptual Blending"):
704
+ blending_output = gr.Markdown()
705
+ blending_visual = gr.HTML()
706
+
707
+ # 3. Sound Symbolism
708
+ with gr.Tab("๐Ÿ”Š Sound Symbolism"):
709
+ sound_output = gr.Markdown()
710
+ sound_visual = gr.HTML()
711
+
712
+ # 4. Linguistic Relativity
713
+ with gr.Tab("๐ŸŒ Linguistic Relativity"):
714
+ linguistic_output = gr.Markdown()
715
+ linguistic_visual = gr.HTML()
716
+
717
+ # 5. Archetype Theory
718
+ with gr.Tab("๐ŸŽญ Archetype Theory"):
719
+ archetype_output = gr.Markdown()
720
+ archetype_visual = gr.HTML()
721
+
722
+ # 6. Jobs-to-be-Done
723
+ with gr.Tab("โœ… Jobs-to-be-Done"):
724
+ jobs_output = gr.Markdown()
725
+ jobs_visual = gr.HTML()
726
+
727
+ # 7. SCAMPER
728
+ with gr.Tab("๐Ÿ”ง SCAMPER Method"):
729
+ scamper_output = gr.Markdown()
730
+ scamper_visual = gr.HTML()
731
 
732
+ # 8. Design Thinking
733
+ with gr.Tab("๐Ÿ’ญ Design Thinking"):
734
+ design_output = gr.Markdown()
735
+ design_visual = gr.HTML()
736
 
737
+ # 9. Biomimicry
738
+ with gr.Tab("๐ŸŒฟ Biomimicry"):
739
+ biomimicry_output = gr.Markdown()
740
+ biomimicry_visual = gr.HTML()
741
+
742
+ # 10. Cognitive Load
743
+ with gr.Tab("๐Ÿง  Cognitive Load"):
744
+ cognitive_output = gr.Markdown()
745
+ cognitive_visual = gr.HTML()
746
+
747
+ # 11. Von Restorff
748
+ with gr.Tab("โšก Von Restorff Effect"):
749
+ vonrestorff_output = gr.Markdown()
750
+ vonrestorff_visual = gr.HTML()
751
+
752
+ # 12. Network Effects
753
+ with gr.Tab("๐ŸŒ Network Effects"):
754
+ network_output = gr.Markdown()
755
+ network_visual = gr.HTML()
756
+
757
+ # 13. Memetics
758
+ with gr.Tab("๐Ÿงฌ Memetics"):
759
+ memetics_output = gr.Markdown()
760
+ memetics_visual = gr.HTML()
761
+
762
+ # 14. Color Psychology
763
+ with gr.Tab("๐ŸŽจ Color Psychology"):
764
+ color_output = gr.Markdown()
765
+ color_visual = gr.HTML()
766
+
767
+ # 15. Gestalt Principles
768
+ with gr.Tab("๐Ÿ‘๏ธ Gestalt Principles"):
769
+ gestalt_output = gr.Markdown()
770
+ gestalt_visual = gr.HTML()
771
+
772
+ # ๋ชจ๋“  ์ด๋ก  ๋™์‹œ ์ƒ์„ฑ ํ•จ์ˆ˜
773
+ def generate_all_theories(industry, keywords):
774
+ results = {}
775
+
776
+ theories = [
777
+ ("square", square_output, square_visual),
778
+ ("blending", blending_output, blending_visual),
779
+ ("sound", sound_output, sound_visual),
780
+ ("linguistic", linguistic_output, linguistic_visual),
781
+ ("archetype", archetype_output, archetype_visual),
782
+ ("jobs", jobs_output, jobs_visual),
783
+ ("scamper", scamper_output, scamper_visual),
784
+ ("design", design_output, design_visual),
785
+ ("biomimicry", biomimicry_output, biomimicry_visual),
786
+ ("cognitive", cognitive_output, cognitive_visual),
787
+ ("vonrestorff", vonrestorff_output, vonrestorff_visual),
788
+ ("network", network_output, network_visual),
789
+ ("memetics", memetics_output, memetics_visual),
790
+ ("color", color_output, color_visual),
791
+ ("gestalt", gestalt_output, gestalt_visual)
792
+ ]
793
+
794
+ outputs = []
795
+ for theory_key, md_output, html_output in theories:
796
+ md, html = generate_by_theory(industry, keywords, theory_key)
797
+ outputs.extend([md, html])
798
+
799
+ return outputs
800
+
801
+ # ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
802
+ generate_btn.click(
803
+ fn=generate_all_theories,
804
+ inputs=[industry_input, keywords_input],
805
+ outputs=[
806
+ square_output, square_visual,
807
+ blending_output, blending_visual,
808
+ sound_output, sound_visual,
809
+ linguistic_output, linguistic_visual,
810
+ archetype_output, archetype_visual,
811
+ jobs_output, jobs_visual,
812
+ scamper_output, scamper_visual,
813
+ design_output, design_visual,
814
+ biomimicry_output, biomimicry_visual,
815
+ cognitive_output, cognitive_visual,
816
+ vonrestorff_output, vonrestorff_visual,
817
+ network_output, network_visual,
818
+ memetics_output, memetics_visual,
819
+ color_output, color_visual,
820
+ gestalt_output, gestalt_visual
821
+ ]
822
+ )
823
 
 
824
  gr.Examples(
825
  examples=[
826
  ["์นดํŽ˜/์ปคํ”ผ์ˆ", "ํ”„๋ฆฌ๋ฏธ์—„, ์•„๋Š‘ํ•œ, ๋„์‹œ"],
 
832
  inputs=[industry_input, keywords_input]
833
  )
834
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
835
  gr.Markdown("""
836
  ---
837
+ ### ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ ํ™œ์šฉ ๊ฐ€์ด๋“œ
838
 
839
+ 1. **๋น„๊ต ๋ถ„์„**: ๊ฐ ์ด๋ก ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋น„๊ตํ•˜์—ฌ ๊ฐ€์žฅ ์ ํ•ฉํ•œ ๋ธŒ๋žœ๋“œ ์„ ํƒ
840
+ 2. **ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์ ‘๊ทผ**: ์—ฌ๋Ÿฌ ์ด๋ก ์˜ ์žฅ์ ์„ ๊ฒฐํ•ฉํ•œ ์ƒˆ๋กœ์šด ๋ธŒ๋žœ๋“œ ์ฐฝ์กฐ
841
+ 3. **ํƒ€๊ฒŸ๋ณ„ ์„ ํƒ**: ๋ชฉํ‘œ ๊ณ ๊ฐ์ธต์— ๋”ฐ๋ผ ๊ฐ€์žฅ ํšจ๊ณผ์ ์ธ ์ด๋ก  ์„ ํƒ
842
+ 4. **A/B ํ…Œ์ŠคํŠธ**: ๋‹ค์–‘ํ•œ ์ด๋ก  ๊ธฐ๋ฐ˜ ๋ธŒ๋žœ๋“œ๋กœ ์‹œ์žฅ ํ…Œ์ŠคํŠธ
843
 
844
+ ### ๐Ÿ“š ๊ฐ ์ด๋ก ์˜ ๊ฐ•์ 
845
 
846
+ - **์ฆ‰๊ฐ์  ์ดํ•ด**: Cognitive Load, Sound Symbolism
847
+ - **๊ฐ์ •์  ์—ฐ๊ฒฐ**: Archetype, Color Psychology
848
+ - **์ฐจ๋ณ„ํ™”**: Von Restorff, SCAMPER
849
+ - **๋ฐ”์ด๋Ÿด ์ž ์žฌ๋ ฅ**: Memetics, Network Effects
850
+ - **๋ฌธ์ œ ํ•ด๊ฒฐ**: Jobs-to-be-Done, Design Thinking
851
+ - **ํ˜์‹ ์„ฑ**: Biomimicry, Conceptual Blending
852
+ - **๊ตฌ์กฐ์  ์™„์„ฑ๋„**: Square Theory, Gestalt
853
  """)
854
 
855
  if __name__ == "__main__":