Naming / app.py
openfree's picture
Update app.py
7f0c2bb verified
raw
history blame
5.3 kB
"""
Square Theory Generator (Markdownโ€‘only, up to 20 ideas)
=====================================================
2025โ€‘05โ€‘28ย v9 โ— ์ถœ๋ ฅ ํฌ๋งท ๊ฐœ์„  & ํ•„๋“œ ๊ตฌ๋ถ„ ๋ช…ํ™•ํ™”
---------------------------------------------------
๋ณ€๊ฒฝ ์š”์•ฝ
---------
1. **์Šฌ๋กœ๊ฑด ยท ๋ธŒ๋žœ๋“œ ๋„ค์ž„ ๊ตฌํš** โ€” Markdown ํ…œํ”Œ๋ฆฟ์„ ๋‹ค์Œ ๊ตฌ์กฐ๋กœ ๊ฐœ์„ 
```md
### 1. ๋ธŒ๋žœ๋“œ ๋„ค์ž„: ๋ชจ๋‹์ปคํ”ผ
**๋ฉ”์ธ ์นดํ”ผ**
โ€ข ์ƒ๋‹จ: ํ’๋ฏธ๋ฅผ ๋‹ด์€ ์ปคํ”ผ
โ€ข ํ•˜๋‹จ: ๋‹น์‹ ์˜ ํ•˜๋ฃจ๋ฅผ ํŠน๋ณ„ํ•˜๊ฒŒ
**์Šฌ๋กœ๊ฑด**
> ์ปคํ”ผ ํ•œ์ž”์˜ ์—ฌ์œ 
**์‚ฌ๊ฐํ˜• ํ‚ค์›Œ๋“œ**
TL: ํ’๋ฏธ ยท TR: ์ปคํ”ผ ยท BR: ํ–ฅ๊ธฐ ยท BL: ํ•œ์ž”
```
2. **ํ”„๋กฌํ”„ํŠธ ๋ช…์„ธ ์œ ์ง€** โ€” JSON ๊ตฌ์กฐ ๋ณ€๋™์€ ์—†์Œ(ํ˜ธํ™˜).
3. **์ถ”๊ฐ€ ๊ฐœ์„  ์ œ์•ˆ** โ€” ์ฝ”๋“œ ๋‚ด ์ฃผ์„์œผ๋กœ โ€˜์ถ”๊ฐ€ ํ•„๋“œยท๋žญํ‚น ๊ธฐ์ค€ยทCSV ๋‹ค์šด๋กœ๋“œโ€™ ์•„์ด๋””์–ด ์‚ฝ์ž….
์‹คํ–‰๋ฒ•
------
```bash
pip install --upgrade gradio openai
export OPENAI_API_KEY="sk-..."
python square_theory_gradio.py
```
"""
import os
import json
import gradio as gr
from openai import OpenAI, error as oai_err
# -------------------------------------------------
# 0. OpenAI ํด๋ผ์ด์–ธํŠธ
# -------------------------------------------------
if not os.getenv("OPENAI_API_KEY"):
raise EnvironmentError("OPENAI_API_KEY ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜์„ธ์š”.")
client = OpenAI()
# -------------------------------------------------
# 1. LLM Prompt & Utilities
# -------------------------------------------------
SYSTEM_PROMPT = (
"๋„ˆ๋Š” ํ•œ๊ตญ์–ด ์นดํ”ผยท๋ธŒ๋žœ๋“œ ๋„ค์ด๋ฐ ์ „๋ฌธ๊ฐ€์ด์ž Square Theory ๋„์šฐ๋ฏธ๋‹ค. "
"์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ•˜๋‚˜์˜ ๋‹จ์–ด(tl)๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ’ˆ์งˆ์ด ๋›ฐ์–ด๋‚œ ์ˆœ์„œ๋Œ€๋กœ ์ตœ๋Œ€ 20๊ฐœ์˜ ์ œ์•ˆ์„ JSON ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•ด๋ผ. "
"๊ฐ ์›์†Œ๋Š” tl, tr, br, bl, top_phrase, bottom_phrase, slogan, brand ํ•„๋“œ๋ฅผ ๊ฐ€์ง„๋‹ค. "
"๋ฐฐ์—ด ์ฒซ ๋ฒˆ์งธ ์›์†Œ๊ฐ€ ๊ฐ€์žฅ ์šฐ์ˆ˜ํ•ด์•ผ ํ•œ๋‹ค. JSON ์™ธ ๋ฌธ์ž๋Š” ๊ธˆ์ง€ํ•œ๋‹ค."
)
FALLBACK_MODELS = ["gpt-4o-mini", "gpt-4o", "gpt-4o-preview", "gpt-4-turbo"]
def _clean_json_block(text: str) -> str:
"""Strip ```json fences if present."""
text = text.strip()
if text.startswith("```"):
text = text.split("\n", 1)[1] if "\n" in text else text[3:]
if text.endswith("```"):
text = text[:-3]
return text.strip()
def _call_llm(seed: str):
last_exc = None
for model in FALLBACK_MODELS:
try:
resp = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": seed},
],
temperature=0.9,
max_tokens=2048,
)
cleaned = _clean_json_block(resp.choices[0].message.content)
data = json.loads(cleaned) if cleaned else []
if isinstance(data, dict):
data = [data]
if not isinstance(data, list) or not (1 <= len(data) <= 20):
raise ValueError("LLM ์‘๋‹ต์ด ์˜ฌ๋ฐ”๋ฅธ 1โ€‘20๊ฐœ ๋ฆฌ์ŠคํŠธ๊ฐ€ ์•„๋‹˜")
return data
except (oai_err.OpenAIError, json.JSONDecodeError, ValueError, TypeError) as exc:
last_exc = exc
continue
raise RuntimeError(f"LLM ํ˜ธ์ถœ ์‹คํŒจ: {last_exc}")
# -------------------------------------------------
# 2. Gradio callback
# -------------------------------------------------
def generate(seed_word: str):
seed_word = seed_word.strip()
if not seed_word:
return "โš ๏ธ **์‹œ๋“œ ๋‹จ์–ด๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.**"
try:
results = _call_llm(seed_word)
md = [f"## ์ด {len(results)}๊ฐœ ์ œ์•ˆ"]
for idx, item in enumerate(results, 1):
md.append(
f"### {idx}. ๋ธŒ๋žœ๋“œ ๋„ค์ž„: {item['brand']}\n"
f"**๋ฉ”์ธ ์นดํ”ผ** \
โ€ข ์ƒ๋‹จ: {item['top_phrase']} \
โ€ข ํ•˜๋‹จ: {item['bottom_phrase']}\n\n"
f"**์Šฌ๋กœ๊ฑด** \
> {item['slogan']}\n\n"
f"**์‚ฌ๊ฐํ˜• ํ‚ค์›Œ๋“œ** \
TL: {item['tl']} ยท TR: {item['tr']} ยท BR: {item['br']} ยท BL: {item['bl']}\n"
)
return "\n".join(md)
except Exception as exc:
return f"โŒ **์˜ค๋ฅ˜:** {exc}"
# -------------------------------------------------
# 3. UI
# -------------------------------------------------
with gr.Blocks(title="Square Theory โ€“ ์ตœ๋Œ€ 20๊ฐœ ๐Ÿ‡ฐ๐Ÿ‡ท") as demo:
gr.Markdown("""# ๐ŸŸง Square Theory ์ œ์•ˆ (์ตœ๋Œ€ 20๊ฐœ)\n๋‹จ์–ด ํ•˜๋‚˜ ์ž…๋ ฅ โ†’ LLM์ด ์ •๋ ฌํ•œ ์‚ฌ๊ฐํ˜•/์นดํ”ผ/๋ธŒ๋žœ๋“œ ๋„ค์ž„""")
seed = gr.Textbox(label="์‹œ๋“œ ๋‹จ์–ด(TL)", placeholder="์˜ˆ: ๊ณจ๋“ ")
run = gr.Button("์ƒ์„ฑ")
md_out = gr.Markdown()
run.click(generate, inputs=seed, outputs=md_out)
# queue(): ๋กœ๋”ฉ ์ธ๋””์ผ€์ดํ„ฐ & ๋™์‹œ ์ ‘์† ์•ˆ์ •ํ™”
demo.queue().launch()
# -------------------------------------------------
# 4. (Optional) ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ์•„์ด๋””์–ด
# -------------------------------------------------
# - JSON์— "why"(์„ ์ • ์ด์œ ) ํ•„๋“œ ์š”์ฒญ โ†’ ์•„์ด๋””์–ด ์„ค๋“๋ ฅ ๊ฐ•ํ™”
# - ์ฑ„๋„๋ณ„ ํƒœ๊ทธ๋ผ์ธ ๋ณ€ํ˜•(OOHยทSNSยทTV) ์ž๋™ ์ƒ์„ฑ ์˜ต์…˜
# - ๊ฒฐ๊ณผ CSV ๋‹ค์šด๋กœ๋“œ ๋ฒ„ํŠผ ์ถ”๊ฐ€(๊ทธ๋ผ๋””์˜ค File component)