openfree commited on
Commit
7f0c2bb
ยท
verified ยท
1 Parent(s): e420f43

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -148
app.py CHANGED
@@ -1,14 +1,25 @@
1
  """
2
  Square Theory Generator (Markdownโ€‘only, up to 20 ideas)
3
  =====================================================
4
- 2025โ€‘05โ€‘28ย v7 โ— ๋ฐ•์Šค ๋‹ค์ด์–ด๊ทธ๋žจ ์ œ๊ฑฐ & ์ œ์•ˆย 20๊ฐœ๋กœ ํ™•์žฅ
5
  ---------------------------------------------------
6
  ๋ณ€๊ฒฝ ์š”์•ฝ
7
  ---------
8
- 1. **์‚ฌ๊ฐํ˜• ์‹œ๊ฐํ™” ์ œ๊ฑฐ** โ€’ ์ถœ๋ ฅ/์˜์กด์—์„œ `matplotlib` ์ „๋ถ€ ์‚ญ์ œ.
9
- 2. **์ œ์•ˆ ๊ฐœ์ˆ˜ ์ƒํ–ฅ** โ€’ LLM์ด ์ตœ๋Œ€ **20๊ฐœ** ์•„์ด๋””์–ด ๋ฐ˜ํ™˜.
10
- 3. **์œ ์—ฐ ๊ธธ์ด ํ—ˆ์šฉ** โ€’ 1โ€ฏโ‰คโ€ฏNโ€ฏโ‰คโ€ฏ20 ๋ฆฌ์ŠคํŠธ๋ฉด OK.
11
- 4. **UI ๋‹จ์ˆœํ™”** โ€’ ์‹œ๋“œ ์ž…๋ ฅ โ†’ ๋ฒ„ํŠผ โ†’ ๋งˆํฌ๋‹ค์šด ๊ฒฐ๊ณผ.
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  ์‹คํ–‰๋ฒ•
14
  ------
@@ -22,7 +33,7 @@ python square_theory_gradio.py
22
  import os
23
  import json
24
  import gradio as gr
25
- from openai import OpenAI
26
 
27
  # -------------------------------------------------
28
  # 0. OpenAI ํด๋ผ์ด์–ธํŠธ
@@ -42,8 +53,11 @@ SYSTEM_PROMPT = (
42
  "๋ฐฐ์—ด ์ฒซ ๋ฒˆ์งธ ์›์†Œ๊ฐ€ ๊ฐ€์žฅ ์šฐ์ˆ˜ํ•ด์•ผ ํ•œ๋‹ค. JSON ์™ธ ๋ฌธ์ž๋Š” ๊ธˆ์ง€ํ•œ๋‹ค."
43
  )
44
 
 
45
 
46
- def clean_json_block(text: str) -> str:
 
 
47
  text = text.strip()
48
  if text.startswith("```"):
49
  text = text.split("\n", 1)[1] if "\n" in text else text[3:]
@@ -52,163 +66,74 @@ def clean_json_block(text: str) -> str:
52
  return text.strip()
53
 
54
 
55
- def call_llm(seed: str):
56
- resp = client.chat.completions.create(
57
- model="gpt-4o-mini",
58
- messages=[
59
- {"role": "system", "content": SYSTEM_PROMPT},
60
- {"role": "user", "content": seed},
61
- ],
62
- temperature=0.9,
63
- max_tokens=2048,
64
- )
65
- raw = resp.choices[0].message.content
66
- cleaned = clean_json_block(raw)
67
- try:
68
- data = json.loads(cleaned)
69
- if isinstance(data, dict):
70
- data = [data]
71
- if not isinstance(data, list):
72
- raise TypeError("LLM ์‘๋‹ต์ด ๋ฆฌ์ŠคํŠธ๊ฐ€ ์•„๋‹˜")
73
- if not 1 <= len(data) <= 20:
74
- raise ValueError("์‘๋‹ต ๋ฆฌ์ŠคํŠธ ๊ธธ์ด๊ฐ€ 1~20 ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚จ")
75
- except Exception as exc:
76
- raise ValueError(f"LLM JSON ํŒŒ์‹ฑ ์‹คํŒจ: {exc}\n์›๋ฌธ ์ผ๋ถ€: {cleaned[:300]} โ€ฆ")
77
- return data
 
78
 
79
  # -------------------------------------------------
80
  # 2. Gradio callback
81
  # -------------------------------------------------
82
 
83
  def generate(seed_word: str):
84
- results = call_llm(seed_word)
85
- md_lines = [f"## ์ด {len(results)}๊ฐœ ์ œ์•ˆ\n"]
86
- for idx, item in enumerate(results, 1):
87
- md_lines.append(
88
- f"### {idx}. {item['top_phrase']} / {item['bottom_phrase']}\n"
89
- f"- **์Šฌ๋กœ๊ฑด**: {item['slogan']}\n"
90
- f"- **๋ธŒ๋žœ๋“œ ๋„ค์ž„**: {item['brand']}\n"
91
- f"- (tl={item['tl']}, tr={item['tr']}, br={item['br']}, bl={item['bl']})\n"
92
- )
93
- return "\n".join(md_lines)
 
 
 
 
 
 
 
 
 
 
94
 
95
  # -------------------------------------------------
96
  # 3. UI
97
  # -------------------------------------------------
98
  with gr.Blocks(title="Square Theory โ€“ ์ตœ๋Œ€ 20๊ฐœ ๐Ÿ‡ฐ๐Ÿ‡ท") as demo:
99
- gr.Markdown("""# ๐ŸŸง Square Theory ์ œ์•ˆ (์ตœ๋Œ€ 20๊ฐœ)\n๋‹จ์–ด ํ•˜๋‚˜ ์ž…๋ ฅ โ†’ LLM์ด ์ ์ˆ˜ํ™”ยท์ •๋ ฌํ•œ ์‚ฌ๊ฐํ˜•/์นดํ”ผ/๋ธŒ๋žœ๋“œ ๋„ค์ž„""")
100
  seed = gr.Textbox(label="์‹œ๋“œ ๋‹จ์–ด(TL)", placeholder="์˜ˆ: ๊ณจ๋“ ")
101
  run = gr.Button("์ƒ์„ฑ")
102
- md_out = gr.Markdown(label="์ œ์•ˆ ๋ชฉ๋ก")
103
 
104
  run.click(generate, inputs=seed, outputs=md_out)
105
 
106
- if __name__ == "__main__":
107
- demo.launch()
108
- """
109
- Square Theory Generator (Markdownโ€‘only, up to 20 ideas)
110
- =====================================================
111
- 2025โ€‘05โ€‘28ย v7 โ— ๋ฐ•์Šค ๋‹ค์ด์–ด๊ทธ๋žจ ์ œ๊ฑฐ & ์ œ์•ˆย 20๊ฐœ๋กœ ํ™•์žฅ
112
- ---------------------------------------------------
113
- ๋ณ€๊ฒฝ ์š”์•ฝ
114
- ---------
115
- 1. **์‚ฌ๊ฐํ˜• ์‹œ๊ฐํ™” ์ œ๊ฑฐ** โ€’ ์ถœ๋ ฅ/์˜์กด์—์„œ `matplotlib` ์ „๋ถ€ ์‚ญ์ œ.
116
- 2. **์ œ์•ˆ ๊ฐœ์ˆ˜ ์ƒํ–ฅ** โ€’ LLM์ด ์ตœ๋Œ€ **20๊ฐœ** ์•„์ด๋””์–ด ๋ฐ˜ํ™˜.
117
- 3. **์œ ์—ฐ ๊ธธ์ด ํ—ˆ์šฉ** โ€’ 1โ€ฏโ‰คโ€ฏNโ€ฏโ‰คโ€ฏ20 ๋ฆฌ์ŠคํŠธ๋ฉด OK.
118
- 4. **UI ๋‹จ์ˆœํ™”** โ€’ ์‹œ๋“œ ์ž…๋ ฅ โ†’ ๋ฒ„ํŠผ โ†’ ๋งˆํฌ๋‹ค์šด ๊ฒฐ๊ณผ.
119
-
120
- ์‹คํ–‰๋ฒ•
121
- ------
122
- ```bash
123
- pip install --upgrade gradio openai
124
- export OPENAI_API_KEY="sk-..."
125
- python square_theory_gradio.py
126
- ```
127
- """
128
-
129
- import os
130
- import json
131
- import gradio as gr
132
- from openai import OpenAI
133
 
134
  # -------------------------------------------------
135
- # 0. OpenAI ํด๋ผ์ด์–ธํŠธ
136
  # -------------------------------------------------
137
- if not os.getenv("OPENAI_API_KEY"):
138
- raise EnvironmentError("OPENAI_API_KEY ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜์„ธ์š”.")
139
-
140
- client = OpenAI()
141
-
142
- # -------------------------------------------------
143
- # 1. LLM Prompt & Utilities
144
- # -------------------------------------------------
145
- SYSTEM_PROMPT = (
146
- "๋„ˆ๋Š” ํ•œ๊ตญ์–ด ์นดํ”ผยท๋ธŒ๋žœ๋“œ ๋„ค์ด๋ฐ ์ „๋ฌธ๊ฐ€์ด์ž Square Theory ๋„์šฐ๋ฏธ๋‹ค. "
147
- "์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ•˜๋‚˜์˜ ๋‹จ์–ด(tl)๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ’ˆ์งˆ์ด ๋›ฐ์–ด๋‚œ ์ˆœ์„œ๋Œ€๋กœ ์ตœ๋Œ€ 20๊ฐœ์˜ ์ œ์•ˆ์„ JSON ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•ด๋ผ. "
148
- "๊ฐ ์›์†Œ๋Š” tl, tr, br, bl, top_phrase, bottom_phrase, slogan, brand ํ•„๋“œ๋ฅผ ๊ฐ€์ง„๋‹ค. "
149
- "๋ฐฐ์—ด ์ฒซ ๋ฒˆ์งธ ์›์†Œ๊ฐ€ ๊ฐ€์žฅ ์šฐ์ˆ˜ํ•ด์•ผ ํ•œ๋‹ค. JSON ์™ธ ๋ฌธ์ž๋Š” ๊ธˆ์ง€ํ•œ๋‹ค."
150
- )
151
-
152
-
153
- def clean_json_block(text: str) -> str:
154
- text = text.strip()
155
- if text.startswith("```"):
156
- text = text.split("\n", 1)[1] if "\n" in text else text[3:]
157
- if text.endswith("```"):
158
- text = text[:-3]
159
- return text.strip()
160
-
161
-
162
- def call_llm(seed: str):
163
- resp = client.chat.completions.create(
164
- model="gpt-4o-mini",
165
- messages=[
166
- {"role": "system", "content": SYSTEM_PROMPT},
167
- {"role": "user", "content": seed},
168
- ],
169
- temperature=0.9,
170
- max_tokens=2048,
171
- )
172
- raw = resp.choices[0].message.content
173
- cleaned = clean_json_block(raw)
174
- try:
175
- data = json.loads(cleaned)
176
- if isinstance(data, dict):
177
- data = [data]
178
- if not isinstance(data, list):
179
- raise TypeError("LLM ์‘๋‹ต์ด ๋ฆฌ์ŠคํŠธ๊ฐ€ ์•„๋‹˜")
180
- if not 1 <= len(data) <= 20:
181
- raise ValueError("์‘๋‹ต ๋ฆฌ์ŠคํŠธ ๊ธธ์ด๊ฐ€ 1~20 ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚จ")
182
- except Exception as exc:
183
- raise ValueError(f"LLM JSON ํŒŒ์‹ฑ ์‹คํŒจ: {exc}\n์›๋ฌธ ์ผ๋ถ€: {cleaned[:300]} โ€ฆ")
184
- return data
185
-
186
- # -------------------------------------------------
187
- # 2. Gradio callback
188
- # -------------------------------------------------
189
-
190
- def generate(seed_word: str):
191
- results = call_llm(seed_word)
192
- md_lines = [f"## ์ด {len(results)}๊ฐœ ์ œ์•ˆ\n"]
193
- for idx, item in enumerate(results, 1):
194
- md_lines.append(
195
- f"### {idx}. {item['top_phrase']} / {item['bottom_phrase']}\n"
196
- f"- **์Šฌ๋กœ๊ฑด**: {item['slogan']}\n"
197
- f"- **๋ธŒ๋žœ๋“œ ๋„ค์ž„**: {item['brand']}\n"
198
- f"- (tl={item['tl']}, tr={item['tr']}, br={item['br']}, bl={item['bl']})\n"
199
- )
200
- return "\n".join(md_lines)
201
-
202
- # -------------------------------------------------
203
- # 3. UI
204
- # -------------------------------------------------
205
- with gr.Blocks(title="Square Theory โ€“ ์ตœ๋Œ€ 20๊ฐœ ๐Ÿ‡ฐ๐Ÿ‡ท") as demo:
206
- gr.Markdown("""# ๐ŸŸง Square Theory ์ œ์•ˆ (์ตœ๋Œ€ 20๊ฐœ)\n๋‹จ์–ด ํ•˜๋‚˜ ์ž…๋ ฅ โ†’ LLM์ด ์ ์ˆ˜ํ™”ยท์ •๋ ฌํ•œ ์‚ฌ๊ฐํ˜•/์นดํ”ผ/๋ธŒ๋žœ๋“œ ๋„ค์ž„""")
207
- seed = gr.Textbox(label="์‹œ๋“œ ๋‹จ์–ด(TL)", placeholder="์˜ˆ: ๊ณจ๋“ ")
208
- run = gr.Button("์ƒ์„ฑ")
209
- md_out = gr.Markdown(label="์ œ์•ˆ ๋ชฉ๋ก")
210
-
211
- run.click(generate, inputs=seed, outputs=md_out)
212
-
213
- if __name__ == "__main__":
214
- demo.launch()
 
1
  """
2
  Square Theory Generator (Markdownโ€‘only, up to 20 ideas)
3
  =====================================================
4
+ 2025โ€‘05โ€‘28ย v9 โ— ์ถœ๋ ฅ ํฌ๋งท ๊ฐœ์„  & ํ•„๋“œ ๊ตฌ๋ถ„ ๋ช…ํ™•ํ™”
5
  ---------------------------------------------------
6
  ๋ณ€๊ฒฝ ์š”์•ฝ
7
  ---------
8
+ 1. **์Šฌ๋กœ๊ฑด ยท ๋ธŒ๋žœ๋“œ ๋„ค์ž„ ๊ตฌํš** โ€” Markdown ํ…œํ”Œ๋ฆฟ์„ ๋‹ค์Œ ๊ตฌ์กฐ๋กœ ๊ฐœ์„ 
9
+ ```md
10
+ ### 1. ๋ธŒ๋žœ๋“œ ๋„ค์ž„: ๋ชจ๋‹์ปคํ”ผ
11
+ **๋ฉ”์ธ ์นดํ”ผ**
12
+ โ€ข ์ƒ๋‹จ: ํ’๋ฏธ๋ฅผ ๋‹ด์€ ์ปคํ”ผ
13
+ โ€ข ํ•˜๋‹จ: ๋‹น์‹ ์˜ ํ•˜๋ฃจ๋ฅผ ํŠน๋ณ„ํ•˜๊ฒŒ
14
+
15
+ **์Šฌ๋กœ๊ฑด**
16
+ > ์ปคํ”ผ ํ•œ์ž”์˜ ์—ฌ์œ 
17
+
18
+ **์‚ฌ๊ฐํ˜• ํ‚ค์›Œ๋“œ**
19
+ TL: ํ’๋ฏธ ยท TR: ์ปคํ”ผ ยท BR: ํ–ฅ๊ธฐ ยท BL: ํ•œ์ž”
20
+ ```
21
+ 2. **ํ”„๋กฌํ”„ํŠธ ๋ช…์„ธ ์œ ์ง€** โ€” JSON ๊ตฌ์กฐ ๋ณ€๋™์€ ์—†์Œ(ํ˜ธํ™˜).
22
+ 3. **์ถ”๊ฐ€ ๊ฐœ์„  ์ œ์•ˆ** โ€” ์ฝ”๋“œ ๋‚ด ์ฃผ์„์œผ๋กœ โ€˜์ถ”๊ฐ€ ํ•„๋“œยท๋žญํ‚น ๊ธฐ์ค€ยทCSV ๋‹ค์šด๋กœ๋“œโ€™ ์•„์ด๋””์–ด ์‚ฝ์ž….
23
 
24
  ์‹คํ–‰๋ฒ•
25
  ------
 
33
  import os
34
  import json
35
  import gradio as gr
36
+ from openai import OpenAI, error as oai_err
37
 
38
  # -------------------------------------------------
39
  # 0. OpenAI ํด๋ผ์ด์–ธํŠธ
 
53
  "๋ฐฐ์—ด ์ฒซ ๋ฒˆ์งธ ์›์†Œ๊ฐ€ ๊ฐ€์žฅ ์šฐ์ˆ˜ํ•ด์•ผ ํ•œ๋‹ค. JSON ์™ธ ๋ฌธ์ž๋Š” ๊ธˆ์ง€ํ•œ๋‹ค."
54
  )
55
 
56
+ FALLBACK_MODELS = ["gpt-4o-mini", "gpt-4o", "gpt-4o-preview", "gpt-4-turbo"]
57
 
58
+
59
+ def _clean_json_block(text: str) -> str:
60
+ """Strip ```json fences if present."""
61
  text = text.strip()
62
  if text.startswith("```"):
63
  text = text.split("\n", 1)[1] if "\n" in text else text[3:]
 
66
  return text.strip()
67
 
68
 
69
+ def _call_llm(seed: str):
70
+ last_exc = None
71
+ for model in FALLBACK_MODELS:
72
+ try:
73
+ resp = client.chat.completions.create(
74
+ model=model,
75
+ messages=[
76
+ {"role": "system", "content": SYSTEM_PROMPT},
77
+ {"role": "user", "content": seed},
78
+ ],
79
+ temperature=0.9,
80
+ max_tokens=2048,
81
+ )
82
+ cleaned = _clean_json_block(resp.choices[0].message.content)
83
+ data = json.loads(cleaned) if cleaned else []
84
+ if isinstance(data, dict):
85
+ data = [data]
86
+ if not isinstance(data, list) or not (1 <= len(data) <= 20):
87
+ raise ValueError("LLM ์‘๋‹ต์ด ์˜ฌ๋ฐ”๋ฅธ 1โ€‘20๊ฐœ ๋ฆฌ์ŠคํŠธ๊ฐ€ ์•„๋‹˜")
88
+ return data
89
+ except (oai_err.OpenAIError, json.JSONDecodeError, ValueError, TypeError) as exc:
90
+ last_exc = exc
91
+ continue
92
+ raise RuntimeError(f"LLM ํ˜ธ์ถœ ์‹คํŒจ: {last_exc}")
93
 
94
  # -------------------------------------------------
95
  # 2. Gradio callback
96
  # -------------------------------------------------
97
 
98
  def generate(seed_word: str):
99
+ seed_word = seed_word.strip()
100
+ if not seed_word:
101
+ return "โš ๏ธ **์‹œ๋“œ ๋‹จ์–ด๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.**"
102
+ try:
103
+ results = _call_llm(seed_word)
104
+ md = [f"## ์ด {len(results)}๊ฐœ ์ œ์•ˆ"]
105
+ for idx, item in enumerate(results, 1):
106
+ md.append(
107
+ f"### {idx}. ๋ธŒ๋žœ๋“œ ๋„ค์ž„: {item['brand']}\n"
108
+ f"**๋ฉ”์ธ ์นดํ”ผ** \
109
+ โ€ข ์ƒ๋‹จ: {item['top_phrase']} \
110
+ โ€ข ํ•˜๋‹จ: {item['bottom_phrase']}\n\n"
111
+ f"**์Šฌ๋กœ๊ฑด** \
112
+ > {item['slogan']}\n\n"
113
+ f"**์‚ฌ๊ฐํ˜• ํ‚ค์›Œ๋“œ** \
114
+ TL: {item['tl']} ยท TR: {item['tr']} ยท BR: {item['br']} ยท BL: {item['bl']}\n"
115
+ )
116
+ return "\n".join(md)
117
+ except Exception as exc:
118
+ return f"โŒ **์˜ค๋ฅ˜:** {exc}"
119
 
120
  # -------------------------------------------------
121
  # 3. UI
122
  # -------------------------------------------------
123
  with gr.Blocks(title="Square Theory โ€“ ์ตœ๋Œ€ 20๊ฐœ ๐Ÿ‡ฐ๐Ÿ‡ท") as demo:
124
+ gr.Markdown("""# ๐ŸŸง Square Theory ์ œ์•ˆ (์ตœ๋Œ€ 20๊ฐœ)\n๋‹จ์–ด ํ•˜๋‚˜ ์ž…๋ ฅ โ†’ LLM์ด ์ •๋ ฌํ•œ ์‚ฌ๊ฐํ˜•/์นดํ”ผ/๋ธŒ๋žœ๋“œ ๋„ค์ž„""")
125
  seed = gr.Textbox(label="์‹œ๋“œ ๋‹จ์–ด(TL)", placeholder="์˜ˆ: ๊ณจ๋“ ")
126
  run = gr.Button("์ƒ์„ฑ")
127
+ md_out = gr.Markdown()
128
 
129
  run.click(generate, inputs=seed, outputs=md_out)
130
 
131
+ # queue(): ๋กœ๋”ฉ ์ธ๋””์ผ€์ดํ„ฐ & ๋™์‹œ ์ ‘์† ์•ˆ์ •ํ™”
132
+ demo.queue().launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
  # -------------------------------------------------
135
+ # 4. (Optional) ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ์•„์ด๋””์–ด
136
  # -------------------------------------------------
137
+ # - JSON์— "why"(์„ ์ • ์ด์œ ) ํ•„๋“œ ์š”์ฒญ โ†’ ์•„์ด๋””์–ด ์„ค๋“๋ ฅ ๊ฐ•ํ™”
138
+ # - ์ฑ„๋„๋ณ„ ํƒœ๊ทธ๋ผ์ธ ๋ณ€ํ˜•(OOHยทSNSยทTV) ์ž๋™ ์ƒ์„ฑ ์˜ต์…˜
139
+ # - ๊ฒฐ๊ณผ CSV ๋‹ค์šด๋กœ๋“œ ๋ฒ„ํŠผ ์ถ”๊ฐ€(๊ทธ๋ผ๋””์˜ค File component)