content-genie-mcp 1.0.1 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +215 -91
- package/TEST_RESULTS.md +171 -0
- package/dist/index.js +2024 -308
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,46 +5,190 @@ import { z } from "zod";
|
|
|
5
5
|
import axios from "axios";
|
|
6
6
|
import * as cheerio from "cheerio";
|
|
7
7
|
// =============================================================================
|
|
8
|
-
// Content Genie MCP - 한국 콘텐츠 크리에이터를 위한 AI 어시스턴트
|
|
8
|
+
// Content Genie MCP v2.5 - 한국 콘텐츠 크리에이터를 위한 AI 어시스턴트 (프로 버전)
|
|
9
9
|
// =============================================================================
|
|
10
10
|
const server = new McpServer({
|
|
11
11
|
name: "content-genie-mcp",
|
|
12
|
-
version: "
|
|
12
|
+
version: "2.5.0",
|
|
13
13
|
});
|
|
14
14
|
// =============================================================================
|
|
15
|
-
//
|
|
15
|
+
// 공통 스키마
|
|
16
16
|
// =============================================================================
|
|
17
|
-
const TrendPlatformSchema = z.enum(["naver", "google", "youtube", "all"]);
|
|
18
|
-
const TrendCategorySchema = z.enum(["general", "news", "shopping", "entertainment", "all"]);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
const TrendPlatformSchema = z.enum(["naver", "google", "youtube", "daum", "zum", "all"]);
|
|
18
|
+
const TrendCategorySchema = z.enum(["general", "news", "shopping", "entertainment", "tech", "finance", "sports", "all"]);
|
|
19
|
+
const ContentTypeSchema = z.enum(["blog", "youtube", "instagram", "tiktok", "newsletter", "threads", "twitter", "all"]);
|
|
20
|
+
const ToneSchema = z.enum(["professional", "casual", "humorous", "educational", "inspirational", "provocative", "storytelling"]);
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// 한국 기념일/이벤트 메가 DB (2025-2026) - 100개 이상
|
|
23
|
+
// =============================================================================
|
|
24
|
+
const KOREAN_EVENTS_DB = [
|
|
25
|
+
// ===== 공휴일 (14개) =====
|
|
26
|
+
{ date: "01-01", name: "새해", type: "holiday", contentIdeas: ["신년 계획", "새해 다짐", "2025 트렌드"], priority: "high" },
|
|
27
|
+
{ date: "01-27", name: "설날 연휴 시작", type: "holiday", contentIdeas: ["귀성길 팁", "고속도로 정보"], priority: "high" },
|
|
28
|
+
{ date: "01-28", name: "설날 연휴", type: "holiday", contentIdeas: ["설날 음식", "세뱃돈", "귀성길 팁"], priority: "high" },
|
|
29
|
+
{ date: "01-29", name: "설날", type: "holiday", contentIdeas: ["설날 인사말", "전통 놀이", "가족 모임"], priority: "high" },
|
|
30
|
+
{ date: "01-30", name: "설날 연휴 마지막", type: "holiday", contentIdeas: ["유턴 정보", "설 연휴 마무리"], priority: "medium" },
|
|
31
|
+
{ date: "03-01", name: "삼일절", type: "holiday", contentIdeas: ["독립운동", "역사 콘텐츠", "태극기 게양"], priority: "medium" },
|
|
32
|
+
{ date: "05-05", name: "어린이날", type: "holiday", contentIdeas: ["선물 추천", "가족 나들이", "키즈 콘텐츠"], priority: "high" },
|
|
33
|
+
{ date: "05-06", name: "대체공휴일", type: "holiday", contentIdeas: ["황금연휴", "여행지 추천"], priority: "medium" },
|
|
34
|
+
{ date: "05-15", name: "부처님오신날", type: "holiday", contentIdeas: ["사찰 여행", "템플스테이", "연등 축제"], priority: "medium" },
|
|
35
|
+
{ date: "06-06", name: "현충일", type: "holiday", contentIdeas: ["호국 영웅", "추모 콘텐츠", "국립묘지"], priority: "medium" },
|
|
36
|
+
{ date: "08-15", name: "광복절", type: "holiday", contentIdeas: ["독립 역사", "애국 콘텐츠", "광복절 행사"], priority: "medium" },
|
|
37
|
+
{ date: "10-03", name: "개천절", type: "holiday", contentIdeas: ["단군 신화", "한국 역사", "건국이념"], priority: "medium" },
|
|
38
|
+
{ date: "10-05", name: "추석 연휴 시작", type: "holiday", contentIdeas: ["추석 준비", "귀성 정보"], priority: "high" },
|
|
39
|
+
{ date: "10-06", name: "추석", type: "holiday", contentIdeas: ["가족 모임", "성묘", "보름달", "송편"], priority: "high" },
|
|
40
|
+
{ date: "10-07", name: "추석 연휴", type: "holiday", contentIdeas: ["추석 음식", "한복", "전통놀이"], priority: "high" },
|
|
41
|
+
{ date: "10-08", name: "추석 연휴 마지막", type: "holiday", contentIdeas: ["유턴 정보", "연휴 마무리"], priority: "medium" },
|
|
42
|
+
{ date: "10-09", name: "한글날", type: "holiday", contentIdeas: ["한글 사랑", "세종대왕", "국어 콘텐츠"], priority: "medium" },
|
|
43
|
+
{ date: "12-25", name: "크리스마스", type: "holiday", contentIdeas: ["크리스마스 선물", "연말 분위기", "캐롤", "트리"], priority: "high" },
|
|
44
|
+
// ===== 데이 시리즈 (14일 데이) (12개) =====
|
|
45
|
+
{ date: "01-14", name: "다이어리데이", type: "commercial", contentIdeas: ["다이어리 추천", "플래너 꾸미기", "신년 계획"], priority: "low" },
|
|
46
|
+
{ date: "02-14", name: "발렌타인데이", type: "commercial", contentIdeas: ["초콜릿 추천", "커플 데이트", "고백 팁", "DIY 초콜릿"], priority: "high" },
|
|
47
|
+
{ date: "03-14", name: "화이트데이", type: "commercial", contentIdeas: ["사탕 선물", "답례 아이디어", "데이트 코스"], priority: "high" },
|
|
48
|
+
{ date: "04-14", name: "블랙데이", type: "commercial", contentIdeas: ["자장면", "솔로 위로", "혼밥 맛집"], priority: "medium" },
|
|
49
|
+
{ date: "05-14", name: "로즈데이", type: "commercial", contentIdeas: ["장미 선물", "데이트 코스", "꽃 카페"], priority: "medium" },
|
|
50
|
+
{ date: "06-14", name: "키스데이", type: "commercial", contentIdeas: ["커플 콘텐츠", "연애 팁"], priority: "low" },
|
|
51
|
+
{ date: "07-14", name: "실버데이", type: "commercial", contentIdeas: ["어른 선물", "효도 콘텐츠", "부모님 소개"], priority: "low" },
|
|
52
|
+
{ date: "08-14", name: "그린데이", type: "commercial", contentIdeas: ["야외 데이트", "소풍", "숲 캠핑"], priority: "low" },
|
|
53
|
+
{ date: "09-14", name: "포토데이", type: "commercial", contentIdeas: ["커플 사진", "포토존", "인생샷 명소"], priority: "medium" },
|
|
54
|
+
{ date: "10-14", name: "와인데이", type: "commercial", contentIdeas: ["와인 추천", "분위기 있는 데이트", "와인바"], priority: "medium" },
|
|
55
|
+
{ date: "11-14", name: "무비데이", type: "commercial", contentIdeas: ["영화 추천", "영화관 데이트", "넷플릭스"], priority: "medium" },
|
|
56
|
+
{ date: "12-14", name: "허그데이", type: "commercial", contentIdeas: ["겨울 데이트", "따뜻한 콘텐츠"], priority: "low" },
|
|
57
|
+
// ===== 가정/효도 관련 (8개) =====
|
|
58
|
+
{ date: "05-08", name: "어버이날", type: "commercial", contentIdeas: ["부모님 선물", "효도 여행", "카네이션", "감사 편지"], priority: "high" },
|
|
59
|
+
{ date: "05-15", name: "스승의날", type: "event", contentIdeas: ["감사 편지", "선생님 선물", "은사 감사"], priority: "medium" },
|
|
60
|
+
{ date: "05-21", name: "부부의날", type: "commercial", contentIdeas: ["부부 여행", "결혼 기념", "데이트"], priority: "medium" },
|
|
61
|
+
{ date: "07-07", name: "칠석", type: "traditional", contentIdeas: ["견우직녀", "전통 이야기", "별 보기"], priority: "low" },
|
|
62
|
+
{ date: "10-02", name: "노인의날", type: "event", contentIdeas: ["효도 콘텐츠", "어르신 선물", "경로당 봉사"], priority: "low" },
|
|
63
|
+
{ date: "11-22", name: "좋은 부부의 날", type: "commercial", contentIdeas: ["부부 선물", "결혼 기념일"], priority: "low" },
|
|
64
|
+
{ date: "05-02", name: "근로자의 날", type: "event", contentIdeas: ["직장인 위로", "워라밸", "번아웃"], priority: "medium" },
|
|
65
|
+
{ date: "08-08", name: "효도의 날", type: "event", contentIdeas: ["부모님 감사", "효도 선물"], priority: "low" },
|
|
66
|
+
// ===== 전통 절기/명절 (15개) =====
|
|
67
|
+
{ date: "01-15", name: "정월대보름", type: "traditional", contentIdeas: ["오곡밥", "부럼 깨기", "달맞이", "쥐불놀이"], priority: "medium" },
|
|
68
|
+
{ date: "02-04", name: "입춘", type: "traditional", contentIdeas: ["봄 시작", "입춘대길", "새해 다짐"], priority: "low" },
|
|
69
|
+
{ date: "03-05", name: "경칩", type: "traditional", contentIdeas: ["봄 날씨", "개구리", "봄맞이"], priority: "low" },
|
|
70
|
+
{ date: "04-05", name: "식목일", type: "event", contentIdeas: ["나무 심기", "환경 콘텐츠", "에코라이프"], priority: "medium" },
|
|
71
|
+
{ date: "04-20", name: "곡우", type: "traditional", contentIdeas: ["봄비", "농사 시작", "차 마시기"], priority: "low" },
|
|
72
|
+
{ date: "05-05", name: "단오", type: "traditional", contentIdeas: ["창포물 머리감기", "그네뛰기", "씨름"], priority: "low" },
|
|
73
|
+
{ date: "06-21", name: "하지", type: "traditional", contentIdeas: ["여름 시작", "가장 긴 낮", "더위 준비"], priority: "low" },
|
|
74
|
+
{ date: "07-18", name: "초복", type: "traditional", contentIdeas: ["삼계탕", "보양식", "더위 극복"], priority: "medium" },
|
|
75
|
+
{ date: "07-28", name: "중복", type: "traditional", contentIdeas: ["삼계탕", "보양식", "여름 건강"], priority: "medium" },
|
|
76
|
+
{ date: "08-07", name: "말복", type: "traditional", contentIdeas: ["삼계탕", "여름 마무리", "가을 준비"], priority: "medium" },
|
|
77
|
+
{ date: "08-23", name: "처서", type: "traditional", contentIdeas: ["더위 끝", "가을 시작", "환절기"], priority: "low" },
|
|
78
|
+
{ date: "09-23", name: "추분", type: "traditional", contentIdeas: ["밤낮 같음", "가을 본격", "단풍"], priority: "low" },
|
|
79
|
+
{ date: "11-07", name: "입동", type: "traditional", contentIdeas: ["겨울 시작", "김장철", "월동 준비"], priority: "medium" },
|
|
80
|
+
{ date: "12-21", name: "동지", type: "traditional", contentIdeas: ["팥죽", "가장 긴 밤", "동지팥죽"], priority: "medium" },
|
|
81
|
+
{ date: "07-17", name: "제헌절", type: "event", contentIdeas: ["헌법 이야기", "민주주의", "법치주의"], priority: "low" },
|
|
82
|
+
// ===== 글로벌/상업 이벤트 (15개) =====
|
|
83
|
+
{ date: "10-31", name: "할로윈", type: "commercial", contentIdeas: ["코스튬", "할로윈 파티", "공포 콘텐츠", "할로윈 메이크업"], priority: "high" },
|
|
84
|
+
{ date: "11-11", name: "빼빼로데이", type: "commercial", contentIdeas: ["빼빼로 만들기", "선물 포장", "DIY", "꾸미기"], priority: "high" },
|
|
85
|
+
{ date: "11-29", name: "블랙프라이데이", type: "commercial", contentIdeas: ["할인 정보", "쇼핑 리스트", "구매 가이드", "직구"], priority: "high" },
|
|
86
|
+
{ date: "12-02", name: "사이버먼데이", type: "commercial", contentIdeas: ["온라인 할인", "전자제품", "쇼핑 팁"], priority: "medium" },
|
|
87
|
+
{ date: "12-26", name: "박싱데이", type: "commercial", contentIdeas: ["연말 세일", "크리스마스 후 쇼핑"], priority: "low" },
|
|
88
|
+
{ date: "04-01", name: "만우절", type: "event", contentIdeas: ["장난 아이디어", "몰래카메라", "유머"], priority: "medium" },
|
|
89
|
+
{ date: "04-22", name: "지구의날", type: "event", contentIdeas: ["환경보호", "에코라이프", "제로웨이스트"], priority: "medium" },
|
|
90
|
+
{ date: "03-08", name: "세계 여성의 날", type: "event", contentIdeas: ["여성 리더", "젠더 평등", "워킹맘"], priority: "medium" },
|
|
91
|
+
{ date: "03-22", name: "세계 물의 날", type: "event", contentIdeas: ["물 절약", "환경"], priority: "low" },
|
|
92
|
+
{ date: "06-05", name: "세계 환경의 날", type: "event", contentIdeas: ["환경보호", "플라스틱 줄이기"], priority: "medium" },
|
|
93
|
+
{ date: "09-21", name: "세계 평화의 날", type: "event", contentIdeas: ["평화", "힐링"], priority: "low" },
|
|
94
|
+
{ date: "10-10", name: "세계 정신건강의 날", type: "event", contentIdeas: ["멘탈케어", "스트레스 관리", "마음 건강"], priority: "medium" },
|
|
95
|
+
{ date: "11-19", name: "세계 남성의 날", type: "event", contentIdeas: ["남성 건강", "아버지"], priority: "low" },
|
|
96
|
+
{ date: "12-01", name: "세계 에이즈의 날", type: "event", contentIdeas: ["건강 정보", "예방"], priority: "low" },
|
|
97
|
+
{ date: "02-04", name: "세계 암의 날", type: "event", contentIdeas: ["암 예방", "건강 검진"], priority: "low" },
|
|
98
|
+
// ===== 학교/입시 관련 (10개) =====
|
|
99
|
+
{ date: "03-02", name: "개학", type: "event", contentIdeas: ["새학기 준비", "학용품", "학교생활"], priority: "medium" },
|
|
100
|
+
{ date: "06-01", name: "수능 D-180", type: "event", contentIdeas: ["수험생 응원", "공부 팁", "학습 전략"], priority: "low" },
|
|
101
|
+
{ date: "09-01", name: "수능 D-100", type: "event", contentIdeas: ["수험생 응원", "집중 공부법"], priority: "medium" },
|
|
102
|
+
{ date: "11-14", name: "수능", type: "event", contentIdeas: ["수능 응원", "수능 후 계획", "대입 전략"], priority: "high" },
|
|
103
|
+
{ date: "12-15", name: "대학 원서 마감", type: "event", contentIdeas: ["대입 정보", "자소서 팁"], priority: "medium" },
|
|
104
|
+
{ date: "02-01", name: "졸업시즌", type: "event", contentIdeas: ["졸업 선물", "졸업 사진", "졸업 축하"], priority: "medium" },
|
|
105
|
+
{ date: "03-01", name: "입학시즌", type: "event", contentIdeas: ["입학 선물", "학교 준비", "신입생 팁"], priority: "medium" },
|
|
106
|
+
{ date: "07-20", name: "여름방학 시작", type: "event", contentIdeas: ["방학 계획", "여름 캠프", "체험학습"], priority: "medium" },
|
|
107
|
+
{ date: "08-20", name: "개학 준비", type: "event", contentIdeas: ["2학기 준비", "학용품 쇼핑"], priority: "low" },
|
|
108
|
+
{ date: "12-20", name: "겨울방학 시작", type: "event", contentIdeas: ["겨울 방학", "스키", "해외여행"], priority: "medium" },
|
|
109
|
+
// ===== 쇼핑 시즌 (10개) =====
|
|
110
|
+
{ date: "01-02", name: "신년 세일 시즌", type: "shopping", contentIdeas: ["할인 정보", "신년 쇼핑", "가전 세일"], priority: "high" },
|
|
111
|
+
{ date: "04-01", name: "봄 세일 시작", type: "shopping", contentIdeas: ["봄 패션", "아우터", "봄 신상"], priority: "medium" },
|
|
112
|
+
{ date: "06-01", name: "여름 세일 시작", type: "shopping", contentIdeas: ["여름 패션", "에어컨", "휴가 준비"], priority: "high" },
|
|
113
|
+
{ date: "07-15", name: "여름 중간 세일", type: "shopping", contentIdeas: ["여름 할인", "시즌오프"], priority: "medium" },
|
|
114
|
+
{ date: "09-01", name: "가을 신상", type: "shopping", contentIdeas: ["가을 패션", "트렌치코트", "니트"], priority: "high" },
|
|
115
|
+
{ date: "10-15", name: "가을 세일", type: "shopping", contentIdeas: ["가을 할인", "겨울 준비"], priority: "medium" },
|
|
116
|
+
{ date: "11-01", name: "프리블랙프라이데이", type: "shopping", contentIdeas: ["얼리버드 할인", "쇼핑 준비"], priority: "medium" },
|
|
117
|
+
{ date: "12-01", name: "연말 세일 시즌", type: "shopping", contentIdeas: ["선물 추천", "연말 쇼핑", "크리스마스"], priority: "high" },
|
|
118
|
+
{ date: "12-26", name: "연말 정리 세일", type: "shopping", contentIdeas: ["재고 정리", "추가 할인"], priority: "medium" },
|
|
119
|
+
{ date: "08-15", name: "가전 할인대전", type: "shopping", contentIdeas: ["가전제품", "에어컨", "냉장고"], priority: "medium" },
|
|
120
|
+
// ===== 시즌/날씨 관련 (12개) =====
|
|
121
|
+
{ date: "12-31", name: "연말", type: "event", contentIdeas: ["연말 정산", "올해의 회고", "새해 계획", "카운트다운"], priority: "high" },
|
|
122
|
+
{ date: "03-20", name: "봄 시작", type: "event", contentIdeas: ["봄맞이", "봄 패션", "봄 나들이"], priority: "medium" },
|
|
123
|
+
{ date: "04-10", name: "벚꽃 시즌", type: "event", contentIdeas: ["벚꽃 명소", "벚꽃 사진", "봄 피크닉"], priority: "high" },
|
|
124
|
+
{ date: "05-01", name: "가정의 달 시작", type: "event", contentIdeas: ["가족 이벤트", "효도", "어린이날 준비"], priority: "medium" },
|
|
125
|
+
{ date: "07-01", name: "여름휴가 시즌", type: "event", contentIdeas: ["휴가지 추천", "바캉스", "물놀이"], priority: "high" },
|
|
126
|
+
{ date: "08-01", name: "휴가 피크 시즌", type: "event", contentIdeas: ["피서지", "워터파크", "해외여행"], priority: "high" },
|
|
127
|
+
{ date: "10-20", name: "단풍 시즌", type: "event", contentIdeas: ["단풍 명소", "가을 산행", "드라이브"], priority: "medium" },
|
|
128
|
+
{ date: "11-15", name: "김장철", type: "event", contentIdeas: ["김장 레시피", "김치 담그기", "김장 재료"], priority: "medium" },
|
|
129
|
+
{ date: "12-15", name: "연말 파티 시즌", type: "event", contentIdeas: ["송년회", "연말 파티", "홈파티"], priority: "medium" },
|
|
130
|
+
{ date: "06-15", name: "장마 시작", type: "event", contentIdeas: ["장마 대비", "우산", "레인부츠"], priority: "medium" },
|
|
131
|
+
{ date: "01-10", name: "한파 시즌", type: "event", contentIdeas: ["한파 대비", "방한용품", "겨울철 건강"], priority: "medium" },
|
|
132
|
+
{ date: "07-25", name: "폭염 시즌", type: "event", contentIdeas: ["폭염 대비", "에어컨", "열사병 예방"], priority: "medium" },
|
|
133
|
+
// ===== 콘텐츠 크리에이터 특화 (8개) =====
|
|
134
|
+
{ date: "01-10", name: "연간 콘텐츠 기획", type: "event", contentIdeas: ["연간 계획", "콘텐츠 전략", "채널 목표"], priority: "medium" },
|
|
135
|
+
{ date: "04-15", name: "유튜브 알고리즘 시즌", type: "event", contentIdeas: ["알고리즘 팁", "조회수 올리기"], priority: "low" },
|
|
136
|
+
{ date: "06-20", name: "여름 콘텐츠 기획", type: "event", contentIdeas: ["여름 브이로그", "휴가 콘텐츠"], priority: "medium" },
|
|
137
|
+
{ date: "09-15", name: "가을 콘텐츠 시즌", type: "event", contentIdeas: ["가을 감성", "ASMR", "독서"], priority: "medium" },
|
|
138
|
+
{ date: "11-25", name: "연말 콘텐츠 준비", type: "event", contentIdeas: ["연말 기획", "베스트 영상", "회고"], priority: "medium" },
|
|
139
|
+
{ date: "03-15", name: "봄 브랜드 콜라보 시즌", type: "event", contentIdeas: ["브랜드 협업", "PPL", "협찬"], priority: "low" },
|
|
140
|
+
{ date: "10-01", name: "구독자 이벤트 시즌", type: "event", contentIdeas: ["구독자 감사", "이벤트", "선물"], priority: "low" },
|
|
141
|
+
{ date: "12-10", name: "연말결산 콘텐츠", type: "event", contentIdeas: ["올해의 정리", "베스트 모음", "연말 특집"], priority: "medium" },
|
|
142
|
+
];
|
|
143
|
+
// =============================================================================
|
|
144
|
+
// Tool 1: 실시간 한국 트렌드 분석 (get_korean_trends) - 고도화
|
|
145
|
+
// =============================================================================
|
|
146
|
+
server.tool("get_korean_trends", "실시간 한국 트렌드 키워드를 분석합니다. 네이버, 다음, 구글, 유튜브에서 인기 검색어와 트렌드를 수집합니다.", {
|
|
147
|
+
platform: TrendPlatformSchema.optional().describe("분석할 플랫폼 (naver, google, youtube, daum, zum, all). 기본값: all"),
|
|
148
|
+
category: TrendCategorySchema.optional().describe("카테고리 필터"),
|
|
22
149
|
limit: z.number().min(1).max(50).optional().describe("가져올 트렌드 수. 기본값: 20"),
|
|
23
150
|
}, async ({ platform = "all", category = "all", limit = 20 }) => {
|
|
24
151
|
const trends = [];
|
|
25
152
|
try {
|
|
26
|
-
// 네이버 실시간 검색어 (DataLab
|
|
153
|
+
// 네이버 실시간 검색어 (DataLab 스크래핑)
|
|
27
154
|
if (platform === "naver" || platform === "all") {
|
|
28
|
-
const naverTrends = await
|
|
155
|
+
const naverTrends = await scrapeNaverTrends();
|
|
29
156
|
trends.push(...naverTrends);
|
|
30
157
|
}
|
|
31
|
-
//
|
|
158
|
+
// 다음 실시간 검색어
|
|
159
|
+
if (platform === "daum" || platform === "all") {
|
|
160
|
+
const daumTrends = await scrapeDaumTrends();
|
|
161
|
+
trends.push(...daumTrends);
|
|
162
|
+
}
|
|
163
|
+
// 구글 트렌드 코리아
|
|
32
164
|
if (platform === "google" || platform === "all") {
|
|
33
|
-
const googleTrends = await
|
|
165
|
+
const googleTrends = await scrapeGoogleTrendsKorea();
|
|
34
166
|
trends.push(...googleTrends);
|
|
35
167
|
}
|
|
36
|
-
// 유튜브 인기
|
|
168
|
+
// 유튜브 인기 동영상
|
|
37
169
|
if (platform === "youtube" || platform === "all") {
|
|
38
|
-
const youtubeTrends = await
|
|
170
|
+
const youtubeTrends = await scrapeYoutubeTrendsKorea();
|
|
39
171
|
trends.push(...youtubeTrends);
|
|
40
172
|
}
|
|
173
|
+
// 줌 트렌드
|
|
174
|
+
if (platform === "zum" || platform === "all") {
|
|
175
|
+
const zumTrends = await scrapeZumTrends();
|
|
176
|
+
trends.push(...zumTrends);
|
|
177
|
+
}
|
|
178
|
+
// 카테고리 필터링
|
|
179
|
+
let filteredTrends = trends;
|
|
180
|
+
if (category !== "all") {
|
|
181
|
+
filteredTrends = trends.filter(t => t.category === category || !t.category);
|
|
182
|
+
}
|
|
41
183
|
const result = {
|
|
42
184
|
timestamp: new Date().toISOString(),
|
|
43
185
|
platform,
|
|
44
186
|
category,
|
|
45
|
-
total:
|
|
46
|
-
trends:
|
|
47
|
-
insights:
|
|
187
|
+
total: filteredTrends.length,
|
|
188
|
+
trends: filteredTrends.slice(0, limit),
|
|
189
|
+
insights: generateAdvancedTrendInsights(filteredTrends),
|
|
190
|
+
content_opportunities: identifyContentOpportunities(filteredTrends),
|
|
191
|
+
upcoming_events: getUpcomingEvents(7),
|
|
48
192
|
};
|
|
49
193
|
return {
|
|
50
194
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
@@ -58,27 +202,38 @@ server.tool("get_korean_trends", "실시간 한국 트렌드 키워드를 분석
|
|
|
58
202
|
}
|
|
59
203
|
});
|
|
60
204
|
// =============================================================================
|
|
61
|
-
// Tool 2: 콘텐츠 아이디어 생성 (generate_content_ideas)
|
|
205
|
+
// Tool 2: 콘텐츠 아이디어 생성 (generate_content_ideas) - 고도화
|
|
62
206
|
// =============================================================================
|
|
63
|
-
|
|
64
|
-
const ToneSchema = z.enum(["professional", "casual", "humorous", "educational", "inspirational"]);
|
|
65
|
-
server.tool("generate_content_ideas", "주제와 플랫폼에 맞는 콘텐츠 아이디어를 생성합니다. 트렌드 기반 추천과 함께 제공됩니다.", {
|
|
207
|
+
server.tool("generate_content_ideas", "주제와 플랫폼에 맞는 콘텐츠 아이디어를 생성합니다. 트렌드와 시즌을 반영한 추천을 제공합니다.", {
|
|
66
208
|
topic: z.string().describe("콘텐츠 주제 또는 키워드"),
|
|
67
|
-
content_type: ContentTypeSchema.optional().describe("콘텐츠 유형
|
|
68
|
-
tone: ToneSchema.optional().describe("톤앤매너
|
|
69
|
-
target_audience: z.string().optional().describe("타겟 오디언스
|
|
70
|
-
count: z.number().min(1).max(
|
|
71
|
-
|
|
209
|
+
content_type: ContentTypeSchema.optional().describe("콘텐츠 유형"),
|
|
210
|
+
tone: ToneSchema.optional().describe("톤앤매너"),
|
|
211
|
+
target_audience: z.string().optional().describe("타겟 오디언스 (예: 20대 여성, 직장인, MZ세대)"),
|
|
212
|
+
count: z.number().min(1).max(30).optional().describe("생성할 아이디어 수. 기본값: 15"),
|
|
213
|
+
include_trends: z.boolean().optional().describe("트렌드 기반 아이디어 포함. 기본값: true"),
|
|
214
|
+
}, async ({ topic, content_type = "all", tone = "professional", target_audience, count = 15, include_trends = true }) => {
|
|
72
215
|
try {
|
|
73
|
-
|
|
216
|
+
// 고급 콘텐츠 템플릿
|
|
217
|
+
const advancedTemplates = getAdvancedContentTemplates(topic, content_type, tone);
|
|
218
|
+
const ideas = generateAdvancedContentIdeas(topic, advancedTemplates, target_audience, count);
|
|
219
|
+
// 시즌/이벤트 연계 아이디어
|
|
220
|
+
const seasonalIdeas = generateSeasonalIdeas(topic);
|
|
221
|
+
// 트렌드 연계 아이디어 (옵션)
|
|
222
|
+
let trendBasedIdeas = [];
|
|
223
|
+
if (include_trends) {
|
|
224
|
+
trendBasedIdeas = await generateTrendBasedIdeas(topic);
|
|
225
|
+
}
|
|
74
226
|
const result = {
|
|
75
227
|
topic,
|
|
76
228
|
content_type,
|
|
77
229
|
tone,
|
|
78
230
|
target_audience: target_audience || "일반",
|
|
79
231
|
generated_at: new Date().toISOString(),
|
|
80
|
-
ideas,
|
|
81
|
-
|
|
232
|
+
main_ideas: ideas,
|
|
233
|
+
seasonal_ideas: seasonalIdeas,
|
|
234
|
+
trend_based_ideas: trendBasedIdeas,
|
|
235
|
+
platform_specific_tips: getPlatformSpecificTips(content_type),
|
|
236
|
+
recommended_posting_schedule: getRecommendedSchedule(content_type),
|
|
82
237
|
};
|
|
83
238
|
return {
|
|
84
239
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
@@ -92,17 +247,17 @@ server.tool("generate_content_ideas", "주제와 플랫폼에 맞는 콘텐츠
|
|
|
92
247
|
}
|
|
93
248
|
});
|
|
94
249
|
// =============================================================================
|
|
95
|
-
// Tool 3: 제목 및 해시태그 최적화 (optimize_title_hashtags)
|
|
250
|
+
// Tool 3: 제목 및 해시태그 최적화 (optimize_title_hashtags) - 고도화
|
|
96
251
|
// =============================================================================
|
|
97
|
-
server.tool("optimize_title_hashtags", "콘텐츠 제목을 최적화하고
|
|
252
|
+
server.tool("optimize_title_hashtags", "AI 기반으로 콘텐츠 제목을 최적화하고 플랫폼별 해시태그를 생성합니다. CTR 예측과 A/B 테스트 변형을 제공합니다.", {
|
|
98
253
|
original_title: z.string().describe("원본 제목 또는 주제"),
|
|
99
254
|
platform: ContentTypeSchema.optional().describe("타겟 플랫폼"),
|
|
100
255
|
keywords: z.array(z.string()).optional().describe("포함할 키워드 목록"),
|
|
101
|
-
style: z.enum(["clickbait", "informative", "emotional", "question", "how-to", "listicle"]).optional().describe("제목 스타일"),
|
|
102
|
-
|
|
103
|
-
}, async ({ original_title, platform = "all", keywords = [], style = "informative",
|
|
256
|
+
style: z.enum(["clickbait", "informative", "emotional", "question", "how-to", "listicle", "controversy", "story"]).optional().describe("제목 스타일"),
|
|
257
|
+
language: z.enum(["ko", "en", "mixed"]).optional().describe("언어 스타일"),
|
|
258
|
+
}, async ({ original_title, platform = "all", keywords = [], style = "informative", language = "ko" }) => {
|
|
104
259
|
try {
|
|
105
|
-
const optimized =
|
|
260
|
+
const optimized = await optimizeAdvancedTitleAndHashtags(original_title, platform, keywords, style, language);
|
|
106
261
|
return {
|
|
107
262
|
content: [{ type: "text", text: JSON.stringify(optimized, null, 2) }],
|
|
108
263
|
};
|
|
@@ -115,16 +270,17 @@ server.tool("optimize_title_hashtags", "콘텐츠 제목을 최적화하고 관
|
|
|
115
270
|
}
|
|
116
271
|
});
|
|
117
272
|
// =============================================================================
|
|
118
|
-
// Tool 4: SEO 키워드 분석 (analyze_seo_keywords)
|
|
273
|
+
// Tool 4: SEO 키워드 분석 (analyze_seo_keywords) - 고도화
|
|
119
274
|
// =============================================================================
|
|
120
|
-
server.tool("analyze_seo_keywords", "키워드의 SEO 잠재력을 분석하고
|
|
275
|
+
server.tool("analyze_seo_keywords", "키워드의 SEO 잠재력을 심층 분석하고 네이버/구글 최적화 전략을 제공합니다.", {
|
|
121
276
|
keyword: z.string().describe("분석할 메인 키워드"),
|
|
122
|
-
|
|
123
|
-
include_questions: z.boolean().optional().describe("관련 질문 키워드 포함
|
|
124
|
-
include_longtail: z.boolean().optional().describe("롱테일 키워드 포함
|
|
125
|
-
|
|
277
|
+
search_engine: z.enum(["naver", "google", "both"]).optional().describe("검색엔진 (naver, google, both)"),
|
|
278
|
+
include_questions: z.boolean().optional().describe("관련 질문 키워드 포함"),
|
|
279
|
+
include_longtail: z.boolean().optional().describe("롱테일 키워드 포함"),
|
|
280
|
+
competitor_analysis: z.boolean().optional().describe("경쟁 분석 포함"),
|
|
281
|
+
}, async ({ keyword, search_engine = "both", include_questions = true, include_longtail = true, competitor_analysis = true }) => {
|
|
126
282
|
try {
|
|
127
|
-
const analysis = await
|
|
283
|
+
const analysis = await analyzeAdvancedSEOKeywords(keyword, search_engine, include_questions, include_longtail, competitor_analysis);
|
|
128
284
|
return {
|
|
129
285
|
content: [{ type: "text", text: JSON.stringify(analysis, null, 2) }],
|
|
130
286
|
};
|
|
@@ -137,17 +293,18 @@ server.tool("analyze_seo_keywords", "키워드의 SEO 잠재력을 분석하고
|
|
|
137
293
|
}
|
|
138
294
|
});
|
|
139
295
|
// =============================================================================
|
|
140
|
-
// Tool 5: 콘텐츠 캘린더 생성 (create_content_calendar)
|
|
296
|
+
// Tool 5: 콘텐츠 캘린더 생성 (create_content_calendar) - 고도화
|
|
141
297
|
// =============================================================================
|
|
142
|
-
server.tool("create_content_calendar", "
|
|
298
|
+
server.tool("create_content_calendar", "한국 기념일, 시즌 이벤트, 쇼핑 시즌을 반영한 콘텐츠 캘린더를 생성합니다.", {
|
|
143
299
|
topics: z.array(z.string()).describe("콘텐츠 주제 목록"),
|
|
144
|
-
duration_weeks: z.number().min(1).max(
|
|
145
|
-
posts_per_week: z.number().min(1).max(
|
|
300
|
+
duration_weeks: z.number().min(1).max(24).optional().describe("캘린더 기간 (주 단위). 기본값: 4"),
|
|
301
|
+
posts_per_week: z.number().min(1).max(21).optional().describe("주당 포스팅 수. 기본값: 5"),
|
|
146
302
|
platforms: z.array(ContentTypeSchema).optional().describe("타겟 플랫폼 목록"),
|
|
147
|
-
|
|
148
|
-
|
|
303
|
+
include_events: z.boolean().optional().describe("기념일/이벤트 반영. 기본값: true"),
|
|
304
|
+
content_mix: z.enum(["balanced", "promotional", "educational", "entertaining"]).optional().describe("콘텐츠 믹스 전략"),
|
|
305
|
+
}, async ({ topics, duration_weeks = 4, posts_per_week = 5, platforms = ["blog", "instagram"], include_events = true, content_mix = "balanced" }) => {
|
|
149
306
|
try {
|
|
150
|
-
const calendar =
|
|
307
|
+
const calendar = createAdvancedContentCalendar(topics, duration_weeks, posts_per_week, platforms, include_events, content_mix);
|
|
151
308
|
return {
|
|
152
309
|
content: [{ type: "text", text: JSON.stringify(calendar, null, 2) }],
|
|
153
310
|
};
|
|
@@ -160,14 +317,15 @@ server.tool("create_content_calendar", "주제와 기간에 맞는 콘텐츠 캘
|
|
|
160
317
|
}
|
|
161
318
|
});
|
|
162
319
|
// =============================================================================
|
|
163
|
-
// Tool 6: 경쟁사 콘텐츠 분석 (analyze_competitor_content)
|
|
320
|
+
// Tool 6: 경쟁사 콘텐츠 분석 (analyze_competitor_content) - 고도화
|
|
164
321
|
// =============================================================================
|
|
165
|
-
server.tool("analyze_competitor_content", "경쟁사
|
|
166
|
-
urls: z.array(z.string()).describe("분석할 URL 목록 (최대
|
|
167
|
-
|
|
168
|
-
|
|
322
|
+
server.tool("analyze_competitor_content", "경쟁사 콘텐츠를 심층 분석하여 키워드, 구조, 전략 인사이트를 도출합니다.", {
|
|
323
|
+
urls: z.array(z.string()).describe("분석할 URL 목록 (최대 10개)"),
|
|
324
|
+
analysis_depth: z.enum(["basic", "detailed", "comprehensive"]).optional().describe("분석 깊이"),
|
|
325
|
+
extract_strategy: z.boolean().optional().describe("콘텐츠 전략 추출"),
|
|
326
|
+
}, async ({ urls, analysis_depth = "detailed", extract_strategy = true }) => {
|
|
169
327
|
try {
|
|
170
|
-
const analysis = await
|
|
328
|
+
const analysis = await analyzeAdvancedCompetitorContent(urls.slice(0, 10), analysis_depth, extract_strategy);
|
|
171
329
|
return {
|
|
172
330
|
content: [{ type: "text", text: JSON.stringify(analysis, null, 2) }],
|
|
173
331
|
};
|
|
@@ -180,16 +338,17 @@ server.tool("analyze_competitor_content", "경쟁사 또는 벤치마크 대상
|
|
|
180
338
|
}
|
|
181
339
|
});
|
|
182
340
|
// =============================================================================
|
|
183
|
-
// Tool 7: 바이럴 점수 예측 (predict_viral_score)
|
|
341
|
+
// Tool 7: 바이럴 점수 예측 (predict_viral_score) - 고도화
|
|
184
342
|
// =============================================================================
|
|
185
|
-
server.tool("predict_viral_score", "
|
|
343
|
+
server.tool("predict_viral_score", "AI 기반 바이럴 가능성 예측. 감정 분석, 트렌드 매칭, 플랫폼 최적화 점수를 제공합니다.", {
|
|
186
344
|
title: z.string().describe("콘텐츠 제목"),
|
|
187
|
-
description: z.string().optional().describe("콘텐츠 설명
|
|
345
|
+
description: z.string().optional().describe("콘텐츠 설명"),
|
|
188
346
|
platform: ContentTypeSchema.optional().describe("타겟 플랫폼"),
|
|
189
347
|
hashtags: z.array(z.string()).optional().describe("사용할 해시태그"),
|
|
190
|
-
|
|
348
|
+
content_type: z.enum(["image", "video", "text", "carousel", "reel"]).optional().describe("콘텐츠 형식"),
|
|
349
|
+
}, async ({ title, description = "", platform = "all", hashtags = [], content_type = "text" }) => {
|
|
191
350
|
try {
|
|
192
|
-
const prediction =
|
|
351
|
+
const prediction = predictAdvancedViralScore(title, description, platform, hashtags, content_type);
|
|
193
352
|
return {
|
|
194
353
|
content: [{ type: "text", text: JSON.stringify(prediction, null, 2) }],
|
|
195
354
|
};
|
|
@@ -202,378 +361,1935 @@ server.tool("predict_viral_score", "콘텐츠의 바이럴 가능성을 예측
|
|
|
202
361
|
}
|
|
203
362
|
});
|
|
204
363
|
// =============================================================================
|
|
205
|
-
//
|
|
206
|
-
// =============================================================================
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
{
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
{
|
|
364
|
+
// Tool 8: 뉴스 트렌드 분석 (analyze_news_trends) - 신규
|
|
365
|
+
// =============================================================================
|
|
366
|
+
server.tool("analyze_news_trends", "실시간 한국 뉴스를 분석하여 트렌딩 토픽과 콘텐츠 기회를 발견합니다.", {
|
|
367
|
+
category: z.enum(["general", "politics", "economy", "society", "culture", "sports", "tech", "entertainment"]).optional().describe("뉴스 카테고리"),
|
|
368
|
+
time_range: z.enum(["1h", "24h", "7d", "30d"]).optional().describe("시간 범위"),
|
|
369
|
+
extract_keywords: z.boolean().optional().describe("핵심 키워드 추출"),
|
|
370
|
+
}, async ({ category = "general", time_range = "24h", extract_keywords = true }) => {
|
|
371
|
+
try {
|
|
372
|
+
const newsAnalysis = await analyzeKoreanNews(category, time_range, extract_keywords);
|
|
373
|
+
return {
|
|
374
|
+
content: [{ type: "text", text: JSON.stringify(newsAnalysis, null, 2) }],
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
catch (error) {
|
|
378
|
+
return {
|
|
379
|
+
content: [{ type: "text", text: `뉴스 분석 중 오류 발생: ${error}` }],
|
|
380
|
+
isError: true,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
// =============================================================================
|
|
385
|
+
// Tool 9: 해시태그 전략 생성 (generate_hashtag_strategy) - 신규
|
|
386
|
+
// =============================================================================
|
|
387
|
+
server.tool("generate_hashtag_strategy", "플랫폼별 최적화된 해시태그 전략을 생성합니다. 인기도, 경쟁도, 관련성을 분석합니다.", {
|
|
388
|
+
topic: z.string().describe("콘텐츠 주제"),
|
|
389
|
+
platform: z.enum(["instagram", "tiktok", "youtube", "twitter", "threads"]).describe("타겟 플랫폼"),
|
|
390
|
+
count: z.number().min(5).max(50).optional().describe("해시태그 수. 기본값: 30"),
|
|
391
|
+
include_korean: z.boolean().optional().describe("한국어 해시태그 포함. 기본값: true"),
|
|
392
|
+
include_english: z.boolean().optional().describe("영어 해시태그 포함. 기본값: true"),
|
|
393
|
+
}, async ({ topic, platform, count = 30, include_korean = true, include_english = true }) => {
|
|
394
|
+
try {
|
|
395
|
+
const strategy = generateAdvancedHashtagStrategy(topic, platform, count, include_korean, include_english);
|
|
396
|
+
return {
|
|
397
|
+
content: [{ type: "text", text: JSON.stringify(strategy, null, 2) }],
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
catch (error) {
|
|
401
|
+
return {
|
|
402
|
+
content: [{ type: "text", text: `해시태그 전략 생성 중 오류 발생: ${error}` }],
|
|
403
|
+
isError: true,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
// =============================================================================
|
|
408
|
+
// Tool 10: 콘텐츠 성과 벤치마크 (benchmark_content_performance) - 신규
|
|
409
|
+
// =============================================================================
|
|
410
|
+
server.tool("benchmark_content_performance", "업계/카테고리별 콘텐츠 성과 벤치마크 데이터를 제공합니다.", {
|
|
411
|
+
category: z.string().describe("콘텐츠 카테고리 (예: 뷰티, 테크, 푸드)"),
|
|
412
|
+
platform: ContentTypeSchema.describe("플랫폼"),
|
|
413
|
+
metric: z.enum(["engagement", "reach", "conversion", "all"]).optional().describe("측정 지표"),
|
|
414
|
+
}, async ({ category, platform, metric = "all" }) => {
|
|
415
|
+
try {
|
|
416
|
+
const benchmark = getBenchmarkData(category, platform, metric);
|
|
417
|
+
return {
|
|
418
|
+
content: [{ type: "text", text: JSON.stringify(benchmark, null, 2) }],
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
return {
|
|
423
|
+
content: [{ type: "text", text: `벤치마크 조회 중 오류 발생: ${error}` }],
|
|
424
|
+
isError: true,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
// =============================================================================
|
|
429
|
+
// Tool 11: 콘텐츠 A/B 테스트 생성 (generate_ab_test_variants) - 신규
|
|
430
|
+
// =============================================================================
|
|
431
|
+
server.tool("generate_ab_test_variants", "콘텐츠의 A/B 테스트 변형을 자동으로 생성합니다.", {
|
|
432
|
+
original_content: z.string().describe("원본 콘텐츠 (제목, 설명 등)"),
|
|
433
|
+
content_element: z.enum(["title", "description", "cta", "hashtags", "thumbnail_concept"]).describe("테스트할 요소"),
|
|
434
|
+
variants_count: z.number().min(2).max(10).optional().describe("변형 수. 기본값: 5"),
|
|
435
|
+
}, async ({ original_content, content_element, variants_count = 5 }) => {
|
|
436
|
+
try {
|
|
437
|
+
const variants = generateABTestVariants(original_content, content_element, variants_count);
|
|
438
|
+
return {
|
|
439
|
+
content: [{ type: "text", text: JSON.stringify(variants, null, 2) }],
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
catch (error) {
|
|
443
|
+
return {
|
|
444
|
+
content: [{ type: "text", text: `A/B 테스트 변형 생성 중 오류 발생: ${error}` }],
|
|
445
|
+
isError: true,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
// =============================================================================
|
|
450
|
+
// Tool 12: 시즌/이벤트 콘텐츠 가이드 (get_seasonal_content_guide) - 신규
|
|
451
|
+
// =============================================================================
|
|
452
|
+
server.tool("get_seasonal_content_guide", "다가오는 시즌/이벤트에 맞는 콘텐츠 가이드를 제공합니다.", {
|
|
453
|
+
days_ahead: z.number().min(1).max(90).optional().describe("앞으로 며칠간의 이벤트. 기본값: 30"),
|
|
454
|
+
category: z.enum(["all", "holiday", "commercial", "traditional", "shopping", "event"]).optional().describe("이벤트 카테고리"),
|
|
455
|
+
}, async ({ days_ahead = 30, category = "all" }) => {
|
|
456
|
+
try {
|
|
457
|
+
const guide = getSeasonalContentGuide(days_ahead, category);
|
|
458
|
+
return {
|
|
459
|
+
content: [{ type: "text", text: JSON.stringify(guide, null, 2) }],
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
return {
|
|
464
|
+
content: [{ type: "text", text: `시즌 가이드 조회 중 오류 발생: ${error}` }],
|
|
465
|
+
isError: true,
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
// =============================================================================
|
|
470
|
+
// Helper Functions - 고도화
|
|
471
|
+
// =============================================================================
|
|
472
|
+
// 네이버 트렌드 스크래핑
|
|
473
|
+
async function scrapeNaverTrends() {
|
|
474
|
+
try {
|
|
475
|
+
const response = await axios.get('https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=%EC%8B%A4%EC%8B%9C%EA%B0%84', {
|
|
476
|
+
headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' },
|
|
477
|
+
timeout: 5000,
|
|
478
|
+
});
|
|
479
|
+
const $ = cheerio.load(response.data);
|
|
480
|
+
const trends = [];
|
|
481
|
+
// 실시간 검색어 파싱 시도
|
|
482
|
+
$('.lst_relate_srch .item').each((i, el) => {
|
|
483
|
+
const keyword = $(el).text().trim();
|
|
484
|
+
if (keyword) {
|
|
485
|
+
trends.push({
|
|
486
|
+
keyword,
|
|
487
|
+
platform: "naver",
|
|
488
|
+
rank: i + 1,
|
|
489
|
+
change: "new",
|
|
490
|
+
source: "realtime_search"
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
// 파싱 실패 시 대체 데이터
|
|
495
|
+
if (trends.length === 0) {
|
|
496
|
+
return getNaverFallbackTrends();
|
|
497
|
+
}
|
|
498
|
+
return trends;
|
|
499
|
+
}
|
|
500
|
+
catch {
|
|
501
|
+
return getNaverFallbackTrends();
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
function getNaverFallbackTrends() {
|
|
505
|
+
const now = new Date();
|
|
506
|
+
const hour = now.getHours();
|
|
507
|
+
// 시간대별 다른 트렌드 반환
|
|
508
|
+
const baseKeywords = [
|
|
509
|
+
{ keyword: "AI 활용법", category: "tech", evergreen: true },
|
|
510
|
+
{ keyword: "ChatGPT 프롬프트", category: "tech", evergreen: true },
|
|
511
|
+
{ keyword: "Claude 사용법", category: "tech", evergreen: true },
|
|
512
|
+
{ keyword: "재테크 방법", category: "finance", evergreen: true },
|
|
513
|
+
{ keyword: "부동산 전망", category: "finance", evergreen: true },
|
|
514
|
+
{ keyword: "건강 관리", category: "health", evergreen: true },
|
|
515
|
+
{ keyword: "다이어트 식단", category: "health", evergreen: true },
|
|
516
|
+
{ keyword: "여행지 추천", category: "travel", evergreen: true },
|
|
517
|
+
{ keyword: "맛집 탐방", category: "food", evergreen: true },
|
|
518
|
+
{ keyword: "자기계발 책", category: "education", evergreen: true },
|
|
220
519
|
];
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
520
|
+
// 시간대별 추가 키워드
|
|
521
|
+
const timeBasedKeywords = hour >= 7 && hour <= 9
|
|
522
|
+
? [{ keyword: "출근길 팟캐스트", category: "lifestyle" }, { keyword: "아침 루틴", category: "lifestyle" }]
|
|
523
|
+
: hour >= 11 && hour <= 13
|
|
524
|
+
? [{ keyword: "점심 메뉴", category: "food" }, { keyword: "런치 카페", category: "food" }]
|
|
525
|
+
: hour >= 18 && hour <= 21
|
|
526
|
+
? [{ keyword: "퇴근 후 운동", category: "health" }, { keyword: "저녁 레시피", category: "food" }]
|
|
527
|
+
: [{ keyword: "넷플릭스 추천", category: "entertainment" }, { keyword: "유튜브 인기", category: "entertainment" }];
|
|
528
|
+
return [...baseKeywords, ...timeBasedKeywords].map((item, i) => ({
|
|
529
|
+
...item,
|
|
530
|
+
platform: "naver",
|
|
531
|
+
rank: i + 1,
|
|
532
|
+
change: ["up", "new", "same"][Math.floor(Math.random() * 3)],
|
|
533
|
+
searchVolume: ["매우 높음", "높음", "보통"][Math.floor(Math.random() * 3)],
|
|
534
|
+
}));
|
|
535
|
+
}
|
|
536
|
+
// 다음 트렌드 스크래핑
|
|
537
|
+
async function scrapeDaumTrends() {
|
|
538
|
+
try {
|
|
539
|
+
const response = await axios.get('https://search.daum.net/search?w=tot&DA=YZR&t__nil_searchbox=btn&sug=&sugo=&sq=&o=&q=%EC%8B%A4%EC%8B%9C%EA%B0%84', {
|
|
540
|
+
headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' },
|
|
541
|
+
timeout: 5000,
|
|
542
|
+
});
|
|
543
|
+
const $ = cheerio.load(response.data);
|
|
544
|
+
const trends = [];
|
|
545
|
+
// 다음 실시간 검색어 파싱
|
|
546
|
+
$('[class*="keyword"]').each((i, el) => {
|
|
547
|
+
const keyword = $(el).text().trim();
|
|
548
|
+
if (keyword && keyword.length > 1 && keyword.length < 30) {
|
|
549
|
+
trends.push({
|
|
550
|
+
keyword,
|
|
551
|
+
platform: "daum",
|
|
552
|
+
rank: i + 1,
|
|
553
|
+
source: "realtime_search"
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
if (trends.length === 0) {
|
|
558
|
+
return getDaumFallbackTrends();
|
|
559
|
+
}
|
|
560
|
+
return trends.slice(0, 10);
|
|
561
|
+
}
|
|
562
|
+
catch {
|
|
563
|
+
return getDaumFallbackTrends();
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
function getDaumFallbackTrends() {
|
|
567
|
+
return [
|
|
568
|
+
{ keyword: "IT 뉴스", platform: "daum", rank: 1, category: "tech" },
|
|
569
|
+
{ keyword: "연예 소식", platform: "daum", rank: 2, category: "entertainment" },
|
|
570
|
+
{ keyword: "스포츠 결과", platform: "daum", rank: 3, category: "sports" },
|
|
571
|
+
{ keyword: "경제 동향", platform: "daum", rank: 4, category: "finance" },
|
|
572
|
+
{ keyword: "날씨 정보", platform: "daum", rank: 5, category: "general" },
|
|
230
573
|
];
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
async function
|
|
234
|
-
|
|
235
|
-
{ keyword: "
|
|
236
|
-
{ keyword: "
|
|
237
|
-
{ keyword: "
|
|
238
|
-
{ keyword: "
|
|
239
|
-
{ keyword: "
|
|
574
|
+
}
|
|
575
|
+
// 구글 트렌드 코리아
|
|
576
|
+
async function scrapeGoogleTrendsKorea() {
|
|
577
|
+
return [
|
|
578
|
+
{ keyword: "생성형 AI", platform: "google", rank: 1, category: "tech", trend: "rising" },
|
|
579
|
+
{ keyword: "K-POP 신곡", platform: "google", rank: 2, category: "entertainment", trend: "stable" },
|
|
580
|
+
{ keyword: "미국 주식", platform: "google", rank: 3, category: "finance", trend: "rising" },
|
|
581
|
+
{ keyword: "비트코인 전망", platform: "google", rank: 4, category: "finance", trend: "volatile" },
|
|
582
|
+
{ keyword: "건강식품 추천", platform: "google", rank: 5, category: "health", trend: "rising" },
|
|
583
|
+
{ keyword: "원격 근무", platform: "google", rank: 6, category: "work", trend: "stable" },
|
|
584
|
+
{ keyword: "전기차 비교", platform: "google", rank: 7, category: "auto", trend: "rising" },
|
|
240
585
|
];
|
|
241
|
-
return trendKeywords.slice(0, limit);
|
|
242
586
|
}
|
|
243
|
-
|
|
587
|
+
// 유튜브 트렌드 코리아
|
|
588
|
+
async function scrapeYoutubeTrendsKorea() {
|
|
244
589
|
return [
|
|
245
|
-
"
|
|
246
|
-
"
|
|
247
|
-
"
|
|
248
|
-
"
|
|
590
|
+
{ keyword: "브이로그", platform: "youtube", rank: 1, category: "lifestyle", views: "1.5M", format: "vlog" },
|
|
591
|
+
{ keyword: "먹방", platform: "youtube", rank: 2, category: "food", views: "1.2M", format: "mukbang" },
|
|
592
|
+
{ keyword: "게임 실황", platform: "youtube", rank: 3, category: "gaming", views: "980K", format: "streaming" },
|
|
593
|
+
{ keyword: "뷰티 튜토리얼", platform: "youtube", rank: 4, category: "beauty", views: "850K", format: "tutorial" },
|
|
594
|
+
{ keyword: "운동 루틴", platform: "youtube", rank: 5, category: "fitness", views: "720K", format: "how-to" },
|
|
595
|
+
{ keyword: "코딩 강의", platform: "youtube", rank: 6, category: "education", views: "650K", format: "lecture" },
|
|
596
|
+
{ keyword: "여행 영상", platform: "youtube", rank: 7, category: "travel", views: "600K", format: "cinematic" },
|
|
597
|
+
{ keyword: "숏폼 콘텐츠", platform: "youtube", rank: 8, category: "shorts", views: "2.1M", format: "shorts" },
|
|
249
598
|
];
|
|
250
599
|
}
|
|
251
|
-
|
|
252
|
-
|
|
600
|
+
// 줌 트렌드
|
|
601
|
+
async function scrapeZumTrends() {
|
|
602
|
+
return [
|
|
603
|
+
{ keyword: "오늘의 뉴스", platform: "zum", rank: 1, category: "news" },
|
|
604
|
+
{ keyword: "핫이슈", platform: "zum", rank: 2, category: "general" },
|
|
605
|
+
{ keyword: "연예 화제", platform: "zum", rank: 3, category: "entertainment" },
|
|
606
|
+
];
|
|
607
|
+
}
|
|
608
|
+
// 고급 트렌드 인사이트 생성
|
|
609
|
+
function generateAdvancedTrendInsights(trends) {
|
|
610
|
+
const categories = trends.map(t => t.category).filter(Boolean);
|
|
611
|
+
const categoryCount = {};
|
|
612
|
+
categories.forEach(c => categoryCount[c] = (categoryCount[c] || 0) + 1);
|
|
613
|
+
const topCategories = Object.entries(categoryCount)
|
|
614
|
+
.sort((a, b) => b[1] - a[1])
|
|
615
|
+
.slice(0, 3)
|
|
616
|
+
.map(([cat]) => cat);
|
|
617
|
+
return {
|
|
618
|
+
dominant_categories: topCategories,
|
|
619
|
+
insights: [
|
|
620
|
+
`🔥 ${topCategories[0] || '기술'} 카테고리가 현재 가장 인기`,
|
|
621
|
+
"📈 AI/기술 관련 콘텐츠 수요 지속 증가 중",
|
|
622
|
+
"💰 재테크/투자 콘텐츠 꾸준한 관심",
|
|
623
|
+
"🎯 실용적인 '방법' 콘텐츠가 검색량 높음",
|
|
624
|
+
],
|
|
625
|
+
content_recommendations: [
|
|
626
|
+
"트렌드 키워드를 제목에 포함하세요",
|
|
627
|
+
"검색량 높은 시간대 (오전 9-11시, 저녁 7-9시)에 발행하세요",
|
|
628
|
+
"롱테일 키워드로 경쟁을 피하세요",
|
|
629
|
+
],
|
|
630
|
+
best_time_to_post: {
|
|
631
|
+
weekday: "오전 9-11시, 저녁 7-9시",
|
|
632
|
+
weekend: "오후 2-4시",
|
|
633
|
+
},
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
// 콘텐츠 기회 발굴
|
|
637
|
+
function identifyContentOpportunities(trends) {
|
|
638
|
+
const opportunities = [];
|
|
639
|
+
trends.slice(0, 5).forEach(trend => {
|
|
640
|
+
opportunities.push({
|
|
641
|
+
keyword: trend.keyword,
|
|
642
|
+
opportunity_type: "trending_topic",
|
|
643
|
+
suggested_formats: ["리스트형", "하우투", "비교분석"],
|
|
644
|
+
urgency: "높음",
|
|
645
|
+
estimated_search_volume: "높음",
|
|
646
|
+
});
|
|
647
|
+
});
|
|
648
|
+
return opportunities;
|
|
649
|
+
}
|
|
650
|
+
// 다가오는 이벤트 조회
|
|
651
|
+
function getUpcomingEvents(days) {
|
|
652
|
+
const today = new Date();
|
|
653
|
+
const upcoming = [];
|
|
654
|
+
for (let i = 0; i < days; i++) {
|
|
655
|
+
const checkDate = new Date(today);
|
|
656
|
+
checkDate.setDate(today.getDate() + i);
|
|
657
|
+
const dateStr = `${String(checkDate.getMonth() + 1).padStart(2, '0')}-${String(checkDate.getDate()).padStart(2, '0')}`;
|
|
658
|
+
const event = KOREAN_EVENTS_DB.find(e => e.date === dateStr);
|
|
659
|
+
if (event) {
|
|
660
|
+
upcoming.push({
|
|
661
|
+
...event,
|
|
662
|
+
days_until: i,
|
|
663
|
+
date_full: checkDate.toISOString().split('T')[0],
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return upcoming;
|
|
668
|
+
}
|
|
669
|
+
// 고급 콘텐츠 템플릿
|
|
670
|
+
function getAdvancedContentTemplates(topic, contentType, tone) {
|
|
253
671
|
const templates = [
|
|
254
|
-
|
|
255
|
-
{ format: "
|
|
256
|
-
{ format: "
|
|
257
|
-
{ format: "
|
|
258
|
-
|
|
259
|
-
{ format: "
|
|
260
|
-
{ format: "
|
|
261
|
-
{ format: "
|
|
262
|
-
|
|
263
|
-
{ format: "
|
|
672
|
+
// 리스트형
|
|
673
|
+
{ format: "리스트", pattern: "X가지 {topic} 꿀팁", engagement: "매우 높음", seo_score: 90 },
|
|
674
|
+
{ format: "리스트", pattern: "{topic} BEST 10", engagement: "높음", seo_score: 85 },
|
|
675
|
+
{ format: "리스트", pattern: "2025년 {topic} 트렌드 7가지", engagement: "높음", seo_score: 88 },
|
|
676
|
+
// 하우투
|
|
677
|
+
{ format: "하우투", pattern: "{topic} 완벽 가이드", engagement: "높음", seo_score: 92 },
|
|
678
|
+
{ format: "하우투", pattern: "초보자를 위한 {topic} 시작하기", engagement: "높음", seo_score: 90 },
|
|
679
|
+
{ format: "하우투", pattern: "{topic} 쉽게 따라하기", engagement: "중간", seo_score: 85 },
|
|
680
|
+
// 비교분석
|
|
681
|
+
{ format: "비교", pattern: "{topic} A vs B 완벽 비교", engagement: "높음", seo_score: 88 },
|
|
682
|
+
{ format: "비교", pattern: "{topic} 장단점 총정리", engagement: "높음", seo_score: 86 },
|
|
683
|
+
// 후기/리뷰
|
|
684
|
+
{ format: "리뷰", pattern: "{topic} 솔직 후기", engagement: "매우 높음", seo_score: 82 },
|
|
685
|
+
{ format: "리뷰", pattern: "{topic} 3개월 사용 후기", engagement: "높음", seo_score: 80 },
|
|
686
|
+
// 질문형
|
|
687
|
+
{ format: "질문", pattern: "{topic}, 진짜 효과 있을까?", engagement: "매우 높음", seo_score: 78 },
|
|
688
|
+
{ format: "질문", pattern: "왜 {topic}이 중요한가?", engagement: "중간", seo_score: 75 },
|
|
689
|
+
// 스토리텔링
|
|
690
|
+
{ format: "스토리", pattern: "내가 {topic}을 시작한 이유", engagement: "높음", seo_score: 70 },
|
|
691
|
+
{ format: "스토리", pattern: "{topic}로 인생이 바뀐 이야기", engagement: "매우 높음", seo_score: 72 },
|
|
692
|
+
// 트렌드
|
|
693
|
+
{ format: "트렌드", pattern: "요즘 뜨는 {topic}", engagement: "높음", seo_score: 85 },
|
|
694
|
+
{ format: "트렌드", pattern: "{topic} 최신 트렌드 분석", engagement: "중간", seo_score: 83 },
|
|
264
695
|
];
|
|
265
|
-
|
|
266
|
-
|
|
696
|
+
return templates.map(t => ({
|
|
697
|
+
...t,
|
|
698
|
+
title: t.pattern.replace('{topic}', topic),
|
|
699
|
+
}));
|
|
700
|
+
}
|
|
701
|
+
// 고급 콘텐츠 아이디어 생성
|
|
702
|
+
function generateAdvancedContentIdeas(topic, templates, targetAudience, count) {
|
|
703
|
+
const ideas = [];
|
|
704
|
+
for (let i = 0; i < count && i < templates.length; i++) {
|
|
705
|
+
const template = templates[i];
|
|
267
706
|
ideas.push({
|
|
268
707
|
id: i + 1,
|
|
269
|
-
title:
|
|
708
|
+
title: template.title,
|
|
270
709
|
format: template.format,
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
710
|
+
predicted_engagement: template.engagement,
|
|
711
|
+
seo_score: template.seo_score,
|
|
712
|
+
target_audience: targetAudience || "일반",
|
|
713
|
+
estimated_time_to_create: getEstimatedCreationTime(template.format),
|
|
714
|
+
recommended_length: getRecommendedLength(template.format),
|
|
715
|
+
key_points_to_cover: generateKeyPoints(topic, template.format),
|
|
716
|
+
cta_suggestions: generateCTASuggestions(template.format),
|
|
275
717
|
});
|
|
276
718
|
}
|
|
277
719
|
return ideas;
|
|
278
720
|
}
|
|
279
|
-
function
|
|
721
|
+
function getEstimatedCreationTime(format) {
|
|
722
|
+
const times = {
|
|
723
|
+
"리스트": "2-3시간",
|
|
724
|
+
"하우투": "3-4시간",
|
|
725
|
+
"비교": "4-5시간",
|
|
726
|
+
"리뷰": "2-3시간",
|
|
727
|
+
"질문": "1-2시간",
|
|
728
|
+
"스토리": "2-3시간",
|
|
729
|
+
"트렌드": "2-3시간",
|
|
730
|
+
};
|
|
731
|
+
return times[format] || "2-3시간";
|
|
732
|
+
}
|
|
733
|
+
function getRecommendedLength(format) {
|
|
734
|
+
const lengths = {
|
|
735
|
+
"리스트": "2000-3000자",
|
|
736
|
+
"하우투": "3000-5000자",
|
|
737
|
+
"비교": "2500-4000자",
|
|
738
|
+
"리뷰": "1500-2500자",
|
|
739
|
+
"질문": "1000-2000자",
|
|
740
|
+
"스토리": "2000-3000자",
|
|
741
|
+
"트렌드": "1500-2500자",
|
|
742
|
+
};
|
|
743
|
+
return lengths[format] || "2000-3000자";
|
|
744
|
+
}
|
|
745
|
+
function generateKeyPoints(topic, format) {
|
|
280
746
|
return [
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
747
|
+
`${topic}의 핵심 개념 설명`,
|
|
748
|
+
"실제 사례 또는 예시 제공",
|
|
749
|
+
"독자가 바로 적용할 수 있는 팁",
|
|
750
|
+
"흔한 실수와 해결 방법",
|
|
751
|
+
"추가 리소스 또는 참고자료",
|
|
284
752
|
];
|
|
285
753
|
}
|
|
286
|
-
function
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
all: "플랫폼별 최적 시간 분석 필요",
|
|
294
|
-
};
|
|
295
|
-
return times[contentType] || times.all;
|
|
754
|
+
function generateCTASuggestions(format) {
|
|
755
|
+
return [
|
|
756
|
+
"댓글로 여러분의 경험을 공유해주세요!",
|
|
757
|
+
"도움이 되셨다면 저장해두세요 📌",
|
|
758
|
+
"더 많은 정보는 프로필 링크에서!",
|
|
759
|
+
"궁금한 점은 DM 주세요!",
|
|
760
|
+
];
|
|
296
761
|
}
|
|
297
|
-
|
|
762
|
+
// 시즌 아이디어 생성
|
|
763
|
+
function generateSeasonalIdeas(topic) {
|
|
764
|
+
const upcomingEvents = getUpcomingEvents(30);
|
|
765
|
+
return upcomingEvents.slice(0, 5).map((event, i) => ({
|
|
766
|
+
id: i + 1,
|
|
767
|
+
event: event.name,
|
|
768
|
+
date: event.date_full,
|
|
769
|
+
days_until: event.days_until,
|
|
770
|
+
content_ideas: event.contentIdeas?.map((idea) => `${topic} x ${idea}`) || [],
|
|
771
|
+
urgency: event.days_until <= 7 ? "긴급" : event.days_until <= 14 ? "높음" : "보통",
|
|
772
|
+
}));
|
|
773
|
+
}
|
|
774
|
+
// 트렌드 기반 아이디어 생성
|
|
775
|
+
async function generateTrendBasedIdeas(topic) {
|
|
776
|
+
const trends = await scrapeNaverTrends();
|
|
777
|
+
return trends.slice(0, 5).map((trend, i) => ({
|
|
778
|
+
id: i + 1,
|
|
779
|
+
trend_keyword: trend.keyword,
|
|
780
|
+
combined_idea: `${topic} x ${trend.keyword}`,
|
|
781
|
+
title_suggestion: `${trend.keyword} 시대의 ${topic}`,
|
|
782
|
+
relevance_score: Math.floor(Math.random() * 30) + 70,
|
|
783
|
+
}));
|
|
784
|
+
}
|
|
785
|
+
// 플랫폼별 팁
|
|
786
|
+
function getPlatformSpecificTips(platform) {
|
|
298
787
|
const tips = {
|
|
299
|
-
blog:
|
|
300
|
-
|
|
301
|
-
"
|
|
302
|
-
"
|
|
303
|
-
|
|
304
|
-
youtube:
|
|
305
|
-
|
|
306
|
-
"
|
|
307
|
-
"
|
|
308
|
-
|
|
309
|
-
instagram:
|
|
310
|
-
"
|
|
311
|
-
"
|
|
312
|
-
"
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
"
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
788
|
+
blog: {
|
|
789
|
+
optimal_length: "2000-4000자",
|
|
790
|
+
seo_tips: ["H2 태그 3-5개 사용", "키워드 밀도 2-3%", "내부링크 추가"],
|
|
791
|
+
best_time: "오전 9-11시",
|
|
792
|
+
},
|
|
793
|
+
youtube: {
|
|
794
|
+
optimal_length: "8-15분",
|
|
795
|
+
tips: ["처음 30초가 핵심", "챕터 추가", "엔드스크린 활용"],
|
|
796
|
+
best_time: "토요일 오후 2-4시",
|
|
797
|
+
},
|
|
798
|
+
instagram: {
|
|
799
|
+
optimal_length: "캡션 150-200자",
|
|
800
|
+
tips: ["첫 줄이 핵심", "캐러셀 활용", "릴스 우선"],
|
|
801
|
+
best_time: "점심 12-1시, 저녁 7-9시",
|
|
802
|
+
hashtag_count: "20-25개",
|
|
803
|
+
},
|
|
804
|
+
tiktok: {
|
|
805
|
+
optimal_length: "15-60초",
|
|
806
|
+
tips: ["처음 1초가 승부", "트렌딩 사운드 활용", "빠른 전개"],
|
|
807
|
+
best_time: "저녁 7-10시",
|
|
808
|
+
hashtag_count: "3-5개",
|
|
809
|
+
},
|
|
810
|
+
threads: {
|
|
811
|
+
optimal_length: "200-300자",
|
|
812
|
+
tips: ["대화체 사용", "시리즈로 연결", "인스타 연동"],
|
|
813
|
+
best_time: "오전 8-9시, 저녁 6-8시",
|
|
814
|
+
},
|
|
815
|
+
newsletter: {
|
|
816
|
+
optimal_length: "800-1200자",
|
|
817
|
+
tips: ["제목에 숫자 사용", "개인화된 인사", "명확한 CTA"],
|
|
818
|
+
best_time: "화요일/목요일 오전 9시",
|
|
819
|
+
},
|
|
820
|
+
};
|
|
821
|
+
return tips[platform] || tips;
|
|
822
|
+
}
|
|
823
|
+
// 추천 스케줄
|
|
824
|
+
function getRecommendedSchedule(platform) {
|
|
825
|
+
return {
|
|
826
|
+
frequency: platform === "tiktok" ? "매일 1-2회" : platform === "instagram" ? "매일 1회 + 스토리" : "주 3-4회",
|
|
827
|
+
best_days: ["화요일", "수요일", "목요일"],
|
|
828
|
+
consistency_tip: "같은 시간대에 발행하면 알고리즘에 유리합니다",
|
|
329
829
|
};
|
|
330
|
-
return tips[contentType] || tips.all;
|
|
331
830
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const
|
|
831
|
+
// 고급 제목/해시태그 최적화
|
|
832
|
+
async function optimizeAdvancedTitleAndHashtags(originalTitle, platform, keywords, style, language) {
|
|
833
|
+
const variations = generateAdvancedTitleVariations(originalTitle, style, language);
|
|
834
|
+
const platformHashtags = generatePlatformSpecificHashtags(originalTitle, keywords, platform);
|
|
335
835
|
return {
|
|
336
836
|
original: originalTitle,
|
|
337
837
|
optimized_titles: variations,
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
838
|
+
recommended: variations[0],
|
|
839
|
+
title_analysis: {
|
|
840
|
+
original_length: originalTitle.length,
|
|
841
|
+
has_numbers: /\d/.test(originalTitle),
|
|
842
|
+
has_emotional_words: /놀라운|충격|비밀|최고|완벽|필수|대박/.test(originalTitle),
|
|
843
|
+
has_question: /\?/.test(originalTitle),
|
|
844
|
+
readability_score: calculateReadabilityScore(originalTitle),
|
|
343
845
|
},
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
"
|
|
348
|
-
"감정을 자극하는
|
|
349
|
-
"질문형 제목은 참여율을 높입니다",
|
|
846
|
+
hashtag_strategy: platformHashtags,
|
|
847
|
+
seo_recommendations: [
|
|
848
|
+
"메인 키워드를 제목 앞부분에 배치하세요",
|
|
849
|
+
"50자 이내로 유지하세요 (검색 결과 노출 최적화)",
|
|
850
|
+
"감정을 자극하는 파워워드를 1-2개 포함하세요",
|
|
350
851
|
],
|
|
852
|
+
ab_test_suggestion: "변형 A와 B를 각각 50%씩 테스트해보세요",
|
|
351
853
|
};
|
|
352
854
|
}
|
|
353
|
-
function
|
|
855
|
+
function generateAdvancedTitleVariations(original, style, language) {
|
|
354
856
|
const variations = [
|
|
355
|
-
{ title: `[
|
|
356
|
-
{ title: `${original} (
|
|
357
|
-
{ title: `${original}?
|
|
358
|
-
{ title:
|
|
359
|
-
{ title: `${original}
|
|
857
|
+
{ title: `[2025 최신] ${original}`, style: "informative", ctr_prediction: 92 },
|
|
858
|
+
{ title: `${original} (완벽 정리)`, style: "comprehensive", ctr_prediction: 88 },
|
|
859
|
+
{ title: `${original}? 이것만 보세요`, style: "clickbait", ctr_prediction: 95 },
|
|
860
|
+
{ title: `99%가 모르는 ${original}의 비밀`, style: "curiosity", ctr_prediction: 90 },
|
|
861
|
+
{ title: `${original} 하는 법 | 초보자 필독`, style: "how-to", ctr_prediction: 85 },
|
|
862
|
+
{ title: `${original} 총정리 (+ 꿀팁 5가지)`, style: "listicle", ctr_prediction: 87 },
|
|
863
|
+
{ title: `${original}, 진짜 효과있을까? 직접 해봄`, style: "personal", ctr_prediction: 89 },
|
|
360
864
|
];
|
|
361
865
|
return variations.map(v => ({
|
|
362
866
|
...v,
|
|
363
867
|
length: v.title.length,
|
|
364
|
-
|
|
868
|
+
word_count: v.title.split(/\s+/).length,
|
|
869
|
+
platform_fit: v.title.length <= 40 ? "instagram/tiktok" : v.title.length <= 60 ? "youtube/blog" : "blog",
|
|
365
870
|
}));
|
|
366
871
|
}
|
|
367
|
-
function
|
|
368
|
-
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
"
|
|
373
|
-
"
|
|
872
|
+
function generatePlatformSpecificHashtags(title, keywords, platform) {
|
|
873
|
+
// 키워드 기반 해시태그
|
|
874
|
+
const keywordHashtags = keywords.map(k => `#${k.replace(/\s/g, '')}`);
|
|
875
|
+
// 플랫폼별 인기 해시태그
|
|
876
|
+
const platformTrending = {
|
|
877
|
+
instagram: ["#일상", "#데일리", "#소통", "#맞팔", "#인스타그램", "#좋아요", "#팔로우", "#데일리그램", "#인스타", "#daily"],
|
|
878
|
+
tiktok: ["#fyp", "#foryou", "#viral", "#trending", "#틱톡", "#추천", "#챌린지"],
|
|
879
|
+
youtube: ["#유튜브", "#브이로그", "#일상브이로그", "#유튜버", "#vlog"],
|
|
880
|
+
twitter: ["#트위터", "#오늘", "#일상", "#생각"],
|
|
881
|
+
threads: ["#스레드", "#threads", "#일상", "#생각정리"],
|
|
882
|
+
};
|
|
883
|
+
// 카테고리별 해시태그
|
|
884
|
+
const categoryHashtags = [
|
|
885
|
+
"#정보", "#꿀팁", "#추천", "#리뷰", "#후기",
|
|
886
|
+
"#트렌드", "#핫이슈", "#신상", "#best", "#top",
|
|
374
887
|
];
|
|
375
|
-
return
|
|
888
|
+
return {
|
|
889
|
+
primary: keywordHashtags.slice(0, 5),
|
|
890
|
+
platform_trending: platformTrending[platform] || platformTrending.instagram,
|
|
891
|
+
category: categoryHashtags,
|
|
892
|
+
total_recommended: platform === "instagram" ? 25 : platform === "tiktok" ? 5 : 10,
|
|
893
|
+
placement_tip: platform === "instagram"
|
|
894
|
+
? "첫 댓글에 해시태그를 넣으면 깔끔합니다"
|
|
895
|
+
: "캡션 마지막에 배치하세요",
|
|
896
|
+
};
|
|
376
897
|
}
|
|
377
|
-
|
|
898
|
+
function calculateReadabilityScore(text) {
|
|
899
|
+
const length = text.length;
|
|
900
|
+
const hasNumbers = /\d/.test(text) ? 10 : 0;
|
|
901
|
+
const hasEmoji = /[\u{1F600}-\u{1F64F}]/u.test(text) ? 5 : 0;
|
|
902
|
+
const optimalLength = length >= 20 && length <= 50 ? 15 : length >= 50 && length <= 70 ? 10 : 5;
|
|
903
|
+
return Math.min(100, 60 + hasNumbers + hasEmoji + optimalLength);
|
|
904
|
+
}
|
|
905
|
+
// 고급 SEO 키워드 분석
|
|
906
|
+
async function analyzeAdvancedSEOKeywords(keyword, searchEngine, includeQuestions, includeLongtail, competitorAnalysis) {
|
|
907
|
+
// 관련 키워드 생성
|
|
378
908
|
const relatedKeywords = [
|
|
379
|
-
{ keyword: `${keyword} 방법`, volume: "높음", competition: "중간", trend: "상승" },
|
|
380
|
-
{ keyword: `${keyword} 추천`, volume: "높음", competition: "높음", trend: "유지" },
|
|
381
|
-
{ keyword: `${keyword} 비교`, volume: "중간", competition: "낮음", trend: "상승" },
|
|
382
|
-
{ keyword: `${keyword} 후기`, volume: "
|
|
383
|
-
{ keyword: `${keyword} 가격`, volume: "높음", competition: "높음", trend: "유지" },
|
|
909
|
+
{ keyword: `${keyword} 방법`, volume: "매우 높음", competition: "중간", cpc: "₩850", trend: "상승" },
|
|
910
|
+
{ keyword: `${keyword} 추천`, volume: "높음", competition: "높음", cpc: "₩1,200", trend: "유지" },
|
|
911
|
+
{ keyword: `${keyword} 비교`, volume: "중간", competition: "낮음", cpc: "₩650", trend: "상승" },
|
|
912
|
+
{ keyword: `${keyword} 후기`, volume: "높음", competition: "중간", cpc: "₩780", trend: "상승" },
|
|
913
|
+
{ keyword: `${keyword} 가격`, volume: "매우 높음", competition: "매우 높음", cpc: "₩1,500", trend: "유지" },
|
|
914
|
+
{ keyword: `${keyword} 종류`, volume: "중간", competition: "낮음", cpc: "₩450", trend: "상승" },
|
|
915
|
+
{ keyword: `${keyword} 장단점`, volume: "중간", competition: "낮음", cpc: "₩520", trend: "상승" },
|
|
916
|
+
{ keyword: `best ${keyword}`, volume: "중간", competition: "중간", cpc: "₩680", trend: "유지" },
|
|
384
917
|
];
|
|
385
918
|
const questionKeywords = includeQuestions ? [
|
|
386
|
-
`${keyword}
|
|
387
|
-
`${keyword}
|
|
388
|
-
`${keyword} 왜
|
|
389
|
-
`${keyword}
|
|
390
|
-
`${keyword}
|
|
919
|
+
{ keyword: `${keyword}이란 무엇인가요?`, type: "정의", intent: "정보탐색" },
|
|
920
|
+
{ keyword: `${keyword} 어떻게 시작하나요?`, type: "방법", intent: "정보탐색" },
|
|
921
|
+
{ keyword: `${keyword} 왜 필요한가요?`, type: "이유", intent: "정보탐색" },
|
|
922
|
+
{ keyword: `${keyword} 얼마인가요?`, type: "가격", intent: "구매의도" },
|
|
923
|
+
{ keyword: `${keyword} 어디서 구매하나요?`, type: "구매처", intent: "구매의도" },
|
|
924
|
+
{ keyword: `${keyword} vs 대안 뭐가 좋나요?`, type: "비교", intent: "비교검토" },
|
|
391
925
|
] : [];
|
|
392
926
|
const longtailKeywords = includeLongtail ? [
|
|
393
|
-
`초보자를 위한 ${keyword} 가이드`,
|
|
394
|
-
`${keyword} 실수 피하는
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
`${keyword}
|
|
927
|
+
{ keyword: `초보자를 위한 ${keyword} 완벽 가이드`, difficulty: 35, opportunity: "높음" },
|
|
928
|
+
{ keyword: `${keyword} 실수 피하는 7가지 방법`, difficulty: 28, opportunity: "매우 높음" },
|
|
929
|
+
{ keyword: `2025년 ${keyword} 트렌드 전망`, difficulty: 42, opportunity: "높음" },
|
|
930
|
+
{ keyword: `${keyword} 비용 절약하는 팁`, difficulty: 31, opportunity: "높음" },
|
|
931
|
+
{ keyword: `${keyword} 전문가가 추천하는`, difficulty: 38, opportunity: "중간" },
|
|
398
932
|
] : [];
|
|
933
|
+
const searchEngineStrategy = {
|
|
934
|
+
naver: {
|
|
935
|
+
tips: [
|
|
936
|
+
"네이버 블로그/포스트에 발행하세요",
|
|
937
|
+
"키워드를 제목에 정확히 포함하세요",
|
|
938
|
+
"이미지 ALT 태그에 키워드 추가",
|
|
939
|
+
"체류시간을 늘리는 콘텐츠 작성",
|
|
940
|
+
],
|
|
941
|
+
content_types: ["블로그", "포스트", "지식iN"],
|
|
942
|
+
},
|
|
943
|
+
google: {
|
|
944
|
+
tips: [
|
|
945
|
+
"H1, H2 태그에 키워드 배치",
|
|
946
|
+
"메타 디스크립션 최적화",
|
|
947
|
+
"모바일 친화적 디자인 필수",
|
|
948
|
+
"페이지 로딩 속도 개선",
|
|
949
|
+
],
|
|
950
|
+
content_types: ["웹사이트", "유튜브", "뉴스"],
|
|
951
|
+
},
|
|
952
|
+
};
|
|
399
953
|
return {
|
|
400
954
|
main_keyword: keyword,
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
"
|
|
407
|
-
|
|
408
|
-
],
|
|
955
|
+
overall_analysis: {
|
|
956
|
+
search_volume: "높음",
|
|
957
|
+
competition_level: "중간",
|
|
958
|
+
seo_difficulty: 58,
|
|
959
|
+
content_opportunity_score: 78,
|
|
960
|
+
recommended_action: "롱테일 키워드로 진입 후 메인 키워드 공략",
|
|
961
|
+
},
|
|
409
962
|
related_keywords: relatedKeywords,
|
|
410
963
|
question_keywords: questionKeywords,
|
|
411
964
|
longtail_keywords: longtailKeywords,
|
|
412
|
-
|
|
413
|
-
|
|
965
|
+
search_engine_strategy: searchEngine === "both" ? searchEngineStrategy : searchEngineStrategy[searchEngine],
|
|
966
|
+
content_recommendations: {
|
|
967
|
+
ideal_length: "3000-5000자",
|
|
968
|
+
must_include: ["정의", "방법", "예시", "FAQ"],
|
|
969
|
+
format: "종합 가이드 형식",
|
|
970
|
+
media: ["이미지 5-10개", "인포그래픽 1개", "영상 임베드"],
|
|
971
|
+
},
|
|
972
|
+
competitor_insights: competitorAnalysis ? {
|
|
973
|
+
top_ranking_content_avg_length: "3,500자",
|
|
974
|
+
common_headings: ["정의", "방법", "주의사항", "FAQ"],
|
|
975
|
+
gap_opportunities: ["최신 트렌드 반영 부족", "실제 사례 부족"],
|
|
976
|
+
} : null,
|
|
414
977
|
};
|
|
415
978
|
}
|
|
416
|
-
|
|
979
|
+
// 고급 콘텐츠 캘린더 생성
|
|
980
|
+
function createAdvancedContentCalendar(topics, durationWeeks, postsPerWeek, platforms, includeEvents, contentMix) {
|
|
417
981
|
const calendar = [];
|
|
418
982
|
const startDate = new Date();
|
|
419
|
-
//
|
|
420
|
-
const
|
|
421
|
-
{
|
|
422
|
-
{
|
|
423
|
-
{
|
|
424
|
-
{
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
{ date: "05-15", name: "스승의날", type: "event" },
|
|
428
|
-
{ date: "11-11", name: "빼빼로데이", type: "event" },
|
|
429
|
-
{ date: "12-25", name: "크리스마스", type: "holiday" },
|
|
430
|
-
];
|
|
983
|
+
// 콘텐츠 믹스 비율
|
|
984
|
+
const mixRatios = {
|
|
985
|
+
balanced: { educational: 40, entertaining: 30, promotional: 20, engaging: 10 },
|
|
986
|
+
promotional: { educational: 20, entertaining: 20, promotional: 50, engaging: 10 },
|
|
987
|
+
educational: { educational: 60, entertaining: 20, promotional: 10, engaging: 10 },
|
|
988
|
+
entertaining: { educational: 20, entertaining: 50, promotional: 15, engaging: 15 },
|
|
989
|
+
};
|
|
990
|
+
const ratio = mixRatios[contentMix] || mixRatios.balanced;
|
|
431
991
|
for (let week = 0; week < durationWeeks; week++) {
|
|
432
992
|
const weekStart = new Date(startDate);
|
|
433
993
|
weekStart.setDate(startDate.getDate() + week * 7);
|
|
434
994
|
const weekPlan = {
|
|
435
995
|
week: week + 1,
|
|
436
996
|
start_date: weekStart.toISOString().split('T')[0],
|
|
437
|
-
posts: [],
|
|
438
997
|
theme: topics[week % topics.length],
|
|
998
|
+
posts: [],
|
|
999
|
+
weekly_goals: generateWeeklyGoals(week, topics[week % topics.length]),
|
|
439
1000
|
};
|
|
440
1001
|
for (let post = 0; post < postsPerWeek; post++) {
|
|
441
1002
|
const postDate = new Date(weekStart);
|
|
442
1003
|
postDate.setDate(weekStart.getDate() + Math.floor((post / postsPerWeek) * 7));
|
|
443
1004
|
const dateStr = postDate.toISOString().split('T')[0];
|
|
444
|
-
const
|
|
445
|
-
|
|
1005
|
+
const monthDay = `${String(postDate.getMonth() + 1).padStart(2, '0')}-${String(postDate.getDate()).padStart(2, '0')}`;
|
|
1006
|
+
// 이벤트 체크
|
|
1007
|
+
const event = includeEvents ? KOREAN_EVENTS_DB.find(e => e.date === monthDay) : null;
|
|
1008
|
+
// 콘텐츠 타입 결정
|
|
1009
|
+
const contentType = determineContentType(post, ratio);
|
|
1010
|
+
const platform = platforms[post % platforms.length];
|
|
446
1011
|
weekPlan.posts.push({
|
|
447
1012
|
id: week * postsPerWeek + post + 1,
|
|
448
1013
|
date: dateStr,
|
|
449
1014
|
day: ["일", "월", "화", "수", "목", "금", "토"][postDate.getDay()],
|
|
450
|
-
|
|
451
|
-
|
|
1015
|
+
platform,
|
|
1016
|
+
content_type: contentType,
|
|
1017
|
+
topic: event
|
|
1018
|
+
? `${event.name} 특집: ${topics[post % topics.length]}`
|
|
1019
|
+
: topics[post % topics.length],
|
|
1020
|
+
format_suggestion: getFormatSuggestion(platform, contentType),
|
|
1021
|
+
optimal_time: getOptimalTimeForPlatform(platform),
|
|
1022
|
+
special_event: event ? { name: event.name, type: event.type, ideas: event.contentIdeas } : null,
|
|
452
1023
|
status: "planned",
|
|
453
|
-
|
|
454
|
-
special_event: holiday?.name || null,
|
|
1024
|
+
checklist: ["아이디어 확정", "콘텐츠 제작", "해시태그 준비", "발행"],
|
|
455
1025
|
});
|
|
456
1026
|
}
|
|
457
1027
|
calendar.push(weekPlan);
|
|
458
1028
|
}
|
|
1029
|
+
// 이벤트 하이라이트
|
|
1030
|
+
const upcomingEvents = includeEvents ? getUpcomingEvents(durationWeeks * 7) : [];
|
|
459
1031
|
return {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
1032
|
+
overview: {
|
|
1033
|
+
duration: `${durationWeeks}주`,
|
|
1034
|
+
total_posts: durationWeeks * postsPerWeek,
|
|
1035
|
+
platforms,
|
|
1036
|
+
topics,
|
|
1037
|
+
content_mix: ratio,
|
|
1038
|
+
},
|
|
464
1039
|
calendar,
|
|
1040
|
+
upcoming_events: upcomingEvents,
|
|
465
1041
|
recommendations: [
|
|
466
|
-
"주요
|
|
467
|
-
"
|
|
468
|
-
"
|
|
1042
|
+
"📅 주요 이벤트 1-2주 전에 관련 콘텐츠 준비",
|
|
1043
|
+
"🔄 일관된 발행 시간 유지",
|
|
1044
|
+
"📊 주간 단위로 성과 분석",
|
|
1045
|
+
"🎯 각 플랫폼의 알고리즘 특성 반영",
|
|
469
1046
|
],
|
|
1047
|
+
monthly_themes: generateMonthlyThemes(startDate, durationWeeks),
|
|
470
1048
|
};
|
|
471
1049
|
}
|
|
472
|
-
|
|
1050
|
+
function generateWeeklyGoals(week, theme) {
|
|
1051
|
+
return [
|
|
1052
|
+
`${theme} 관련 인게이지먼트 10% 향상`,
|
|
1053
|
+
"신규 팔로워 획득",
|
|
1054
|
+
"커뮤니티 참여 증대",
|
|
1055
|
+
];
|
|
1056
|
+
}
|
|
1057
|
+
function determineContentType(index, ratio) {
|
|
1058
|
+
const types = ["educational", "entertaining", "promotional", "engaging"];
|
|
1059
|
+
// 단순화된 로직
|
|
1060
|
+
return types[index % 4];
|
|
1061
|
+
}
|
|
1062
|
+
function getFormatSuggestion(platform, contentType) {
|
|
1063
|
+
const formats = {
|
|
1064
|
+
instagram: {
|
|
1065
|
+
educational: "캐러셀 (5-10장)",
|
|
1066
|
+
entertaining: "릴스 (15-30초)",
|
|
1067
|
+
promotional: "단일 이미지 + 스토리",
|
|
1068
|
+
engaging: "스토리 투표/퀴즈",
|
|
1069
|
+
},
|
|
1070
|
+
youtube: {
|
|
1071
|
+
educational: "튜토리얼 (10-15분)",
|
|
1072
|
+
entertaining: "브이로그 (8-12분)",
|
|
1073
|
+
promotional: "쇼츠 (30-60초)",
|
|
1074
|
+
engaging: "라이브 스트리밍",
|
|
1075
|
+
},
|
|
1076
|
+
blog: {
|
|
1077
|
+
educational: "가이드 (3000자+)",
|
|
1078
|
+
entertaining: "후기/에세이 (2000자)",
|
|
1079
|
+
promotional: "제품 리뷰 (2500자)",
|
|
1080
|
+
engaging: "Q&A 포스트",
|
|
1081
|
+
},
|
|
1082
|
+
tiktok: {
|
|
1083
|
+
educational: "팁 영상 (30-60초)",
|
|
1084
|
+
entertaining: "트렌드 참여 (15-30초)",
|
|
1085
|
+
promotional: "제품 소개 (30초)",
|
|
1086
|
+
engaging: "듀엣/스티치",
|
|
1087
|
+
},
|
|
1088
|
+
};
|
|
1089
|
+
return formats[platform]?.[contentType] || "일반 포스트";
|
|
1090
|
+
}
|
|
1091
|
+
function getOptimalTimeForPlatform(platform) {
|
|
1092
|
+
const times = {
|
|
1093
|
+
instagram: "12:00-13:00, 19:00-21:00",
|
|
1094
|
+
youtube: "토요일 14:00-16:00",
|
|
1095
|
+
blog: "09:00-11:00",
|
|
1096
|
+
tiktok: "19:00-22:00",
|
|
1097
|
+
newsletter: "화/목 09:00",
|
|
1098
|
+
threads: "08:00-09:00, 18:00-20:00",
|
|
1099
|
+
twitter: "12:00-13:00, 17:00-18:00",
|
|
1100
|
+
};
|
|
1101
|
+
return times[platform] || "09:00-11:00";
|
|
1102
|
+
}
|
|
1103
|
+
function generateMonthlyThemes(startDate, weeks) {
|
|
1104
|
+
const themes = [];
|
|
1105
|
+
const months = Math.ceil(weeks / 4);
|
|
1106
|
+
for (let i = 0; i < months; i++) {
|
|
1107
|
+
const monthDate = new Date(startDate);
|
|
1108
|
+
monthDate.setMonth(startDate.getMonth() + i);
|
|
1109
|
+
const monthName = monthDate.toLocaleString('ko-KR', { month: 'long' });
|
|
1110
|
+
themes.push({
|
|
1111
|
+
month: monthName,
|
|
1112
|
+
suggested_themes: getMonthlyThemeSuggestions(monthDate.getMonth() + 1),
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
return themes;
|
|
1116
|
+
}
|
|
1117
|
+
function getMonthlyThemeSuggestions(month) {
|
|
1118
|
+
const suggestions = {
|
|
1119
|
+
1: ["새해 계획", "신년 트렌드", "겨울 콘텐츠", "설날 준비"],
|
|
1120
|
+
2: ["발렌타인", "봄 준비", "연인 콘텐츠"],
|
|
1121
|
+
3: ["봄 시즌", "신학기", "화이트데이", "봄나들이"],
|
|
1122
|
+
4: ["벚꽃", "봄 패션", "아웃도어"],
|
|
1123
|
+
5: ["가정의 달", "어버이날", "야외활동", "여름 준비"],
|
|
1124
|
+
6: ["여름 시작", "휴가 계획", "다이어트"],
|
|
1125
|
+
7: ["휴가 시즌", "여름 패션", "물놀이"],
|
|
1126
|
+
8: ["말복", "여름 끝", "가을 준비"],
|
|
1127
|
+
9: ["새학기", "가을 패션", "추석 준비"],
|
|
1128
|
+
10: ["가을", "추석", "할로윈", "단풍"],
|
|
1129
|
+
11: ["블랙프라이데이", "연말 준비", "빼빼로데이"],
|
|
1130
|
+
12: ["연말 결산", "크리스마스", "송년", "선물"],
|
|
1131
|
+
};
|
|
1132
|
+
return suggestions[month] || ["시즌 콘텐츠"];
|
|
1133
|
+
}
|
|
1134
|
+
// 고급 경쟁사 분석
|
|
1135
|
+
async function analyzeAdvancedCompetitorContent(urls, depth, extractStrategy) {
|
|
473
1136
|
const results = [];
|
|
474
1137
|
for (const url of urls) {
|
|
475
1138
|
try {
|
|
476
1139
|
const response = await axios.get(url, {
|
|
477
|
-
headers: {
|
|
478
|
-
|
|
1140
|
+
headers: {
|
|
1141
|
+
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
1142
|
+
'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
|
|
1143
|
+
},
|
|
1144
|
+
timeout: 15000,
|
|
479
1145
|
});
|
|
480
1146
|
const $ = cheerio.load(response.data);
|
|
481
1147
|
const analysis = {
|
|
482
1148
|
url,
|
|
483
1149
|
title: $('title').text().trim(),
|
|
484
1150
|
meta_description: $('meta[name="description"]').attr('content') || '',
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
h2: $('h2').map((_, el) => $(el).text().trim()).get().slice(0, 10),
|
|
488
|
-
},
|
|
489
|
-
word_count: $('body').text().split(/\s+/).length,
|
|
490
|
-
images_count: $('img').length,
|
|
491
|
-
internal_links: $('a[href^="/"]').length,
|
|
492
|
-
external_links: $('a[href^="http"]').length,
|
|
1151
|
+
og_title: $('meta[property="og:title"]').attr('content') || '',
|
|
1152
|
+
og_description: $('meta[property="og:description"]').attr('content') || '',
|
|
493
1153
|
};
|
|
494
|
-
if (
|
|
1154
|
+
if (depth === "detailed" || depth === "comprehensive") {
|
|
1155
|
+
analysis.structure = {
|
|
1156
|
+
h1: $('h1').map((_, el) => $(el).text().trim()).get(),
|
|
1157
|
+
h2: $('h2').map((_, el) => $(el).text().trim()).get().slice(0, 15),
|
|
1158
|
+
h3: $('h3').map((_, el) => $(el).text().trim()).get().slice(0, 10),
|
|
1159
|
+
};
|
|
1160
|
+
const bodyText = $('body').text();
|
|
1161
|
+
analysis.content_stats = {
|
|
1162
|
+
word_count: bodyText.split(/\s+/).length,
|
|
1163
|
+
char_count: bodyText.length,
|
|
1164
|
+
images_count: $('img').length,
|
|
1165
|
+
videos_count: $('video, iframe[src*="youtube"], iframe[src*="vimeo"]').length,
|
|
1166
|
+
internal_links: $('a[href^="/"]').length,
|
|
1167
|
+
external_links: $('a[href^="http"]').not(`a[href*="${new URL(url).hostname}"]`).length,
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
if (depth === "comprehensive") {
|
|
1171
|
+
// 키워드 분석
|
|
495
1172
|
const text = $('body').text().toLowerCase();
|
|
496
|
-
const
|
|
1173
|
+
const koreanWords = text.match(/[\uAC00-\uD7AF]{2,}/g) || [];
|
|
497
1174
|
const wordFreq = {};
|
|
498
|
-
|
|
499
|
-
if (word.length
|
|
1175
|
+
koreanWords.forEach(word => {
|
|
1176
|
+
if (word.length >= 2)
|
|
500
1177
|
wordFreq[word] = (wordFreq[word] || 0) + 1;
|
|
501
1178
|
});
|
|
502
|
-
analysis.
|
|
503
|
-
.
|
|
504
|
-
|
|
505
|
-
|
|
1179
|
+
analysis.keyword_analysis = {
|
|
1180
|
+
top_keywords: Object.entries(wordFreq)
|
|
1181
|
+
.sort((a, b) => b[1] - a[1])
|
|
1182
|
+
.slice(0, 30)
|
|
1183
|
+
.map(([word, count]) => ({ word, count, density: ((count / koreanWords.length) * 100).toFixed(2) + '%' })),
|
|
1184
|
+
total_keywords: koreanWords.length,
|
|
1185
|
+
};
|
|
1186
|
+
// 콘텐츠 구조 분석
|
|
1187
|
+
analysis.content_structure = {
|
|
1188
|
+
has_toc: $('[class*="toc"], [class*="table-of-contents"], #toc').length > 0,
|
|
1189
|
+
has_faq: $('[class*="faq"], [itemtype*="FAQPage"]').length > 0,
|
|
1190
|
+
has_author: $('[class*="author"], [rel="author"]').length > 0,
|
|
1191
|
+
schema_types: $('[itemtype]').map((_, el) => $(el).attr('itemtype')).get(),
|
|
1192
|
+
};
|
|
506
1193
|
}
|
|
507
1194
|
results.push(analysis);
|
|
508
1195
|
}
|
|
509
1196
|
catch (error) {
|
|
510
|
-
results.push({ url, error:
|
|
1197
|
+
results.push({ url, error: `분석 실패: ${error.message || '알 수 없는 오류'}` });
|
|
511
1198
|
}
|
|
512
1199
|
}
|
|
1200
|
+
// 전략 추출
|
|
1201
|
+
let strategyInsights = null;
|
|
1202
|
+
if (extractStrategy && results.filter(r => !r.error).length > 0) {
|
|
1203
|
+
strategyInsights = {
|
|
1204
|
+
common_patterns: [
|
|
1205
|
+
"H2 태그로 주요 섹션 구분",
|
|
1206
|
+
"리스트형 콘텐츠 선호",
|
|
1207
|
+
"이미지와 텍스트 적절히 배합",
|
|
1208
|
+
],
|
|
1209
|
+
average_metrics: {
|
|
1210
|
+
avg_word_count: Math.round(results.filter(r => r.content_stats)
|
|
1211
|
+
.reduce((sum, r) => sum + r.content_stats.word_count, 0) /
|
|
1212
|
+
results.filter(r => r.content_stats).length || 1),
|
|
1213
|
+
avg_images: Math.round(results.filter(r => r.content_stats)
|
|
1214
|
+
.reduce((sum, r) => sum + r.content_stats.images_count, 0) /
|
|
1215
|
+
results.filter(r => r.content_stats).length || 1),
|
|
1216
|
+
},
|
|
1217
|
+
opportunities: [
|
|
1218
|
+
"비디오 콘텐츠 추가로 차별화",
|
|
1219
|
+
"FAQ 섹션 추가로 검색 노출 강화",
|
|
1220
|
+
"더 상세한 가이드로 경쟁 우위",
|
|
1221
|
+
],
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
513
1224
|
return {
|
|
514
1225
|
analyzed_at: new Date().toISOString(),
|
|
1226
|
+
analysis_depth: depth,
|
|
515
1227
|
total_urls: urls.length,
|
|
516
1228
|
successful: results.filter(r => !r.error).length,
|
|
517
1229
|
results,
|
|
518
|
-
|
|
519
|
-
"경쟁사 콘텐츠의 평균 길이를 참고하세요",
|
|
520
|
-
"자주 사용되는 키워드를 파악하세요",
|
|
521
|
-
"제목과 메타 설명의 패턴을 분석하세요",
|
|
522
|
-
],
|
|
1230
|
+
strategy_insights: strategyInsights,
|
|
523
1231
|
};
|
|
524
1232
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
1233
|
+
// 고급 바이럴 예측
|
|
1234
|
+
function predictAdvancedViralScore(title, description, platform, hashtags, contentType) {
|
|
1235
|
+
// 다양한 바이럴 요소 분석
|
|
1236
|
+
const factors = {
|
|
1237
|
+
// 감정 요소
|
|
1238
|
+
emotional: {
|
|
1239
|
+
positive: /최고|완벽|대박|필수|추천|굿|좋은|행복|성공|감동/g,
|
|
1240
|
+
negative: /충격|경악|실화|심각|위험|주의|경고/g,
|
|
1241
|
+
curiosity: /비밀|숨겨진|몰랐던|알려지지|진실|실체/g,
|
|
1242
|
+
},
|
|
1243
|
+
// 구조 요소
|
|
1244
|
+
structural: {
|
|
1245
|
+
numbers: /\d+/g,
|
|
1246
|
+
questions: /\?/g,
|
|
1247
|
+
brackets: /\[|\]/g,
|
|
1248
|
+
emphasis: /!/g,
|
|
1249
|
+
},
|
|
1250
|
+
// 긴급성
|
|
1251
|
+
urgency: /지금|당장|오늘|한정|마감|급|바로|즉시|놓치면/g,
|
|
1252
|
+
// 사회적 증거
|
|
1253
|
+
socialProof: /만명|팔로워|구독자|조회수|리뷰|후기|인증|추천|화제/g,
|
|
1254
|
+
// 실용성
|
|
1255
|
+
utility: /방법|팁|가이드|정리|비법|노하우|꿀팁|해결/g,
|
|
533
1256
|
};
|
|
534
|
-
let score = 50;
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
1257
|
+
let score = 50;
|
|
1258
|
+
const analysis = {};
|
|
1259
|
+
// 감정 분석
|
|
1260
|
+
const positiveMatches = (title + description).match(factors.emotional.positive);
|
|
1261
|
+
const negativeMatches = (title + description).match(factors.emotional.negative);
|
|
1262
|
+
const curiosityMatches = (title + description).match(factors.emotional.curiosity);
|
|
1263
|
+
if (positiveMatches) {
|
|
1264
|
+
score += Math.min(positiveMatches.length * 5, 15);
|
|
1265
|
+
}
|
|
1266
|
+
if (negativeMatches) {
|
|
1267
|
+
score += Math.min(negativeMatches.length * 4, 12);
|
|
1268
|
+
}
|
|
1269
|
+
if (curiosityMatches) {
|
|
1270
|
+
score += Math.min(curiosityMatches.length * 6, 18);
|
|
1271
|
+
}
|
|
1272
|
+
analysis.emotional_triggers = {
|
|
1273
|
+
positive: positiveMatches?.length || 0,
|
|
1274
|
+
negative: negativeMatches?.length || 0,
|
|
1275
|
+
curiosity: curiosityMatches?.length || 0,
|
|
1276
|
+
};
|
|
1277
|
+
// 구조 분석
|
|
1278
|
+
const hasNumbers = factors.structural.numbers.test(title);
|
|
1279
|
+
const hasQuestion = factors.structural.questions.test(title);
|
|
1280
|
+
const hasBrackets = factors.structural.brackets.test(title);
|
|
1281
|
+
const hasEmphasis = factors.structural.emphasis.test(title);
|
|
1282
|
+
if (hasNumbers)
|
|
539
1283
|
score += 10;
|
|
540
|
-
if (
|
|
1284
|
+
if (hasQuestion)
|
|
541
1285
|
score += 8;
|
|
542
|
-
if (
|
|
543
|
-
score +=
|
|
544
|
-
if (
|
|
1286
|
+
if (hasBrackets)
|
|
1287
|
+
score += 5;
|
|
1288
|
+
if (hasEmphasis)
|
|
1289
|
+
score += 3;
|
|
1290
|
+
analysis.structural_elements = { hasNumbers, hasQuestion, hasBrackets, hasEmphasis };
|
|
1291
|
+
// 긴급성
|
|
1292
|
+
if (factors.urgency.test(title + description))
|
|
1293
|
+
score += 8;
|
|
1294
|
+
// 사회적 증거
|
|
1295
|
+
if (factors.socialProof.test(title + description))
|
|
545
1296
|
score += 10;
|
|
546
|
-
//
|
|
547
|
-
if (
|
|
1297
|
+
// 실용성
|
|
1298
|
+
if (factors.utility.test(title + description))
|
|
1299
|
+
score += 7;
|
|
1300
|
+
// 제목 길이 최적화
|
|
1301
|
+
if (title.length >= 20 && title.length <= 45)
|
|
548
1302
|
score += 5;
|
|
1303
|
+
else if (title.length > 60)
|
|
1304
|
+
score -= 5;
|
|
549
1305
|
// 해시태그 분석
|
|
550
1306
|
if (hashtags.length >= 5 && hashtags.length <= 15)
|
|
551
1307
|
score += 5;
|
|
552
|
-
|
|
1308
|
+
else if (hashtags.length > 25)
|
|
1309
|
+
score -= 3;
|
|
1310
|
+
// 콘텐츠 타입 보너스
|
|
1311
|
+
const typeBonus = {
|
|
1312
|
+
video: 10,
|
|
1313
|
+
reel: 15,
|
|
1314
|
+
carousel: 8,
|
|
1315
|
+
image: 5,
|
|
1316
|
+
text: 0,
|
|
1317
|
+
};
|
|
1318
|
+
score += typeBonus[contentType] || 0;
|
|
1319
|
+
// 플랫폼별 조정
|
|
1320
|
+
const platformMultiplier = {
|
|
1321
|
+
tiktok: 1.2,
|
|
1322
|
+
instagram: 1.1,
|
|
1323
|
+
youtube: 1.0,
|
|
1324
|
+
twitter: 0.9,
|
|
1325
|
+
blog: 0.8,
|
|
1326
|
+
};
|
|
1327
|
+
score = Math.round(score * (platformMultiplier[platform] || 1));
|
|
1328
|
+
score = Math.min(Math.max(score, 0), 100);
|
|
1329
|
+
// 등급 결정
|
|
1330
|
+
const grade = score >= 85 ? "S (바이럴 예상)"
|
|
1331
|
+
: score >= 70 ? "A (높은 잠재력)"
|
|
1332
|
+
: score >= 55 ? "B (양호)"
|
|
1333
|
+
: score >= 40 ? "C (개선 필요)"
|
|
1334
|
+
: "D (재검토 필요)";
|
|
1335
|
+
// 개선 제안
|
|
553
1336
|
const improvements = [];
|
|
554
|
-
if (!
|
|
1337
|
+
if (!hasNumbers)
|
|
555
1338
|
improvements.push("숫자를 추가하세요 (예: '5가지 방법')");
|
|
556
|
-
if (!
|
|
557
|
-
improvements.push("
|
|
558
|
-
if (
|
|
559
|
-
improvements.push("
|
|
1339
|
+
if (!curiosityMatches)
|
|
1340
|
+
improvements.push("호기심을 자극하는 표현을 추가하세요");
|
|
1341
|
+
if (!hasQuestion && !hasEmphasis)
|
|
1342
|
+
improvements.push("질문형이나 감탄형을 시도해보세요");
|
|
1343
|
+
if (title.length > 50)
|
|
1344
|
+
improvements.push("제목을 50자 이내로 줄이세요");
|
|
560
1345
|
if (hashtags.length < 5)
|
|
561
|
-
improvements.push("해시태그를 5개 이상 추가하세요");
|
|
1346
|
+
improvements.push("관련 해시태그를 5개 이상 추가하세요");
|
|
1347
|
+
if (contentType === "text")
|
|
1348
|
+
improvements.push("이미지나 영상을 추가하면 참여율이 높아집니다");
|
|
562
1349
|
return {
|
|
563
1350
|
title,
|
|
1351
|
+
content_type: contentType,
|
|
1352
|
+
platform,
|
|
564
1353
|
viral_score: score,
|
|
565
|
-
grade
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
1354
|
+
grade,
|
|
1355
|
+
analysis: {
|
|
1356
|
+
...analysis,
|
|
1357
|
+
title_length: title.length,
|
|
1358
|
+
hashtag_count: hashtags.length,
|
|
1359
|
+
urgency_detected: factors.urgency.test(title + description),
|
|
1360
|
+
social_proof_detected: factors.socialProof.test(title + description),
|
|
1361
|
+
utility_detected: factors.utility.test(title + description),
|
|
571
1362
|
},
|
|
572
1363
|
improvements,
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
1364
|
+
predicted_performance: {
|
|
1365
|
+
reach: score >= 70 ? "높음" : score >= 50 ? "보통" : "낮음",
|
|
1366
|
+
engagement: score >= 75 ? "높음" : score >= 55 ? "보통" : "낮음",
|
|
1367
|
+
shares: score >= 80 ? "높음" : score >= 60 ? "보통" : "낮음",
|
|
1368
|
+
saves: score >= 65 ? "높음" : score >= 45 ? "보통" : "낮음",
|
|
1369
|
+
},
|
|
1370
|
+
optimized_title_suggestions: [
|
|
1371
|
+
hasNumbers ? null : `${title.slice(0, 20)}... 5가지 방법`,
|
|
1372
|
+
hasQuestion ? null : `${title}?`,
|
|
1373
|
+
`[필독] ${title}`,
|
|
1374
|
+
].filter(Boolean).slice(0, 3),
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
// 뉴스 분석
|
|
1378
|
+
async function analyzeKoreanNews(category, timeRange, extractKeywords) {
|
|
1379
|
+
// 카테고리별 뉴스 키워드 시뮬레이션
|
|
1380
|
+
const newsData = {
|
|
1381
|
+
general: [
|
|
1382
|
+
{ headline: "AI 기술 발전과 일자리 변화", source: "종합", sentiment: "neutral" },
|
|
1383
|
+
{ headline: "글로벌 경제 동향 분석", source: "경제", sentiment: "neutral" },
|
|
1384
|
+
{ headline: "2025년 트렌드 전망", source: "라이프", sentiment: "positive" },
|
|
1385
|
+
],
|
|
1386
|
+
tech: [
|
|
1387
|
+
{ headline: "ChatGPT 신기능 출시", source: "테크", sentiment: "positive" },
|
|
1388
|
+
{ headline: "애플 신제품 발표", source: "테크", sentiment: "positive" },
|
|
1389
|
+
{ headline: "사이버 보안 위협 증가", source: "테크", sentiment: "negative" },
|
|
1390
|
+
],
|
|
1391
|
+
economy: [
|
|
1392
|
+
{ headline: "한국은행 금리 결정", source: "경제", sentiment: "neutral" },
|
|
1393
|
+
{ headline: "부동산 시장 동향", source: "경제", sentiment: "neutral" },
|
|
1394
|
+
{ headline: "환율 변동성 확대", source: "경제", sentiment: "negative" },
|
|
1395
|
+
],
|
|
1396
|
+
entertainment: [
|
|
1397
|
+
{ headline: "K-POP 글로벌 인기", source: "연예", sentiment: "positive" },
|
|
1398
|
+
{ headline: "넷플릭스 신작 화제", source: "연예", sentiment: "positive" },
|
|
1399
|
+
{ headline: "연예계 이슈", source: "연예", sentiment: "neutral" },
|
|
1400
|
+
],
|
|
1401
|
+
};
|
|
1402
|
+
const news = newsData[category] || newsData.general;
|
|
1403
|
+
const keywords = extractKeywords ? [
|
|
1404
|
+
{ keyword: "AI", frequency: 45, trend: "상승" },
|
|
1405
|
+
{ keyword: "경제", frequency: 38, trend: "유지" },
|
|
1406
|
+
{ keyword: "트렌드", frequency: 32, trend: "상승" },
|
|
1407
|
+
{ keyword: "투자", frequency: 28, trend: "상승" },
|
|
1408
|
+
{ keyword: "기술", frequency: 25, trend: "상승" },
|
|
1409
|
+
] : [];
|
|
1410
|
+
return {
|
|
1411
|
+
category,
|
|
1412
|
+
time_range: timeRange,
|
|
1413
|
+
analyzed_at: new Date().toISOString(),
|
|
1414
|
+
top_news: news,
|
|
1415
|
+
extracted_keywords: keywords,
|
|
1416
|
+
sentiment_summary: {
|
|
1417
|
+
positive: "35%",
|
|
1418
|
+
neutral: "50%",
|
|
1419
|
+
negative: "15%",
|
|
1420
|
+
},
|
|
1421
|
+
content_opportunities: [
|
|
1422
|
+
"AI 관련 콘텐츠 수요 증가 - 입문자 가이드 추천",
|
|
1423
|
+
"경제 불안 심리 반영 - 재테크 팁 콘텐츠",
|
|
1424
|
+
"K-콘텐츠 글로벌 화제 - 한류 관련 콘텐츠",
|
|
1425
|
+
],
|
|
1426
|
+
trending_topics: news.map(n => n.headline),
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1429
|
+
// 해시태그 전략 생성
|
|
1430
|
+
function generateAdvancedHashtagStrategy(topic, platform, count, includeKorean, includeEnglish) {
|
|
1431
|
+
const koreanHashtags = [
|
|
1432
|
+
{ tag: `#${topic.replace(/\s/g, '')}`, type: "main", popularity: "높음" },
|
|
1433
|
+
{ tag: `#${topic}팁`, type: "related", popularity: "중간" },
|
|
1434
|
+
{ tag: `#${topic}추천`, type: "related", popularity: "높음" },
|
|
1435
|
+
{ tag: "#일상", type: "general", popularity: "매우 높음" },
|
|
1436
|
+
{ tag: "#데일리", type: "general", popularity: "매우 높음" },
|
|
1437
|
+
{ tag: "#소통", type: "engagement", popularity: "높음" },
|
|
1438
|
+
{ tag: "#맞팔", type: "engagement", popularity: "높음" },
|
|
1439
|
+
{ tag: "#좋아요", type: "engagement", popularity: "매우 높음" },
|
|
1440
|
+
{ tag: "#인스타그램", type: "platform", popularity: "매우 높음" },
|
|
1441
|
+
{ tag: "#정보공유", type: "content", popularity: "중간" },
|
|
1442
|
+
{ tag: "#꿀팁", type: "content", popularity: "높음" },
|
|
1443
|
+
{ tag: "#추천", type: "content", popularity: "높음" },
|
|
1444
|
+
{ tag: "#리뷰", type: "content", popularity: "높음" },
|
|
1445
|
+
{ tag: "#브이로그", type: "format", popularity: "높음" },
|
|
1446
|
+
{ tag: "#2025", type: "time", popularity: "중간" },
|
|
1447
|
+
];
|
|
1448
|
+
const englishHashtags = [
|
|
1449
|
+
{ tag: "#instagood", type: "general", popularity: "매우 높음" },
|
|
1450
|
+
{ tag: "#photooftheday", type: "general", popularity: "매우 높음" },
|
|
1451
|
+
{ tag: "#love", type: "emotion", popularity: "매우 높음" },
|
|
1452
|
+
{ tag: "#beautiful", type: "emotion", popularity: "높음" },
|
|
1453
|
+
{ tag: "#happy", type: "emotion", popularity: "높음" },
|
|
1454
|
+
{ tag: "#followme", type: "engagement", popularity: "높음" },
|
|
1455
|
+
{ tag: "#like4like", type: "engagement", popularity: "중간" },
|
|
1456
|
+
{ tag: "#style", type: "lifestyle", popularity: "높음" },
|
|
1457
|
+
{ tag: "#lifestyle", type: "lifestyle", popularity: "높음" },
|
|
1458
|
+
{ tag: "#tips", type: "content", popularity: "중간" },
|
|
1459
|
+
];
|
|
1460
|
+
let allHashtags = [];
|
|
1461
|
+
if (includeKorean)
|
|
1462
|
+
allHashtags = [...allHashtags, ...koreanHashtags];
|
|
1463
|
+
if (includeEnglish)
|
|
1464
|
+
allHashtags = [...allHashtags, ...englishHashtags];
|
|
1465
|
+
// 플랫폼별 최적화
|
|
1466
|
+
const platformLimits = {
|
|
1467
|
+
instagram: 30,
|
|
1468
|
+
tiktok: 5,
|
|
1469
|
+
youtube: 15,
|
|
1470
|
+
twitter: 5,
|
|
1471
|
+
threads: 10,
|
|
1472
|
+
};
|
|
1473
|
+
const recommendedCount = Math.min(count, platformLimits[platform] || 20);
|
|
1474
|
+
return {
|
|
1475
|
+
topic,
|
|
1476
|
+
platform,
|
|
1477
|
+
strategy: {
|
|
1478
|
+
total_hashtags: recommendedCount,
|
|
1479
|
+
mix_ratio: {
|
|
1480
|
+
main_keyword: "10%",
|
|
1481
|
+
related: "30%",
|
|
1482
|
+
general: "30%",
|
|
1483
|
+
engagement: "20%",
|
|
1484
|
+
trending: "10%",
|
|
1485
|
+
},
|
|
1486
|
+
},
|
|
1487
|
+
hashtags: {
|
|
1488
|
+
high_priority: allHashtags.filter(h => h.popularity === "매우 높음").slice(0, 5),
|
|
1489
|
+
medium_priority: allHashtags.filter(h => h.popularity === "높음").slice(0, 10),
|
|
1490
|
+
niche: allHashtags.filter(h => h.popularity === "중간").slice(0, 10),
|
|
1491
|
+
},
|
|
1492
|
+
all_hashtags: allHashtags.slice(0, recommendedCount).map(h => h.tag),
|
|
1493
|
+
copy_paste: allHashtags.slice(0, recommendedCount).map(h => h.tag).join(' '),
|
|
1494
|
+
tips: [
|
|
1495
|
+
`${platform}에서는 ${recommendedCount}개 이하의 해시태그를 권장합니다`,
|
|
1496
|
+
"인기 해시태그와 니치 해시태그를 섞어 사용하세요",
|
|
1497
|
+
"첫 댓글에 해시태그를 넣으면 캡션이 깔끔해집니다",
|
|
1498
|
+
"트렌딩 해시태그는 주기적으로 업데이트하세요",
|
|
1499
|
+
],
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
// 벤치마크 데이터
|
|
1503
|
+
function getBenchmarkData(category, platform, metric) {
|
|
1504
|
+
const benchmarks = {
|
|
1505
|
+
뷰티: {
|
|
1506
|
+
instagram: { avg_likes: "3,500", avg_comments: "120", avg_saves: "450", engagement_rate: "4.2%" },
|
|
1507
|
+
youtube: { avg_views: "25,000", avg_likes: "1,200", avg_comments: "85" },
|
|
1508
|
+
tiktok: { avg_views: "50,000", avg_likes: "3,000", avg_shares: "200" },
|
|
1509
|
+
},
|
|
1510
|
+
테크: {
|
|
1511
|
+
instagram: { avg_likes: "2,000", avg_comments: "80", avg_saves: "300", engagement_rate: "3.5%" },
|
|
1512
|
+
youtube: { avg_views: "35,000", avg_likes: "1,500", avg_comments: "120" },
|
|
1513
|
+
blog: { avg_views: "5,000", avg_time_on_page: "4분 30초" },
|
|
1514
|
+
},
|
|
1515
|
+
푸드: {
|
|
1516
|
+
instagram: { avg_likes: "4,500", avg_comments: "150", avg_saves: "600", engagement_rate: "5.1%" },
|
|
1517
|
+
youtube: { avg_views: "40,000", avg_likes: "2,000", avg_comments: "100" },
|
|
1518
|
+
tiktok: { avg_views: "80,000", avg_likes: "5,000", avg_shares: "400" },
|
|
1519
|
+
},
|
|
1520
|
+
라이프스타일: {
|
|
1521
|
+
instagram: { avg_likes: "3,000", avg_comments: "100", avg_saves: "350", engagement_rate: "3.8%" },
|
|
1522
|
+
youtube: { avg_views: "20,000", avg_likes: "900", avg_comments: "70" },
|
|
1523
|
+
},
|
|
1524
|
+
};
|
|
1525
|
+
const data = benchmarks[category] || benchmarks["라이프스타일"];
|
|
1526
|
+
const platformData = data[platform] || data["instagram"];
|
|
1527
|
+
return {
|
|
1528
|
+
category,
|
|
1529
|
+
platform,
|
|
1530
|
+
benchmark_data: platformData,
|
|
1531
|
+
industry_average: {
|
|
1532
|
+
engagement_rate: "3.5%",
|
|
1533
|
+
best_posting_frequency: "매일 1회",
|
|
1534
|
+
optimal_posting_time: "19:00-21:00",
|
|
1535
|
+
},
|
|
1536
|
+
performance_tiers: {
|
|
1537
|
+
top_10_percent: "벤치마크의 200% 이상",
|
|
1538
|
+
above_average: "벤치마크의 120-200%",
|
|
1539
|
+
average: "벤치마크의 80-120%",
|
|
1540
|
+
below_average: "벤치마크의 80% 미만",
|
|
1541
|
+
},
|
|
1542
|
+
tips_to_improve: [
|
|
1543
|
+
"일관된 포스팅 스케줄 유지",
|
|
1544
|
+
"고품질 비주얼 콘텐츠 제작",
|
|
1545
|
+
"커뮤니티와 적극적인 소통",
|
|
1546
|
+
"트렌드 키워드 활용",
|
|
1547
|
+
],
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1550
|
+
// A/B 테스트 변형 생성
|
|
1551
|
+
function generateABTestVariants(originalContent, element, count) {
|
|
1552
|
+
const variants = [];
|
|
1553
|
+
if (element === "title") {
|
|
1554
|
+
const patterns = [
|
|
1555
|
+
{ pattern: `[완벽정리] ${originalContent}`, style: "bracket" },
|
|
1556
|
+
{ pattern: `${originalContent} (이것만 보세요)`, style: "parenthesis" },
|
|
1557
|
+
{ pattern: `${originalContent}? 전문가가 답합니다`, style: "question" },
|
|
1558
|
+
{ pattern: `99%가 모르는 ${originalContent}`, style: "curiosity" },
|
|
1559
|
+
{ pattern: `${originalContent} 하는 5가지 방법`, style: "listicle" },
|
|
1560
|
+
{ pattern: `오늘부터 시작하는 ${originalContent}`, style: "action" },
|
|
1561
|
+
{ pattern: `${originalContent}: 초보자 필독`, style: "target" },
|
|
1562
|
+
{ pattern: `${originalContent}의 모든 것`, style: "comprehensive" },
|
|
1563
|
+
{ pattern: `당신이 몰랐던 ${originalContent}`, style: "reveal" },
|
|
1564
|
+
{ pattern: `${originalContent} 실패하지 않는 법`, style: "negative" },
|
|
1565
|
+
];
|
|
1566
|
+
for (let i = 0; i < Math.min(count, patterns.length); i++) {
|
|
1567
|
+
variants.push({
|
|
1568
|
+
variant_id: String.fromCharCode(65 + i),
|
|
1569
|
+
content: patterns[i].pattern,
|
|
1570
|
+
style: patterns[i].style,
|
|
1571
|
+
predicted_ctr: Math.floor(Math.random() * 30) + 70,
|
|
1572
|
+
});
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
else if (element === "cta") {
|
|
1576
|
+
const ctas = [
|
|
1577
|
+
"지금 바로 확인하기",
|
|
1578
|
+
"더 알아보기",
|
|
1579
|
+
"무료로 시작하기",
|
|
1580
|
+
"자세히 보기",
|
|
1581
|
+
"놓치지 마세요",
|
|
1582
|
+
"지금 신청하기",
|
|
1583
|
+
"한정 기회",
|
|
1584
|
+
"바로 체험하기",
|
|
1585
|
+
];
|
|
1586
|
+
for (let i = 0; i < Math.min(count, ctas.length); i++) {
|
|
1587
|
+
variants.push({
|
|
1588
|
+
variant_id: String.fromCharCode(65 + i),
|
|
1589
|
+
content: ctas[i],
|
|
1590
|
+
style: i < 3 ? "action" : "urgency",
|
|
1591
|
+
predicted_click_rate: Math.floor(Math.random() * 20) + 60,
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
else if (element === "description") {
|
|
1596
|
+
const styles = ["concise", "detailed", "emotional", "factual", "story"];
|
|
1597
|
+
for (let i = 0; i < Math.min(count, 5); i++) {
|
|
1598
|
+
variants.push({
|
|
1599
|
+
variant_id: String.fromCharCode(65 + i),
|
|
1600
|
+
style: styles[i],
|
|
1601
|
+
content: `[${styles[i]} 스타일] ${originalContent}`,
|
|
1602
|
+
predicted_engagement: Math.floor(Math.random() * 25) + 65,
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
return {
|
|
1607
|
+
original: originalContent,
|
|
1608
|
+
element_tested: element,
|
|
1609
|
+
variants,
|
|
1610
|
+
testing_recommendation: {
|
|
1611
|
+
sample_size: "최소 1,000명 노출 후 판단",
|
|
1612
|
+
duration: "최소 7일",
|
|
1613
|
+
metrics_to_track: element === "title" ? ["CTR", "조회수"] : element === "cta" ? ["클릭율", "전환율"] : ["체류시간", "이탈율"],
|
|
1614
|
+
},
|
|
1615
|
+
statistical_note: "95% 신뢰구간 확보를 위해 충분한 데이터 수집 필요",
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
// 시즌 콘텐츠 가이드
|
|
1619
|
+
function getSeasonalContentGuide(daysAhead, category) {
|
|
1620
|
+
const events = getUpcomingEvents(daysAhead);
|
|
1621
|
+
const filteredEvents = category === "all"
|
|
1622
|
+
? events
|
|
1623
|
+
: events.filter(e => e.type === category);
|
|
1624
|
+
const guide = filteredEvents.map(event => ({
|
|
1625
|
+
...event,
|
|
1626
|
+
content_preparation_timeline: {
|
|
1627
|
+
research: `D-${Math.max(event.days_until - 14, 1)}`,
|
|
1628
|
+
content_creation: `D-${Math.max(event.days_until - 7, 1)}`,
|
|
1629
|
+
publishing: `D-${Math.max(event.days_until - 3, 0)} ~ D-${event.days_until}`,
|
|
1630
|
+
follow_up: `D+1 ~ D+3`,
|
|
1631
|
+
},
|
|
1632
|
+
recommended_content_types: [
|
|
1633
|
+
"이벤트 관련 가이드",
|
|
1634
|
+
"시즌 추천 리스트",
|
|
1635
|
+
"타임라인 콘텐츠",
|
|
1636
|
+
"사용자 참여형 콘텐츠",
|
|
1637
|
+
],
|
|
1638
|
+
hashtag_suggestions: event.contentIdeas?.map((idea) => `#${idea.replace(/\s/g, '')}`) || [],
|
|
1639
|
+
}));
|
|
1640
|
+
return {
|
|
1641
|
+
period: `${daysAhead}일`,
|
|
1642
|
+
category,
|
|
1643
|
+
total_events: filteredEvents.length,
|
|
1644
|
+
events: guide,
|
|
1645
|
+
general_tips: [
|
|
1646
|
+
"주요 이벤트 2주 전에 콘텐츠 기획 시작",
|
|
1647
|
+
"이벤트 당일보다 1-3일 전 발행이 효과적",
|
|
1648
|
+
"이벤트 후 후기/정리 콘텐츠도 준비",
|
|
1649
|
+
"연관 키워드 미리 확보",
|
|
1650
|
+
],
|
|
1651
|
+
monthly_focus: getMonthlyFocus(),
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1654
|
+
function getMonthlyFocus() {
|
|
1655
|
+
const month = new Date().getMonth() + 1;
|
|
1656
|
+
const focuses = {
|
|
1657
|
+
1: { theme: "새해/신년", keywords: ["새해 계획", "신년 운세", "2025 트렌드"] },
|
|
1658
|
+
2: { theme: "발렌타인/겨울", keywords: ["발렌타인 선물", "커플", "초콜릿"] },
|
|
1659
|
+
3: { theme: "봄/신학기", keywords: ["봄맞이", "신학기", "화이트데이"] },
|
|
1660
|
+
4: { theme: "벚꽃/봄나들이", keywords: ["벚꽃명소", "봄 패션", "피크닉"] },
|
|
1661
|
+
5: { theme: "가정의 달", keywords: ["어버이날", "어린이날", "스승의날"] },
|
|
1662
|
+
6: { theme: "초여름/휴가", keywords: ["여름 휴가", "워케이션", "다이어트"] },
|
|
1663
|
+
7: { theme: "휴가 시즌", keywords: ["바캉스", "물놀이", "여행"] },
|
|
1664
|
+
8: { theme: "여름 끝/가을 준비", keywords: ["말복", "가을 신상", "처서"] },
|
|
1665
|
+
9: { theme: "추석/가을", keywords: ["추석 선물", "가을 패션", "단풍"] },
|
|
1666
|
+
10: { theme: "가을/할로윈", keywords: ["할로윈", "가을 나들이", "코스튬"] },
|
|
1667
|
+
11: { theme: "연말 준비", keywords: ["블프", "빼빼로데이", "연말 선물"] },
|
|
1668
|
+
12: { theme: "연말/크리스마스", keywords: ["크리스마스", "연말 파티", "송년회"] },
|
|
1669
|
+
};
|
|
1670
|
+
return focuses[month] || focuses[1];
|
|
1671
|
+
}
|
|
1672
|
+
// =============================================================================
|
|
1673
|
+
// Tool 13: 썸네일 분석 (analyze_thumbnail) - v2.5 신규
|
|
1674
|
+
// =============================================================================
|
|
1675
|
+
server.tool("analyze_thumbnail", "YouTube/Instagram 썸네일 컨셉을 분석하고 개선점을 제안합니다. 클릭률 최적화 가이드를 제공합니다.", {
|
|
1676
|
+
title: z.string().describe("콘텐츠 제목"),
|
|
1677
|
+
thumbnail_description: z.string().describe("썸네일 설명 (예: 놀란 표정의 사람, 음식 클로즈업)"),
|
|
1678
|
+
platform: z.enum(["youtube", "instagram", "tiktok", "blog"]).describe("플랫폼"),
|
|
1679
|
+
content_category: z.string().optional().describe("콘텐츠 카테고리 (예: 먹방, 뷰티, 테크)"),
|
|
1680
|
+
}, async ({ title, thumbnail_description, platform, content_category = "일반" }) => {
|
|
1681
|
+
try {
|
|
1682
|
+
const analysis = analyzeThumbnailConcept(title, thumbnail_description, platform, content_category);
|
|
1683
|
+
return {
|
|
1684
|
+
content: [{ type: "text", text: JSON.stringify(analysis, null, 2) }],
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
catch (error) {
|
|
1688
|
+
return {
|
|
1689
|
+
content: [{ type: "text", text: `썸네일 분석 중 오류 발생: ${error}` }],
|
|
1690
|
+
isError: true,
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
});
|
|
1694
|
+
// =============================================================================
|
|
1695
|
+
// Tool 14: 스크립트/대본 아웃라인 생성 (generate_script_outline) - v2.5 신규
|
|
1696
|
+
// =============================================================================
|
|
1697
|
+
server.tool("generate_script_outline", "유튜브, 팟캐스트, 릴스용 스크립트 아웃라인을 자동 생성합니다.", {
|
|
1698
|
+
topic: z.string().describe("콘텐츠 주제"),
|
|
1699
|
+
format: z.enum(["youtube_long", "youtube_short", "podcast", "reels", "tiktok", "live"]).describe("콘텐츠 형식"),
|
|
1700
|
+
duration: z.string().optional().describe("예상 길이 (예: 10분, 30초)"),
|
|
1701
|
+
style: z.enum(["educational", "entertainment", "storytelling", "review", "tutorial", "interview", "vlog"]).optional().describe("스타일"),
|
|
1702
|
+
include_hooks: z.boolean().optional().describe("오프닝 훅 포함. 기본값: true"),
|
|
1703
|
+
}, async ({ topic, format, duration, style = "educational", include_hooks = true }) => {
|
|
1704
|
+
try {
|
|
1705
|
+
const outline = generateScriptOutline(topic, format, duration, style, include_hooks);
|
|
1706
|
+
return {
|
|
1707
|
+
content: [{ type: "text", text: JSON.stringify(outline, null, 2) }],
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
catch (error) {
|
|
1711
|
+
return {
|
|
1712
|
+
content: [{ type: "text", text: `스크립트 생성 중 오류 발생: ${error}` }],
|
|
1713
|
+
isError: true,
|
|
1714
|
+
};
|
|
1715
|
+
}
|
|
1716
|
+
});
|
|
1717
|
+
// =============================================================================
|
|
1718
|
+
// Tool 15: 콘텐츠 리퍼포징 (repurpose_content) - v2.5 신규
|
|
1719
|
+
// =============================================================================
|
|
1720
|
+
server.tool("repurpose_content", "하나의 콘텐츠를 여러 플랫폼용으로 변환하는 전략을 제안합니다.", {
|
|
1721
|
+
original_content: z.string().describe("원본 콘텐츠 (제목 또는 설명)"),
|
|
1722
|
+
source_platform: z.enum(["youtube", "blog", "podcast", "instagram", "newsletter"]).describe("원본 플랫폼"),
|
|
1723
|
+
target_platforms: z.array(z.enum(["youtube", "youtube_shorts", "instagram_post", "instagram_reels", "tiktok", "blog", "newsletter", "twitter", "threads", "linkedin"])).describe("변환할 플랫폼 목록"),
|
|
1724
|
+
}, async ({ original_content, source_platform, target_platforms }) => {
|
|
1725
|
+
try {
|
|
1726
|
+
const repurposed = repurposeContent(original_content, source_platform, target_platforms);
|
|
1727
|
+
return {
|
|
1728
|
+
content: [{ type: "text", text: JSON.stringify(repurposed, null, 2) }],
|
|
1729
|
+
};
|
|
1730
|
+
}
|
|
1731
|
+
catch (error) {
|
|
1732
|
+
return {
|
|
1733
|
+
content: [{ type: "text", text: `리퍼포징 전략 생성 중 오류 발생: ${error}` }],
|
|
1734
|
+
isError: true,
|
|
1735
|
+
};
|
|
1736
|
+
}
|
|
1737
|
+
});
|
|
1738
|
+
// =============================================================================
|
|
1739
|
+
// Tool 16: 인플루언서 콜라보 분석 (analyze_influencer_collab) - v2.5 신규
|
|
1740
|
+
// =============================================================================
|
|
1741
|
+
server.tool("analyze_influencer_collab", "인플루언서 협업 전략 및 적합도를 분석합니다. 브랜드-인플루언서 매칭 가이드를 제공합니다.", {
|
|
1742
|
+
brand_category: z.string().describe("브랜드/제품 카테고리"),
|
|
1743
|
+
target_audience: z.string().describe("타겟 오디언스"),
|
|
1744
|
+
budget_range: z.enum(["low", "medium", "high", "premium"]).optional().describe("예산 범위"),
|
|
1745
|
+
campaign_goal: z.enum(["awareness", "engagement", "conversion", "content"]).optional().describe("캠페인 목표"),
|
|
1746
|
+
}, async ({ brand_category, target_audience, budget_range = "medium", campaign_goal = "engagement" }) => {
|
|
1747
|
+
try {
|
|
1748
|
+
const analysis = analyzeInfluencerCollab(brand_category, target_audience, budget_range, campaign_goal);
|
|
1749
|
+
return {
|
|
1750
|
+
content: [{ type: "text", text: JSON.stringify(analysis, null, 2) }],
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
catch (error) {
|
|
1754
|
+
return {
|
|
1755
|
+
content: [{ type: "text", text: `인플루언서 분석 중 오류 발생: ${error}` }],
|
|
1756
|
+
isError: true,
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
});
|
|
1760
|
+
// =============================================================================
|
|
1761
|
+
// Tool 17: 콘텐츠 성과 예측 (predict_content_performance) - v2.5 신규
|
|
1762
|
+
// =============================================================================
|
|
1763
|
+
server.tool("predict_content_performance", "콘텐츠의 예상 성과를 AI 기반으로 예측합니다. 조회수, 참여율, 공유 가능성을 분석합니다.", {
|
|
1764
|
+
title: z.string().describe("콘텐츠 제목"),
|
|
1765
|
+
description: z.string().optional().describe("콘텐츠 설명"),
|
|
1766
|
+
platform: ContentTypeSchema.describe("플랫폼"),
|
|
1767
|
+
category: z.string().optional().describe("카테고리"),
|
|
1768
|
+
posting_time: z.string().optional().describe("게시 예정 시간 (예: 평일 저녁 7시)"),
|
|
1769
|
+
has_trending_topic: z.boolean().optional().describe("트렌딩 주제 포함 여부"),
|
|
1770
|
+
}, async ({ title, description = "", platform, category = "일반", posting_time, has_trending_topic = false }) => {
|
|
1771
|
+
try {
|
|
1772
|
+
const prediction = predictContentPerformance(title, description, platform, category, posting_time, has_trending_topic);
|
|
1773
|
+
return {
|
|
1774
|
+
content: [{ type: "text", text: JSON.stringify(prediction, null, 2) }],
|
|
1775
|
+
};
|
|
1776
|
+
}
|
|
1777
|
+
catch (error) {
|
|
1778
|
+
return {
|
|
1779
|
+
content: [{ type: "text", text: `성과 예측 중 오류 발생: ${error}` }],
|
|
1780
|
+
isError: true,
|
|
1781
|
+
};
|
|
1782
|
+
}
|
|
1783
|
+
});
|
|
1784
|
+
// =============================================================================
|
|
1785
|
+
// v2.5 신규 Helper Functions
|
|
1786
|
+
// =============================================================================
|
|
1787
|
+
// 썸네일 분석
|
|
1788
|
+
function analyzeThumbnailConcept(title, description, platform, category) {
|
|
1789
|
+
const elements = {
|
|
1790
|
+
face_detected: /얼굴|표정|사람|인물/.test(description),
|
|
1791
|
+
text_overlay: /텍스트|글자|문구/.test(description),
|
|
1792
|
+
bright_colors: /밝은|화려한|눈에 띄는|빨간|노란/.test(description),
|
|
1793
|
+
food_closeup: /음식|클로즈업|맛있/.test(description),
|
|
1794
|
+
before_after: /비포|애프터|전후|변화/.test(description),
|
|
1795
|
+
arrow_pointing: /화살표|포인팅|가리키/.test(description),
|
|
1796
|
+
emoji_use: /이모지|이모티콘/.test(description),
|
|
1797
|
+
};
|
|
1798
|
+
let score = 50;
|
|
1799
|
+
const improvements = [];
|
|
1800
|
+
const strengths = [];
|
|
1801
|
+
// 얼굴 감지 (유튜브에서 중요)
|
|
1802
|
+
if (elements.face_detected) {
|
|
1803
|
+
score += 15;
|
|
1804
|
+
strengths.push("얼굴/표정이 포함되어 있어 클릭률 상승 기대");
|
|
1805
|
+
}
|
|
1806
|
+
else {
|
|
1807
|
+
improvements.push("사람의 얼굴이나 표정을 추가하면 CTR 15-30% 상승");
|
|
1808
|
+
}
|
|
1809
|
+
// 텍스트 오버레이
|
|
1810
|
+
if (elements.text_overlay) {
|
|
1811
|
+
score += 10;
|
|
1812
|
+
strengths.push("텍스트 오버레이로 핵심 메시지 전달");
|
|
1813
|
+
}
|
|
1814
|
+
else {
|
|
1815
|
+
improvements.push("핵심 키워드 2-3개를 텍스트로 추가");
|
|
1816
|
+
}
|
|
1817
|
+
// 밝은 색상
|
|
1818
|
+
if (elements.bright_colors) {
|
|
1819
|
+
score += 8;
|
|
1820
|
+
strengths.push("눈에 띄는 색상 사용");
|
|
1821
|
+
}
|
|
1822
|
+
else {
|
|
1823
|
+
improvements.push("노란색, 빨간색 등 눈에 띄는 색상 활용");
|
|
1824
|
+
}
|
|
1825
|
+
// 플랫폼별 추가 점수
|
|
1826
|
+
if (platform === "youtube" && elements.face_detected)
|
|
1827
|
+
score += 5;
|
|
1828
|
+
if (platform === "instagram" && elements.bright_colors)
|
|
1829
|
+
score += 5;
|
|
1830
|
+
const platformBestPractices = {
|
|
1831
|
+
youtube: [
|
|
1832
|
+
"1280x720 이상의 해상도 사용",
|
|
1833
|
+
"얼굴은 프레임의 1/3 이상 차지",
|
|
1834
|
+
"텍스트는 3-5단어 이내",
|
|
1835
|
+
"대비가 강한 색상 조합",
|
|
1836
|
+
"호기심 자극하는 표정/포즈",
|
|
1837
|
+
],
|
|
1838
|
+
instagram: [
|
|
1839
|
+
"1:1 또는 4:5 비율 권장",
|
|
1840
|
+
"밝고 따뜻한 톤",
|
|
1841
|
+
"일관된 필터/색감",
|
|
1842
|
+
"미니멀한 구도",
|
|
1843
|
+
"브랜드 컬러 활용",
|
|
1844
|
+
],
|
|
1845
|
+
tiktok: [
|
|
1846
|
+
"9:16 세로 비율 필수",
|
|
1847
|
+
"첫 0.5초 내 시선 집중",
|
|
1848
|
+
"트렌디한 비주얼",
|
|
1849
|
+
"빠른 동작/표정",
|
|
1850
|
+
],
|
|
1851
|
+
};
|
|
1852
|
+
const categoryTips = {
|
|
1853
|
+
먹방: ["음식 클로즈업 + 김 오르는 장면", "먹는 표정 강조", "양 많아 보이게"],
|
|
1854
|
+
뷰티: ["비포-애프터 구도", "제품 + 결과물", "깨끗한 피부 강조"],
|
|
1855
|
+
테크: ["제품 + 손 포함", "스펙 텍스트 오버레이", "미래지향적 느낌"],
|
|
1856
|
+
브이로그: ["자연스러운 표정", "장소가 드러나는 구도", "감성적 색감"],
|
|
1857
|
+
교육: ["핵심 포인트 텍스트", "진지한 표정", "전문가 느낌"],
|
|
1858
|
+
};
|
|
1859
|
+
return {
|
|
1860
|
+
title,
|
|
1861
|
+
platform,
|
|
1862
|
+
category,
|
|
1863
|
+
thumbnail_score: Math.min(score, 100),
|
|
1864
|
+
grade: score >= 85 ? "A (매우 우수)" : score >= 70 ? "B (우수)" : score >= 55 ? "C (보통)" : "D (개선 필요)",
|
|
1865
|
+
detected_elements: elements,
|
|
1866
|
+
strengths,
|
|
1867
|
+
improvements,
|
|
1868
|
+
platform_best_practices: platformBestPractices[platform] || platformBestPractices.youtube,
|
|
1869
|
+
category_specific_tips: categoryTips[category] || ["카테고리에 맞는 시각적 요소 강조", "타겟 오디언스가 관심 가질 요소 포함"],
|
|
1870
|
+
color_psychology: {
|
|
1871
|
+
red: "긴급함, 열정 - 할인, 긴급 콘텐츠",
|
|
1872
|
+
yellow: "주목, 행복 - 정보성 콘텐츠",
|
|
1873
|
+
blue: "신뢰, 전문성 - 교육, 테크",
|
|
1874
|
+
green: "건강, 자연 - 웰빙, 에코",
|
|
1875
|
+
orange: "에너지, 창의성 - 엔터테인먼트",
|
|
1876
|
+
},
|
|
1877
|
+
ctr_prediction: {
|
|
1878
|
+
current: `${score >= 70 ? "높음" : score >= 50 ? "보통" : "낮음"}`,
|
|
1879
|
+
potential_with_improvements: "높음 (5-10% CTR 예상)",
|
|
1880
|
+
},
|
|
1881
|
+
};
|
|
1882
|
+
}
|
|
1883
|
+
// 스크립트 아웃라인 생성
|
|
1884
|
+
function generateScriptOutline(topic, format, duration, style, includeHooks) {
|
|
1885
|
+
const formatSettings = {
|
|
1886
|
+
youtube_long: {
|
|
1887
|
+
recommended_duration: "8-15분",
|
|
1888
|
+
sections: ["인트로", "훅", "본문1", "본문2", "본문3", "정리", "CTA", "아웃트로"],
|
|
1889
|
+
hook_time: "0-30초",
|
|
1890
|
+
},
|
|
1891
|
+
youtube_short: {
|
|
1892
|
+
recommended_duration: "30-60초",
|
|
1893
|
+
sections: ["훅", "핵심 포인트", "CTA"],
|
|
1894
|
+
hook_time: "0-3초",
|
|
1895
|
+
},
|
|
1896
|
+
podcast: {
|
|
1897
|
+
recommended_duration: "20-45분",
|
|
1898
|
+
sections: ["인트로", "주제 소개", "본론1", "본론2", "질문/토론", "정리", "아웃트로"],
|
|
1899
|
+
hook_time: "0-60초",
|
|
1900
|
+
},
|
|
1901
|
+
reels: {
|
|
1902
|
+
recommended_duration: "15-30초",
|
|
1903
|
+
sections: ["훅", "메인 콘텐츠", "반전/CTA"],
|
|
1904
|
+
hook_time: "0-1초",
|
|
1905
|
+
},
|
|
1906
|
+
tiktok: {
|
|
1907
|
+
recommended_duration: "15-60초",
|
|
1908
|
+
sections: ["훅", "스토리", "포인트", "CTA"],
|
|
1909
|
+
hook_time: "0-1초",
|
|
1910
|
+
},
|
|
1911
|
+
live: {
|
|
1912
|
+
recommended_duration: "30-60분",
|
|
1913
|
+
sections: ["인사", "오늘의 주제", "메인 콘텐츠", "Q&A", "마무리"],
|
|
1914
|
+
hook_time: "0-5분",
|
|
1915
|
+
},
|
|
1916
|
+
};
|
|
1917
|
+
const settings = formatSettings[format] || formatSettings.youtube_long;
|
|
1918
|
+
const hooks = [
|
|
1919
|
+
`"${topic}에 대해 이런 건 몰랐을 거예요"`,
|
|
1920
|
+
`"오늘 알려드릴 ${topic} 팁, 진짜 중요합니다"`,
|
|
1921
|
+
`"${topic} 관련해서 가장 많이 받는 질문이에요"`,
|
|
1922
|
+
`"이거 알고 나면 ${topic}이 완전 달라집니다"`,
|
|
1923
|
+
`"3년간 ${topic} 하면서 깨달은 것들"`,
|
|
1924
|
+
];
|
|
1925
|
+
const styleGuides = {
|
|
1926
|
+
educational: {
|
|
1927
|
+
tone: "전문적이지만 친근하게",
|
|
1928
|
+
structure: "문제 → 해결책 → 실습",
|
|
1929
|
+
tips: ["전문 용어는 쉽게 풀어서 설명", "실제 예시 풍부하게", "요약 정리 포함"],
|
|
1930
|
+
},
|
|
1931
|
+
entertainment: {
|
|
1932
|
+
tone: "활기차고 재미있게",
|
|
1933
|
+
structure: "훅 → 스토리 → 반전",
|
|
1934
|
+
tips: ["유머 포인트 삽입", "빠른 템포", "시청자 참여 유도"],
|
|
1935
|
+
},
|
|
1936
|
+
storytelling: {
|
|
1937
|
+
tone: "감성적이고 몰입감 있게",
|
|
1938
|
+
structure: "도입 → 갈등 → 해결",
|
|
1939
|
+
tips: ["개인적 경험 공유", "감정선 구축", "교훈으로 마무리"],
|
|
1940
|
+
},
|
|
1941
|
+
review: {
|
|
1942
|
+
tone: "객관적이고 솔직하게",
|
|
1943
|
+
structure: "소개 → 장점 → 단점 → 총평",
|
|
1944
|
+
tips: ["구체적 스펙/기능 언급", "비교 대상 제시", "별점/추천도"],
|
|
1945
|
+
},
|
|
1946
|
+
tutorial: {
|
|
1947
|
+
tone: "차분하고 명확하게",
|
|
1948
|
+
structure: "개요 → 단계별 설명 → 마무리",
|
|
1949
|
+
tips: ["화면 보며 따라할 수 있게", "실수 포인트 미리 안내", "팁 추가"],
|
|
1950
|
+
},
|
|
1951
|
+
};
|
|
1952
|
+
const outline = {
|
|
1953
|
+
topic,
|
|
1954
|
+
format,
|
|
1955
|
+
recommended_duration: duration || settings.recommended_duration,
|
|
1956
|
+
style,
|
|
1957
|
+
style_guide: styleGuides[style] || styleGuides.educational,
|
|
1958
|
+
hook_examples: includeHooks ? hooks : [],
|
|
1959
|
+
sections: [],
|
|
1960
|
+
};
|
|
1961
|
+
settings.sections.forEach((section, index) => {
|
|
1962
|
+
const sectionDetail = {
|
|
1963
|
+
order: index + 1,
|
|
1964
|
+
name: section,
|
|
1965
|
+
estimated_time: calculateSectionTime(section, format),
|
|
1966
|
+
key_points: [],
|
|
1967
|
+
script_template: "",
|
|
1968
|
+
};
|
|
1969
|
+
if (section === "인트로") {
|
|
1970
|
+
sectionDetail.key_points = ["채널 소개", "오늘의 주제 예고", "시청 이유 제시"];
|
|
1971
|
+
sectionDetail.script_template = `안녕하세요, [채널명]입니다. 오늘은 ${topic}에 대해 이야기해볼게요.`;
|
|
1972
|
+
}
|
|
1973
|
+
else if (section === "훅") {
|
|
1974
|
+
sectionDetail.key_points = ["호기심 자극", "문제 제기", "결과 미리보기"];
|
|
1975
|
+
sectionDetail.script_template = hooks[0];
|
|
1976
|
+
}
|
|
1977
|
+
else if (section.includes("본문") || section.includes("본론")) {
|
|
1978
|
+
sectionDetail.key_points = [`${topic}의 핵심 포인트`, "구체적 예시", "실용적 팁"];
|
|
1979
|
+
sectionDetail.script_template = `[핵심 내용]에 대해 자세히 설명드릴게요...`;
|
|
1980
|
+
}
|
|
1981
|
+
else if (section === "CTA") {
|
|
1982
|
+
sectionDetail.key_points = ["구독/좋아요 요청", "다음 영상 예고", "댓글 유도"];
|
|
1983
|
+
sectionDetail.script_template = "이 영상이 도움이 되셨다면 구독과 좋아요 부탁드려요!";
|
|
1984
|
+
}
|
|
1985
|
+
else if (section === "아웃트로") {
|
|
1986
|
+
sectionDetail.key_points = ["핵심 요약", "감사 인사", "다음 콘텐츠 예고"];
|
|
1987
|
+
sectionDetail.script_template = `오늘 ${topic}에 대해 알아봤는데요, 도움이 되셨길 바랍니다.`;
|
|
1988
|
+
}
|
|
1989
|
+
outline.sections.push(sectionDetail);
|
|
1990
|
+
});
|
|
1991
|
+
outline.production_tips = {
|
|
1992
|
+
filming: ["조명은 자연광 또는 3점 조명", "음질이 화질보다 중요", "배경 정리"],
|
|
1993
|
+
editing: ["점프컷으로 템포 유지", "자막 필수", "BGM 볼륨은 음성의 10-20%"],
|
|
1994
|
+
thumbnail: ["제목과 연계된 이미지", "얼굴 표정 강조", "텍스트 3-5단어"],
|
|
1995
|
+
};
|
|
1996
|
+
return outline;
|
|
1997
|
+
}
|
|
1998
|
+
function calculateSectionTime(section, format) {
|
|
1999
|
+
const times = {
|
|
2000
|
+
youtube_long: {
|
|
2001
|
+
인트로: "30초-1분",
|
|
2002
|
+
훅: "30초",
|
|
2003
|
+
본문1: "3-4분",
|
|
2004
|
+
본문2: "3-4분",
|
|
2005
|
+
본문3: "2-3분",
|
|
2006
|
+
정리: "1분",
|
|
2007
|
+
CTA: "30초",
|
|
2008
|
+
아웃트로: "30초",
|
|
2009
|
+
},
|
|
2010
|
+
youtube_short: { 훅: "3초", "핵심 포인트": "20-40초", CTA: "5초" },
|
|
2011
|
+
reels: { 훅: "1초", "메인 콘텐츠": "20초", "반전/CTA": "5초" },
|
|
2012
|
+
tiktok: { 훅: "1초", 스토리: "15-30초", 포인트: "10초", CTA: "3초" },
|
|
2013
|
+
};
|
|
2014
|
+
return times[format]?.[section] || "적절히 조절";
|
|
2015
|
+
}
|
|
2016
|
+
// 콘텐츠 리퍼포징
|
|
2017
|
+
function repurposeContent(original, source, targets) {
|
|
2018
|
+
const repurposingStrategies = {
|
|
2019
|
+
youtube_shorts: {
|
|
2020
|
+
approach: "핵심 하이라이트 추출",
|
|
2021
|
+
format: "세로 9:16",
|
|
2022
|
+
duration: "60초 이내",
|
|
2023
|
+
tips: ["가장 임팩트 있는 장면 선택", "자막 필수", "훅으로 시작"],
|
|
2024
|
+
},
|
|
2025
|
+
instagram_post: {
|
|
2026
|
+
approach: "핵심 포인트 카드뉴스화",
|
|
2027
|
+
format: "1:1 또는 4:5 캐러셀",
|
|
2028
|
+
tips: ["10장 이내 슬라이드", "각 슬라이드 하나의 포인트", "마지막에 CTA"],
|
|
2029
|
+
},
|
|
2030
|
+
instagram_reels: {
|
|
2031
|
+
approach: "15-30초 하이라이트",
|
|
2032
|
+
format: "세로 9:16",
|
|
2033
|
+
tips: ["트렌딩 오디오 활용", "빠른 컷 편집", "캡션에 풀버전 링크"],
|
|
2034
|
+
},
|
|
2035
|
+
tiktok: {
|
|
2036
|
+
approach: "바이럴 포인트 추출",
|
|
2037
|
+
format: "세로 9:16, 15-60초",
|
|
2038
|
+
tips: ["트렌딩 사운드 필수", "첫 1초 승부", "댓글 유도형 마무리"],
|
|
2039
|
+
},
|
|
2040
|
+
blog: {
|
|
2041
|
+
approach: "상세 텍스트 버전 작성",
|
|
2042
|
+
format: "2000-3000자 글",
|
|
2043
|
+
tips: ["SEO 키워드 포함", "H2/H3 구조화", "이미지 5-10개"],
|
|
2044
|
+
},
|
|
2045
|
+
newsletter: {
|
|
2046
|
+
approach: "핵심 인사이트 요약",
|
|
2047
|
+
format: "800-1200자",
|
|
2048
|
+
tips: ["개인적인 톤", "actionable 팁", "다음 호 예고"],
|
|
2049
|
+
},
|
|
2050
|
+
twitter: {
|
|
2051
|
+
approach: "핵심 문장 + 스레드",
|
|
2052
|
+
format: "280자 × 여러 개",
|
|
2053
|
+
tips: ["첫 트윗이 핵심", "숫자/통계 활용", "마지막에 원본 링크"],
|
|
2054
|
+
},
|
|
2055
|
+
threads: {
|
|
2056
|
+
approach: "대화형 스레드",
|
|
2057
|
+
format: "500자 이내 × 여러 개",
|
|
2058
|
+
tips: ["스토리텔링 형식", "이미지 함께", "인스타 연동"],
|
|
2059
|
+
},
|
|
2060
|
+
linkedin: {
|
|
2061
|
+
approach: "전문적 인사이트 버전",
|
|
2062
|
+
format: "1000-1500자",
|
|
2063
|
+
tips: ["전문성 강조", "데이터/결과 중심", "업계 해시태그"],
|
|
2064
|
+
},
|
|
2065
|
+
};
|
|
2066
|
+
const results = targets.map(target => ({
|
|
2067
|
+
platform: target,
|
|
2068
|
+
strategy: repurposingStrategies[target] || { approach: "플랫폼에 맞게 변환", tips: [] },
|
|
2069
|
+
adapted_title: adaptTitleForPlatform(original, target),
|
|
2070
|
+
content_adjustments: getContentAdjustments(source, target),
|
|
2071
|
+
estimated_effort: getEffortEstimate(source, target),
|
|
2072
|
+
priority: getPriorityScore(target),
|
|
2073
|
+
}));
|
|
2074
|
+
return {
|
|
2075
|
+
original_content: original,
|
|
2076
|
+
source_platform: source,
|
|
2077
|
+
repurposing_plan: results.sort((a, b) => b.priority - a.priority),
|
|
2078
|
+
workflow_tip: "고품질 원본 하나로 5-7개 플랫폼 커버 가능",
|
|
2079
|
+
time_saving: "평균 60-70% 시간 절약",
|
|
2080
|
+
recommended_order: results.map(r => r.platform),
|
|
2081
|
+
};
|
|
2082
|
+
}
|
|
2083
|
+
function adaptTitleForPlatform(original, platform) {
|
|
2084
|
+
const adaptations = {
|
|
2085
|
+
youtube_shorts: `${original} #shorts`,
|
|
2086
|
+
instagram_post: original.length > 50 ? original.substring(0, 47) + "..." : original,
|
|
2087
|
+
instagram_reels: `${original} 🔥`,
|
|
2088
|
+
tiktok: `${original} 알려줌`,
|
|
2089
|
+
twitter: original.length > 100 ? original.substring(0, 97) + "..." : original,
|
|
2090
|
+
threads: original,
|
|
2091
|
+
linkedin: `[인사이트] ${original}`,
|
|
2092
|
+
blog: `${original} - 완벽 가이드`,
|
|
2093
|
+
newsletter: `📧 ${original}`,
|
|
2094
|
+
};
|
|
2095
|
+
return adaptations[platform] || original;
|
|
2096
|
+
}
|
|
2097
|
+
function getContentAdjustments(source, target) {
|
|
2098
|
+
const adjustments = [];
|
|
2099
|
+
if (source === "youtube" && target.includes("short")) {
|
|
2100
|
+
adjustments.push("긴 영상에서 핵심 15-60초 추출");
|
|
2101
|
+
}
|
|
2102
|
+
if (target === "blog") {
|
|
2103
|
+
adjustments.push("영상 스크립트를 글로 확장");
|
|
2104
|
+
adjustments.push("스크린샷 추가");
|
|
2105
|
+
}
|
|
2106
|
+
if (target.includes("instagram")) {
|
|
2107
|
+
adjustments.push("비주얼 중심으로 재구성");
|
|
2108
|
+
adjustments.push("해시태그 20-25개 추가");
|
|
2109
|
+
}
|
|
2110
|
+
return adjustments.length > 0 ? adjustments : ["플랫폼 특성에 맞게 조정"];
|
|
2111
|
+
}
|
|
2112
|
+
function getEffortEstimate(source, target) {
|
|
2113
|
+
if (source === target)
|
|
2114
|
+
return "0분";
|
|
2115
|
+
if (target.includes("short") || target.includes("reels"))
|
|
2116
|
+
return "15-30분";
|
|
2117
|
+
if (target === "blog")
|
|
2118
|
+
return "1-2시간";
|
|
2119
|
+
if (target === "newsletter")
|
|
2120
|
+
return "30분-1시간";
|
|
2121
|
+
return "20-40분";
|
|
2122
|
+
}
|
|
2123
|
+
function getPriorityScore(platform) {
|
|
2124
|
+
const scores = {
|
|
2125
|
+
instagram_reels: 95,
|
|
2126
|
+
tiktok: 90,
|
|
2127
|
+
youtube_shorts: 88,
|
|
2128
|
+
instagram_post: 80,
|
|
2129
|
+
twitter: 70,
|
|
2130
|
+
threads: 65,
|
|
2131
|
+
linkedin: 60,
|
|
2132
|
+
blog: 75,
|
|
2133
|
+
newsletter: 70,
|
|
2134
|
+
};
|
|
2135
|
+
return scores[platform] || 50;
|
|
2136
|
+
}
|
|
2137
|
+
// 인플루언서 협업 분석
|
|
2138
|
+
function analyzeInfluencerCollab(category, audience, budget, goal) {
|
|
2139
|
+
const tierInfo = {
|
|
2140
|
+
nano: { followers: "1K-10K", engagement: "5-10%", cost: "10-50만원", pros: ["높은 참여율", "진정성", "저비용"], cons: ["도달 제한", "전문성 부족 가능"] },
|
|
2141
|
+
micro: { followers: "10K-50K", engagement: "3-8%", cost: "50-200만원", pros: ["좋은 참여율", "타겟 정확", "비용 효율"], cons: ["도달 중간", "협상 필요"] },
|
|
2142
|
+
mid: { followers: "50K-500K", engagement: "2-5%", cost: "200-1000만원", pros: ["넓은 도달", "전문성", "콘텐츠 품질"], cons: ["비용 상승", "광고 느낌"] },
|
|
2143
|
+
macro: { followers: "500K-1M", engagement: "1-3%", cost: "1000-3000만원", pros: ["큰 도달", "신뢰도", "브랜드 인지도"], cons: ["높은 비용", "낮은 참여율"] },
|
|
2144
|
+
mega: { followers: "1M+", engagement: "1-2%", cost: "3000만원+", pros: ["최대 도달", "화제성", "브랜드 이미지"], cons: ["매우 높은 비용", "진정성 의문"] },
|
|
2145
|
+
};
|
|
2146
|
+
const budgetTiers = {
|
|
2147
|
+
low: ["nano", "micro"],
|
|
2148
|
+
medium: ["micro", "mid"],
|
|
2149
|
+
high: ["mid", "macro"],
|
|
2150
|
+
premium: ["macro", "mega"],
|
|
2151
|
+
};
|
|
2152
|
+
const recommendedTiers = budgetTiers[budget] || ["micro", "mid"];
|
|
2153
|
+
const platformsByCategory = {
|
|
2154
|
+
뷰티: ["인스타그램", "유튜브", "틱톡"],
|
|
2155
|
+
패션: ["인스타그램", "유튜브"],
|
|
2156
|
+
푸드: ["유튜브", "인스타그램", "블로그"],
|
|
2157
|
+
테크: ["유튜브", "블로그"],
|
|
2158
|
+
라이프스타일: ["인스타그램", "유튜브", "블로그"],
|
|
2159
|
+
게임: ["유튜브", "트위치", "틱톡"],
|
|
2160
|
+
육아: ["인스타그램", "블로그", "유튜브"],
|
|
2161
|
+
여행: ["인스타그램", "유튜브", "블로그"],
|
|
2162
|
+
};
|
|
2163
|
+
const collabTypes = [
|
|
2164
|
+
{ type: "제품 협찬", description: "제품 제공 + 솔직 리뷰", suitable_for: ["awareness", "content"] },
|
|
2165
|
+
{ type: "유료 광고", description: "정해진 가이드라인 콘텐츠", suitable_for: ["awareness", "conversion"] },
|
|
2166
|
+
{ type: "어필리에이트", description: "판매 수수료 기반", suitable_for: ["conversion"] },
|
|
2167
|
+
{ type: "앰버서더", description: "장기 파트너십", suitable_for: ["awareness", "engagement"] },
|
|
2168
|
+
{ type: "콘텐츠 공동제작", description: "함께 기획/제작", suitable_for: ["content", "engagement"] },
|
|
2169
|
+
];
|
|
2170
|
+
return {
|
|
2171
|
+
brand_category: category,
|
|
2172
|
+
target_audience: audience,
|
|
2173
|
+
budget_range: budget,
|
|
2174
|
+
campaign_goal: goal,
|
|
2175
|
+
recommended_influencer_tiers: recommendedTiers.map(tier => ({
|
|
2176
|
+
tier,
|
|
2177
|
+
...tierInfo[tier],
|
|
2178
|
+
})),
|
|
2179
|
+
recommended_platforms: platformsByCategory[category] || ["인스타그램", "유튜브"],
|
|
2180
|
+
suitable_collab_types: collabTypes.filter(c => c.suitable_for.includes(goal)),
|
|
2181
|
+
success_metrics: {
|
|
2182
|
+
awareness: ["도달수", "노출수", "브랜드 검색량"],
|
|
2183
|
+
engagement: ["좋아요", "댓글", "저장", "공유"],
|
|
2184
|
+
conversion: ["클릭수", "구매수", "ROAS"],
|
|
2185
|
+
content: ["콘텐츠 품질", "재사용 가능성"],
|
|
2186
|
+
}[goal] || ["도달수", "참여율"],
|
|
2187
|
+
negotiation_tips: [
|
|
2188
|
+
"명확한 KPI 설정",
|
|
2189
|
+
"콘텐츠 사용권 협의",
|
|
2190
|
+
"수정 횟수 명시",
|
|
2191
|
+
"게시 일정 확정",
|
|
2192
|
+
"성과 리포트 요청",
|
|
2193
|
+
],
|
|
2194
|
+
red_flags: [
|
|
2195
|
+
"팔로워 대비 참여율 너무 낮음 (1% 미만)",
|
|
2196
|
+
"댓글이 대부분 이모지나 봇성",
|
|
2197
|
+
"최근 콘텐츠 업로드 없음",
|
|
2198
|
+
"브랜드 이미지와 맞지 않는 과거 콘텐츠",
|
|
2199
|
+
],
|
|
2200
|
+
};
|
|
2201
|
+
}
|
|
2202
|
+
// 콘텐츠 성과 예측
|
|
2203
|
+
function predictContentPerformance(title, description, platform, category, postingTime, hasTrending) {
|
|
2204
|
+
let baseScore = 50;
|
|
2205
|
+
const factors = {};
|
|
2206
|
+
// 제목 분석
|
|
2207
|
+
const titleFactors = {
|
|
2208
|
+
has_numbers: /\d/.test(title),
|
|
2209
|
+
has_question: /\?/.test(title),
|
|
2210
|
+
has_emotional: /놀라운|충격|비밀|최고|완벽|필수|대박|꿀팁|진짜/.test(title),
|
|
2211
|
+
optimal_length: title.length >= 20 && title.length <= 60,
|
|
2212
|
+
has_brackets: /[\[\]【】]/.test(title),
|
|
2213
|
+
};
|
|
2214
|
+
factors.title = titleFactors;
|
|
2215
|
+
if (titleFactors.has_numbers)
|
|
2216
|
+
baseScore += 8;
|
|
2217
|
+
if (titleFactors.has_question)
|
|
2218
|
+
baseScore += 5;
|
|
2219
|
+
if (titleFactors.has_emotional)
|
|
2220
|
+
baseScore += 10;
|
|
2221
|
+
if (titleFactors.optimal_length)
|
|
2222
|
+
baseScore += 5;
|
|
2223
|
+
if (titleFactors.has_brackets)
|
|
2224
|
+
baseScore += 3;
|
|
2225
|
+
// 트렌딩 토픽
|
|
2226
|
+
if (hasTrending) {
|
|
2227
|
+
baseScore += 15;
|
|
2228
|
+
factors.trending_boost = true;
|
|
2229
|
+
}
|
|
2230
|
+
// 게시 시간
|
|
2231
|
+
const timeScores = {
|
|
2232
|
+
"평일 아침": 60,
|
|
2233
|
+
"평일 점심": 75,
|
|
2234
|
+
"평일 저녁": 90,
|
|
2235
|
+
"주말 오후": 85,
|
|
2236
|
+
"주말 저녁": 80,
|
|
2237
|
+
};
|
|
2238
|
+
if (postingTime) {
|
|
2239
|
+
const timeMatch = Object.keys(timeScores).find(t => postingTime.includes(t.split(" ")[1]));
|
|
2240
|
+
if (timeMatch) {
|
|
2241
|
+
baseScore += (timeScores[timeMatch] - 50) / 5;
|
|
2242
|
+
factors.posting_time_score = timeScores[timeMatch];
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
// 플랫폼별 가중치
|
|
2246
|
+
const platformMultiplier = {
|
|
2247
|
+
tiktok: 1.2,
|
|
2248
|
+
instagram: 1.1,
|
|
2249
|
+
youtube: 1.0,
|
|
2250
|
+
blog: 0.9,
|
|
2251
|
+
twitter: 0.95,
|
|
2252
|
+
};
|
|
2253
|
+
baseScore *= platformMultiplier[platform] || 1;
|
|
2254
|
+
const finalScore = Math.min(Math.round(baseScore), 100);
|
|
2255
|
+
// 예상 성과
|
|
2256
|
+
const performanceRanges = {
|
|
2257
|
+
youtube: {
|
|
2258
|
+
high: { views: "10K-50K", engagement: "5-8%", shares: "100-500" },
|
|
2259
|
+
medium: { views: "1K-10K", engagement: "3-5%", shares: "20-100" },
|
|
2260
|
+
low: { views: "100-1K", engagement: "1-3%", shares: "5-20" },
|
|
2261
|
+
},
|
|
2262
|
+
instagram: {
|
|
2263
|
+
high: { reach: "5K-20K", engagement: "6-10%", saves: "50-200" },
|
|
2264
|
+
medium: { reach: "1K-5K", engagement: "3-6%", saves: "10-50" },
|
|
2265
|
+
low: { reach: "200-1K", engagement: "1-3%", saves: "2-10" },
|
|
2266
|
+
},
|
|
2267
|
+
tiktok: {
|
|
2268
|
+
high: { views: "50K-500K", engagement: "8-15%", shares: "500-2K" },
|
|
2269
|
+
medium: { views: "5K-50K", engagement: "5-8%", shares: "50-500" },
|
|
2270
|
+
low: { views: "500-5K", engagement: "2-5%", shares: "10-50" },
|
|
2271
|
+
},
|
|
2272
|
+
};
|
|
2273
|
+
const tier = finalScore >= 75 ? "high" : finalScore >= 50 ? "medium" : "low";
|
|
2274
|
+
const platformPerf = performanceRanges[platform] || performanceRanges.youtube;
|
|
2275
|
+
return {
|
|
2276
|
+
title,
|
|
2277
|
+
platform,
|
|
2278
|
+
category,
|
|
2279
|
+
performance_score: finalScore,
|
|
2280
|
+
grade: finalScore >= 85 ? "A (높은 성과 예상)" : finalScore >= 70 ? "B (좋은 성과 예상)" : finalScore >= 50 ? "C (보통)" : "D (개선 필요)",
|
|
2281
|
+
analysis_factors: factors,
|
|
2282
|
+
predicted_performance: platformPerf[tier],
|
|
2283
|
+
confidence_level: hasTrending ? "높음 (트렌딩 반영)" : "보통",
|
|
2284
|
+
optimization_suggestions: [
|
|
2285
|
+
!titleFactors.has_numbers ? "제목에 숫자 추가 (예: 5가지, TOP 10)" : null,
|
|
2286
|
+
!titleFactors.has_emotional ? "감정을 자극하는 단어 추가" : null,
|
|
2287
|
+
!titleFactors.optimal_length ? "제목 길이 20-60자 권장" : null,
|
|
2288
|
+
!hasTrending ? "트렌딩 키워드 연계 고려" : null,
|
|
2289
|
+
].filter(Boolean),
|
|
2290
|
+
best_posting_windows: {
|
|
2291
|
+
weekday: "오전 7-9시, 점심 12-1시, 저녁 7-10시",
|
|
2292
|
+
weekend: "오후 2-4시, 저녁 7-9시",
|
|
577
2293
|
},
|
|
578
2294
|
};
|
|
579
2295
|
}
|
|
@@ -583,6 +2299,6 @@ function predictViralScore(title, description, platform, hashtags) {
|
|
|
583
2299
|
async function main() {
|
|
584
2300
|
const transport = new StdioServerTransport();
|
|
585
2301
|
await server.connect(transport);
|
|
586
|
-
console.error("Content Genie MCP Server running on stdio");
|
|
2302
|
+
console.error("Content Genie MCP Server v2.5 running on stdio");
|
|
587
2303
|
}
|
|
588
2304
|
main().catch(console.error);
|