openfree commited on
Commit
f5376bd
ยท
verified ยท
1 Parent(s): 0d73e49

Delete app-backup.py

Browse files
Files changed (1) hide show
  1. app-backup.py +0 -436
app-backup.py DELETED
@@ -1,436 +0,0 @@
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
12
- import json
13
- import gradio as gr
14
- 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"):
21
- raise EnvironmentError("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
-
104
- content = response.choices[0].message.content
105
- data = json.loads(content)
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
-
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__":
432
- demo.launch(
433
- server_name="0.0.0.0",
434
- server_port=7860,
435
- share=False
436
- )