openfree commited on
Commit
9db6da0
ยท
verified ยท
1 Parent(s): 7155164

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -47
app.py CHANGED
@@ -1,20 +1,25 @@
1
  """
2
- Square Theory Generator (Korean-friendly, LLM-powered)
3
- -----------------------------------------------------
4
- 2025โ€‘05โ€‘28 Hotโ€‘patch โ˜… ์˜ค๋ฅ˜ ์ˆ˜์ •
5
- ================================
6
- * **๋ฒ„๊ทธ ์›์ธ**: `openai` Python SDK v1.x์˜ `client.responses.create()` ๋ฐ˜ํ™˜ ๊ฐ์ฒด์—๋Š” `.choices` ์†์„ฑ์ด ์—†์Œ โ†’ `AttributeError: 'Response' object has no attribute 'choices'` ๋ฐœ์ƒ.
7
- * **ํ•ด๊ฒฐ**: `client.chat.completions.create()` ์—”๋“œํฌ์ธํŠธ๋กœ ๊ต์ฒด โ†’ ์ต์ˆ™ํ•œ `.choices[0].message.content` ๊ตฌ์กฐ ์‚ฌ์šฉ.
8
- * ์ถ”๊ฐ€: ์˜ˆ์™ธ ์ฒ˜๋ฆฌยท๋””๋ฒ„๊ทธ ํ”„๋ฆฐํŠธ ์˜ต์…˜.
9
-
10
- ์‚ฌ์šฉ ๋ฐฉ๋ฒ•
11
- =========
 
 
 
 
 
 
12
  ```bash
13
  pip install --upgrade gradio matplotlib openai
14
  export OPENAI_API_KEY="sk-..."
15
  python square_theory_gradio.py
16
  ```
17
-
18
  """
19
 
20
  import os
@@ -25,14 +30,12 @@ from matplotlib import patches, font_manager, rcParams
25
  from openai import OpenAI
26
 
27
  # -------------------------------------------------
28
- # 0. ํ•œ๊ธ€ ํฐํŠธ ์ž๋™ ํƒ์ƒ‰ & ์„ค์ •
29
  # -------------------------------------------------
30
 
31
  def _set_korean_font():
32
- candidates = ["Malgun Gothic", "NanumGothic", "AppleGothic", "DejaVu Sans"]
33
- available = {f.name for f in font_manager.fontManager.ttflist}
34
- for cand in candidates:
35
- if cand in available:
36
  rcParams["font.family"] = cand
37
  break
38
  rcParams["axes.unicode_minus"] = False
@@ -40,7 +43,7 @@ def _set_korean_font():
40
  _set_korean_font()
41
 
42
  # -------------------------------------------------
43
- # 1. OpenAI ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™”
44
  # -------------------------------------------------
45
  if not os.getenv("OPENAI_API_KEY"):
46
  raise EnvironmentError("OPENAI_API_KEY ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜์„ธ์š”.")
@@ -48,7 +51,7 @@ if not os.getenv("OPENAI_API_KEY"):
48
  client = OpenAI()
49
 
50
  # -------------------------------------------------
51
- # 2. Square Theory ๋„์‹ ๊ทธ๋ฆฌ๊ธฐ
52
  # -------------------------------------------------
53
 
54
  def draw_square(words):
@@ -66,59 +69,69 @@ def draw_square(words):
66
  return fig
67
 
68
  # -------------------------------------------------
69
- # 3. LLM ํ”„๋กฌํ”„ํŠธ & ์‘๋‹ต ํŒŒ์‹ฑ
70
  # -------------------------------------------------
71
  SYSTEM_PROMPT = (
72
- "๋„ˆ๋Š” ํ•œ๊ตญ์–ด ์นดํ”ผยท๋ธŒ๋žœ๋“œ ๋„ค์ด๋ฐ ์ „๋ฌธ๊ฐ€์ด์ž Square Theory(์‚ฌ๊ฐํ˜• ์ด๋ก ) ๋„์šฐ๋ฏธ๋‹ค.\n"
73
- "์‚ฌ์šฉ์ž๊ฐ€ ์ œ์‹œํ•œ ํ•˜๋‚˜์˜ ๋‹จ์–ด(TL)๋กœ ๋‹ค์Œ JSON์„ ์™„์„ฑํ•ด๋ผ: \n"
74
- "{\n \"tl\": str, \"tr\": str, \"br\": str, \"bl\": str,\n \"top_phrase\": str, \"bottom_phrase\": str, \n \"slogan\": str, \"brand\": str\n}\n"
75
- "๊ฐ corner ๋Š” ์™„์ „ํ•œ ์‚ฌ๊ฐํ˜•์„ ์ด๋ฃจ๋„๋ก ์˜๋ฏธยท์Œ์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์—ฐ๊ฒฐ๋ผ์•ผ ํ•œ๋‹ค. ๊ฒฐ๊ณผ๋Š” **JSON ๋ฌธ์ž์—ด**๋งŒ ์ถœ๋ ฅํ•œ๋‹ค."
 
 
76
  )
77
 
78
 
79
- def call_llm(seed: str, debug: bool = False):
80
- """LLM ํ˜ธ์ถœ โ†’ JSON dict ๋ฐ˜ํ™˜"""
81
  resp = client.chat.completions.create(
82
- model="gpt-4.1-mini", # ๋˜๋Š” gpt-4-turbo (์กฐ์ • ๊ฐ€๋Šฅ)
83
  messages=[
84
  {"role": "system", "content": SYSTEM_PROMPT},
85
  {"role": "user", "content": seed},
86
  ],
87
  temperature=0.9,
88
- max_tokens=512,
89
  )
90
  raw = resp.choices[0].message.content.strip()
91
- if debug:
92
- print("LLM raw:", raw)
93
  try:
94
  data = json.loads(raw)
95
- except json.JSONDecodeError as exc:
96
- raise ValueError(f"LLM ์‘๋‹ต JSON ํŒŒ์‹ฑ ์‹คํŒจ: {exc}\n์›๋ฌธ: {raw}")
 
 
97
  return data
98
 
99
  # -------------------------------------------------
100
- # 4. Gradio ์ฝœ๋ฐฑ
101
  # -------------------------------------------------
102
 
103
- def generate(seed_word):
104
- data = call_llm(seed_word)
105
- fig = draw_square({k: data[k] for k in ("tl", "tr", "br", "bl")})
106
- return fig, data["top_phrase"], data["bottom_phrase"], data["slogan"], data["brand"]
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  # -------------------------------------------------
109
- # 5. Gradio UI
110
  # -------------------------------------------------
111
- with gr.Blocks(title="Square Theory Generator โ€“ LLM Powered ๐Ÿ‡ฐ๐Ÿ‡ท") as demo:
112
- gr.Markdown("""# ๐ŸŸง Square Theory Generator\n๋‹จ์–ด ํ•˜๋‚˜๋งŒ ์ž…๋ ฅํ•˜๋ฉด LLM์ด ์‚ฌ๊ฐํ˜• ๊ตฌ์กฐยท์นดํ”ผยท๋ธŒ๋žœ๋“œ ๋„ค์ž„์„ ์ž๋™ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.""")
113
  seed = gr.Textbox(label="์‹œ๋“œ ๋‹จ์–ด(TL)", placeholder="์˜ˆ: ๊ณจ๋“ ")
114
- run = gr.Button("์‚ฌ๊ฐํ˜• ์ƒ์„ฑ")
115
- fig_out = gr.Plot(label="์‚ฌ๊ฐํ˜• ๋‹ค์ด์–ด๊ทธ๋žจ")
116
- top_out = gr.Textbox(label="์œ—๋ณ€ ํ‘œํ˜„")
117
- bottom_out = gr.Textbox(label="์•„๋žซ๋ณ€ ํ‘œํ˜„")
118
- slogan_out = gr.Textbox(label="๋‘ ์ค„ ์Šฌ๋กœ๊ฑด")
119
- brand_out = gr.Textbox(label="๋ธŒ๋žœ๋“œ ๋„ค์ž„")
120
-
121
- run.click(generate, inputs=seed, outputs=[fig_out, top_out, bottom_out, slogan_out, brand_out])
122
 
123
  if __name__ == "__main__":
124
  demo.launch()
 
1
  """
2
+ Square Theory Generator (10 best variations)
3
+ ===========================================
4
+ 2025โ€‘05โ€‘28ย v3 โ— ํ•œ ์ž…๋ ฅ โ†’ ์šฐ์ˆ˜๋„ ์ˆœ 10๊ฐ€์ง€ ๊ฒฐ๊ณผ
5
+ ------------------------------------------------
6
+ ๋ณ€๊ฒฝ ์š”์•ฝ
7
+ ---------
8
+ 1. **LLM ํ•œย ํšŒ ํ˜ธ์ถœ๋กœ 10๊ฐœ์˜ ์‚ฌ๊ฐํ˜• ์ œ์•ˆ**
9
+ * JSON ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜, ํ’ˆ์งˆ์ด ๋†’์€ ์ˆœ์„œ๋กœ ์ •๋ ฌ (1ย โ€“ย 10)
10
+ 2. **์ถœ๋ ฅ**
11
+ * โ‘  1์œ„ ์ œ์•ˆ์˜ ์‚ฌ๊ฐํ˜• ๋„์‹(Plot)
12
+ * โ‘ก 10๊ฐœ ์ œ์•ˆ์„ ๋งˆํฌ๋‹ค์šด ๋ฆฌ์ŠคํŠธ๋กœ ์ •๋ฆฌํ•˜์—ฌ ํ‘œ์‹œ
13
+ 3. **UI ๊ฐ„์†Œํ™”** : seed ์ž…๋ ฅย +ย ์‹คํ–‰ ๋ฒ„ํŠผ + Plot + Markdown
14
+ 4. **์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ•ํ™”**
15
+
16
+ ์‹คํ–‰๋ฒ•
17
+ ------
18
  ```bash
19
  pip install --upgrade gradio matplotlib openai
20
  export OPENAI_API_KEY="sk-..."
21
  python square_theory_gradio.py
22
  ```
 
23
  """
24
 
25
  import os
 
30
  from openai import OpenAI
31
 
32
  # -------------------------------------------------
33
+ # 0. ํ•œ๊ธ€ ํฐํŠธ ์„ค์ •
34
  # -------------------------------------------------
35
 
36
  def _set_korean_font():
37
+ for cand in ("Malgun Gothic", "NanumGothic", "AppleGothic", "DejaVu Sans"):
38
+ if cand in {f.name for f in font_manager.fontManager.ttflist}:
 
 
39
  rcParams["font.family"] = cand
40
  break
41
  rcParams["axes.unicode_minus"] = False
 
43
  _set_korean_font()
44
 
45
  # -------------------------------------------------
46
+ # 1. OpenAI ํด๋ผ์ด์–ธํŠธ
47
  # -------------------------------------------------
48
  if not os.getenv("OPENAI_API_KEY"):
49
  raise EnvironmentError("OPENAI_API_KEY ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜์„ธ์š”.")
 
51
  client = OpenAI()
52
 
53
  # -------------------------------------------------
54
+ # 2. Square Diagram
55
  # -------------------------------------------------
56
 
57
  def draw_square(words):
 
69
  return fig
70
 
71
  # -------------------------------------------------
72
+ # 3. LLM Prompt & Call
73
  # -------------------------------------------------
74
  SYSTEM_PROMPT = (
75
+ "๋„ˆ๋Š” ํ•œ๊ตญ์–ด ์นดํ”ผยท๋ธŒ๋žœ๋“œ ๋„ค์ด๋ฐ ์ „๋ฌธ๊ฐ€์ด์ž Square Theory ๋„์šฐ๋ฏธ๋‹ค. "
76
+ "์‚ฌ์šฉ์ž๊ฐ€ ์ค€ ํ•˜๋‚˜์˜ ๋‹จ์–ด(tl)๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ’ˆ์งˆ์ด ๊ฐ€์žฅ ๋›ฐ์–ด๋‚œ ๊ฒƒ๋ถ€ํ„ฐ 10๊ฐœ์˜ ์ œ์•ˆ์„ JSON ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•ด๋ผ. "
77
+ "๊ฐ ๋ฐฐ์—ด ์›์†Œ๋Š” tl, tr, br, bl, top_phrase, bottom_phrase, slogan, brand ํ•„๋“œ๋ฅผ ๊ฐ€์ง€๋ฉฐ, "
78
+ "์‚ฌ๊ฐํ˜• ๋„ค ๊ผญ์ง“์ (tl>tr>br>bl)๊ณผ ๋‘ ํ‘œํ˜„ยท์Šฌ๋กœ๊ฑดยท๋ธŒ๋žœ๋“œ ๋„ค์ž„์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์—ฐ๊ฒฐ๋ผ์•ผ ํ•œ๋‹ค. "
79
+ "๋ฐฐ์—ด์€ ์ตœ๊ณ ์˜ ์ œ์•ˆ์ด index 0, ๊ทธ๋‹ค์Œ์ด index 1 โ€ฆ 9 ์ˆœ์„œ์—ฌ์•ผ ํ•œ๋‹ค. "
80
+ "๊ฒฐ๊ณผ๋Š” JSON ์™ธ ๋‹ค๋ฅธ ํ…์ŠคํŠธ๋ฅผ ํฌํ•จํ•˜๋ฉด ์•ˆ ๋œ๋‹ค."
81
  )
82
 
83
 
84
+ def call_llm(seed: str):
 
85
  resp = client.chat.completions.create(
86
+ model="gpt-4o-mini",
87
  messages=[
88
  {"role": "system", "content": SYSTEM_PROMPT},
89
  {"role": "user", "content": seed},
90
  ],
91
  temperature=0.9,
92
+ max_tokens=1024,
93
  )
94
  raw = resp.choices[0].message.content.strip()
 
 
95
  try:
96
  data = json.loads(raw)
97
+ if not isinstance(data, list) or len(data) != 10:
98
+ raise ValueError("JSON ๋ฐฐ์—ด ๊ธธ์ด๊ฐ€ 10์ด ์•„๋‹˜")
99
+ except Exception as exc:
100
+ raise ValueError(f"LLM JSON ํŒŒ์‹ฑ ์‹คํŒจ: {exc}\n์›๋ฌธ: {raw[:300]} โ€ฆ")
101
  return data
102
 
103
  # -------------------------------------------------
104
+ # 4. Gradio callback
105
  # -------------------------------------------------
106
 
107
+ def generate(seed_word: str):
108
+ results = call_llm(seed_word)
109
+ # 1์œ„ ๋„์‹
110
+ fig = draw_square({k: results[0][k] for k in ("tl", "tr", "br", "bl")})
111
+
112
+ # ๋ฆฌ์ŠคํŠธ ๋งˆํฌ๋‹ค์šด
113
+ md_lines = []
114
+ for idx, item in enumerate(results, 1):
115
+ md_lines.append(
116
+ f"### {idx}. {item['top_phrase']} / {item['bottom_phrase']}\n"
117
+ f"- **์Šฌ๋กœ๊ฑด**: {item['slogan']}\n"
118
+ f"- **๋ธŒ๋žœ๋“œ ๋„ค์ž„**: {item['brand']}\n"
119
+ f"- (tl={item['tl']}, tr={item['tr']}, br={item['br']}, bl={item['bl']})\n"
120
+ )
121
+ markdown_out = "\n".join(md_lines)
122
+ return fig, markdown_out
123
 
124
  # -------------------------------------------------
125
+ # 5. UI
126
  # -------------------------------------------------
127
+ with gr.Blocks(title="Square Theory โ€“ Topย 10 ๐Ÿ‡ฐ๐Ÿ‡ท") as demo:
128
+ gr.Markdown("""# ๐Ÿ”Ÿ Square Theory ์ œ์•ˆ Topย 10\n๋‹จ์–ด 1๊ฐœ โ†’ LLM์ด ํ‰๊ฐ€ยท์ •๋ ฌํ•œ 10๊ฐœ ์‚ฌ๊ฐํ˜•/์นดํ”ผ/๋ธŒ๋žœ๋“œ ๋„ค์ž„""")
129
  seed = gr.Textbox(label="์‹œ๋“œ ๋‹จ์–ด(TL)", placeholder="์˜ˆ: ๊ณจ๋“ ")
130
+ run = gr.Button("์ƒ์„ฑ")
131
+ fig_out = gr.Plot(label="1์œ„ ์‚ฌ๊ฐํ˜•")
132
+ md_out = gr.Markdown(label="Topย 10 ์ œ์•ˆ")
133
+
134
+ run.click(generate, inputs=seed, outputs=[fig_out, md_out])
 
 
 
135
 
136
  if __name__ == "__main__":
137
  demo.launch()