Naming / app-backup.py
openfree's picture
Create app-backup.py
56acaac verified
raw
history blame
17.9 kB
"""
Square Theory Brand Generator
=============================
2025-05-28 | Square Theory๋ฅผ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ ๋„ค์ด๋ฐ & ์Šฌ๋กœ๊ฑด ์ƒ์„ฑ๊ธฐ
----------------------------------------------------------
Square Theory๋ฅผ ๋ธŒ๋žœ๋”ฉ์— ์ ์šฉ: ๋ธŒ๋žœ๋“œ๋ช…์ด Square๋ฅผ ์™„์„ฑํ•˜๋Š” ๊ตฌ์กฐ
์˜ˆ: GRUBHUB = GRUB(์Œ์‹) + HUB(์ค‘์‹ฌ) โ†’ ์Œ์‹ ๋ฐฐ๋‹ฌ์˜ ์ค‘์‹ฌ
"""
import os
import json
import gradio as gr
import openai
from openai import OpenAI
from datetime import datetime
from typing import List, Dict, Tuple, Optional
# OpenAI ํด๋ผ์ด์–ธํŠธ
if not os.getenv("OPENAI_API_KEY"):
raise EnvironmentError("OPENAI_API_KEY ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜์„ธ์š”.")
client = OpenAI()
# Square Theory ๋ธŒ๋žœ๋”ฉ ์ „์šฉ ํ”„๋กฌํ”„ํŠธ
BRANDING_SQUARE_PROMPT = """
๋‹น์‹ ์€ Square Theory๋ฅผ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ ๋„ค์ด๋ฐ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
Square Theory๋Š” 4๊ฐœ์˜ ๋‹จ์–ด๊ฐ€ ์˜๋ฏธ์  ๊ด€๊ณ„๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์‚ฌ๊ฐํ˜•์„ ์ด๋ฃจ๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
์ด๋ฅผ ๋ธŒ๋žœ๋”ฉ์— ์ ์šฉํ•˜๋ฉด, ๋ธŒ๋žœ๋“œ๋ช…์ด Square๋ฅผ ์™„์„ฑํ•˜๋ฉฐ "์•„ํ•˜!" ๋ชจ๋จผํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
์„ฑ๊ณต์ ์ธ ๋ธŒ๋žœ๋“œ Square ์˜ˆ์‹œ:
1. GRUBHUB: GRUB(์Œ์‹) + HUB(์ค‘์‹ฌ) = ์Œ์‹ ๋ฐฐ๋‹ฌ์˜ ์ค‘์‹ฌ์ง€
2. Brand New (๋ฆฌ๋ธŒ๋žœ๋”ฉ ๋ธ”๋กœ๊ทธ): BRAND + NEW = ์ƒˆ๋กœ์šด ๋ธŒ๋žœ๋“œ = ์—…๋ฐ์ดํŠธ๋œ ๋ธŒ๋žœ๋“œ
3. Crosscord: CROSSWORD + DISCORD = ํฌ๋กœ์Šค์›Œ๋“œ ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋ฒ„
๋ธŒ๋žœ๋“œ Square ์ƒ์„ฑ ์›์น™:
1. ๋ธŒ๋žœ๋“œ๋ช…์€ ๋‘ ๋‹จ์–ด์˜ ์กฐํ•ฉ (ํ•ฉ์„ฑ์–ด, ํฌํŠธ๋งจํ† , ๋˜๋Š” ๊ตฌ๋ฌธ)
2. ๊ฐ ๋‹จ์–ด๋Š” ๋น„์ฆˆ๋‹ˆ์Šค์˜ ํ•ต์‹ฌ ์†์„ฑ๊ณผ ์—ฐ๊ฒฐ
3. ์ „์ฒด Square๊ฐ€ ๋ธŒ๋žœ๋“œ์˜ ์ •์ฒด์„ฑ์„ ๊ฐ•ํ™”
4. ์Šฌ๋กœ๊ฑด์€ Square์˜ ์˜๋ฏธ๋ฅผ ํ™•์žฅ
์‚ฌ์šฉ์ž ์ž…๋ ฅ(์—…์ข…/ํ‚ค์›Œ๋“œ)์„ ๋ฐ›์•„ ๋‹ค์Œ ํ˜•์‹์˜ JSON ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜์„ธ์š”:
{
"brand_name": "๋ธŒ๋žœ๋“œ๋ช…",
"brand_type": "compound/portmanteau/phrase",
"tl": "์™ผ์ชฝ์ƒ๋‹จ ๋‹จ์–ด",
"tr": "์˜ค๋ฅธ์ชฝ์ƒ๋‹จ ๋‹จ์–ด",
"bl": "์™ผ์ชฝํ•˜๋‹จ ๋‹จ์–ด",
"br": "์˜ค๋ฅธ์ชฝํ•˜๋‹จ ๋‹จ์–ด",
"top_edge": "์ƒ๋‹จ ๊ด€๊ณ„",
"bottom_edge": "ํ•˜๋‹จ ๊ด€๊ณ„",
"left_edge": "์™ผ์ชฝ ๊ด€๊ณ„",
"right_edge": "์˜ค๋ฅธ์ชฝ ๊ด€๊ณ„",
"slogan": "๋ธŒ๋žœ๋“œ ์Šฌ๋กœ๊ฑด",
"tagline": "์งง์€ ํƒœ๊ทธ๋ผ์ธ",
"business_description": "๋น„์ฆˆ๋‹ˆ์Šค ์„ค๋ช…",
"why_it_works": "์™œ ์ด Square๊ฐ€ ํšจ๊ณผ์ ์ธ์ง€",
"target_audience": "ํƒ€๊ฒŸ ๊ณ ๊ฐ",
"brand_personality": "๋ธŒ๋žœ๋“œ ๊ฐœ์„ฑ",
"impact_score": 1-10
}
์ฐฝ์˜์ ์ด๋ฉด์„œ๋„ ๊ธฐ์–ตํ•˜๊ธฐ ์‰ฝ๊ณ , ๋น„์ฆˆ๋‹ˆ์Šค ๋ณธ์งˆ์„ ๋‹ด์€ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“œ์„ธ์š”.
"""
# ์—…์ข…๋ณ„ ์˜ˆ์‹œ
INDUSTRY_EXAMPLES = [
"์นดํŽ˜/์ปคํ”ผ์ˆ",
"ํ”ผํŠธ๋‹ˆ์Šค/ํ—ฌ์Šค์žฅ",
"๊ต์œก/์—๋“€ํ…Œํฌ",
"๋ทฐํ‹ฐ/ํ™”์žฅํ’ˆ",
"์Œ์‹ ๋ฐฐ๋‹ฌ",
"์—ฌํ–‰/๊ด€๊ด‘",
"๊ธˆ์œต/ํ•€ํ…Œํฌ",
"ํŒจ์…˜/์˜๋ฅ˜",
"๋ฐ˜๋ ค๋™๋ฌผ",
"์นœํ™˜๊ฒฝ/์ง€์†๊ฐ€๋Šฅ"
]
def generate_brand_squares(industry: str, keywords: str, count: int = 5) -> List[Dict]:
"""Square Theory ๊ธฐ๋ฐ˜ ๋ธŒ๋žœ๋“œ ์ƒ์„ฑ"""
user_prompt = f"""
์—…์ข…: {industry}
ํ‚ค์›Œ๋“œ: {keywords}
์œ„ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ Square Theory๋ฅผ ํ™œ์šฉํ•œ ๋ธŒ๋žœ๋“œ {count}๊ฐœ๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”.
๊ฐ ๋ธŒ๋žœ๋“œ๋Š” ์™„์ „ํ•œ Square๋ฅผ ํ˜•์„ฑํ•ด์•ผ ํ•˜๋ฉฐ, ๋ธŒ๋žœ๋“œ๋ช…์ด Square์˜ ํ•ต์‹ฌ์ด ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
"""
try:
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": BRANDING_SQUARE_PROMPT},
{"role": "user", "content": user_prompt}
],
temperature=0.85,
max_tokens=4000,
response_format={"type": "json_object"}
)
content = response.choices[0].message.content
data = json.loads(content)
# ์‘๋‹ต ์ •๊ทœํ™”
if isinstance(data, dict):
if "brands" in data:
results = data["brands"]
elif "results" in data:
results = data["results"]
else:
results = [data]
else:
results = data
# ์ ์ˆ˜์ˆœ ์ •๋ ฌ
results.sort(key=lambda x: x.get("impact_score", 0), reverse=True)
return results[:count]
except Exception as e:
raise RuntimeError(f"๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ์‹คํŒจ: {e}")
def visualize_brand_square(brand: Dict) -> str:
"""๋ธŒ๋žœ๋“œ Square ์‹œ๊ฐํ™”"""
brand_name = brand.get('brand_name', 'BRAND')
tl, tr = brand.get('tl', '?'), brand.get('tr', '?')
bl, br = brand.get('bl', '?'), brand.get('br', '?')
# ๋ธŒ๋žœ๋“œ๋ช… ๋ถ„ํ•ด (compound/portmanteau์ธ ๊ฒฝ์šฐ)
if brand.get('brand_type') == 'compound':
parts = brand_name.split()
brand_part1 = parts[0] if len(parts) > 0 else brand_name[:len(brand_name)//2]
brand_part2 = parts[1] if len(parts) > 1 else brand_name[len(brand_name)//2:]
else:
# ํฌํŠธ๋งจํ† ์˜ ๊ฒฝ์šฐ ๋Œ€๋žต์ ์œผ๋กœ ๋ถ„ํ• 
mid = len(brand_name) // 2
brand_part1 = brand_name[:mid+1]
brand_part2 = brand_name[mid-1:]
return f"""
<div style="max-width: 700px; margin: 20px auto; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
<!-- ๋ธŒ๋žœ๋“œ๋ช… ํ—ค๋” -->
<div style="text-align: center; margin-bottom: 30px;">
<h2 style="font-size: 2.5em; margin: 0; color: #2c3e50; letter-spacing: -1px;">{brand_name}</h2>
<p style="font-size: 1.2em; color: #7f8c8d; margin: 10px 0; font-style: italic;">"{brand.get('slogan', '')}"</p>
<p style="font-size: 0.9em; color: #95a5a6; margin: 5px 0;">{brand.get('tagline', '')}</p>
</div>
<!-- Square ๋‹ค์ด์–ด๊ทธ๋žจ -->
<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);">
<!-- ์ค‘์•™ ๋ธŒ๋žœ๋“œ๋ช… -->
<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;">
<div style="font-size: 1.8em; font-weight: bold; color: #2c3e50; text-align: center;">{brand_name}</div>
<div style="font-size: 0.9em; color: #7f8c8d; text-align: center; margin-top: 5px;">{brand.get('brand_type', 'compound')}</div>
</div>
<!-- ๊ผญ์ง“์  -->
<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);">
{tl}
</div>
<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);">
{tr}
</div>
<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);">
{bl}
</div>
<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);">
{br}
</div>
<!-- ๊ด€๊ณ„ ๋ ˆ์ด๋ธ” -->
<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;">
{brand.get('top_edge', '๊ด€๊ณ„')}
</div>
<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;">
{brand.get('bottom_edge', '๊ด€๊ณ„')}
</div>
<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;">
{brand.get('left_edge', '๊ด€๊ณ„')}
</div>
<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;">
{brand.get('right_edge', '๊ด€๊ณ„')}
</div>
<!-- ์—ฐ๊ฒฐ์„  -->
<svg style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none;">
<defs>
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:#3498db;stop-opacity:0.5" />
<stop offset="100%" style="stop-color:#e74c3c;stop-opacity:0.5" />
</linearGradient>
<linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" style="stop-color:#f39c12;stop-opacity:0.5" />
<stop offset="100%" style="stop-color:#27ae60;stop-opacity:0.5" />
</linearGradient>
</defs>
<!-- ์ƒ๋‹จ -->
<line x1="100" y1="45" x2="600" y2="45" stroke="url(#grad1)" stroke-width="3"/>
<!-- ํ•˜๋‹จ -->
<line x1="100" y1="305" x2="600" y2="305" stroke="url(#grad2)" stroke-width="3"/>
<!-- ์™ผ์ชฝ -->
<line x1="50" y1="80" x2="50" y2="270" stroke="#7f8c8d" stroke-width="3" opacity="0.5"/>
<!-- ์˜ค๋ฅธ์ชฝ -->
<line x1="650" y1="80" x2="650" y2="270" stroke="#7f8c8d" stroke-width="3" opacity="0.5"/>
</svg>
</div>
<!-- ๋ธŒ๋žœ๋“œ ์ •๋ณด -->
<div style="margin-top: 30px; display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
<div style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.05);">
<h4 style="margin: 0 0 10px 0; color: #2c3e50;">๐ŸŽฏ ํƒ€๊ฒŸ ๊ณ ๊ฐ</h4>
<p style="margin: 0; color: #7f8c8d;">{brand.get('target_audience', 'N/A')}</p>
</div>
<div style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.05);">
<h4 style="margin: 0 0 10px 0; color: #2c3e50;">โœจ ๋ธŒ๋žœ๋“œ ๊ฐœ์„ฑ</h4>
<p style="margin: 0; color: #7f8c8d;">{brand.get('brand_personality', 'N/A')}</p>
</div>
</div>
<div style="margin-top: 20px; background: #ecf0f1; padding: 20px; border-radius: 8px;">
<h4 style="margin: 0 0 10px 0; color: #2c3e50;">๐Ÿ’ก ์™œ ํšจ๊ณผ์ ์ธ๊ฐ€?</h4>
<p style="margin: 0; color: #34495e;">{brand.get('why_it_works', '')}</p>
</div>
</div>
"""
def generate_brands(industry: str, keywords: str, count: int) -> Tuple[str, str, List[Dict]]:
"""๋ธŒ๋žœ๋“œ ์ƒ์„ฑ ๋ฐ ํ‘œ์‹œ"""
if not industry or not keywords:
return "โš ๏ธ ์—…์ข…๊ณผ ํ‚ค์›Œ๋“œ๋ฅผ ๋ชจ๋‘ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.", "", []
try:
brands = generate_brand_squares(industry, keywords, count)
# ๋งˆํฌ๋‹ค์šด ๊ฒฐ๊ณผ
markdown_parts = [
f"# ๐Ÿข Square Theory ๋ธŒ๋žœ๋“œ ์ œ์•ˆ",
f"**์—…์ข…**: {industry} | **ํ‚ค์›Œ๋“œ**: {keywords}",
f"*์ƒ์„ฑ ์‹œ๊ฐ: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*\n"
]
# HTML ์‹œ๊ฐํ™”
html_parts = []
for idx, brand in enumerate(brands, 1):
score = brand.get('impact_score', 0)
markdown_parts.append(f"""
## {idx}. {brand.get('brand_name', 'N/A')} {'โญ' * min(score, 5)}
**์Šฌ๋กœ๊ฑด**: *"{brand.get('slogan', 'N/A')}"*
**ํƒœ๊ทธ๋ผ์ธ**: {brand.get('tagline', 'N/A')}
### ๐Ÿ“ Square ๊ตฌ์กฐ
```
[{brand.get('tl', '?')}] โ”€({brand.get('top_edge', '?')})โ”€ [{brand.get('tr', '?')}]
โ”‚ โ”‚
({brand.get('left_edge', '?')}) ({brand.get('right_edge', '?')})
โ”‚ โ”‚
[{brand.get('bl', '?')}] โ”€({brand.get('bottom_edge', '?')})โ”€ [{brand.get('br', '?')}]
```
**๋น„์ฆˆ๋‹ˆ์Šค**: {brand.get('business_description', 'N/A')}
**ํƒ€๊ฒŸ**: {brand.get('target_audience', 'N/A')}
**๊ฐœ์„ฑ**: {brand.get('brand_personality', 'N/A')}
๐Ÿ’ก **ํšจ๊ณผ**: {brand.get('why_it_works', 'N/A')}
---
""")
# ๋ชจ๋“  ๋ธŒ๋žœ๋“œ ์‹œ๊ฐํ™”
html_parts.append(f"<h3 style='text-align: center; color: #7f8c8d; margin: 40px 0 20px 0;'>#{idx}</h3>")
html_parts.append(visualize_brand_square(brand))
return "\n".join(markdown_parts), "\n".join(html_parts), brands
except Exception as e:
return f"โŒ ์˜ค๋ฅ˜: {str(e)}", "", []
def export_brands(brands: List[Dict]) -> str:
"""๋ธŒ๋žœ๋“œ ์ •๋ณด JSON ๋‚ด๋ณด๋‚ด๊ธฐ"""
if not brands:
return None
export_data = {
"generated_at": datetime.now().isoformat(),
"total_brands": len(brands),
"brands": brands
}
return json.dumps(export_data, ensure_ascii=False, indent=2)
# Gradio UI
with gr.Blocks(title="Square Theory Brand Generator", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# ๐Ÿข Square Theory Brand Generator
### ์˜๋ฏธ์  Square๋ฅผ ์™„์„ฑํ•˜๋Š” ๋ธŒ๋žœ๋“œ ๋„ค์ด๋ฐ & ์Šฌ๋กœ๊ฑด ์ƒ์„ฑ๊ธฐ
Square Theory๋ฅผ ํ™œ์šฉํ•ด ๋ธŒ๋žœ๋“œ๋ช…์ด ์˜๋ฏธ์  ์‚ฌ๊ฐํ˜•์„ ์™„์„ฑํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ๋ธŒ๋žœ๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์„ธ์š”.
์ข‹์€ ๋ธŒ๋žœ๋“œ๋ช…์€ ๋‹จ์ˆœํ•œ ์ด๋ฆ„์ด ์•„๋‹Œ, ๋น„์ฆˆ๋‹ˆ์Šค์˜ ๋ณธ์งˆ์„ ๋‹ด์€ Square๋ฅผ ํ˜•์„ฑํ•ฉ๋‹ˆ๋‹ค.
**์„ฑ๊ณต ์‚ฌ๋ก€**: GRUBHUB (GRUB+HUB), Brand New, Crosscord
""")
with gr.Row():
with gr.Column(scale=2):
industry_input = gr.Dropdown(
choices=INDUSTRY_EXAMPLES,
label="๐Ÿญ ์—…์ข…",
allow_custom_value=True,
value="์นดํŽ˜/์ปคํ”ผ์ˆ"
)
keywords_input = gr.Textbox(
label="๐Ÿ”‘ ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ",
placeholder="ํ”„๋ฆฌ๋ฏธ์—„, ํŽธ์•ˆํ•œ, ๋„์‹œ์ ์ธ, ์นœํ™˜๊ฒฝ...",
info="๋ธŒ๋žœ๋“œ๊ฐ€ ๋‹ด์•„์•ผ ํ•  ํ•ต์‹ฌ ๊ฐ€์น˜๋‚˜ ํŠน์ง•๋“ค"
)
count_slider = gr.Slider(
minimum=3,
maximum=10,
value=5,
step=1,
label="์ƒ์„ฑ ๊ฐœ์ˆ˜"
)
generate_btn = gr.Button("๐Ÿš€ ๋ธŒ๋žœ๋“œ Square ์ƒ์„ฑ", variant="primary", size="lg")
with gr.Column(scale=1):
gr.Markdown("""
### ๐Ÿ’ก Square Theory ๋ธŒ๋žœ๋”ฉ
**์ข‹์€ ๋ธŒ๋žœ๋“œ Square์˜ ์กฐ๊ฑด:**
1. ๋ธŒ๋žœ๋“œ๋ช…์˜ ๊ฐ ๋ถ€๋ถ„์ด ์˜๋ฏธ๋ฅผ ๊ฐ€์ง
2. ๋น„์ฆˆ๋‹ˆ์Šค ๋ณธ์งˆ๊ณผ ์—ฐ๊ฒฐ
3. ๊ธฐ์–ตํ•˜๊ธฐ ์‰ฝ๊ณ  ๋ฐœ์Œ ๊ฐ€๋Šฅ
4. Square๊ฐ€ "์•„ํ•˜!" ๋ชจ๋จผํŠธ ์ƒ์„ฑ
**Square ๊ตฌ์กฐ ์˜ˆ์‹œ:**
```
GRUB โ”€(์Œ์‹)โ”€ FOOD
โ”‚ โ”‚
(์ค‘์‹ฌ) (๋ฐฐ๋‹ฌ)
โ”‚ โ”‚
HUB โ”€(์„œ๋น„์Šค)โ”€ DELIVERY
```
""")
# ์ „์—ญ ๋ณ€์ˆ˜
current_brands = gr.State([])
with gr.Tabs():
with gr.Tab("๐Ÿ“Š ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ"):
output_markdown = gr.Markdown()
with gr.Tab("๐ŸŽจ ๋ธŒ๋žœ๋“œ ์‹œ๊ฐํ™”"):
output_visual = gr.HTML()
with gr.Tab("๐Ÿ’พ ๋‚ด๋ณด๋‚ด๊ธฐ"):
export_btn = gr.Button("JSON ํŒŒ์ผ ์ƒ์„ฑ")
download_file = gr.File(label="๋‹ค์šด๋กœ๋“œ", visible=False)
# ์˜ˆ์‹œ
gr.Examples(
examples=[
["์นดํŽ˜/์ปคํ”ผ์ˆ", "ํ”„๋ฆฌ๋ฏธ์—„, ์•„๋Š‘ํ•œ, ๋„์‹œ"],
["ํ”ผํŠธ๋‹ˆ์Šค/ํ—ฌ์Šค์žฅ", "๊ฐ•๋ ฅํ•œ, ์ปค๋ฎค๋‹ˆํ‹ฐ, ๋ณ€ํ™”"],
["๊ต์œก/์—๋“€ํ…Œํฌ", "์Šค๋งˆํŠธ, ์žฌ๋ฏธ์žˆ๋Š”, ์„ฑ์žฅ"],
["์Œ์‹ ๋ฐฐ๋‹ฌ", "๋น ๋ฅธ, ์‹ ์„ ํ•œ, ๋‹ค์–‘ํ•œ"],
["์นœํ™˜๊ฒฝ/์ง€์†๊ฐ€๋Šฅ", "์ž์—ฐ, ๋ฏธ๋ž˜, ์ˆœํ™˜"]
],
inputs=[industry_input, keywords_input]
)
# ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
def generate_and_store(industry, keywords, count):
markdown, html, brands = generate_brands(industry, keywords, count)
return markdown, html, brands
generate_btn.click(
fn=generate_and_store,
inputs=[industry_input, keywords_input, count_slider],
outputs=[output_markdown, output_visual, current_brands]
)
def create_export_file(brands):
if not brands:
return None
content = export_brands(brands)
filename = f"square_theory_brands_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
with open(filename, 'w', encoding='utf-8') as f:
f.write(content)
return gr.File(value=filename, visible=True)
export_btn.click(
fn=create_export_file,
inputs=[current_brands],
outputs=[download_file]
)
gr.Markdown("""
---
### ๐ŸŽฏ ํ™œ์šฉ ๋ฐฉ๋ฒ•
1. **๋ธŒ๋žœ๋“œ ๊ฐœ๋ฐœ**: ์ƒ์„ฑ๋œ Square ์ค‘ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ฒƒ ์„ ํƒ
2. **๋งˆ์ผ€ํŒ… ์ „๋žต**: Square์˜ ๊ฐ ์š”์†Œ๋ฅผ ์บ ํŽ˜์ธ์— ํ™œ์šฉ
3. **์Šคํ† ๋ฆฌํ…”๋ง**: Square๊ฐ€ ๋งŒ๋“œ๋Š” ๋‚ด๋Ÿฌํ‹ฐ๋ธŒ ํ™œ์šฉ
4. **ํ™•์žฅ ๊ฐ€๋Šฅ์„ฑ**: Square์˜ ๊ฐ ๋ชจ์„œ๋ฆฌ์—์„œ ์„œ๋ธŒ๋ธŒ๋žœ๋“œ ํŒŒ์ƒ
### ๐Ÿ“š Square Theory ๋ธŒ๋žœ๋”ฉ์˜ ํž˜
Square๋ฅผ ์™„์„ฑํ•˜๋Š” ๋ธŒ๋žœ๋“œ๋Š”:
- **๊ธฐ์–ตํ•˜๊ธฐ ์‰ฌ์›€**: ์˜๋ฏธ์  ์—ฐ๊ฒฐ์ด ๊ธฐ์–ต์„ ๊ฐ•ํ™”
- **์Šคํ† ๋ฆฌ๊ฐ€ ์žˆ์Œ**: Square ์ž์ฒด๊ฐ€ ๋ธŒ๋žœ๋“œ ์Šคํ† ๋ฆฌ
- **ํ™•์žฅ ๊ฐ€๋Šฅ**: ๊ฐ ์š”์†Œ์—์„œ ์ƒˆ๋กœ์šด ์˜๋ฏธ ํŒŒ์ƒ
- **์ฐจ๋ณ„ํ™”๋จ**: ๋…ํŠนํ•œ ์˜๋ฏธ ๊ตฌ์กฐ๋กœ ๊ฒฝ์Ÿ์‚ฌ์™€ ๊ตฌ๋ณ„
""")
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False
)