Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,797 +1,59 @@
|
|
1 |
-
"""
|
2 |
-
이벤트 공지사항 생성기 - 완전 버전
|
3 |
-
그라디오 최신 버전 지원
|
4 |
-
"""
|
5 |
-
|
6 |
import gradio as gr
|
7 |
-
from datetime import datetime
|
8 |
-
from typing import List, Dict, Any
|
9 |
-
import json
|
10 |
-
import tempfile
|
11 |
-
import os
|
12 |
-
|
13 |
-
class EventGenerator:
|
14 |
-
"""이벤트 생성기 메인 클래스"""
|
15 |
-
|
16 |
-
def __init__(self):
|
17 |
-
self.monthly_data = {
|
18 |
-
1: {
|
19 |
-
"holidays": ["신정", "설날", "대보름"],
|
20 |
-
"special_days": ["새해", "신년", "다이어트의 달"],
|
21 |
-
"seasons": ["겨울", "새해맞이", "신년다짐"],
|
22 |
-
"trends": ["새해 계획", "다이어트", "정리정돈", "미니멀라이프"],
|
23 |
-
"colors": ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7"]
|
24 |
-
},
|
25 |
-
2: {
|
26 |
-
"holidays": ["밸런타인데이", "정월대보름"],
|
27 |
-
"special_days": ["초콜릿데이", "로즈데이"],
|
28 |
-
"seasons": ["겨울", "입춘", "매화꽃"],
|
29 |
-
"trends": ["러브", "로맨스", "셀프케어", "따뜻함"],
|
30 |
-
"colors": ["#FF69B4", "#FFB6C1", "#DC143C", "#FFC0CB", "#8B0000"]
|
31 |
-
},
|
32 |
-
3: {
|
33 |
-
"holidays": ["삼일절", "화이트데이"],
|
34 |
-
"special_days": ["여성의 날", "화이트데이"],
|
35 |
-
"seasons": ["봄", "벚꽃", "춘분", "개화"],
|
36 |
-
"trends": ["봄맞이", "새학기", "벚꽃놀이", "봄나들이"],
|
37 |
-
"colors": ["#FFB6C1", "#98FB98", "#87CEEB", "#F0E68C", "#DDA0DD"]
|
38 |
-
},
|
39 |
-
4: {
|
40 |
-
"holidays": ["만우절", "식목일"],
|
41 |
-
"special_days": ["블랙데이", "킹데이"],
|
42 |
-
"seasons": ["봄", "벚꽃만개", "꽃구경"],
|
43 |
-
"trends": ["벚꽃축제", "봄피크닉", "새학기적응", "아웃도어"],
|
44 |
-
"colors": ["#FFB6C1", "#98FB98", "#F0E68C", "#DDA0DD", "#87CEEB"]
|
45 |
-
},
|
46 |
-
5: {
|
47 |
-
"holidays": ["어린이날", "어버이날", "스승의날", "부처님오신날"],
|
48 |
-
"special_days": ["가정의 달", "로즈데이", "감사데이"],
|
49 |
-
"seasons": ["봄", "신록", "야외활동"],
|
50 |
-
"trends": ["가족사랑", "감사", "나들이", "어린이날선물"],
|
51 |
-
"colors": ["#32CD32", "#FFB6C1", "#87CEEB", "#F0E68C", "#DDA0DD"]
|
52 |
-
},
|
53 |
-
6: {
|
54 |
-
"holidays": ["현충일", "단오"],
|
55 |
-
"special_days": ["키스데이", "패밀리데이"],
|
56 |
-
"seasons": ["초여름", "장마준비", "여름나기"],
|
57 |
-
"trends": ["여름준비", "다이어트", "워터파크", "바캉스준비"],
|
58 |
-
"colors": ["#00CED1", "#FFD700", "#FF6347", "#32CD32", "#FF69B4"]
|
59 |
-
},
|
60 |
-
7: {
|
61 |
-
"holidays": ["제헌절", "초복", "중복"],
|
62 |
-
"special_days": ["실버데이", "썸머데이"],
|
63 |
-
"seasons": ["여름", "장마", "휴가철"],
|
64 |
-
"trends": ["여름휴가", "워터액티비티", "시원한음식", "휴가패션"],
|
65 |
-
"colors": ["#00BFFF", "#FFD700", "#FF6347", "#32CD32", "#FF69B4"]
|
66 |
-
},
|
67 |
-
8: {
|
68 |
-
"holidays": ["광복절", "말복"],
|
69 |
-
"special_days": ["그린데이", "썸머바캉스"],
|
70 |
-
"seasons": ["여름", "휴가철", "더위절정"],
|
71 |
-
"trends": ["여름휴가절정", "바다여행", "축제", "여름추억"],
|
72 |
-
"colors": ["#00BFFF", "#FF6347", "#FFD700", "#32CD32", "#FF69B4"]
|
73 |
-
},
|
74 |
-
9: {
|
75 |
-
"holidays": ["추석", "추분"],
|
76 |
-
"special_days": ["포토데이", "뮤직데이"],
|
77 |
-
"seasons": ["가을", "추석연휴", "선선함"],
|
78 |
-
"trends": ["추석준비", "가을패션", "독서의계절", "문화생활"],
|
79 |
-
"colors": ["#FF8C00", "#DC143C", "#B8860B", "#CD853F", "#D2691E"]
|
80 |
-
},
|
81 |
-
10: {
|
82 |
-
"holidays": ["개천절", "한글날"],
|
83 |
-
"special_days": ["와인데이", "커피데이"],
|
84 |
-
"seasons": ["가을", "단풍", "쌀쌀함"],
|
85 |
-
"trends": ["가을단풍", "독서", "카페문화", "가을나들이"],
|
86 |
-
"colors": ["#FF8C00", "#DC143C", "#B8860B", "#8B4513", "#A0522D"]
|
87 |
-
},
|
88 |
-
11: {
|
89 |
-
"holidays": ["빼빼로데이", "수능"],
|
90 |
-
"special_days": ["무비데이", "오렌지데이"],
|
91 |
-
"seasons": ["늦가을", "쌀쌀함", "겨울준비"],
|
92 |
-
"trends": ["빼빼로데이", "수능응원", "겨울준비", "연말준비"],
|
93 |
-
"colors": ["#8B4513", "#A0522D", "#CD853F", "#D2691E", "#FF8C00"]
|
94 |
-
},
|
95 |
-
12: {
|
96 |
-
"holidays": ["크리스마스", "성탄절", "동지"],
|
97 |
-
"special_days": ["허그데이", "키스데이"],
|
98 |
-
"seasons": ["겨울", "연말", "크리스마스"],
|
99 |
-
"trends": ["크리스마스", "연말파티", "선물", "한해마무리"],
|
100 |
-
"colors": ["#DC143C", "#228B22", "#FFD700", "#800080", "#FF69B4"]
|
101 |
-
}
|
102 |
-
}
|
103 |
-
|
104 |
-
self.event_templates = {
|
105 |
-
"댓글 달기 이벤트": {
|
106 |
-
"steps": ["해당 게시글 찾아가기", "감성적인 댓글 작성하기", "댓글 등록 완료"],
|
107 |
-
"description": "지정된 게시글에 댓글을 달아주세요"
|
108 |
-
},
|
109 |
-
"게시글 작성 이벤트": {
|
110 |
-
"steps": ["이벤트 주제 확인하기", "창의적인 게시글 작성하기", "해시태그 포함하여 업로드"],
|
111 |
-
"description": "주제에 맞는 게시글을 작성해주세요"
|
112 |
-
},
|
113 |
-
"좋아요/공감 이벤트": {
|
114 |
-
"steps": ["이벤트 게시글 확인하기", "좋아요 버튼 클릭하기", "추가 액션 완료하기"],
|
115 |
-
"description": "마음에 드는 게시글에 좋아요를 눌러주세요"
|
116 |
-
},
|
117 |
-
"출석체크 이벤트": {
|
118 |
-
"steps": ["매일 커뮤니티 접속하기", "출석체크 버튼 클릭하기", "연속 출석 달성하기"],
|
119 |
-
"description": "매일 커뮤니티에 방문하여 출석체크를 해주세요"
|
120 |
-
},
|
121 |
-
"추천인 이벤트": {
|
122 |
-
"steps": ["초대 링크 생성하기", "친구에게 링크 공유하기", "친구 가입 완료 확인하기"],
|
123 |
-
"description": "친구를 초대하고 함께 이벤트에 참여해주세요"
|
124 |
-
},
|
125 |
-
"사진 업로드 이벤트": {
|
126 |
-
"steps": ["테마에 맞는 사진 촬영하기", "사진 업로드하기", "설명글과 함께 공유하기"],
|
127 |
-
"description": "테마에 맞는 사진을 업로드해주세요"
|
128 |
-
},
|
129 |
-
"퀴즈/설문 이벤트": {
|
130 |
-
"steps": ["퀴즈 문제 확인하기", "정답 또는 의견 제출하기", "제출 완료 확인하기"],
|
131 |
-
"description": "퀴즈를 풀거나 설문에 참여해주세요"
|
132 |
-
}
|
133 |
-
}
|
134 |
-
|
135 |
-
def analyze_monthly_concepts(self, month: int, year: int = 2025) -> List[Dict[str, Any]]:
|
136 |
-
"""월별 컨셉 분석"""
|
137 |
-
|
138 |
-
month_data = self.monthly_data.get(month, {})
|
139 |
-
concepts = []
|
140 |
-
|
141 |
-
# 컨셉 1: 주요 기념일 기반
|
142 |
-
if month_data.get("holidays"):
|
143 |
-
main_holiday = month_data["holidays"][0]
|
144 |
-
concepts.append({
|
145 |
-
"name": f"{main_holiday} 특별 이벤트",
|
146 |
-
"theme": f"{main_holiday}를 테마로 한 감성 이벤트",
|
147 |
-
"catchphrase": f"💕 {main_holiday}과 함께 특별한 추억을 만들어요!",
|
148 |
-
"reason": f"{month}월의 대표 기념일인 {main_holiday}로 높은 관심과 참여도 예상",
|
149 |
-
"colors": month_data.get("colors", ["#FF69B4"])[:3],
|
150 |
-
"participation_score": 8.5,
|
151 |
-
"participation_reason": "주요 기념일로 인한 높은 관심도와 시즌성",
|
152 |
-
"event_style": "댓글 이벤트 + 인증샷 업로드",
|
153 |
-
"competitive_edge": "시즌 특화 컨텐츠로 차별화",
|
154 |
-
"target_appeal": "기념일 감성과 공감대 형성"
|
155 |
-
})
|
156 |
-
|
157 |
-
# 컨셉 2: 계절/트렌드 기반
|
158 |
-
if month_data.get("trends"):
|
159 |
-
trend_theme = month_data["trends"][0]
|
160 |
-
concepts.append({
|
161 |
-
"name": f"{trend_theme} 챌린지",
|
162 |
-
"theme": f"최신 {trend_theme} 트렌드 참여형 이벤트",
|
163 |
-
"catchphrase": f"✨ 지금 핫한 {trend_theme}! 함께 도전해요!",
|
164 |
-
"reason": f"현재 인기 트렌드인 {trend_theme}로 젊은 층 어필",
|
165 |
-
"colors": month_data.get("colors", ["#4ECDC4"])[1:4],
|
166 |
-
"participation_score": 8.0,
|
167 |
-
"participation_reason": "최신 트렌드로 인한 화제성과 참여욕구",
|
168 |
-
"event_style": "챌린지 참여 + SNS 공유",
|
169 |
-
"competitive_edge": "트렌드 선도적 이벤트",
|
170 |
-
"target_appeal": "트렌드 민감층과 SNS 활용"
|
171 |
-
})
|
172 |
-
|
173 |
-
# 컨셉 3: 계절감 기반
|
174 |
-
if month_data.get("seasons"):
|
175 |
-
season_theme = month_data["seasons"][0]
|
176 |
-
concepts.append({
|
177 |
-
"name": f"{season_theme} 라이프 이벤트",
|
178 |
-
"theme": f"{season_theme} 계절 맞이 라이프스타일 이벤트",
|
179 |
-
"catchphrase": f"🌸 {season_theme}과 함께하는 일상의 소소한 행복!",
|
180 |
-
"reason": f"{season_theme} 계절감으로 자연스러운 참여 유도",
|
181 |
-
"colors": month_data.get("colors", ["#98FB98"])[2:5],
|
182 |
-
"participation_score": 7.5,
|
183 |
-
"participation_reason": "계절적 공감대와 일상 연관성",
|
184 |
-
"event_style": "포토 챌린지 + 후기 공유",
|
185 |
-
"competitive_edge": "계절별 맞춤 컨텐츠",
|
186 |
-
"target_appeal": "일상 속 계절감과 감성"
|
187 |
-
})
|
188 |
-
|
189 |
-
# 컨셉 4: 커뮤니티 소통 기반
|
190 |
-
concepts.append({
|
191 |
-
"name": f"{month}월 우리들의 이야기",
|
192 |
-
"theme": "커뮤니티 멤버 간 소통과 공감 이벤트",
|
193 |
-
"catchphrase": f"💬 {month}월, 우리의 특별한 이야기를 들려주세요!",
|
194 |
-
"reason": "커뮤니티 결속력 강화와 지속적 참여 유도",
|
195 |
-
"colors": month_data.get("colors", ["#87CEEB"])[-3:],
|
196 |
-
"participation_score": 7.0,
|
197 |
-
"participation_reason": "커뮤니티 애착도와 소속감 기반 참여",
|
198 |
-
"event_style": "스토리텔링 + 공감 이벤트",
|
199 |
-
"competitive_edge": "진정성 있는 커뮤니티 소통",
|
200 |
-
"target_appeal": "소속감과 공감대 형성"
|
201 |
-
})
|
202 |
-
|
203 |
-
# 컨셉 5: 스페셜 데이 기반
|
204 |
-
if month_data.get("special_days"):
|
205 |
-
special_day = month_data["special_days"][0]
|
206 |
-
concepts.append({
|
207 |
-
"name": f"{special_day} 스페셜 위크",
|
208 |
-
"theme": f"{special_day} 맞이 특별 혜택 이벤트",
|
209 |
-
"catchphrase": f"🎁 {special_day} 특별한 선물이 기다려요!",
|
210 |
-
"reason": f"{special_day}의 특별함을 활용한 프리미엄 이벤트",
|
211 |
-
"colors": month_data.get("colors", ["#FFB6C1"])[:3],
|
212 |
-
"participation_score": 7.8,
|
213 |
-
"participation_reason": "특별한 날에 대한 기대감과 혜택 관심",
|
214 |
-
"event_style": "미션 완료 + 럭키박스",
|
215 |
-
"competitive_edge": "특별 혜택과 깜짝 이벤트",
|
216 |
-
"target_appeal": "특별함과 혜택에 대한 기대"
|
217 |
-
})
|
218 |
-
|
219 |
-
return concepts
|
220 |
-
|
221 |
-
def generate_event_notice(self, concept_data: Dict, event_type: str, custom_event: str = None) -> str:
|
222 |
-
"""완성된 이벤트 공지사항 생성"""
|
223 |
-
|
224 |
-
concept_name = concept_data.get("name", "특별 이벤트")
|
225 |
-
catchphrase = concept_data.get("catchphrase", "✨ 특별한 이벤트에 참여하세요!")
|
226 |
-
theme = concept_data.get("theme", "커뮤니티 이벤트")
|
227 |
-
|
228 |
-
# 이벤트 기간 설정
|
229 |
-
now = datetime.now()
|
230 |
-
start_date = now.strftime("%Y.%m.%d")
|
231 |
-
end_date = (now + timedelta(days=7)).strftime("%Y.%m.%d")
|
232 |
-
|
233 |
-
# 템플릿 선택
|
234 |
-
if custom_event and event_type == "직접 입력":
|
235 |
-
template = {
|
236 |
-
"description": custom_event,
|
237 |
-
"steps": ["이벤트 내용 확인하기", "요구사항에 맞게 참여하기", "참여 완료 확인하기"]
|
238 |
-
}
|
239 |
-
else:
|
240 |
-
template = self.event_templates.get(event_type, self.event_templates["댓글 달기 이벤트"])
|
241 |
-
|
242 |
-
# 공지사항 생성
|
243 |
-
notice = f"""{catchphrase}
|
244 |
-
|
245 |
-
🎉 {concept_name} 🎉
|
246 |
-
|
247 |
-
📅 이벤트 기간: {start_date} ~ {end_date} 23:59
|
248 |
-
|
249 |
-
========================
|
250 |
-
✨ EVENT
|
251 |
-
{theme}을 테마로 한 특별한 이벤트에 참여하세요!
|
252 |
-
많은 분들의 적극적인 참여를 기다리고 있어요 💕
|
253 |
-
|
254 |
-
📅 이벤트 기간: {start_date} ~ {end_date}
|
255 |
-
========================
|
256 |
-
|
257 |
-
🎯 STEP 1
|
258 |
-
{template["steps"][0]}
|
259 |
-
* 이벤트 게시글을 꼼꼼히 확인해주세요!
|
260 |
-
|
261 |
-
🎯 STEP 2
|
262 |
-
{template["steps"][1]}
|
263 |
-
* 진심이 담긴 따뜻한 마음으로 참여해주세요
|
264 |
-
|
265 |
-
🎯 STEP 3
|
266 |
-
{template["steps"][2]}
|
267 |
-
* 모든 과정을 완료하시면 참여 완료입니다!
|
268 |
-
|
269 |
-
=================
|
270 |
-
🎁 당첨혜택
|
271 |
-
✨ 1등 (1명): 스타벅스 5만원 기프트카드
|
272 |
-
🎉 2등 (3명): 베스킨라빈스 아이스크림 쿠폰
|
273 |
-
💝 3등 (10명): 편의점 5천원 상품권
|
274 |
-
🌟 참가상 (50명): 모바일 치킨 쿠폰
|
275 |
-
|
276 |
-
📋 추첨 방식: 참여자 중 무작위 추첨
|
277 |
-
========================
|
278 |
-
|
279 |
-
👥 이벤트 대상
|
280 |
-
✅ 커뮤니티 정회원 (가입 후 7일 경과)
|
281 |
-
✅ 만 18세 이상 성인
|
282 |
-
✅ 이벤트 기간 내 정상 참여자
|
283 |
-
|
284 |
-
(*중복 참여, 어뷰징 계정 제외)
|
285 |
-
========================
|
286 |
-
|
287 |
-
📮 수령방법
|
288 |
-
1️⃣ 당첨자 발표: 이벤트 종료 후 3일 이내
|
289 |
-
2️⃣ 개별 메시지를 통한 당첨 안내
|
290 |
-
3️⃣ 본인 확인 후 7일 이내 회신 필수
|
291 |
-
4️⃣ 모바일 쿠폰/기프트카드 발송
|
292 |
-
|
293 |
-
📞 문의처: 커뮤니티 고객센터
|
294 |
-
🕐 수령 기한: 당첨 안내 후 30일 이내
|
295 |
-
=========================
|
296 |
-
|
297 |
-
⚠️ 꼭 확인하세요!
|
298 |
-
※ 부적절한 내용의 댓글/게시글은 삭제될 수 있습니다
|
299 |
-
※ 중복 계정이나 어뷰징으로 의심되는 참여는 제외됩니다
|
300 |
-
※ 당첨자는 본인 확인을 위해 추가 정보 요청이 있을 수 있습니다
|
301 |
-
※ 상품은 현금으로 교환되지 않으며, 재판매가 불가합니다
|
302 |
-
※ 이벤트 내용은 운영진의 판단에 따라 변경될 수 있습니다
|
303 |
-
※ 문의사항은 고객센터를 통��� 연락해주세요
|
304 |
-
|
305 |
-
===========================
|
306 |
-
📞 고객센터: 1234-5678
|
307 |
-
🕐 운영시간: 평일 09:30~18:00 (점심시간 12:00~13:00)
|
308 |
-
💬 카카오톡: @event_community
|
309 |
-
※ 주말 및 공휴일 휴무
|
310 |
-
|
311 |
-
💝 많은 분들의 참여 부탁드려요! 감사합니다 💕"""
|
312 |
-
|
313 |
-
return notice.strip()
|
314 |
-
|
315 |
-
def count_text_stats(self, text: str) -> str:
|
316 |
-
"""텍스트 통계 계산"""
|
317 |
-
total_chars = len(text)
|
318 |
-
chars_no_space = len(text.replace(" ", "").replace("\n", ""))
|
319 |
-
words = len(text.split())
|
320 |
-
lines = len(text.split("\n"))
|
321 |
-
|
322 |
-
return f"총 글자수: {total_chars:,}자 | 공백제외: {chars_no_space:,}자 | 단어수: {words:,}개 | 줄수: {lines:,}줄"
|
323 |
|
324 |
-
def
|
325 |
-
"""
|
326 |
-
|
327 |
-
generator = EventGenerator()
|
328 |
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
padding: 25px;
|
343 |
-
border-radius: 15px;
|
344 |
-
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
|
345 |
-
margin-bottom: 20px;
|
346 |
-
}
|
347 |
-
.output-section {
|
348 |
-
background: white;
|
349 |
-
padding: 25px;
|
350 |
-
border-radius: 15px;
|
351 |
-
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
|
352 |
-
}
|
353 |
-
.concept-card {
|
354 |
-
background: linear-gradient(45deg, #e3f2fd, #f1f8e9);
|
355 |
-
padding: 20px;
|
356 |
-
border-radius: 12px;
|
357 |
-
margin: 15px 0;
|
358 |
-
border-left: 5px solid #2196f3;
|
359 |
-
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
360 |
-
}
|
361 |
-
.stats-box {
|
362 |
-
background: #fff3cd;
|
363 |
-
padding: 10px;
|
364 |
-
border-radius: 8px;
|
365 |
-
border: 1px solid #ffeaa7;
|
366 |
-
margin-top: 10px;
|
367 |
}
|
368 |
-
"""
|
369 |
|
370 |
-
|
371 |
-
title="🎉 AI 이벤트 공지사항 생성기",
|
372 |
-
theme=gr.themes.Soft(),
|
373 |
-
css=custom_css
|
374 |
-
) as demo:
|
375 |
-
|
376 |
-
# 헤더
|
377 |
-
with gr.Column(elem_classes="main-header"):
|
378 |
-
gr.Markdown("""
|
379 |
-
# 🎉 AI 이벤트 공지사항 생성기
|
380 |
-
### 실시간 트렌드 분석으로 완벽한 이벤트 기획을 도와드립니다
|
381 |
-
#### 20-40대 여성 타겟 커뮤니티 이벤트 전문 생성기
|
382 |
-
""")
|
383 |
-
|
384 |
-
with gr.Row():
|
385 |
-
# 좌측: 입력 영역
|
386 |
-
with gr.Column(scale=1, elem_classes="input-section"):
|
387 |
-
gr.Markdown("## ⚙️ 기본 설정")
|
388 |
-
|
389 |
-
with gr.Row():
|
390 |
-
year_input = gr.Number(
|
391 |
-
value=2025,
|
392 |
-
label="📅 연도",
|
393 |
-
minimum=2024,
|
394 |
-
maximum=2030,
|
395 |
-
step=1
|
396 |
-
)
|
397 |
-
|
398 |
-
month_input = gr.Dropdown(
|
399 |
-
choices=[f"{i}월" for i in range(1, 13)],
|
400 |
-
label="📅 이벤트 월 선택",
|
401 |
-
value=f"{datetime.now().month}월"
|
402 |
-
)
|
403 |
-
|
404 |
-
analyze_btn = gr.Button(
|
405 |
-
"🧠 AI 컨셉 분석 시작",
|
406 |
-
variant="secondary",
|
407 |
-
size="lg"
|
408 |
-
)
|
409 |
-
|
410 |
-
# 컨셉 선택 영역
|
411 |
-
with gr.Group(visible=False) as concept_group:
|
412 |
-
gr.Markdown("### 🎨 추천 컨셉 선택")
|
413 |
-
|
414 |
-
concept_selector = gr.Dropdown(
|
415 |
-
label="컨셉을 선택해주세요",
|
416 |
-
interactive=True
|
417 |
-
)
|
418 |
-
|
419 |
-
concept_preview = gr.Textbox(
|
420 |
-
label="📊 선택된 컨셉 미리보기",
|
421 |
-
lines=8,
|
422 |
-
interactive=False
|
423 |
-
)
|
424 |
-
|
425 |
-
gr.Markdown("## 🎯 이벤트 설정")
|
426 |
-
|
427 |
-
event_type_selector = gr.Dropdown(
|
428 |
-
choices=[
|
429 |
-
"댓글 달기 이벤트",
|
430 |
-
"게시글 작성 이벤트",
|
431 |
-
"좋아요/공감 이벤트",
|
432 |
-
"출석체크 이벤트",
|
433 |
-
"추천인 이벤트",
|
434 |
-
"사진 업로드 이벤트",
|
435 |
-
"퀴즈/설문 이벤트",
|
436 |
-
"직접 입력"
|
437 |
-
],
|
438 |
-
label="🎯 이벤트 유형 선택",
|
439 |
-
value="댓글 달기 이벤트"
|
440 |
-
)
|
441 |
-
|
442 |
-
custom_event_input = gr.Textbox(
|
443 |
-
label="✏️ 커스텀 이벤트 설명",
|
444 |
-
placeholder="'직접 입력' 선택시 원하는 이벤트 내용을 자세히 설명해주세요",
|
445 |
-
visible=False,
|
446 |
-
lines=4
|
447 |
-
)
|
448 |
-
|
449 |
-
generate_btn = gr.Button(
|
450 |
-
"✨ 완성된 공지사항 생성하기",
|
451 |
-
variant="primary",
|
452 |
-
size="lg",
|
453 |
-
visible=False
|
454 |
-
)
|
455 |
-
|
456 |
-
# 우측: 결과 출력 영역
|
457 |
-
with gr.Column(scale=2, elem_classes="output-section"):
|
458 |
-
|
459 |
-
with gr.Tabs() as tabs:
|
460 |
-
|
461 |
-
with gr.TabItem("🧠 AI 컨셉 분석"):
|
462 |
-
concept_analysis_output = gr.Markdown(
|
463 |
-
value="👆 먼저 좌측에서 연도와 월을 선택한 후 'AI 컨셉 분석 시작' 버튼을 클릭해주세요",
|
464 |
-
elem_classes="concept-card"
|
465 |
-
)
|
466 |
-
|
467 |
-
with gr.TabItem("📝 완성된 공지사항"):
|
468 |
-
final_notice_output = gr.Textbox(
|
469 |
-
label="생성된 이벤트 공지사항",
|
470 |
-
lines=35,
|
471 |
-
placeholder="컨셉 선택 후 '완성된 공지사항 생성하기' 버튼을 클릭하면 결과가 나타납니다",
|
472 |
-
show_copy_button=True,
|
473 |
-
max_lines=50
|
474 |
-
)
|
475 |
-
|
476 |
-
# 통계 및 버튼
|
477 |
-
with gr.Row():
|
478 |
-
text_stats_output = gr.Textbox(
|
479 |
-
label="📊 텍스트 통계",
|
480 |
-
lines=1,
|
481 |
-
interactive=False,
|
482 |
-
visible=False,
|
483 |
-
elem_classes="stats-box"
|
484 |
-
)
|
485 |
-
|
486 |
-
with gr.Row():
|
487 |
-
download_btn = gr.DownloadButton(
|
488 |
-
"💾 텍스트 파일로 다운로드",
|
489 |
-
size="sm",
|
490 |
-
variant="secondary",
|
491 |
-
visible=False
|
492 |
-
)
|
493 |
-
regenerate_btn = gr.Button(
|
494 |
-
"🔄 다시 생성하기",
|
495 |
-
size="sm",
|
496 |
-
visible=False
|
497 |
-
)
|
498 |
-
|
499 |
-
with gr.TabItem("🎨 컨셉 상세정보"):
|
500 |
-
concept_details_output = gr.JSON(
|
501 |
-
label="선택된 컨셉의 상세 정보",
|
502 |
-
visible=False
|
503 |
-
)
|
504 |
-
|
505 |
-
# 상태 관리
|
506 |
-
concepts_state = gr.State([])
|
507 |
-
selected_concept_state = gr.State(None)
|
508 |
-
|
509 |
-
# 이벤트 핸들러 함수들
|
510 |
-
def handle_concept_analysis(year, month):
|
511 |
-
"""AI 컨셉 분석 처리"""
|
512 |
-
try:
|
513 |
-
month_num = int(month.replace('월', ''))
|
514 |
-
concepts = generator.analyze_monthly_concepts(month_num, year)
|
515 |
-
|
516 |
-
concept_choices = [f"{concept['name']} - {concept['theme']}" for concept in concepts]
|
517 |
-
|
518 |
-
# 분석 결과 마크다운 생성
|
519 |
-
analysis_md = f"# 🎯 {year}년 {month} AI 분석 결과\n\n"
|
520 |
-
analysis_md += f"**분석 완료:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
|
521 |
-
analysis_md += f"**총 {len(concepts)}개 컨셉 추천**\n\n"
|
522 |
-
|
523 |
-
for i, concept in enumerate(concepts, 1):
|
524 |
-
colors_display = " ".join([f"`{color}`" for color in concept['colors'][:3]])
|
525 |
-
|
526 |
-
analysis_md += f"""
|
527 |
-
## {i}. {concept['name']}
|
528 |
-
**🏷️ 테마:** {concept['theme']}
|
529 |
-
**🎯 타겟 어필:** {concept['target_appeal']}
|
530 |
-
**⭐ 예상 참여도:** {concept['participation_score']}/10점
|
531 |
-
**🎪 추천 이벤트:** {concept['event_style']}
|
532 |
-
**🎨 색상 팔레트:** {colors_display}
|
533 |
-
**💡 선정 이유:** {concept['reason']}
|
534 |
-
|
535 |
-
---
|
536 |
-
"""
|
537 |
-
|
538 |
-
return (
|
539 |
-
gr.update(visible=True), # concept_group
|
540 |
-
gr.update(choices=concept_choices, value=concept_choices[0] if concept_choices else None), # concept_selector
|
541 |
-
gr.update(visible=True), # generate_btn
|
542 |
-
analysis_md, # concept_analysis_output
|
543 |
-
concepts # concepts_state
|
544 |
-
)
|
545 |
-
|
546 |
-
except Exception as e:
|
547 |
-
error_message = f"❌ 컨셉 분석 중 오류가 발생했습니다: {str(e)}"
|
548 |
-
return (
|
549 |
-
gr.update(visible=False),
|
550 |
-
gr.update(choices=[], value=None),
|
551 |
-
gr.update(visible=False),
|
552 |
-
error_message,
|
553 |
-
[]
|
554 |
-
)
|
555 |
-
|
556 |
-
def handle_concept_selection(selected_concept_name, concepts_data):
|
557 |
-
"""컨셉 선택 처리"""
|
558 |
-
try:
|
559 |
-
if selected_concept_name and concepts_data:
|
560 |
-
selected_idx = next(i for i, c in enumerate(concepts_data)
|
561 |
-
if f"{c['name']} - {c['theme']}" == selected_concept_name)
|
562 |
-
selected_concept = concepts_data[selected_idx]
|
563 |
-
|
564 |
-
# 미리보기 텍스트 생성
|
565 |
-
preview_text = f"""🎨 컨셉명: {selected_concept['name']}
|
566 |
-
|
567 |
-
🏷️ 테마: {selected_concept['theme']}
|
568 |
-
|
569 |
-
💬 캐치프레이즈: {selected_concept['catchphrase']}
|
570 |
-
|
571 |
-
🎯 타겟 어필: {selected_concept['target_appeal']}
|
572 |
-
|
573 |
-
⭐ 예상 참여도: {selected_concept['participation_score']}/10점
|
574 |
-
📊 참여 근거: {selected_concept['participation_reason']}
|
575 |
-
|
576 |
-
🎪 추천 이벤트: {selected_concept['event_style']}
|
577 |
-
|
578 |
-
🎨 색상 팔레트: {', '.join(selected_concept['colors'][:3])}
|
579 |
-
|
580 |
-
💡 차별화 포인트: {selected_concept['competitive_edge']}"""
|
581 |
-
|
582 |
-
return preview_text, selected_concept, gr.update(value=selected_concept, visible=True)
|
583 |
-
return "", None, gr.update(visible=False)
|
584 |
-
except Exception as e:
|
585 |
-
return f"❌ 컨셉 선택 오류: {str(e)}", None, gr.update(visible=False)
|
586 |
-
|
587 |
-
def handle_event_type_change(event_type):
|
588 |
-
"""이벤트 유형 변경 처리"""
|
589 |
-
return gr.update(visible=(event_type == "직접 입력"))
|
590 |
-
|
591 |
-
def handle_final_generation(year, month, selected_concept, event_type, custom_event):
|
592 |
-
"""최종 공지사항 생성 처리"""
|
593 |
-
try:
|
594 |
-
if not selected_concept:
|
595 |
-
return (
|
596 |
-
"❌ 먼저 컨셉을 선택해주세요!",
|
597 |
-
gr.update(visible=False),
|
598 |
-
gr.update(visible=False),
|
599 |
-
gr.update(visible=False),
|
600 |
-
""
|
601 |
-
)
|
602 |
-
|
603 |
-
# 공지사항 생성
|
604 |
-
notice = generator.generate_event_notice(
|
605 |
-
concept_data=selected_concept,
|
606 |
-
event_type=event_type,
|
607 |
-
custom_event=custom_event
|
608 |
-
)
|
609 |
-
|
610 |
-
# 텍스트 통계
|
611 |
-
stats = generator.count_text_stats(notice)
|
612 |
-
|
613 |
-
# 다운로드 파일 준비
|
614 |
-
def prepare_download():
|
615 |
-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
616 |
-
filename = f"event_notice_{timestamp}.txt"
|
617 |
-
|
618 |
-
temp_file = tempfile.NamedTemporaryFile(
|
619 |
-
mode='w',
|
620 |
-
suffix='.txt',
|
621 |
-
delete=False,
|
622 |
-
encoding='utf-8'
|
623 |
-
)
|
624 |
-
temp_file.write(notice)
|
625 |
-
temp_file.close()
|
626 |
-
|
627 |
-
return temp_file.name
|
628 |
-
|
629 |
-
return (
|
630 |
-
notice, # final_notice_output
|
631 |
-
gr.update(visible=True, value=stats), # text_stats_output
|
632 |
-
gr.update(visible=True), # download_btn
|
633 |
-
gr.update(visible=True), # regenerate_btn
|
634 |
-
prepare_download() # 다운로드 파일
|
635 |
-
)
|
636 |
-
|
637 |
-
except Exception as e:
|
638 |
-
error_message = f"❌ 공지사항 생성 중 오류가 발생했습니다: {str(e)}"
|
639 |
-
return (
|
640 |
-
error_message,
|
641 |
-
gr.update(visible=False),
|
642 |
-
gr.update(visible=False),
|
643 |
-
gr.update(visible=False),
|
644 |
-
""
|
645 |
-
)
|
646 |
-
|
647 |
-
def handle_regeneration(year, month, selected_concept, event_type, custom_event):
|
648 |
-
"""공지사항 재생성"""
|
649 |
-
return handle_final_generation(year, month, selected_concept, event_type, custom_event)
|
650 |
-
|
651 |
-
# 이벤트 바인딩
|
652 |
-
analyze_btn.click(
|
653 |
-
handle_concept_analysis,
|
654 |
-
inputs=[year_input, month_input],
|
655 |
-
outputs=[concept_group, concept_selector, generate_btn, concept_analysis_output, concepts_state]
|
656 |
-
)
|
657 |
-
|
658 |
-
concept_selector.change(
|
659 |
-
handle_concept_selection,
|
660 |
-
inputs=[concept_selector, concepts_state],
|
661 |
-
outputs=[concept_preview, selected_concept_state, concept_details_output]
|
662 |
-
)
|
663 |
-
|
664 |
-
event_type_selector.change(
|
665 |
-
handle_event_type_change,
|
666 |
-
inputs=[event_type_selector],
|
667 |
-
outputs=[custom_event_input]
|
668 |
-
)
|
669 |
-
|
670 |
-
generate_btn.click(
|
671 |
-
handle_final_generation,
|
672 |
-
inputs=[year_input, month_input, selected_concept_state, event_type_selector, custom_event_input],
|
673 |
-
outputs=[final_notice_output, text_stats_output, download_btn, regenerate_btn, download_btn]
|
674 |
-
)
|
675 |
-
|
676 |
-
regenerate_btn.click(
|
677 |
-
handle_regeneration,
|
678 |
-
inputs=[year_input, month_input, selected_concept_state, event_type_selector, custom_event_input],
|
679 |
-
outputs=[final_notice_output, text_stats_output, download_btn, regenerate_btn, download_btn]
|
680 |
-
)
|
681 |
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
print("📚 그라디오 최신 버전으로 실행 중...")
|
688 |
|
689 |
-
|
690 |
-
# 애플리케이션 생성
|
691 |
-
demo = create_app()
|
692 |
-
|
693 |
-
# 서버 실행
|
694 |
-
print("🚀 서버를 시작합니다...")
|
695 |
-
demo.launch(
|
696 |
-
server_name="0.0.0.0",
|
697 |
-
server_port=7860,
|
698 |
-
share=True,
|
699 |
-
show_tips=True,
|
700 |
-
show_error=True
|
701 |
-
)
|
702 |
-
|
703 |
-
except Exception as e:
|
704 |
-
print(f"❌ 애플리케이션 시작 중 오류 발생: {e}")
|
705 |
-
import traceback
|
706 |
-
traceback.print_exc()
|
707 |
-
|
708 |
-
if __name__ == "__main__":
|
709 |
-
main()"""
|
710 |
-
이벤트 공지사항 생성기 - 기본 버전 (MVP)
|
711 |
-
"""
|
712 |
|
713 |
-
|
714 |
-
|
715 |
-
from typing import List, Dict, Any
|
716 |
-
|
717 |
-
class BasicEventGenerator:
|
718 |
-
"""기본 이벤트 생성기"""
|
719 |
|
720 |
-
|
721 |
-
|
722 |
-
1: {"holidays": ["신정", "설날"], "trends": ["새해 계획", "다이어트"], "colors": ["#FF6B6B", "#4ECDC4", "#45B7D1"]},
|
723 |
-
2: {"holidays": ["밸런타인데이"], "trends": ["러브", "로맨스"], "colors": ["#FF69B4", "#FFB6C1", "#DC143C"]},
|
724 |
-
3: {"holidays": ["삼일절", "화이트데이"], "trends": ["봄맞이", "벚꽃놀이"], "colors": ["#FFB6C1", "#98FB98", "#87CEEB"]},
|
725 |
-
4: {"holidays": ["만우절"], "trends": ["벚꽃축제", "봄피크닉"], "colors": ["#98FB98", "#F0E68C", "#DDA0DD"]},
|
726 |
-
5: {"holidays": ["어린이날", "어버이날"], "trends": ["가족사랑", "나들이"], "colors": ["#32CD32", "#FFB6C1", "#87CEEB"]},
|
727 |
-
6: {"holidays": ["현충일"], "trends": ["여름준비", "바캉스준비"], "colors": ["#00CED1", "#FFD700", "#FF6347"]},
|
728 |
-
7: {"holidays": ["제헌절"], "trends": ["여름휴가", "바다여행"], "colors": ["#00BFFF", "#FFD700", "#FF6347"]},
|
729 |
-
8: {"holidays": ["광복절"], "trends": ["여름휴가절정", "축제"], "colors": ["#00BFFF", "#FF6347", "#FFD700"]},
|
730 |
-
9: {"holidays": ["추석"], "trends": ["추석준비", "가을패션"], "colors": ["#FF8C00", "#DC143C", "#B8860B"]},
|
731 |
-
10: {"holidays": ["개천절", "한글날"], "trends": ["가을단풍", "독서"], "colors": ["#FF8C00", "#DC143C", "#B8860B"]},
|
732 |
-
11: {"holidays": ["빼빼로데이"], "trends": ["빼빼로데이", "겨울준비"], "colors": ["#8B4513", "#A0522D", "#CD853F"]},
|
733 |
-
12: {"holidays": ["크리스마스"], "trends": ["크리스마스", "연말파티"], "colors": ["#DC143C", "#228B22", "#FFD700"]}
|
734 |
-
}
|
735 |
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
month_data = self.monthly_data.get(month, {})
|
740 |
-
concepts = []
|
741 |
-
|
742 |
-
# 컨셉 1: 기념일 기반
|
743 |
-
if month_data.get("holidays"):
|
744 |
-
holiday = month_data["holidays"][0]
|
745 |
-
concepts.append({
|
746 |
-
"name": f"{holiday} 특별 이벤트",
|
747 |
-
"theme": f"{holiday}를 테마로 한 이벤트",
|
748 |
-
"score": 8.5,
|
749 |
-
"colors": month_data.get("colors", ["#FF69B4"])
|
750 |
-
})
|
751 |
-
|
752 |
-
# 컨셉 2: 트렌드 기반
|
753 |
-
if month_data.get("trends"):
|
754 |
-
trend = month_data["trends"][0]
|
755 |
-
concepts.append({
|
756 |
-
"name": f"{trend} 챌린지",
|
757 |
-
"theme": f"{trend} 트렌드 이벤트",
|
758 |
-
"score": 7.8,
|
759 |
-
"colors": month_data.get("colors", ["#87CEEB"])
|
760 |
-
})
|
761 |
-
|
762 |
-
# 컨셉 3: 커뮤니티 기반
|
763 |
-
concepts.append({
|
764 |
-
"name": f"{month}월 소통 이벤트",
|
765 |
-
"theme": "커뮤니티 멤버 소통 이벤트",
|
766 |
-
"score": 7.0,
|
767 |
-
"colors": month_data.get("colors", ["#98FB98"])
|
768 |
-
})
|
769 |
-
|
770 |
-
return concepts
|
771 |
|
772 |
-
|
773 |
-
"""기본 공지사항 생성"""
|
774 |
-
|
775 |
-
now = datetime.now()
|
776 |
-
start_date = f"{now.year}.{now.month}.{now.day}"
|
777 |
-
end_date = f"{now.year}.{now.month}.{now.day + 7}"
|
778 |
-
|
779 |
-
notice = f"""
|
780 |
-
💕 {concept['name']}에 참여하세요!
|
781 |
|
782 |
-
🎉 {concept
|
783 |
|
784 |
📅 이벤트 기간: {start_date} ~ {end_date} 23:59
|
785 |
|
786 |
========================
|
787 |
✨ EVENT
|
788 |
-
{concept
|
789 |
-
많은 분들의 적극적인 참여를 기다리고
|
790 |
========================
|
791 |
|
792 |
🎯 참여 방법
|
793 |
-
1️⃣ 이벤트
|
794 |
-
2️⃣ {event_type} 참여하기
|
795 |
3️⃣ 참여 완료!
|
796 |
|
797 |
=================
|
@@ -804,147 +66,116 @@ class BasicEventGenerator:
|
|
804 |
========================
|
805 |
|
806 |
👥 이벤트 대상
|
807 |
-
✅ 커뮤니티
|
808 |
✅ 만 18세 이상
|
809 |
✅ 이벤트 기간 내 참여자
|
810 |
========================
|
811 |
|
812 |
⚠️ 주의사항
|
813 |
※ 부적절한 참여는 제외됩니다
|
814 |
-
※ 중복
|
815 |
※ 당첨자는 본인 확인 필요
|
816 |
|
817 |
===========================
|
818 |
📞 문의: 1234-5678
|
819 |
💬 카카오톡: @event_community
|
820 |
|
821 |
-
💝 많은 참여 부탁드려요! 감사합니다 💕
|
822 |
-
|
823 |
-
|
824 |
-
return notice.strip()
|
825 |
|
826 |
def create_interface():
|
827 |
"""그라디오 인터페이스 생성"""
|
828 |
|
829 |
-
generator = BasicEventGenerator()
|
830 |
-
|
831 |
with gr.Blocks(title="이벤트 공지사항 생성기") as demo:
|
832 |
|
833 |
-
gr.Markdown(""
|
834 |
-
|
835 |
-
### 간편하게 이벤트 공지사항을 만들어보세요!
|
836 |
-
""")
|
837 |
|
838 |
with gr.Row():
|
839 |
with gr.Column():
|
840 |
-
gr.Markdown("##
|
841 |
|
842 |
-
|
843 |
choices=[f"{i}월" for i in range(1, 13)],
|
844 |
-
label="
|
845 |
-
value=
|
846 |
-
)
|
847 |
-
|
848 |
-
event_type_input = gr.Dropdown(
|
849 |
-
choices=["댓글 달기", "게시글 작성", "좋아요 누르기", "출석체크"],
|
850 |
-
label="🎯 이벤트 유형",
|
851 |
-
value="댓글 달기"
|
852 |
)
|
853 |
|
854 |
-
analyze_btn = gr.Button("
|
855 |
|
856 |
concept_dropdown = gr.Dropdown(
|
857 |
-
label="
|
858 |
visible=False
|
859 |
)
|
860 |
|
861 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
862 |
|
863 |
with gr.Column():
|
864 |
-
gr.Markdown("##
|
865 |
|
866 |
-
|
867 |
-
label="
|
868 |
-
lines=
|
869 |
placeholder="먼저 '컨셉 분석하기' 버튼을 클릭하세요"
|
870 |
)
|
871 |
|
872 |
-
|
873 |
label="생성된 공지사항",
|
874 |
lines=20,
|
875 |
-
placeholder="컨셉을 선택하고 '공지사항 생성하기' 버튼을 클릭하세요"
|
876 |
-
show_copy_button=True
|
877 |
)
|
878 |
|
879 |
# 상태 변수
|
880 |
concepts_state = gr.State([])
|
881 |
-
selected_concept_state = gr.State(
|
882 |
|
883 |
def handle_analyze(month):
|
884 |
-
"""
|
885 |
-
|
886 |
-
|
887 |
-
|
888 |
-
|
889 |
-
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
result_text += f"- 예상 점수: {concept['score']}/10점\n\n"
|
897 |
-
|
898 |
-
concept_choices.append(concept['name'])
|
899 |
-
|
900 |
-
return (
|
901 |
-
result_text,
|
902 |
-
gr.update(visible=True, choices=concept_choices, value=concept_choices[0]),
|
903 |
-
gr.update(visible=True),
|
904 |
-
concepts
|
905 |
-
)
|
906 |
-
except Exception as e:
|
907 |
-
return f"❌ 오류: {str(e)}", gr.update(visible=False), gr.update(visible=False), []
|
908 |
-
|
909 |
-
def handle_concept_select(concept_name, concepts):
|
910 |
-
"""컨셉 선택 처리"""
|
911 |
-
if concept_name and concepts:
|
912 |
-
selected = next((c for c in concepts if c['name'] == concept_name), None)
|
913 |
-
return selected
|
914 |
-
return None
|
915 |
|
916 |
def handle_generate(concept, event_type):
|
917 |
-
"""
|
918 |
-
|
919 |
-
|
920 |
-
return notice
|
921 |
-
return "❌ 컨셉을 먼저 선택해주세요!"
|
922 |
|
923 |
# 이벤트 연결
|
924 |
analyze_btn.click(
|
925 |
handle_analyze,
|
926 |
-
inputs=[
|
927 |
-
outputs=[
|
928 |
)
|
929 |
|
930 |
concept_dropdown.change(
|
931 |
-
|
932 |
inputs=[concept_dropdown, concepts_state],
|
933 |
outputs=[selected_concept_state]
|
934 |
)
|
935 |
|
936 |
generate_btn.click(
|
937 |
handle_generate,
|
938 |
-
inputs=[selected_concept_state,
|
939 |
-
outputs=[
|
940 |
)
|
941 |
|
942 |
return demo
|
943 |
|
944 |
if __name__ == "__main__":
|
945 |
demo = create_interface()
|
946 |
-
demo.launch(
|
947 |
-
server_name="0.0.0.0",
|
948 |
-
server_port=7860,
|
949 |
-
share=True
|
950 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
+
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
+
def analyze_concepts(month):
|
5 |
+
"""간단한 월별 컨셉 분석"""
|
|
|
|
|
6 |
|
7 |
+
concepts = {
|
8 |
+
"1월": ["신년 다짐 이벤트", "겨울 감성 이벤트", "새해 소망 이벤트"],
|
9 |
+
"2월": ["밸런타인 이벤트", "사랑 고백 이벤트", "겨울 마무리 이벤트"],
|
10 |
+
"3월": ["봄맞이 이벤트", "새학기 이벤트", "벚꽃 축제 이벤트"],
|
11 |
+
"4월": ["꽃구경 이벤트", "봄나들이 이벤트", "새싹 키우기 이벤트"],
|
12 |
+
"5월": ["가정의 달 이벤트", "어린이날 이벤트", "어버이날 이벤트"],
|
13 |
+
"6월": ["여름준비 이벤트", "현충일 추모 이벤트", "장마 대비 이벤트"],
|
14 |
+
"7월": ["여름휴가 이벤트", "바다 여행 이벤트", "시원한 음식 이벤트"],
|
15 |
+
"8월": ["휴가철 이벤트", "광복절 이벤트", "여름 추억 이벤트"],
|
16 |
+
"9월": ["추석 이벤트", "가을 시작 이벤트", "독서의 계절 이벤트"],
|
17 |
+
"10월": ["가을 단풍 이벤트", "한글날 이벤트", "가을 나들이 이벤트"],
|
18 |
+
"11월": ["빼빼로데이 이벤트", "수능 응원 이벤트", "겨울 준비 이벤트"],
|
19 |
+
"12월": ["크리스마스 이벤트", "연말 파티 이벤트", "한해 마무리 이벤트"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
}
|
|
|
21 |
|
22 |
+
month_concepts = concepts.get(month, ["기본 이벤트"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
+
result = f"# {month} 추천 컨셉\n\n"
|
25 |
+
for i, concept in enumerate(month_concepts, 1):
|
26 |
+
result += f"## {i}. {concept}\n"
|
27 |
+
result += f"- 20-40대 여성 타겟\n"
|
28 |
+
result += f"- 예상 참여도: 높음\n\n"
|
|
|
29 |
|
30 |
+
return result, month_concepts
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
|
32 |
+
def generate_notice(concept, event_type):
|
33 |
+
"""기본 공지사항 생성"""
|
|
|
|
|
|
|
|
|
34 |
|
35 |
+
if not concept:
|
36 |
+
return "먼저 컨셉을 선택해주세요."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
|
38 |
+
now = datetime.now()
|
39 |
+
start_date = now.strftime("%Y.%m.%d")
|
40 |
+
end_date = f"{now.year}.{now.month}.{now.day + 7}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
+
notice = f"""💕 {concept}에 참여하세요!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
|
44 |
+
🎉 {concept} 🎉
|
45 |
|
46 |
📅 이벤트 기간: {start_date} ~ {end_date} 23:59
|
47 |
|
48 |
========================
|
49 |
✨ EVENT
|
50 |
+
특별한 {concept}을 준비했어요!
|
51 |
+
많은 분들의 적극적인 참여를 기다리고 있습니다 💕
|
52 |
========================
|
53 |
|
54 |
🎯 참여 방법
|
55 |
+
1️⃣ 이벤트 내용 확인하기
|
56 |
+
2️⃣ {event_type} 참여하기
|
57 |
3️⃣ 참여 완료!
|
58 |
|
59 |
=================
|
|
|
66 |
========================
|
67 |
|
68 |
👥 이벤트 대상
|
69 |
+
✅ 커뮤니티 회원
|
70 |
✅ 만 18세 이상
|
71 |
✅ 이벤트 기간 내 참여자
|
72 |
========================
|
73 |
|
74 |
⚠️ 주의사항
|
75 |
※ 부적절한 참여는 제외됩니다
|
76 |
+
※ 중복 참여 불가
|
77 |
※ 당첨자는 본인 확인 필요
|
78 |
|
79 |
===========================
|
80 |
📞 문의: 1234-5678
|
81 |
💬 카카오톡: @event_community
|
82 |
|
83 |
+
💝 많은 참여 부탁드려요! 감사합니다 💕"""
|
84 |
+
|
85 |
+
return notice
|
|
|
86 |
|
87 |
def create_interface():
|
88 |
"""그라디오 인터페이스 생성"""
|
89 |
|
|
|
|
|
90 |
with gr.Blocks(title="이벤트 공지사항 생성기") as demo:
|
91 |
|
92 |
+
gr.Markdown("# 🎉 이벤트 공지사항 생성기")
|
93 |
+
gr.Markdown("### 간편하게 이벤트 공지사항을 만들어보세요!")
|
|
|
|
|
94 |
|
95 |
with gr.Row():
|
96 |
with gr.Column():
|
97 |
+
gr.Markdown("## 설정")
|
98 |
|
99 |
+
month_dropdown = gr.Dropdown(
|
100 |
choices=[f"{i}월" for i in range(1, 13)],
|
101 |
+
label="이벤트 월 선택",
|
102 |
+
value="1월"
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
)
|
104 |
|
105 |
+
analyze_btn = gr.Button("컨셉 분석하기", variant="primary")
|
106 |
|
107 |
concept_dropdown = gr.Dropdown(
|
108 |
+
label="컨셉 선택",
|
109 |
visible=False
|
110 |
)
|
111 |
|
112 |
+
event_type_dropdown = gr.Dropdown(
|
113 |
+
choices=["댓글 달기", "게시글 작성", "좋아요 누르기", "사진 업로드"],
|
114 |
+
label="이벤트 유형",
|
115 |
+
value="댓글 달기"
|
116 |
+
)
|
117 |
+
|
118 |
+
generate_btn = gr.Button("공지사항 생성하기", variant="secondary", visible=False)
|
119 |
|
120 |
with gr.Column():
|
121 |
+
gr.Markdown("## 결과")
|
122 |
|
123 |
+
concept_output = gr.Textbox(
|
124 |
+
label="분석 결과",
|
125 |
+
lines=10,
|
126 |
placeholder="먼저 '컨셉 분석하기' 버튼을 클릭하세요"
|
127 |
)
|
128 |
|
129 |
+
notice_output = gr.Textbox(
|
130 |
label="생성된 공지사항",
|
131 |
lines=20,
|
132 |
+
placeholder="컨셉을 선택하고 '공지사항 생성하기' 버튼을 클릭하세요"
|
|
|
133 |
)
|
134 |
|
135 |
# 상태 변수
|
136 |
concepts_state = gr.State([])
|
137 |
+
selected_concept_state = gr.State("")
|
138 |
|
139 |
def handle_analyze(month):
|
140 |
+
"""분석 처리"""
|
141 |
+
result, concepts = analyze_concepts(month)
|
142 |
+
return (
|
143 |
+
result,
|
144 |
+
gr.update(choices=concepts, visible=True, value=concepts[0]),
|
145 |
+
gr.update(visible=True),
|
146 |
+
concepts
|
147 |
+
)
|
148 |
+
|
149 |
+
def handle_concept_change(concept, concepts):
|
150 |
+
"""컨셉 변경 처리"""
|
151 |
+
return concept
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
|
153 |
def handle_generate(concept, event_type):
|
154 |
+
"""생성 처리"""
|
155 |
+
notice = generate_notice(concept, event_type)
|
156 |
+
return notice
|
|
|
|
|
157 |
|
158 |
# 이벤트 연결
|
159 |
analyze_btn.click(
|
160 |
handle_analyze,
|
161 |
+
inputs=[month_dropdown],
|
162 |
+
outputs=[concept_output, concept_dropdown, generate_btn, concepts_state]
|
163 |
)
|
164 |
|
165 |
concept_dropdown.change(
|
166 |
+
handle_concept_change,
|
167 |
inputs=[concept_dropdown, concepts_state],
|
168 |
outputs=[selected_concept_state]
|
169 |
)
|
170 |
|
171 |
generate_btn.click(
|
172 |
handle_generate,
|
173 |
+
inputs=[selected_concept_state, event_type_dropdown],
|
174 |
+
outputs=[notice_output]
|
175 |
)
|
176 |
|
177 |
return demo
|
178 |
|
179 |
if __name__ == "__main__":
|
180 |
demo = create_interface()
|
181 |
+
demo.launch()
|
|
|
|
|
|
|
|