openfree commited on
Commit
5edac77
ยท
verified ยท
1 Parent(s): 72e4fd8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +274 -151
app.py CHANGED
@@ -1,11 +1,11 @@
1
  """
2
- Square Theory Generator - True Implementation
3
- ============================================
4
- 2025-05-28 | Based on the actual Square Theory concept
5
- ------------------------------------------------------
6
 
7
- Square Theory: 4๊ฐœ์˜ ๋‹จ์–ด๊ฐ€ ์˜๋ฏธ์  ๊ด€๊ณ„๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์‚ฌ๊ฐํ˜•์„ ์ด๋ฃจ๋Š” ์–ธ์–ด์œ ํฌ
8
- ์˜ˆ: PUB QUIZ / BAR EXAM (PUB-BAR ๋™์˜์–ด, QUIZ-EXAM ๋™์˜์–ด)
9
  """
10
 
11
  import os
@@ -22,63 +22,82 @@ if not os.getenv("OPENAI_API_KEY"):
22
 
23
  client = OpenAI()
24
 
25
- # Square Theory ์ „์šฉ ํ”„๋กฌํ”„ํŠธ
26
- SQUARE_THEORY_PROMPT = """
27
- ๋‹น์‹ ์€ Square Theory ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. Square Theory๋Š” 4๊ฐœ์˜ ๋‹จ์–ด๊ฐ€ ์‚ฌ๊ฐํ˜•์˜ ๊ผญ์ง“์ ์„ ์ด๋ฃจ๊ณ ,
28
- ๊ฐ ๋ณ€์ด ์˜๋ฏธ์  ๊ด€๊ณ„(๋™์˜์–ด, ๊ตฌ๋ฌธ, ์šด์œจ ๋“ฑ)๋กœ ์—ฐ๊ฒฐ๋˜๋Š” ์–ธ์–ด ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
29
 
30
- ํ•ต์‹ฌ ์›์น™:
31
- 1. 4๊ฐœ์˜ ๋‹จ์–ด๊ฐ€ ์‚ฌ๊ฐํ˜•์˜ ๊ผญ์ง“์ ์„ ํ˜•์„ฑ
32
- 2. ์ธ์ ‘ํ•œ ๋‹จ์–ด๋“ค์€ ํŠน์ • ๊ด€๊ณ„๋กœ ์—ฐ๊ฒฐ (๋ณ€)
33
- 3. ๋Œ€๋ณ€์˜ ๋‹จ์–ด๋“ค์€ ์ง์ ‘ ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์ง€๋งŒ, ๋‹ค๋ฅธ ๋ณ€๋“ค์„ ํ†ตํ•ด ๋†€๋ผ์šด ์ผ์น˜๋ฅผ ์ด๋ฃธ
34
- 4. ์ „์ฒด ๊ตฌ์กฐ๊ฐ€ "์•„ํ•˜!" ๋ชจ๋จผํŠธ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•จ
35
 
36
- ์˜ˆ์‹œ:
37
- - PUB QUIZ / BAR EXAM: PUB-BAR(๋™์˜์–ด), QUIZ-EXAM(๋™์˜์–ด), PUB QUIZ(๊ตฌ๋ฌธ), BAR EXAM(๊ตฌ๋ฌธ)
38
- - BOOTY CALL / BUTT DIAL: BOOTY-BUTT(๋™์˜์–ด), CALL-DIAL(๋™์˜์–ด), BOOTY CALL(๊ตฌ๋ฌธ), BUTT DIAL(๊ตฌ๋ฌธ)
39
- - TOP GUN / TSHIRT CANNON: TOP-TSHIRT(์œ„์น˜), GUN-CANNON(๋ฌด๊ธฐ), TOP GUN(๊ตฌ๋ฌธ), TSHIRT CANNON(๊ตฌ๋ฌธ)
40
 
41
- ์‚ฌ์šฉ์ž๊ฐ€ ์‹œ๋“œ ๋‹จ์–ด๋‚˜ ์ปจ์…‰์„ ์ œ๊ณตํ•˜๋ฉด, ์ด๋ฅผ ํฌํ•จํ•˜๋Š” Square Theory ๊ตฌ์กฐ๋“ค์„ ์ƒ์„ฑํ•˜์„ธ์š”.
 
 
 
 
42
 
43
- ๊ฐ ์ œ์•ˆ์€ ๋‹ค์Œ ํ˜•์‹์˜ JSON์œผ๋กœ:
44
  {
 
 
45
  "tl": "์™ผ์ชฝ์ƒ๋‹จ ๋‹จ์–ด",
46
  "tr": "์˜ค๋ฅธ์ชฝ์ƒ๋‹จ ๋‹จ์–ด",
47
  "bl": "์™ผ์ชฝํ•˜๋‹จ ๋‹จ์–ด",
48
  "br": "์˜ค๋ฅธ์ชฝํ•˜๋‹จ ๋‹จ์–ด",
49
- "top_edge": "์ƒ๋‹จ ๊ด€๊ณ„ ์„ค๋ช… (tl-tr)",
50
- "bottom_edge": "ํ•˜๋‹จ ๊ด€๊ณ„ ์„ค๋ช… (bl-br)",
51
- "left_edge": "์™ผ์ชฝ ๊ด€๊ณ„ ์„ค๋ช… (tl-bl)",
52
- "right_edge": "์˜ค๋ฅธ์ชฝ ๊ด€๊ณ„ ์„ค๋ช… (tr-br)",
53
- "top_phrase": "tl + tr ๊ตฌ๋ฌธ",
54
- "bottom_phrase": "bl + br ๊ตฌ๋ฌธ",
55
- "explanation": "์™œ ์ด ์‚ฌ๊ฐํ˜•์ด ํฅ๋ฏธ๋กœ์šด์ง€",
56
- "cleverness_score": 1-10
 
 
 
57
  }
58
 
59
- ์ฐฝ์˜์ ์ด๊ณ  ๋†€๋ผ์šด ์—ฐ๊ฒฐ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ๋‹จ์ˆœํ•œ ๋™์˜์–ด ๋‚˜์—ด์ด ์•„๋‹Œ,
60
- ๋Œ€๋ณ€ ์‚ฌ์ด์˜ ์ˆจ๊ฒจ์ง„ ์—ฐ๊ฒฐ์ด ๋“œ๋Ÿฌ๋‚  ๋•Œ์˜ "์•„ํ•˜!" ๋ชจ๋จผํŠธ๋ฅผ ๋ชฉํ‘œ๋กœ ํ•˜์„ธ์š”.
61
  """
62
 
63
- def call_square_theory_llm(seed: str, mode: str = "word") -> List[Dict]:
64
- """Square Theory ์ƒ์„ฑ"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
- if mode == "word":
67
- user_prompt = f"์‹œ๋“œ ๋‹จ์–ด '{seed}'๋ฅผ ํฌํ•จํ•˜๋Š” Square Theory ๊ตฌ์กฐ๋ฅผ 5-10๊ฐœ ์ƒ์„ฑํ•˜์„ธ์š”."
68
- elif mode == "concept":
69
- user_prompt = f"'{seed}' ์ฃผ์ œ์™€ ๊ด€๋ จ๋œ Square Theory ๊ตฌ์กฐ๋ฅผ 5-10๊ฐœ ์ƒ์„ฑํ•˜์„ธ์š”."
70
- else: # pair
71
- user_prompt = f"'{seed}'์™€ ๋น„์Šทํ•œ ํ˜•ํƒœ์˜ Square Theory ๊ตฌ์กฐ๋ฅผ 5-10๊ฐœ ์ƒ์„ฑํ•˜์„ธ์š”."
 
72
 
73
  try:
74
  response = client.chat.completions.create(
75
  model="gpt-4o",
76
  messages=[
77
- {"role": "system", "content": SQUARE_THEORY_PROMPT},
78
  {"role": "user", "content": user_prompt}
79
  ],
80
- temperature=0.8,
81
- max_tokens=3000,
82
  response_format={"type": "json_object"}
83
  )
84
 
@@ -87,8 +106,8 @@ def call_square_theory_llm(seed: str, mode: str = "word") -> List[Dict]:
87
 
88
  # ์‘๋‹ต ์ •๊ทœํ™”
89
  if isinstance(data, dict):
90
- if "squares" in data:
91
- results = data["squares"]
92
  elif "results" in data:
93
  results = data["results"]
94
  else:
@@ -97,212 +116,316 @@ def call_square_theory_llm(seed: str, mode: str = "word") -> List[Dict]:
97
  results = data
98
 
99
  # ์ ์ˆ˜์ˆœ ์ •๋ ฌ
100
- results.sort(key=lambda x: x.get("cleverness_score", 0), reverse=True)
101
 
102
- return results[:10]
103
 
104
  except Exception as e:
105
- raise RuntimeError(f"Square Theory ์ƒ์„ฑ ์‹คํŒจ: {e}")
106
 
107
- def visualize_square(square: Dict) -> str:
108
- """Square Theory ์‹œ๊ฐํ™”"""
109
 
110
- tl, tr = square.get('tl', '?'), square.get('tr', '?')
111
- bl, br = square.get('bl', '?'), square.get('br', '?')
 
112
 
113
- top_edge = square.get('top_edge', '๊ด€๊ณ„')
114
- bottom_edge = square.get('bottom_edge', '๊ด€๊ณ„')
115
- left_edge = square.get('left_edge', '๊ด€๊ณ„')
116
- right_edge = square.get('right_edge', '๊ด€๊ณ„')
 
 
 
 
 
 
117
 
118
  return f"""
119
- <div style="max-width: 600px; margin: 20px auto; font-family: 'Courier New', monospace;">
120
- <div style="position: relative; width: 100%; height: 300px; background: #f8f9fa; border-radius: 8px; padding: 20px;">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
- <!-- ๊ผญ์ง“์  (๋‹จ์–ด๋“ค) -->
123
- <div style="position: absolute; top: 20px; left: 20px; background: #3498db; color: white; padding: 15px 25px; border-radius: 8px; font-weight: bold; font-size: 1.2em; box-shadow: 0 2px 4px rgba(0,0,0,0.2);">
124
  {tl}
125
  </div>
126
- <div style="position: absolute; top: 20px; right: 20px; background: #e74c3c; color: white; padding: 15px 25px; border-radius: 8px; font-weight: bold; font-size: 1.2em; box-shadow: 0 2px 4px rgba(0,0,0,0.2);">
127
  {tr}
128
  </div>
129
- <div style="position: absolute; bottom: 20px; left: 20px; background: #f39c12; color: white; padding: 15px 25px; border-radius: 8px; font-weight: bold; font-size: 1.2em; box-shadow: 0 2px 4px rgba(0,0,0,0.2);">
130
  {bl}
131
  </div>
132
- <div style="position: absolute; bottom: 20px; right: 20px; background: #27ae60; color: white; padding: 15px 25px; border-radius: 8px; font-weight: bold; font-size: 1.2em; box-shadow: 0 2px 4px rgba(0,0,0,0.2);">
133
  {br}
134
  </div>
135
 
136
- <!-- ๋ณ€ (๊ด€๊ณ„) -->
137
- <div style="position: absolute; top: 40px; left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.8); color: white; padding: 5px 15px; border-radius: 4px; font-size: 0.9em;">
138
- {top_edge}
139
  </div>
140
- <div style="position: absolute; bottom: 40px; left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.8); color: white; padding: 5px 15px; border-radius: 4px; font-size: 0.9em;">
141
- {bottom_edge}
142
  </div>
143
- <div style="position: absolute; top: 50%; left: 40px; transform: translateY(-50%) rotate(-90deg); background: rgba(0,0,0,0.8); color: white; padding: 5px 15px; border-radius: 4px; font-size: 0.9em;">
144
- {left_edge}
145
  </div>
146
- <div style="position: absolute; top: 50%; right: 40px; transform: translateY(-50%) rotate(90deg); background: rgba(0,0,0,0.8); color: white; padding: 5px 15px; border-radius: 4px; font-size: 0.9em;">
147
- {right_edge}
148
  </div>
149
 
150
  <!-- ์—ฐ๊ฒฐ์„  -->
151
  <svg style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none;">
 
 
 
 
 
 
 
 
 
 
152
  <!-- ์ƒ๋‹จ -->
153
- <line x1="80" y1="40" x2="520" y2="40" stroke="#666" stroke-width="2" stroke-dasharray="5,5"/>
154
  <!-- ํ•˜๋‹จ -->
155
- <line x1="80" y1="260" x2="520" y2="260" stroke="#666" stroke-width="2" stroke-dasharray="5,5"/>
156
  <!-- ์™ผ์ชฝ -->
157
- <line x1="50" y1="70" x2="50" y2="230" stroke="#666" stroke-width="2" stroke-dasharray="5,5"/>
158
  <!-- ์˜ค๋ฅธ์ชฝ -->
159
- <line x1="550" y1="70" x2="550" y2="230" stroke="#666" stroke-width="2" stroke-dasharray="5,5"/>
160
  </svg>
161
  </div>
162
 
163
- <div style="margin-top: 20px; padding: 20px; background: #ecf0f1; border-radius: 8px;">
164
- <p style="margin: 5px 0;"><strong>์ƒ๋‹จ ๊ตฌ๋ฌธ:</strong> {square.get('top_phrase', 'N/A')}</p>
165
- <p style="margin: 5px 0;"><strong>ํ•˜๋‹จ ๊ตฌ๋ฌธ:</strong> {square.get('bottom_phrase', 'N/A')}</p>
166
- <p style="margin: 15px 0 5px 0; font-style: italic; color: #7f8c8d;">๐Ÿ’ก {square.get('explanation', '')}</p>
 
 
 
 
 
 
 
 
 
 
 
167
  </div>
168
  </div>
169
  """
170
 
171
- def generate_squares(user_input: str, mode: str) -> Tuple[str, str]:
172
- """Square Theory ์ƒ์„ฑ ๋ฐ ํ‘œ์‹œ"""
 
 
 
173
 
174
  try:
175
- squares = call_square_theory_llm(user_input, mode)
176
-
177
- if not squares:
178
- return "Square๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.", ""
179
 
180
  # ๋งˆํฌ๋‹ค์šด ๊ฒฐ๊ณผ
181
  markdown_parts = [
182
- f"# ๐ŸŸฆ Square Theory ๊ฒฐ๊ณผ",
183
- f"**์ž…๋ ฅ**: {user_input} ({mode} ๋ชจ๋“œ)\n"
 
184
  ]
185
 
186
  # HTML ์‹œ๊ฐํ™”
187
  html_parts = []
188
 
189
- for idx, square in enumerate(squares, 1):
190
- score = square.get('cleverness_score', 0)
191
 
192
  markdown_parts.append(f"""
193
- ### {idx}. {square.get('top_phrase', '?')} / {square.get('bottom_phrase', '?')} {'โญ' * min(score, 5)}
194
 
195
- **๊ตฌ์กฐ**:
 
 
 
196
  ```
197
- [{square.get('tl', '?')}] โ”€({square.get('top_edge', '?')})โ”€ [{square.get('tr', '?')}]
198
- โ”‚ โ”‚
199
- ({square.get('left_edge', '?')}) ({square.get('right_edge', '?')})
200
- โ”‚ โ”‚
201
- [{square.get('bl', '?')}] โ”€({square.get('bottom_edge', '?')})โ”€ [{square.get('br', '?')}]
202
  ```
203
 
204
- **์„ค๋ช…**: {square.get('explanation', 'N/A')}
 
 
 
 
205
 
206
  ---
207
  """)
208
 
209
- # ์ƒ์œ„ 5๊ฐœ ์‹œ๊ฐํ™”
210
- if idx <= 5:
211
- html_parts.append(visualize_square(square))
212
 
213
- return "\n".join(markdown_parts), "\n".join(html_parts)
214
 
215
  except Exception as e:
216
- return f"โŒ ์˜ค๋ฅ˜: {str(e)}", ""
 
 
 
 
 
 
 
 
 
 
 
 
 
217
 
218
  # Gradio UI
219
- with gr.Blocks(title="Square Theory Generator", theme=gr.themes.Soft()) as demo:
220
  gr.Markdown("""
221
- # ๐ŸŸฆ Square Theory Generator
222
- ### ์˜๋ฏธ์  ๊ด€๊ณ„๋กœ ์—ฐ๊ฒฐ๋œ 4๋‹จ์–ด ์‚ฌ๊ฐํ˜• ๊ตฌ์กฐ ์ƒ์„ฑ๊ธฐ
223
 
224
- [Square Theory](https://www.lesswrong.com/posts/square-theory)๋Š” 4๊ฐœ์˜ ๋‹จ์–ด๊ฐ€ ์˜๋ฏธ์  ๊ด€๊ณ„๋กœ
225
- ์—ฐ๊ฒฐ๋˜์–ด ์‚ฌ๊ฐํ˜•์„ ์ด๋ฃจ๋Š” ์–ธ์–ด ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
226
 
227
- **์˜ˆ์‹œ**: PUB QUIZ / BAR EXAM
228
- - PUB โ†” BAR (๋™์˜์–ด)
229
- - QUIZ โ†” EXAM (๋™์˜์–ด)
230
- - PUB QUIZ (๊ตฌ๋ฌธ)
231
- - BAR EXAM (๊ตฌ๋ฌธ)
232
  """)
233
 
234
  with gr.Row():
235
  with gr.Column(scale=2):
236
- input_text = gr.Textbox(
237
- label="์ž…๋ ฅ",
238
- placeholder="๋‹จ์–ด, ๊ฐœ๋…, ๋˜๋Š” ์˜ˆ์‹œ ์ž…๋ ฅ...",
239
- lines=1
 
 
 
 
 
 
 
240
  )
241
 
242
- mode_radio = gr.Radio(
243
- choices=[
244
- ("๋‹จ์–ด ํฌํ•จ", "word"),
245
- ("์ฃผ์ œ ๊ด€๋ จ", "concept"),
246
- ("์œ ์‚ฌ ํŒจํ„ด", "pair")
247
- ],
248
- label="์ƒ์„ฑ ๋ชจ๋“œ",
249
- value="word"
250
  )
251
 
252
- generate_btn = gr.Button("๐Ÿ”ฒ Square ์ƒ์„ฑ", variant="primary")
253
 
254
  with gr.Column(scale=1):
255
  gr.Markdown("""
256
- ### ๐Ÿ’ก ์‚ฌ์šฉ๋ฒ•
257
-
258
- **๋‹จ์–ด ํฌํ•จ**: ํŠน์ • ๋‹จ์–ด๋ฅผ ํฌํ•จํ•˜๋Š” Square
259
- - ์˜ˆ: "BLACK" โ†’ JET BLACK / JETBLUE
260
 
261
- **์ฃผ์ œ ๊ด€๋ จ**: ํŠน์ • ์ฃผ์ œ์˜ Square
262
- - ์˜ˆ: "์Œ์‹" โ†’ ๊ด€๋ จ Square๋“ค
 
 
 
263
 
264
- **์œ ์‚ฌ ํŒจํ„ด**: ์˜ˆ์‹œ์™€ ๋น„์Šทํ•œ Square
265
- - ์˜ˆ: "PUB QUIZ / BAR EXAM"
 
 
 
 
 
 
266
  """)
267
 
 
 
 
268
  with gr.Tabs():
269
- with gr.Tab("๐Ÿ“ ๊ฒฐ๊ณผ"):
270
  output_markdown = gr.Markdown()
271
 
272
- with gr.Tab("๐ŸŽจ ์‹œ๊ฐํ™”"):
273
  output_visual = gr.HTML()
 
 
 
 
274
 
275
  # ์˜ˆ์‹œ
276
  gr.Examples(
277
  examples=[
278
- ["BLACK", "word"],
279
- ["์Œ์‹", "concept"],
280
- ["PUB QUIZ / BAR EXAM", "pair"],
281
- ["CALL", "word"],
282
- ["๋ธŒ๋žœ๋“œ", "concept"]
283
  ],
284
- inputs=[input_text, mode_radio]
285
  )
286
 
287
  # ์ด๋ฒคํŠธ ์—ฐ๏ฟฝ๏ฟฝ
 
 
 
 
288
  generate_btn.click(
289
- fn=generate_squares,
290
- inputs=[input_text, mode_radio],
291
- outputs=[output_markdown, output_visual]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  )
293
 
294
  gr.Markdown("""
295
  ---
296
- ### ๐Ÿ“š Square Theory๋ž€?
297
 
298
- Square Theory๋Š” ์–ธ์–ด์˜ ์˜๋ฏธ์  ๊ด€๊ณ„๋ฅผ ์‚ฌ๊ฐํ˜• ๊ตฌ์กฐ๋กœ ํ‘œํ˜„ํ•˜๋Š” ๊ฐœ๋…์ž…๋‹ˆ๋‹ค.
299
- ์ข‹์€ Square๋Š” ๋‹ค์Œ ํŠน์ง•์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค:
 
 
300
 
301
- 1. **์™„์„ฑ๋„**: 4๊ฐœ ๋ณ€์ด ๋ชจ๋‘ ์˜๋ฏธ์žˆ๋Š” ๊ด€๊ณ„
302
- 2. **๋†€๋ผ์›€**: ๋Œ€๋ณ€ ์—ฐ๊ฒฐ์ด ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ํ†ต์ฐฐ ์ œ๊ณต
303
- 3. **๊ท ํ˜•**: ๋ชจ๋“  ๊ด€๊ณ„๊ฐ€ ๋น„์Šทํ•œ ๊ฐ•๋„
304
 
305
- ์ด๋Š” ๋ง์žฅ๋‚œ, ๋ธŒ๋žœ๋“œ ๋„ค์ด๋ฐ, ํฌ๋กœ์Šค์›Œ๋“œ ํผ์ฆ ๋“ฑ์—์„œ ์ž์ฃผ ๋ฐœ๊ฒฌ๋ฉ๋‹ˆ๋‹ค.
 
 
 
 
306
  """)
307
 
308
  if __name__ == "__main__":
 
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
 
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
 
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:
 
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
+
322
+ keywords_input = gr.Textbox(
323
+ label="๐Ÿ”‘ ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ",
324
+ placeholder="ํ”„๋ฆฌ๋ฏธ์—„, ํŽธ์•ˆํ•œ, ๋„์‹œ์ ์ธ, ์นœํ™˜๊ฒฝ...",
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
+ ["์นดํŽ˜/์ปคํ”ผ์ˆ", "ํ”„๋ฆฌ๋ฏธ์—„, ์•„๋Š‘ํ•œ, ๋„์‹œ"],
376
+ ["ํ”ผํŠธ๋‹ˆ์Šค/ํ—ฌ์Šค์žฅ", "๊ฐ•๋ ฅํ•œ, ์ปค๋ฎค๋‹ˆํ‹ฐ, ๋ณ€ํ™”"],
377
+ ["๊ต์œก/์—๋“€ํ…Œํฌ", "์Šค๋งˆํŠธ, ์žฌ๋ฏธ์žˆ๋Š”, ์„ฑ์žฅ"],
378
+ ["์Œ์‹ ๋ฐฐ๋‹ฌ", "๋น ๋ฅธ, ์‹ ์„ ํ•œ, ๋‹ค์–‘ํ•œ"],
379
+ ["์นœํ™˜๊ฒฝ/์ง€์†๊ฐ€๋Šฅ", "์ž์—ฐ, ๋ฏธ๋ž˜, ์ˆœํ™˜"]
380
  ],
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__":