Kims12 commited on
Commit
6a0362f
ยท
verified ยท
1 Parent(s): 58d748e

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +220 -0
app.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import openai
4
+ import requests
5
+ import logging
6
+ import asyncio
7
+ import aiohttp
8
+
9
+ # ๋กœ๊น… ์„ค์ •
10
+ logging.basicConfig(level=logging.INFO)
11
+ logger = logging.getLogger(__name__)
12
+
13
+ # OpenAI API ํด๋ผ์ด์–ธํŠธ ์„ค์ •
14
+ openai.api_key = os.getenv("OPENAI_API_KEY")
15
+
16
+ # ์š”์ฒญ์‚ฌํ•ญ์— ๋”ฐ๋ผ ์นดํ…Œ๊ณ ๋ฆฌ ์ˆ˜์ •
17
+ CATEGORIES = [
18
+ "๊ณตํฌ ๋งˆ์ผ€ํŒ…",
19
+ "์Šคํ† ๋ฆฌํ…”๋ง"
20
+ ]
21
+
22
+ def get_category_prompt(category):
23
+ if category == "๊ณตํฌ ๋งˆ์ผ€ํŒ…":
24
+ return """
25
+ # ๊ณตํฌ ๋งˆ์ผ€ํŒ… ์นดํ”ผ๋ผ์ดํŒ… ์ƒ์„ฑ ๊ทœ์น™
26
+ 1. ๋ฐ˜๋“œ์‹œ ํ•œ๊ธ€๋กœ ์ถœ๋ ฅํ•˜๋ผ.
27
+ 2. ๋„ˆ๋Š” ์„ธ๊ณ„ ์ตœ๊ณ ์˜ ๊ณตํฌ ๋งˆ์ผ€ํŒ… ์นดํ”ผ๋ผ์ดํ„ฐ์ด๋‹ค.
28
+ 3. ๋ฐ˜๋“œ์‹œ ์นดํ”ผ๋ผ์ดํŒ…์€ 30์ž ์ด๋‚ด๋กœ ์ž‘์„ฑํ•˜๊ณ , 20๊ฐœ๋งŒ ์ถœ๋ ฅํ•˜๋ผ.(๋‹ค๋ฅธ ๋‚ด์šฉ ์ถœ๋ ฅ ๊ธˆ์ง€)
29
+ 4. ๋ฐ˜๋“œ์‹œ ์ž…๋ ฅ๋œ ์ฃผ์ œ๋กœ๋งŒ ์ž‘์„ฑํ•˜๊ณ  ์˜ˆ์‹œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋‚ด์šฉ์„ ๋ณด๊ฐ•ํ•˜๋ผ.
30
+ 5. ๋ฐ˜๋“œ์‹œ 1 ๋ถ€ํ„ฐ 20๊นŒ์ง€ ๋ฒˆํ˜ธ(๋ฆฌ์ŠคํŠธํ˜•ํƒœ)๋ฅผ ๊ฐ™์ด ์ถœ๋ ฅํ•˜๋ผ
31
+ 6. ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋‘๋ ค์›€์„ ์ฃผ๋ฉด์„œ, ๋™์‹œ์— ์ œํ’ˆ์ด๋‚˜ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•ด์•ผ๋งŒ ํ•˜๋Š” ์ด์œ ๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ์–ดํ•„ํ•˜๋ผ.
32
+ 7. ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๋•Œ์˜ ์œ„ํ—˜์ด๋‚˜ ์†์‹ค์„ ๊ฐ•์กฐํ•˜๋ผ.
33
+ 8. ๊ฐ์ •์ ์ธ ๋‹จ์–ด์™€ ํ‘œํ˜„์„ ์‚ฌ์šฉํ•˜์—ฌ ๋…์ž์˜ ๋ถˆ์•ˆ์„ ์ฆํญ์‹œํ‚ค๋ผ
34
+ 9. ์ œํ’ˆ/์„œ๋น„์Šค์˜ ์ค‘์š”์„ฑ๊ณผ ๊ทธ๊ฒƒ์ด ์—†์„ ๋•Œ์˜ ๊ทน๋‹จ์ ์ธ ๊ฒฐ๊ณผ๋ฅผ ๊ตฌ์ฒด์ ์œผ๋กœ ์„ค๋ช…ํ•˜๋ผ.
35
+ ์˜ˆ์‹œ:
36
+ - ์Šค์ฟผํŠธ ํ•  ๋•Œ ์ด ๋™์ž‘ ํ•˜๋ฉด ๋ฌด๋ฆŽ ๋ถ€์ƒ ์˜ต๋‹ˆ๋‹ค
37
+ - ์ฑ… ์•ˆ ์ฝ๋Š” ์‚ฌ๋žŒ์ด ๊ฐ€๋‚œํ•  ํ™•๋ฅ  98%์ธ ์ด์œ 
38
+ - ์‹ ์ œํ’ˆ์„ ์ถœ์‹œํ•  ๋•Œ ์‹คํŒจํ•˜๋Š” 7 ๊ฐ€์ง€ ์น˜๋ช…์  ์‹ค์ˆ˜
39
+ - ์†Œ์…œ ๋ฏธ๋””์–ด๋ฅผ ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ์—…์ด ๋งํ•  ์ˆ˜ ์žˆ๋Š” ์ด์œ 
40
+ - ์ด ์•ฑ ์•ˆ ์“ฐ๋ฉด ํ•ดํ‚น ๋‹นํ•  ํ™•๋ฅ  80% ์ฆ๊ฐ€
41
+ - ์ด ๋ณดํ—˜ ์—†์œผ๋ฉด ์‚ฌ๊ณ  ์‹œ ํŒŒ์‚ฐ ์œ„๊ธฐ ์˜จ๋‹ค
42
+ - ์ถฉ๊ฒฉ! ์ด ์„ ํฌ๋ฆผ ์•ˆ ๋ฐ”๋ฅด๋ฉด ํ”ผ๋ถ€์•” ์œ„ํ—˜ 500% ์ฆ๊ฐ€
43
+ - ๊ฐ€์Šต๊ธฐ 2์ผ๋งŒ ๊ด€๋ฆฌํ•˜์ง€ ์•Š์•„๋„ "์„ธ๊ท  ๋ฒ”๋ฒ…"
44
+ - ๋ฐ”๋‹ค ํ™˜๊ฒฝ์˜ค์—ผ, ์‹ํƒ์œผ๋กœ ๋˜๋Œ์•„์˜จ๋‹ค. ํ”Œ๋ผ์Šคํ‹ฑ ์‚ฌ์šฉ ์ด๋Œ€๋กœ ๊ดœ์ฐฎ์€๊ฐ€์š”?
45
+ - "๋งฅ์ฃผ ํ•œ์ž”์ด๋ผ๋„ ๋‚ ๋งˆ๋‹ค ์ˆ ์ด ๋•ก๊ธด๋‹ค๋ฉด? ์ด๊ฒƒ ์˜์‹ฌํ•ด์•ผ"
46
+ """
47
+
48
+ elif category == "์Šคํ† ๋ฆฌํ…”๋ง":
49
+ return """
50
+ # ์Šคํ† ๋ฆฌํ…”๋ง ์นดํ”ผ๋ผ์ดํŒ… ์ƒ์„ฑ ๊ทœ์น™
51
+ 1. ๋ฐ˜๋“œ์‹œ ํ•œ๊ธ€๋กœ ์ถœ๋ ฅํ•˜๋ผ.
52
+ 2. ๋„ˆ๋Š” ์„ธ๊ณ„ ์ตœ๊ณ ์˜ ์Šคํ† ๋ฆฌํ…”๋ง ๋งˆ์ผ€ํŒ… ์นดํ”ผ๋ผ์ดํ„ฐ์ด๋‹ค.
53
+ 3. ๋ฐ˜๋“œ์‹œ ์นดํ”ผ๋ผ์ดํŒ…์€ 30์ž ์ด๋‚ด๋กœ ์ž‘์„ฑํ•˜๊ณ , 20๊ฐœ๋งŒ ์ถœ๋ ฅํ•˜๋ผ.(๋‹ค๋ฅธ ๋‚ด์šฉ ์ถœ๋ ฅ ๊ธˆ์ง€)
54
+ 4. ๋ฐ˜๋“œ์‹œ ์ž…๋ ฅ๋œ ์ฃผ์ œ๋กœ๋งŒ ์ž‘์„ฑํ•˜๊ณ  ์˜ˆ์‹œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋‚ด์šฉ์„ ๋ณด๊ฐ•ํ•˜๋ผ.
55
+ 5. ๋ฐ˜๋“œ์‹œ 1 ๋ถ€ํ„ฐ 20๊นŒ์ง€ ๋ฒˆํ˜ธ(๋ฆฌ์ŠคํŠธํ˜•ํƒœ)๋ฅผ ๊ฐ™์ด ์ถœ๋ ฅํ•˜๋ผ
56
+ 6. ์ œํ’ˆ/์„œ๋น„์Šค์™€ ๊ด€๋ จ๋œ ์งง๊ณ  ํฅ๋ฏธ๋กœ์šด ์ด์•ผ๊ธฐ๋ฅผ ๋งŒ๋“ค์–ด๋ผ.
57
+ 7. ๊ณ ๊ฐ์ด ๊ณต๊ฐํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์ด๋‚˜ ์บ๋ฆญํ„ฐ๋ฅผ ์„ค์ •ํ•˜๋ผ.
58
+ 8. ์ด์•ผ๊ธฐ๋ฅผ ํ†ตํ•ด ์ œํ’ˆ/์„œ๋น„์Šค์˜ ๊ฐ€์น˜๋ฅผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ „๋‹ฌํ•˜๋ผ.
59
+ ์˜ˆ์‹œ:
60
+ - ํ•œ ์–ด๋ถ€์˜ ๊ฟˆ์—์„œ ์‹œ์ž‘๋œ ํ˜์‹ ์ ์ธ ๋‚š์‹œ์žฅ๋น„
61
+ - 100๋…„ ๋œ ๊ฐ€์กฑ ๋ ˆ์‹œํ”ผ๋กœ ๋งŒ๋“  ์ˆ˜์ œ ์žผ
62
+ - ์šฐ์ฃผ ๋น„ํ–‰์‚ฌ์˜ ์•„์ด๋””์–ด๋กœ ํƒ„์ƒํ•œ ์ดˆ๊ฒฝ๋Ÿ‰ ์žฌํ‚ท
63
+ - ํ• ๋จธ๋‹ˆ์˜ 100๋…„ ๋œ ๋น„๋ฐ€ ๋ ˆ์‹œํ”ผ๋กœ ๋งŒ๋“  ๊ฑด๊ฐ•ํ•œ ์ง‘๋ฐฅ ๊ฐ„์‹
64
+ - ํžˆ๋ง๋ผ์•ผ ๋“ฑ์‚ฐ๊ฐ์˜ ๊ณ ๋ฏผ์—์„œ ์‹œ์ž‘๋œ ํ˜์‹ ์  ์ดˆ๊ฒฝ๋Ÿ‰ ๋ฐฐ๋‚ญ
65
+ - ๋ชฝ๊ณจ ์œ ๋ชฉ๋ฏผ์˜ ์ฒœ๋…„ ์ง€ํ˜œ๋ฅผ ๋‹ด์€ ์นœํ™˜๊ฒฝ ์˜คํ† ์บ ํ•‘ ํ…ํŠธ
66
+ - ๋ฐ”๋‹ค๋ฅผ ์‚ฌ๋ž‘ํ•œ ํ•ด์–‘์ƒ๋ฌผํ•™์ž์˜ ํ˜์‹ ์ ์ธ ํ•ด์–‘ ์ •ํ™” ๊ธฐ์ˆ 
67
+ - 20๋…„ ๋ถˆ๋ฉด์ฆ ํ™˜์ž๊ฐ€ ์ง์ ‘ ๊ฐœ๋ฐœํ•œ ๊ฟ€์ž  ์œ ๋„ ์Šค๋งˆํŠธ ๋ฒ ๊ฐœ
68
+ - ๊ธธ๊ณ ์–‘์ด 100๋งˆ๋ฆฌ๋ฅผ ๊ตฌ์กฐํ•œ ์ˆ˜์˜์‚ฌ์˜ ๋ฐ˜๋ ค๋™๋ฌผ ๊ฑด๊ฐ•๊ด€๋ฆฌ ์•ฑ
69
+ - ํŒ” ์—†๋Š” ์žฅ์• ์ธ ํ™”๊ฐ€์˜ ๊ฟˆ์„ ์ด๋ค„์ค€ ์ฒจ๋‹จ ๊ทธ๋ฆผ ๋„๊ตฌ
70
+ """
71
+
72
+ ########################################################
73
+ # (๊ธฐ์กด ๋™๊ธฐ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜) - ๊ธฐ์กด ์ฝ”๋“œ ์œ ์ง€
74
+ ########################################################
75
+ def call_api_sync(content, system_message, max_tokens, temperature, top_p):
76
+ response = requests.post(
77
+ "https://api.openai.com/v1/chat/completions",
78
+ headers={"Authorization": f"Bearer {openai.api_key}"},
79
+ json={
80
+ "model": "gpt-4o-mini",
81
+ "messages": [
82
+ {"role": "system", "content": system_message},
83
+ {"role": "user", "content": content},
84
+ ],
85
+ "max_tokens": max_tokens,
86
+ "temperature": temperature,
87
+ "top_p": top_p,
88
+ }
89
+ )
90
+ result = response.json()
91
+ return result['choices'][0]['message']['content']
92
+
93
+ def generate_copywriting(categories, topic):
94
+ max_tokens = 1000
95
+ temperature = 0.8
96
+ top_p = 0.95
97
+
98
+ results = {}
99
+ for category in categories:
100
+ prompt = get_category_prompt(category)
101
+ user_content = f"์ฃผ์ œ: {topic}"
102
+ copywriting = call_api_sync(user_content, prompt, max_tokens, temperature, top_p)
103
+ results[category] = copywriting
104
+ return results
105
+
106
+
107
+ ########################################################
108
+ # (์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋“ค) - ๋ณ‘๋ ฌ ๊ตฌ์กฐ ๋ฐ ์ŠคํŠธ๋ฆฌ๋ฐ
109
+ ########################################################
110
+ async def call_api_async(category, content, system_message, max_tokens, temperature, top_p):
111
+ """
112
+ ๋น„๋™๊ธฐ๋กœ OpenAI API๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜
113
+ """
114
+ async with aiohttp.ClientSession() as session:
115
+ headers = {
116
+ "Authorization": f"Bearer {openai.api_key}",
117
+ "Content-Type": "application/json"
118
+ }
119
+ payload = {
120
+ "model": "gpt-4o-mini",
121
+ "messages": [
122
+ {"role": "system", "content": system_message},
123
+ {"role": "user", "content": content},
124
+ ],
125
+ "max_tokens": max_tokens,
126
+ "temperature": temperature,
127
+ "top_p": top_p,
128
+ }
129
+ async with session.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload) as resp:
130
+ result = await resp.json()
131
+ copywriting = result["choices"][0]["message"]["content"]
132
+ return category, copywriting
133
+
134
+ async def generate_copywriting_async(categories, topic):
135
+ """
136
+ ๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ์— ๋Œ€ํ•ด ๋น„๋™๊ธฐ๋กœ API ํ˜ธ์ถœ์„ ์ˆ˜ํ–‰ํ•˜๊ณ ,
137
+ ์™„๋ฃŒ๋˜๋Š” ์ˆœ์„œ๋Œ€๋กœ (category, ๊ฒฐ๊ณผ) ๋ฅผ yield
138
+ """
139
+ max_tokens = 1000
140
+ temperature = 0.8
141
+ top_p = 0.95
142
+
143
+ tasks = []
144
+ for category in categories:
145
+ prompt = get_category_prompt(category)
146
+ user_content = f"์ฃผ์ œ: {topic}"
147
+ tasks.append(
148
+ asyncio.create_task(
149
+ call_api_async(category, user_content, prompt, max_tokens, temperature, top_p)
150
+ )
151
+ )
152
+
153
+ # ์™„๋ฃŒ๋œ ํƒœ์Šคํฌ๋ถ€ํ„ฐ ์ˆœ์„œ๋Œ€๋กœ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜
154
+ for task in asyncio.as_completed(tasks):
155
+ cat, copywriting = await task
156
+ yield cat, copywriting
157
+
158
+
159
+ ########################################################
160
+ # Gradio ์ธํ„ฐํŽ˜์ด์Šค
161
+ ########################################################
162
+ with gr.Blocks() as iface:
163
+ gr.Markdown("# AI ์นดํ”ผ๋ผ์ดํŒ… ์ƒ์„ฑ๊ธฐ")
164
+
165
+ with gr.Column():
166
+ topic = gr.Textbox(lines=1, label="์ฃผ์ œ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”")
167
+
168
+ generate_btn = gr.Button("์นดํ”ผ๋ผ์ดํŒ… ์ƒ์„ฑํ•˜๊ธฐ")
169
+ status = gr.Markdown("์ค€๋น„๋จ")
170
+
171
+ output_boxes = {}
172
+ with gr.Column():
173
+ for category in CATEGORIES:
174
+ output_box = gr.Textbox(label=category, visible=True)
175
+ output_boxes[category] = output_box
176
+
177
+ ########################################################
178
+ # ๊ธฐ์กด validate_and_generate ํ•จ์ˆ˜ ์ด๋ฆ„/์ถœ๋ ฅ ํ˜•์‹ ์œ ์ง€
179
+ # โ†’ ๋‚ด๋ถ€์—์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ + Gradio ์ŠคํŠธ๋ฆฌ๋ฐ(yield) ์‚ฌ์šฉ
180
+ ########################################################
181
+ def validate_and_generate(topic):
182
+ async def async_gen():
183
+ try:
184
+ # ๋น„๋™๊ธฐ๋กœ ์นดํ”ผ๋ผ์ดํŒ… ์ƒ์„ฑ
185
+ results = {}
186
+
187
+ # ์ˆœ์ฐจ๊ฐ€ ์•„๋‹Œ, '์™„๋ฃŒ๋œ ์ˆœ์„œ๋Œ€๋กœ' ๊ฒฐ๊ณผ๋ฅผ yield
188
+ async for cat, copywriting in generate_copywriting_async(CATEGORIES, topic):
189
+ results[cat] = copywriting
190
+ # ํ˜„์žฌ๊นŒ์ง€ ์™„๋ฃŒ๋œ ๋‚ด์šฉ๋งŒ ์—…๋ฐ์ดํŠธ
191
+ yield [
192
+ gr.update(value=f"์ง„ํ–‰์ค‘: [{cat}] ์นดํ”ผ๋ผ์ดํŒ… ์™„๋ฃŒ"),
193
+ *[gr.update(value=results.get(c, "")) for c in CATEGORIES]
194
+ ]
195
+
196
+ # ๋ชจ๋“  ์นดํ…Œ๊ณ ๋ฆฌ ์™„๋ฃŒ ํ›„ ์ตœ์ข… ๋ฉ”์„ธ์ง€
197
+ yield [
198
+ gr.update(value="์นดํ”ผ๋ผ์ดํŒ… ์ƒ์„ฑ์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."),
199
+ *[gr.update(value=results.get(c, "")) for c in CATEGORIES]
200
+ ]
201
+
202
+ except Exception as e:
203
+ logger.error(f"Error during copywriting generation: {str(e)}")
204
+ yield [
205
+ gr.update(value=f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"),
206
+ *[gr.update(value="") for _ in CATEGORIES]
207
+ ]
208
+
209
+ # Gradio์—์„œ ์ŠคํŠธ๋ฆฌ๋ฐ ์ถœ๋ ฅ์„ ์œ„ํ•ด async_gen ํ•จ์ˆ˜ ์ž์ฒด๋ฅผ ๋ฐ˜ํ™˜
210
+ return async_gen()
211
+
212
+ generate_btn.click(
213
+ fn=validate_and_generate,
214
+ inputs=[topic],
215
+ outputs=[status] + [output_boxes[category] for category in CATEGORIES]
216
+ )
217
+
218
+ # ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด queue()๋ฅผ ์‚ฌ์šฉ(Gradio 3.30+ ๊ธฐ์ค€)
219
+ iface.queue()
220
+ iface.launch()