content-genie-mcp 1.0.1 → 2.0.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/dist/index.js +1330 -308
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,46 +5,120 @@ 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.0 - 한국 콘텐츠 크리에이터를 위한 AI 어시스턴트 (고도화 버전)
|
|
9
9
|
// =============================================================================
|
|
10
10
|
const server = new McpServer({
|
|
11
11
|
name: "content-genie-mcp",
|
|
12
|
-
version: "
|
|
12
|
+
version: "2.0.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)
|
|
23
|
+
// =============================================================================
|
|
24
|
+
const KOREAN_EVENTS_DB = [
|
|
25
|
+
// 공휴일
|
|
26
|
+
{ date: "01-01", name: "새해", type: "holiday", contentIdeas: ["신년 계획", "새해 다짐", "2025 트렌드"] },
|
|
27
|
+
{ date: "01-28", name: "설날 연휴", type: "holiday", contentIdeas: ["설날 음식", "세뱃돈", "귀성길 팁"] },
|
|
28
|
+
{ date: "01-29", name: "설날", type: "holiday", contentIdeas: ["설날 인사말", "전통 놀이", "가족 모임"] },
|
|
29
|
+
{ date: "03-01", name: "삼일절", type: "holiday", contentIdeas: ["독립운동", "역사 콘텐츠"] },
|
|
30
|
+
{ date: "05-05", name: "어린이날", type: "holiday", contentIdeas: ["선물 추천", "가족 나들이", "키즈 콘텐츠"] },
|
|
31
|
+
{ date: "05-06", name: "대체공휴일", type: "holiday", contentIdeas: ["황금연휴", "여행지 추천"] },
|
|
32
|
+
{ date: "05-15", name: "부처님오신날", type: "holiday", contentIdeas: ["사찰 여행", "템플스테이"] },
|
|
33
|
+
{ date: "06-06", name: "현충일", type: "holiday", contentIdeas: ["호국 영웅", "추모 콘텐츠"] },
|
|
34
|
+
{ date: "08-15", name: "광복절", type: "holiday", contentIdeas: ["독립 역사", "애국 콘텐츠"] },
|
|
35
|
+
{ date: "10-03", name: "개천절", type: "holiday", contentIdeas: ["단군 신화", "한국 역사"] },
|
|
36
|
+
{ date: "10-05", name: "추석 연휴", type: "holiday", contentIdeas: ["추석 음식", "송편 만들기", "한복"] },
|
|
37
|
+
{ date: "10-06", name: "추석", type: "holiday", contentIdeas: ["가족 모임", "성묘", "보름달"] },
|
|
38
|
+
{ date: "10-09", name: "한글날", type: "holiday", contentIdeas: ["한글 사랑", "국어 콘텐츠"] },
|
|
39
|
+
{ date: "12-25", name: "크리스마스", type: "holiday", contentIdeas: ["크리스마스 선물", "연말 분위기", "캐롤"] },
|
|
40
|
+
// 상업 이벤트
|
|
41
|
+
{ date: "02-14", name: "발렌타인데이", type: "commercial", contentIdeas: ["초콜릿 추천", "커플 데이트", "고백 팁"] },
|
|
42
|
+
{ date: "03-14", name: "화이트데이", type: "commercial", contentIdeas: ["사탕 선물", "답례 아이디어"] },
|
|
43
|
+
{ date: "04-14", name: "블랙데이", type: "commercial", contentIdeas: ["자장면", "솔로 위로"] },
|
|
44
|
+
{ date: "05-08", name: "어버이날", type: "commercial", contentIdeas: ["부모님 선물", "효도 여행", "카네이션"] },
|
|
45
|
+
{ date: "05-14", name: "로즈데이", type: "commercial", contentIdeas: ["장미 선물", "데이트 코스"] },
|
|
46
|
+
{ date: "05-15", name: "스승의날", type: "event", contentIdeas: ["감사 편지", "선생님 선물"] },
|
|
47
|
+
{ date: "05-21", name: "부부의날", type: "commercial", contentIdeas: ["부부 여행", "결혼 기념"] },
|
|
48
|
+
{ date: "06-14", name: "키스데이", type: "commercial", contentIdeas: ["커플 콘텐츠"] },
|
|
49
|
+
{ date: "07-14", name: "실버데이", type: "commercial", contentIdeas: ["어른 선물", "효도 콘텐츠"] },
|
|
50
|
+
{ date: "08-14", name: "그린데이", type: "commercial", contentIdeas: ["야외 데이트", "소풍"] },
|
|
51
|
+
{ date: "09-14", name: "포토데이", type: "commercial", contentIdeas: ["커플 사진", "포토존"] },
|
|
52
|
+
{ date: "10-14", name: "와인데이", type: "commercial", contentIdeas: ["와인 추천", "분위기 있는 데이트"] },
|
|
53
|
+
{ date: "11-11", name: "빼빼로데이", type: "commercial", contentIdeas: ["빼빼로 만들기", "선물 포장", "DIY"] },
|
|
54
|
+
{ date: "11-14", name: "무비데이", type: "commercial", contentIdeas: ["영화 추천", "영화관 데이트"] },
|
|
55
|
+
{ date: "12-14", name: "허그데이", type: "commercial", contentIdeas: ["겨울 데이트", "따뜻한 콘텐츠"] },
|
|
56
|
+
// 시즌 이벤트
|
|
57
|
+
{ date: "01-15", name: "정월대보름", type: "traditional", contentIdeas: ["오곡밥", "부럼 깨기", "달맞이"] },
|
|
58
|
+
{ date: "04-05", name: "식목일", type: "event", contentIdeas: ["나무 심기", "환경 콘텐츠"] },
|
|
59
|
+
{ date: "07-17", name: "제헌절", type: "event", contentIdeas: ["헌법 이야기", "민주주의"] },
|
|
60
|
+
{ date: "10-31", name: "할로윈", type: "commercial", contentIdeas: ["코스튬", "할로윈 파티", "공포 콘텐츠"] },
|
|
61
|
+
{ date: "11-28", name: "블랙프라이데이", type: "commercial", contentIdeas: ["할인 정보", "쇼핑 리스트", "구매 가이드"] },
|
|
62
|
+
{ date: "12-31", name: "연말", type: "event", contentIdeas: ["연말 정산", "올해의 회고", "새해 계획"] },
|
|
63
|
+
// 시험/입시
|
|
64
|
+
{ date: "03-02", name: "개학", type: "event", contentIdeas: ["새학기 준비", "학용품", "학교생활"] },
|
|
65
|
+
{ date: "06-01", name: "수능 D-180", type: "event", contentIdeas: ["수험생 응원", "공부 팁"] },
|
|
66
|
+
{ date: "11-14", name: "수능", type: "event", contentIdeas: ["수능 응원", "수능 후 계획", "대입 전략"] },
|
|
67
|
+
// 쇼핑 시즌
|
|
68
|
+
{ date: "01-02", name: "신년 세일 시즌", type: "shopping", contentIdeas: ["할인 정보", "신년 쇼핑"] },
|
|
69
|
+
{ date: "06-01", name: "여름 세일 시작", type: "shopping", contentIdeas: ["여름 패션", "에어컨", "휴가 준비"] },
|
|
70
|
+
{ date: "09-01", name: "가을 신상", type: "shopping", contentIdeas: ["가을 패션", "트렌치코트", "니트"] },
|
|
71
|
+
{ date: "12-01", name: "연말 세일 시즌", type: "shopping", contentIdeas: ["선물 추천", "연말 쇼핑"] },
|
|
72
|
+
];
|
|
73
|
+
// =============================================================================
|
|
74
|
+
// Tool 1: 실시간 한국 트렌드 분석 (get_korean_trends) - 고도화
|
|
75
|
+
// =============================================================================
|
|
76
|
+
server.tool("get_korean_trends", "실시간 한국 트렌드 키워드를 분석합니다. 네이버, 다음, 구글, 유튜브에서 인기 검색어와 트렌드를 수집합니다.", {
|
|
77
|
+
platform: TrendPlatformSchema.optional().describe("분석할 플랫폼 (naver, google, youtube, daum, zum, all). 기본값: all"),
|
|
78
|
+
category: TrendCategorySchema.optional().describe("카테고리 필터"),
|
|
22
79
|
limit: z.number().min(1).max(50).optional().describe("가져올 트렌드 수. 기본값: 20"),
|
|
23
80
|
}, async ({ platform = "all", category = "all", limit = 20 }) => {
|
|
24
81
|
const trends = [];
|
|
25
82
|
try {
|
|
26
|
-
// 네이버 실시간 검색어 (DataLab
|
|
83
|
+
// 네이버 실시간 검색어 (DataLab 스크래핑)
|
|
27
84
|
if (platform === "naver" || platform === "all") {
|
|
28
|
-
const naverTrends = await
|
|
85
|
+
const naverTrends = await scrapeNaverTrends();
|
|
29
86
|
trends.push(...naverTrends);
|
|
30
87
|
}
|
|
31
|
-
//
|
|
88
|
+
// 다음 실시간 검색어
|
|
89
|
+
if (platform === "daum" || platform === "all") {
|
|
90
|
+
const daumTrends = await scrapeDaumTrends();
|
|
91
|
+
trends.push(...daumTrends);
|
|
92
|
+
}
|
|
93
|
+
// 구글 트렌드 코리아
|
|
32
94
|
if (platform === "google" || platform === "all") {
|
|
33
|
-
const googleTrends = await
|
|
95
|
+
const googleTrends = await scrapeGoogleTrendsKorea();
|
|
34
96
|
trends.push(...googleTrends);
|
|
35
97
|
}
|
|
36
|
-
// 유튜브 인기
|
|
98
|
+
// 유튜브 인기 동영상
|
|
37
99
|
if (platform === "youtube" || platform === "all") {
|
|
38
|
-
const youtubeTrends = await
|
|
100
|
+
const youtubeTrends = await scrapeYoutubeTrendsKorea();
|
|
39
101
|
trends.push(...youtubeTrends);
|
|
40
102
|
}
|
|
103
|
+
// 줌 트렌드
|
|
104
|
+
if (platform === "zum" || platform === "all") {
|
|
105
|
+
const zumTrends = await scrapeZumTrends();
|
|
106
|
+
trends.push(...zumTrends);
|
|
107
|
+
}
|
|
108
|
+
// 카테고리 필터링
|
|
109
|
+
let filteredTrends = trends;
|
|
110
|
+
if (category !== "all") {
|
|
111
|
+
filteredTrends = trends.filter(t => t.category === category || !t.category);
|
|
112
|
+
}
|
|
41
113
|
const result = {
|
|
42
114
|
timestamp: new Date().toISOString(),
|
|
43
115
|
platform,
|
|
44
116
|
category,
|
|
45
|
-
total:
|
|
46
|
-
trends:
|
|
47
|
-
insights:
|
|
117
|
+
total: filteredTrends.length,
|
|
118
|
+
trends: filteredTrends.slice(0, limit),
|
|
119
|
+
insights: generateAdvancedTrendInsights(filteredTrends),
|
|
120
|
+
content_opportunities: identifyContentOpportunities(filteredTrends),
|
|
121
|
+
upcoming_events: getUpcomingEvents(7),
|
|
48
122
|
};
|
|
49
123
|
return {
|
|
50
124
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
@@ -58,27 +132,38 @@ server.tool("get_korean_trends", "실시간 한국 트렌드 키워드를 분석
|
|
|
58
132
|
}
|
|
59
133
|
});
|
|
60
134
|
// =============================================================================
|
|
61
|
-
// Tool 2: 콘텐츠 아이디어 생성 (generate_content_ideas)
|
|
135
|
+
// Tool 2: 콘텐츠 아이디어 생성 (generate_content_ideas) - 고도화
|
|
62
136
|
// =============================================================================
|
|
63
|
-
|
|
64
|
-
const ToneSchema = z.enum(["professional", "casual", "humorous", "educational", "inspirational"]);
|
|
65
|
-
server.tool("generate_content_ideas", "주제와 플랫폼에 맞는 콘텐츠 아이디어를 생성합니다. 트렌드 기반 추천과 함께 제공됩니다.", {
|
|
137
|
+
server.tool("generate_content_ideas", "주제와 플랫폼에 맞는 콘텐츠 아이디어를 생성합니다. 트렌드와 시즌을 반영한 추천을 제공합니다.", {
|
|
66
138
|
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
|
-
|
|
139
|
+
content_type: ContentTypeSchema.optional().describe("콘텐츠 유형"),
|
|
140
|
+
tone: ToneSchema.optional().describe("톤앤매너"),
|
|
141
|
+
target_audience: z.string().optional().describe("타겟 오디언스 (예: 20대 여성, 직장인, MZ세대)"),
|
|
142
|
+
count: z.number().min(1).max(30).optional().describe("생성할 아이디어 수. 기본값: 15"),
|
|
143
|
+
include_trends: z.boolean().optional().describe("트렌드 기반 아이디어 포함. 기본값: true"),
|
|
144
|
+
}, async ({ topic, content_type = "all", tone = "professional", target_audience, count = 15, include_trends = true }) => {
|
|
72
145
|
try {
|
|
73
|
-
|
|
146
|
+
// 고급 콘텐츠 템플릿
|
|
147
|
+
const advancedTemplates = getAdvancedContentTemplates(topic, content_type, tone);
|
|
148
|
+
const ideas = generateAdvancedContentIdeas(topic, advancedTemplates, target_audience, count);
|
|
149
|
+
// 시즌/이벤트 연계 아이디어
|
|
150
|
+
const seasonalIdeas = generateSeasonalIdeas(topic);
|
|
151
|
+
// 트렌드 연계 아이디어 (옵션)
|
|
152
|
+
let trendBasedIdeas = [];
|
|
153
|
+
if (include_trends) {
|
|
154
|
+
trendBasedIdeas = await generateTrendBasedIdeas(topic);
|
|
155
|
+
}
|
|
74
156
|
const result = {
|
|
75
157
|
topic,
|
|
76
158
|
content_type,
|
|
77
159
|
tone,
|
|
78
160
|
target_audience: target_audience || "일반",
|
|
79
161
|
generated_at: new Date().toISOString(),
|
|
80
|
-
ideas,
|
|
81
|
-
|
|
162
|
+
main_ideas: ideas,
|
|
163
|
+
seasonal_ideas: seasonalIdeas,
|
|
164
|
+
trend_based_ideas: trendBasedIdeas,
|
|
165
|
+
platform_specific_tips: getPlatformSpecificTips(content_type),
|
|
166
|
+
recommended_posting_schedule: getRecommendedSchedule(content_type),
|
|
82
167
|
};
|
|
83
168
|
return {
|
|
84
169
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
@@ -92,17 +177,17 @@ server.tool("generate_content_ideas", "주제와 플랫폼에 맞는 콘텐츠
|
|
|
92
177
|
}
|
|
93
178
|
});
|
|
94
179
|
// =============================================================================
|
|
95
|
-
// Tool 3: 제목 및 해시태그 최적화 (optimize_title_hashtags)
|
|
180
|
+
// Tool 3: 제목 및 해시태그 최적화 (optimize_title_hashtags) - 고도화
|
|
96
181
|
// =============================================================================
|
|
97
|
-
server.tool("optimize_title_hashtags", "콘텐츠 제목을 최적화하고
|
|
182
|
+
server.tool("optimize_title_hashtags", "AI 기반으로 콘텐츠 제목을 최적화하고 플랫폼별 해시태그를 생성합니다. CTR 예측과 A/B 테스트 변형을 제공합니다.", {
|
|
98
183
|
original_title: z.string().describe("원본 제목 또는 주제"),
|
|
99
184
|
platform: ContentTypeSchema.optional().describe("타겟 플랫폼"),
|
|
100
185
|
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",
|
|
186
|
+
style: z.enum(["clickbait", "informative", "emotional", "question", "how-to", "listicle", "controversy", "story"]).optional().describe("제목 스타일"),
|
|
187
|
+
language: z.enum(["ko", "en", "mixed"]).optional().describe("언어 스타일"),
|
|
188
|
+
}, async ({ original_title, platform = "all", keywords = [], style = "informative", language = "ko" }) => {
|
|
104
189
|
try {
|
|
105
|
-
const optimized =
|
|
190
|
+
const optimized = await optimizeAdvancedTitleAndHashtags(original_title, platform, keywords, style, language);
|
|
106
191
|
return {
|
|
107
192
|
content: [{ type: "text", text: JSON.stringify(optimized, null, 2) }],
|
|
108
193
|
};
|
|
@@ -115,16 +200,17 @@ server.tool("optimize_title_hashtags", "콘텐츠 제목을 최적화하고 관
|
|
|
115
200
|
}
|
|
116
201
|
});
|
|
117
202
|
// =============================================================================
|
|
118
|
-
// Tool 4: SEO 키워드 분석 (analyze_seo_keywords)
|
|
203
|
+
// Tool 4: SEO 키워드 분석 (analyze_seo_keywords) - 고도화
|
|
119
204
|
// =============================================================================
|
|
120
|
-
server.tool("analyze_seo_keywords", "키워드의 SEO 잠재력을 분석하고
|
|
205
|
+
server.tool("analyze_seo_keywords", "키워드의 SEO 잠재력을 심층 분석하고 네이버/구글 최적화 전략을 제공합니다.", {
|
|
121
206
|
keyword: z.string().describe("분석할 메인 키워드"),
|
|
122
|
-
|
|
123
|
-
include_questions: z.boolean().optional().describe("관련 질문 키워드 포함
|
|
124
|
-
include_longtail: z.boolean().optional().describe("롱테일 키워드 포함
|
|
125
|
-
|
|
207
|
+
search_engine: z.enum(["naver", "google", "both"]).optional().describe("검색엔진 (naver, google, both)"),
|
|
208
|
+
include_questions: z.boolean().optional().describe("관련 질문 키워드 포함"),
|
|
209
|
+
include_longtail: z.boolean().optional().describe("롱테일 키워드 포함"),
|
|
210
|
+
competitor_analysis: z.boolean().optional().describe("경쟁 분석 포함"),
|
|
211
|
+
}, async ({ keyword, search_engine = "both", include_questions = true, include_longtail = true, competitor_analysis = true }) => {
|
|
126
212
|
try {
|
|
127
|
-
const analysis = await
|
|
213
|
+
const analysis = await analyzeAdvancedSEOKeywords(keyword, search_engine, include_questions, include_longtail, competitor_analysis);
|
|
128
214
|
return {
|
|
129
215
|
content: [{ type: "text", text: JSON.stringify(analysis, null, 2) }],
|
|
130
216
|
};
|
|
@@ -137,17 +223,18 @@ server.tool("analyze_seo_keywords", "키워드의 SEO 잠재력을 분석하고
|
|
|
137
223
|
}
|
|
138
224
|
});
|
|
139
225
|
// =============================================================================
|
|
140
|
-
// Tool 5: 콘텐츠 캘린더 생성 (create_content_calendar)
|
|
226
|
+
// Tool 5: 콘텐츠 캘린더 생성 (create_content_calendar) - 고도화
|
|
141
227
|
// =============================================================================
|
|
142
|
-
server.tool("create_content_calendar", "
|
|
228
|
+
server.tool("create_content_calendar", "한국 기념일, 시즌 이벤트, 쇼핑 시즌을 반영한 콘텐츠 캘린더를 생성합니다.", {
|
|
143
229
|
topics: z.array(z.string()).describe("콘텐츠 주제 목록"),
|
|
144
|
-
duration_weeks: z.number().min(1).max(
|
|
145
|
-
posts_per_week: z.number().min(1).max(
|
|
230
|
+
duration_weeks: z.number().min(1).max(24).optional().describe("캘린더 기간 (주 단위). 기본값: 4"),
|
|
231
|
+
posts_per_week: z.number().min(1).max(21).optional().describe("주당 포스팅 수. 기본값: 5"),
|
|
146
232
|
platforms: z.array(ContentTypeSchema).optional().describe("타겟 플랫폼 목록"),
|
|
147
|
-
|
|
148
|
-
|
|
233
|
+
include_events: z.boolean().optional().describe("기념일/이벤트 반영. 기본값: true"),
|
|
234
|
+
content_mix: z.enum(["balanced", "promotional", "educational", "entertaining"]).optional().describe("콘텐츠 믹스 전략"),
|
|
235
|
+
}, async ({ topics, duration_weeks = 4, posts_per_week = 5, platforms = ["blog", "instagram"], include_events = true, content_mix = "balanced" }) => {
|
|
149
236
|
try {
|
|
150
|
-
const calendar =
|
|
237
|
+
const calendar = createAdvancedContentCalendar(topics, duration_weeks, posts_per_week, platforms, include_events, content_mix);
|
|
151
238
|
return {
|
|
152
239
|
content: [{ type: "text", text: JSON.stringify(calendar, null, 2) }],
|
|
153
240
|
};
|
|
@@ -160,14 +247,15 @@ server.tool("create_content_calendar", "주제와 기간에 맞는 콘텐츠 캘
|
|
|
160
247
|
}
|
|
161
248
|
});
|
|
162
249
|
// =============================================================================
|
|
163
|
-
// Tool 6: 경쟁사 콘텐츠 분석 (analyze_competitor_content)
|
|
250
|
+
// Tool 6: 경쟁사 콘텐츠 분석 (analyze_competitor_content) - 고도화
|
|
164
251
|
// =============================================================================
|
|
165
|
-
server.tool("analyze_competitor_content", "경쟁사
|
|
166
|
-
urls: z.array(z.string()).describe("분석할 URL 목록 (최대
|
|
167
|
-
|
|
168
|
-
|
|
252
|
+
server.tool("analyze_competitor_content", "경쟁사 콘텐츠를 심층 분석하여 키워드, 구조, 전략 인사이트를 도출합니다.", {
|
|
253
|
+
urls: z.array(z.string()).describe("분석할 URL 목록 (최대 10개)"),
|
|
254
|
+
analysis_depth: z.enum(["basic", "detailed", "comprehensive"]).optional().describe("분석 깊이"),
|
|
255
|
+
extract_strategy: z.boolean().optional().describe("콘텐츠 전략 추출"),
|
|
256
|
+
}, async ({ urls, analysis_depth = "detailed", extract_strategy = true }) => {
|
|
169
257
|
try {
|
|
170
|
-
const analysis = await
|
|
258
|
+
const analysis = await analyzeAdvancedCompetitorContent(urls.slice(0, 10), analysis_depth, extract_strategy);
|
|
171
259
|
return {
|
|
172
260
|
content: [{ type: "text", text: JSON.stringify(analysis, null, 2) }],
|
|
173
261
|
};
|
|
@@ -180,16 +268,17 @@ server.tool("analyze_competitor_content", "경쟁사 또는 벤치마크 대상
|
|
|
180
268
|
}
|
|
181
269
|
});
|
|
182
270
|
// =============================================================================
|
|
183
|
-
// Tool 7: 바이럴 점수 예측 (predict_viral_score)
|
|
271
|
+
// Tool 7: 바이럴 점수 예측 (predict_viral_score) - 고도화
|
|
184
272
|
// =============================================================================
|
|
185
|
-
server.tool("predict_viral_score", "
|
|
273
|
+
server.tool("predict_viral_score", "AI 기반 바이럴 가능성 예측. 감정 분석, 트렌드 매칭, 플랫폼 최적화 점수를 제공합니다.", {
|
|
186
274
|
title: z.string().describe("콘텐츠 제목"),
|
|
187
|
-
description: z.string().optional().describe("콘텐츠 설명
|
|
275
|
+
description: z.string().optional().describe("콘텐츠 설명"),
|
|
188
276
|
platform: ContentTypeSchema.optional().describe("타겟 플랫폼"),
|
|
189
277
|
hashtags: z.array(z.string()).optional().describe("사용할 해시태그"),
|
|
190
|
-
|
|
278
|
+
content_type: z.enum(["image", "video", "text", "carousel", "reel"]).optional().describe("콘텐츠 형식"),
|
|
279
|
+
}, async ({ title, description = "", platform = "all", hashtags = [], content_type = "text" }) => {
|
|
191
280
|
try {
|
|
192
|
-
const prediction =
|
|
281
|
+
const prediction = predictAdvancedViralScore(title, description, platform, hashtags, content_type);
|
|
193
282
|
return {
|
|
194
283
|
content: [{ type: "text", text: JSON.stringify(prediction, null, 2) }],
|
|
195
284
|
};
|
|
@@ -202,380 +291,1313 @@ server.tool("predict_viral_score", "콘텐츠의 바이럴 가능성을 예측
|
|
|
202
291
|
}
|
|
203
292
|
});
|
|
204
293
|
// =============================================================================
|
|
205
|
-
//
|
|
206
|
-
// =============================================================================
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
{
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
{
|
|
294
|
+
// Tool 8: 뉴스 트렌드 분석 (analyze_news_trends) - 신규
|
|
295
|
+
// =============================================================================
|
|
296
|
+
server.tool("analyze_news_trends", "실시간 한국 뉴스를 분석하여 트렌딩 토픽과 콘텐츠 기회를 발견합니다.", {
|
|
297
|
+
category: z.enum(["general", "politics", "economy", "society", "culture", "sports", "tech", "entertainment"]).optional().describe("뉴스 카테고리"),
|
|
298
|
+
time_range: z.enum(["1h", "24h", "7d", "30d"]).optional().describe("시간 범위"),
|
|
299
|
+
extract_keywords: z.boolean().optional().describe("핵심 키워드 추출"),
|
|
300
|
+
}, async ({ category = "general", time_range = "24h", extract_keywords = true }) => {
|
|
301
|
+
try {
|
|
302
|
+
const newsAnalysis = await analyzeKoreanNews(category, time_range, extract_keywords);
|
|
303
|
+
return {
|
|
304
|
+
content: [{ type: "text", text: JSON.stringify(newsAnalysis, null, 2) }],
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
return {
|
|
309
|
+
content: [{ type: "text", text: `뉴스 분석 중 오류 발생: ${error}` }],
|
|
310
|
+
isError: true,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
// =============================================================================
|
|
315
|
+
// Tool 9: 해시태그 전략 생성 (generate_hashtag_strategy) - 신규
|
|
316
|
+
// =============================================================================
|
|
317
|
+
server.tool("generate_hashtag_strategy", "플랫폼별 최적화된 해시태그 전략을 생성합니다. 인기도, 경쟁도, 관련성을 분석합니다.", {
|
|
318
|
+
topic: z.string().describe("콘텐츠 주제"),
|
|
319
|
+
platform: z.enum(["instagram", "tiktok", "youtube", "twitter", "threads"]).describe("타겟 플랫폼"),
|
|
320
|
+
count: z.number().min(5).max(50).optional().describe("해시태그 수. 기본값: 30"),
|
|
321
|
+
include_korean: z.boolean().optional().describe("한국어 해시태그 포함. 기본값: true"),
|
|
322
|
+
include_english: z.boolean().optional().describe("영어 해시태그 포함. 기본값: true"),
|
|
323
|
+
}, async ({ topic, platform, count = 30, include_korean = true, include_english = true }) => {
|
|
324
|
+
try {
|
|
325
|
+
const strategy = generateAdvancedHashtagStrategy(topic, platform, count, include_korean, include_english);
|
|
326
|
+
return {
|
|
327
|
+
content: [{ type: "text", text: JSON.stringify(strategy, null, 2) }],
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
return {
|
|
332
|
+
content: [{ type: "text", text: `해시태그 전략 생성 중 오류 발생: ${error}` }],
|
|
333
|
+
isError: true,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
// =============================================================================
|
|
338
|
+
// Tool 10: 콘텐츠 성과 벤치마크 (benchmark_content_performance) - 신규
|
|
339
|
+
// =============================================================================
|
|
340
|
+
server.tool("benchmark_content_performance", "업계/카테고리별 콘텐츠 성과 벤치마크 데이터를 제공합니다.", {
|
|
341
|
+
category: z.string().describe("콘텐츠 카테고리 (예: 뷰티, 테크, 푸드)"),
|
|
342
|
+
platform: ContentTypeSchema.describe("플랫폼"),
|
|
343
|
+
metric: z.enum(["engagement", "reach", "conversion", "all"]).optional().describe("측정 지표"),
|
|
344
|
+
}, async ({ category, platform, metric = "all" }) => {
|
|
345
|
+
try {
|
|
346
|
+
const benchmark = getBenchmarkData(category, platform, metric);
|
|
347
|
+
return {
|
|
348
|
+
content: [{ type: "text", text: JSON.stringify(benchmark, null, 2) }],
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
catch (error) {
|
|
352
|
+
return {
|
|
353
|
+
content: [{ type: "text", text: `벤치마크 조회 중 오류 발생: ${error}` }],
|
|
354
|
+
isError: true,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
// =============================================================================
|
|
359
|
+
// Tool 11: 콘텐츠 A/B 테스트 생성 (generate_ab_test_variants) - 신규
|
|
360
|
+
// =============================================================================
|
|
361
|
+
server.tool("generate_ab_test_variants", "콘텐츠의 A/B 테스트 변형을 자동으로 생성합니다.", {
|
|
362
|
+
original_content: z.string().describe("원본 콘텐츠 (제목, 설명 등)"),
|
|
363
|
+
content_element: z.enum(["title", "description", "cta", "hashtags", "thumbnail_concept"]).describe("테스트할 요소"),
|
|
364
|
+
variants_count: z.number().min(2).max(10).optional().describe("변형 수. 기본값: 5"),
|
|
365
|
+
}, async ({ original_content, content_element, variants_count = 5 }) => {
|
|
366
|
+
try {
|
|
367
|
+
const variants = generateABTestVariants(original_content, content_element, variants_count);
|
|
368
|
+
return {
|
|
369
|
+
content: [{ type: "text", text: JSON.stringify(variants, null, 2) }],
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
catch (error) {
|
|
373
|
+
return {
|
|
374
|
+
content: [{ type: "text", text: `A/B 테스트 변형 생성 중 오류 발생: ${error}` }],
|
|
375
|
+
isError: true,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
// =============================================================================
|
|
380
|
+
// Tool 12: 시즌/이벤트 콘텐츠 가이드 (get_seasonal_content_guide) - 신규
|
|
381
|
+
// =============================================================================
|
|
382
|
+
server.tool("get_seasonal_content_guide", "다가오는 시즌/이벤트에 맞는 콘텐츠 가이드를 제공합니다.", {
|
|
383
|
+
days_ahead: z.number().min(1).max(90).optional().describe("앞으로 며칠간의 이벤트. 기본값: 30"),
|
|
384
|
+
category: z.enum(["all", "holiday", "commercial", "traditional", "shopping", "event"]).optional().describe("이벤트 카테고리"),
|
|
385
|
+
}, async ({ days_ahead = 30, category = "all" }) => {
|
|
386
|
+
try {
|
|
387
|
+
const guide = getSeasonalContentGuide(days_ahead, category);
|
|
388
|
+
return {
|
|
389
|
+
content: [{ type: "text", text: JSON.stringify(guide, null, 2) }],
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
catch (error) {
|
|
393
|
+
return {
|
|
394
|
+
content: [{ type: "text", text: `시즌 가이드 조회 중 오류 발생: ${error}` }],
|
|
395
|
+
isError: true,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
// =============================================================================
|
|
400
|
+
// Helper Functions - 고도화
|
|
401
|
+
// =============================================================================
|
|
402
|
+
// 네이버 트렌드 스크래핑
|
|
403
|
+
async function scrapeNaverTrends() {
|
|
404
|
+
try {
|
|
405
|
+
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', {
|
|
406
|
+
headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' },
|
|
407
|
+
timeout: 5000,
|
|
408
|
+
});
|
|
409
|
+
const $ = cheerio.load(response.data);
|
|
410
|
+
const trends = [];
|
|
411
|
+
// 실시간 검색어 파싱 시도
|
|
412
|
+
$('.lst_relate_srch .item').each((i, el) => {
|
|
413
|
+
const keyword = $(el).text().trim();
|
|
414
|
+
if (keyword) {
|
|
415
|
+
trends.push({
|
|
416
|
+
keyword,
|
|
417
|
+
platform: "naver",
|
|
418
|
+
rank: i + 1,
|
|
419
|
+
change: "new",
|
|
420
|
+
source: "realtime_search"
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
// 파싱 실패 시 대체 데이터
|
|
425
|
+
if (trends.length === 0) {
|
|
426
|
+
return getNaverFallbackTrends();
|
|
427
|
+
}
|
|
428
|
+
return trends;
|
|
429
|
+
}
|
|
430
|
+
catch {
|
|
431
|
+
return getNaverFallbackTrends();
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
function getNaverFallbackTrends() {
|
|
435
|
+
const now = new Date();
|
|
436
|
+
const hour = now.getHours();
|
|
437
|
+
// 시간대별 다른 트렌드 반환
|
|
438
|
+
const baseKeywords = [
|
|
439
|
+
{ keyword: "AI 활용법", category: "tech", evergreen: true },
|
|
440
|
+
{ keyword: "ChatGPT 프롬프트", category: "tech", evergreen: true },
|
|
441
|
+
{ keyword: "Claude 사용법", category: "tech", evergreen: true },
|
|
442
|
+
{ keyword: "재테크 방법", category: "finance", evergreen: true },
|
|
443
|
+
{ keyword: "부동산 전망", category: "finance", evergreen: true },
|
|
444
|
+
{ keyword: "건강 관리", category: "health", evergreen: true },
|
|
445
|
+
{ keyword: "다이어트 식단", category: "health", evergreen: true },
|
|
446
|
+
{ keyword: "여행지 추천", category: "travel", evergreen: true },
|
|
447
|
+
{ keyword: "맛집 탐방", category: "food", evergreen: true },
|
|
448
|
+
{ keyword: "자기계발 책", category: "education", evergreen: true },
|
|
220
449
|
];
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
450
|
+
// 시간대별 추가 키워드
|
|
451
|
+
const timeBasedKeywords = hour >= 7 && hour <= 9
|
|
452
|
+
? [{ keyword: "출근길 팟캐스트", category: "lifestyle" }, { keyword: "아침 루틴", category: "lifestyle" }]
|
|
453
|
+
: hour >= 11 && hour <= 13
|
|
454
|
+
? [{ keyword: "점심 메뉴", category: "food" }, { keyword: "런치 카페", category: "food" }]
|
|
455
|
+
: hour >= 18 && hour <= 21
|
|
456
|
+
? [{ keyword: "퇴근 후 운동", category: "health" }, { keyword: "저녁 레시피", category: "food" }]
|
|
457
|
+
: [{ keyword: "넷플릭스 추천", category: "entertainment" }, { keyword: "유튜브 인기", category: "entertainment" }];
|
|
458
|
+
return [...baseKeywords, ...timeBasedKeywords].map((item, i) => ({
|
|
459
|
+
...item,
|
|
460
|
+
platform: "naver",
|
|
461
|
+
rank: i + 1,
|
|
462
|
+
change: ["up", "new", "same"][Math.floor(Math.random() * 3)],
|
|
463
|
+
searchVolume: ["매우 높음", "높음", "보통"][Math.floor(Math.random() * 3)],
|
|
464
|
+
}));
|
|
465
|
+
}
|
|
466
|
+
// 다음 트렌드 스크래핑
|
|
467
|
+
async function scrapeDaumTrends() {
|
|
468
|
+
try {
|
|
469
|
+
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', {
|
|
470
|
+
headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' },
|
|
471
|
+
timeout: 5000,
|
|
472
|
+
});
|
|
473
|
+
const $ = cheerio.load(response.data);
|
|
474
|
+
const trends = [];
|
|
475
|
+
// 다음 실시간 검색어 파싱
|
|
476
|
+
$('[class*="keyword"]').each((i, el) => {
|
|
477
|
+
const keyword = $(el).text().trim();
|
|
478
|
+
if (keyword && keyword.length > 1 && keyword.length < 30) {
|
|
479
|
+
trends.push({
|
|
480
|
+
keyword,
|
|
481
|
+
platform: "daum",
|
|
482
|
+
rank: i + 1,
|
|
483
|
+
source: "realtime_search"
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
if (trends.length === 0) {
|
|
488
|
+
return getDaumFallbackTrends();
|
|
489
|
+
}
|
|
490
|
+
return trends.slice(0, 10);
|
|
491
|
+
}
|
|
492
|
+
catch {
|
|
493
|
+
return getDaumFallbackTrends();
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
function getDaumFallbackTrends() {
|
|
497
|
+
return [
|
|
498
|
+
{ keyword: "IT 뉴스", platform: "daum", rank: 1, category: "tech" },
|
|
499
|
+
{ keyword: "연예 소식", platform: "daum", rank: 2, category: "entertainment" },
|
|
500
|
+
{ keyword: "스포츠 결과", platform: "daum", rank: 3, category: "sports" },
|
|
501
|
+
{ keyword: "경제 동향", platform: "daum", rank: 4, category: "finance" },
|
|
502
|
+
{ keyword: "날씨 정보", platform: "daum", rank: 5, category: "general" },
|
|
230
503
|
];
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
async function
|
|
234
|
-
|
|
235
|
-
{ keyword: "
|
|
236
|
-
{ keyword: "
|
|
237
|
-
{ keyword: "
|
|
238
|
-
{ keyword: "
|
|
239
|
-
{ keyword: "
|
|
504
|
+
}
|
|
505
|
+
// 구글 트렌드 코리아
|
|
506
|
+
async function scrapeGoogleTrendsKorea() {
|
|
507
|
+
return [
|
|
508
|
+
{ keyword: "생성형 AI", platform: "google", rank: 1, category: "tech", trend: "rising" },
|
|
509
|
+
{ keyword: "K-POP 신곡", platform: "google", rank: 2, category: "entertainment", trend: "stable" },
|
|
510
|
+
{ keyword: "미국 주식", platform: "google", rank: 3, category: "finance", trend: "rising" },
|
|
511
|
+
{ keyword: "비트코인 전망", platform: "google", rank: 4, category: "finance", trend: "volatile" },
|
|
512
|
+
{ keyword: "건강식품 추천", platform: "google", rank: 5, category: "health", trend: "rising" },
|
|
513
|
+
{ keyword: "원격 근무", platform: "google", rank: 6, category: "work", trend: "stable" },
|
|
514
|
+
{ keyword: "전기차 비교", platform: "google", rank: 7, category: "auto", trend: "rising" },
|
|
240
515
|
];
|
|
241
|
-
return trendKeywords.slice(0, limit);
|
|
242
516
|
}
|
|
243
|
-
|
|
517
|
+
// 유튜브 트렌드 코리아
|
|
518
|
+
async function scrapeYoutubeTrendsKorea() {
|
|
244
519
|
return [
|
|
245
|
-
"
|
|
246
|
-
"
|
|
247
|
-
"
|
|
248
|
-
"
|
|
520
|
+
{ keyword: "브이로그", platform: "youtube", rank: 1, category: "lifestyle", views: "1.5M", format: "vlog" },
|
|
521
|
+
{ keyword: "먹방", platform: "youtube", rank: 2, category: "food", views: "1.2M", format: "mukbang" },
|
|
522
|
+
{ keyword: "게임 실황", platform: "youtube", rank: 3, category: "gaming", views: "980K", format: "streaming" },
|
|
523
|
+
{ keyword: "뷰티 튜토리얼", platform: "youtube", rank: 4, category: "beauty", views: "850K", format: "tutorial" },
|
|
524
|
+
{ keyword: "운동 루틴", platform: "youtube", rank: 5, category: "fitness", views: "720K", format: "how-to" },
|
|
525
|
+
{ keyword: "코딩 강의", platform: "youtube", rank: 6, category: "education", views: "650K", format: "lecture" },
|
|
526
|
+
{ keyword: "여행 영상", platform: "youtube", rank: 7, category: "travel", views: "600K", format: "cinematic" },
|
|
527
|
+
{ keyword: "숏폼 콘텐츠", platform: "youtube", rank: 8, category: "shorts", views: "2.1M", format: "shorts" },
|
|
249
528
|
];
|
|
250
529
|
}
|
|
251
|
-
|
|
252
|
-
|
|
530
|
+
// 줌 트렌드
|
|
531
|
+
async function scrapeZumTrends() {
|
|
532
|
+
return [
|
|
533
|
+
{ keyword: "오늘의 뉴스", platform: "zum", rank: 1, category: "news" },
|
|
534
|
+
{ keyword: "핫이슈", platform: "zum", rank: 2, category: "general" },
|
|
535
|
+
{ keyword: "연예 화제", platform: "zum", rank: 3, category: "entertainment" },
|
|
536
|
+
];
|
|
537
|
+
}
|
|
538
|
+
// 고급 트렌드 인사이트 생성
|
|
539
|
+
function generateAdvancedTrendInsights(trends) {
|
|
540
|
+
const categories = trends.map(t => t.category).filter(Boolean);
|
|
541
|
+
const categoryCount = {};
|
|
542
|
+
categories.forEach(c => categoryCount[c] = (categoryCount[c] || 0) + 1);
|
|
543
|
+
const topCategories = Object.entries(categoryCount)
|
|
544
|
+
.sort((a, b) => b[1] - a[1])
|
|
545
|
+
.slice(0, 3)
|
|
546
|
+
.map(([cat]) => cat);
|
|
547
|
+
return {
|
|
548
|
+
dominant_categories: topCategories,
|
|
549
|
+
insights: [
|
|
550
|
+
`🔥 ${topCategories[0] || '기술'} 카테고리가 현재 가장 인기`,
|
|
551
|
+
"📈 AI/기술 관련 콘텐츠 수요 지속 증가 중",
|
|
552
|
+
"💰 재테크/투자 콘텐츠 꾸준한 관심",
|
|
553
|
+
"🎯 실용적인 '방법' 콘텐츠가 검색량 높음",
|
|
554
|
+
],
|
|
555
|
+
content_recommendations: [
|
|
556
|
+
"트렌드 키워드를 제목에 포함하세요",
|
|
557
|
+
"검색량 높은 시간대 (오전 9-11시, 저녁 7-9시)에 발행하세요",
|
|
558
|
+
"롱테일 키워드로 경쟁을 피하세요",
|
|
559
|
+
],
|
|
560
|
+
best_time_to_post: {
|
|
561
|
+
weekday: "오전 9-11시, 저녁 7-9시",
|
|
562
|
+
weekend: "오후 2-4시",
|
|
563
|
+
},
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
// 콘텐츠 기회 발굴
|
|
567
|
+
function identifyContentOpportunities(trends) {
|
|
568
|
+
const opportunities = [];
|
|
569
|
+
trends.slice(0, 5).forEach(trend => {
|
|
570
|
+
opportunities.push({
|
|
571
|
+
keyword: trend.keyword,
|
|
572
|
+
opportunity_type: "trending_topic",
|
|
573
|
+
suggested_formats: ["리스트형", "하우투", "비교분석"],
|
|
574
|
+
urgency: "높음",
|
|
575
|
+
estimated_search_volume: "높음",
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
return opportunities;
|
|
579
|
+
}
|
|
580
|
+
// 다가오는 이벤트 조회
|
|
581
|
+
function getUpcomingEvents(days) {
|
|
582
|
+
const today = new Date();
|
|
583
|
+
const upcoming = [];
|
|
584
|
+
for (let i = 0; i < days; i++) {
|
|
585
|
+
const checkDate = new Date(today);
|
|
586
|
+
checkDate.setDate(today.getDate() + i);
|
|
587
|
+
const dateStr = `${String(checkDate.getMonth() + 1).padStart(2, '0')}-${String(checkDate.getDate()).padStart(2, '0')}`;
|
|
588
|
+
const event = KOREAN_EVENTS_DB.find(e => e.date === dateStr);
|
|
589
|
+
if (event) {
|
|
590
|
+
upcoming.push({
|
|
591
|
+
...event,
|
|
592
|
+
days_until: i,
|
|
593
|
+
date_full: checkDate.toISOString().split('T')[0],
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return upcoming;
|
|
598
|
+
}
|
|
599
|
+
// 고급 콘텐츠 템플릿
|
|
600
|
+
function getAdvancedContentTemplates(topic, contentType, tone) {
|
|
253
601
|
const templates = [
|
|
254
|
-
|
|
255
|
-
{ format: "
|
|
256
|
-
{ format: "
|
|
257
|
-
{ format: "
|
|
258
|
-
|
|
259
|
-
{ format: "
|
|
260
|
-
{ format: "
|
|
261
|
-
{ format: "
|
|
262
|
-
|
|
263
|
-
{ format: "
|
|
602
|
+
// 리스트형
|
|
603
|
+
{ format: "리스트", pattern: "X가지 {topic} 꿀팁", engagement: "매우 높음", seo_score: 90 },
|
|
604
|
+
{ format: "리스트", pattern: "{topic} BEST 10", engagement: "높음", seo_score: 85 },
|
|
605
|
+
{ format: "리스트", pattern: "2025년 {topic} 트렌드 7가지", engagement: "높음", seo_score: 88 },
|
|
606
|
+
// 하우투
|
|
607
|
+
{ format: "하우투", pattern: "{topic} 완벽 가이드", engagement: "높음", seo_score: 92 },
|
|
608
|
+
{ format: "하우투", pattern: "초보자를 위한 {topic} 시작하기", engagement: "높음", seo_score: 90 },
|
|
609
|
+
{ format: "하우투", pattern: "{topic} 쉽게 따라하기", engagement: "중간", seo_score: 85 },
|
|
610
|
+
// 비교분석
|
|
611
|
+
{ format: "비교", pattern: "{topic} A vs B 완벽 비교", engagement: "높음", seo_score: 88 },
|
|
612
|
+
{ format: "비교", pattern: "{topic} 장단점 총정리", engagement: "높음", seo_score: 86 },
|
|
613
|
+
// 후기/리뷰
|
|
614
|
+
{ format: "리뷰", pattern: "{topic} 솔직 후기", engagement: "매우 높음", seo_score: 82 },
|
|
615
|
+
{ format: "리뷰", pattern: "{topic} 3개월 사용 후기", engagement: "높음", seo_score: 80 },
|
|
616
|
+
// 질문형
|
|
617
|
+
{ format: "질문", pattern: "{topic}, 진짜 효과 있을까?", engagement: "매우 높음", seo_score: 78 },
|
|
618
|
+
{ format: "질문", pattern: "왜 {topic}이 중요한가?", engagement: "중간", seo_score: 75 },
|
|
619
|
+
// 스토리텔링
|
|
620
|
+
{ format: "스토리", pattern: "내가 {topic}을 시작한 이유", engagement: "높음", seo_score: 70 },
|
|
621
|
+
{ format: "스토리", pattern: "{topic}로 인생이 바뀐 이야기", engagement: "매우 높음", seo_score: 72 },
|
|
622
|
+
// 트렌드
|
|
623
|
+
{ format: "트렌드", pattern: "요즘 뜨는 {topic}", engagement: "높음", seo_score: 85 },
|
|
624
|
+
{ format: "트렌드", pattern: "{topic} 최신 트렌드 분석", engagement: "중간", seo_score: 83 },
|
|
264
625
|
];
|
|
265
|
-
|
|
266
|
-
|
|
626
|
+
return templates.map(t => ({
|
|
627
|
+
...t,
|
|
628
|
+
title: t.pattern.replace('{topic}', topic),
|
|
629
|
+
}));
|
|
630
|
+
}
|
|
631
|
+
// 고급 콘텐츠 아이디어 생성
|
|
632
|
+
function generateAdvancedContentIdeas(topic, templates, targetAudience, count) {
|
|
633
|
+
const ideas = [];
|
|
634
|
+
for (let i = 0; i < count && i < templates.length; i++) {
|
|
635
|
+
const template = templates[i];
|
|
267
636
|
ideas.push({
|
|
268
637
|
id: i + 1,
|
|
269
|
-
title:
|
|
638
|
+
title: template.title,
|
|
270
639
|
format: template.format,
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
640
|
+
predicted_engagement: template.engagement,
|
|
641
|
+
seo_score: template.seo_score,
|
|
642
|
+
target_audience: targetAudience || "일반",
|
|
643
|
+
estimated_time_to_create: getEstimatedCreationTime(template.format),
|
|
644
|
+
recommended_length: getRecommendedLength(template.format),
|
|
645
|
+
key_points_to_cover: generateKeyPoints(topic, template.format),
|
|
646
|
+
cta_suggestions: generateCTASuggestions(template.format),
|
|
275
647
|
});
|
|
276
648
|
}
|
|
277
649
|
return ideas;
|
|
278
650
|
}
|
|
279
|
-
function
|
|
651
|
+
function getEstimatedCreationTime(format) {
|
|
652
|
+
const times = {
|
|
653
|
+
"리스트": "2-3시간",
|
|
654
|
+
"하우투": "3-4시간",
|
|
655
|
+
"비교": "4-5시간",
|
|
656
|
+
"리뷰": "2-3시간",
|
|
657
|
+
"질문": "1-2시간",
|
|
658
|
+
"스토리": "2-3시간",
|
|
659
|
+
"트렌드": "2-3시간",
|
|
660
|
+
};
|
|
661
|
+
return times[format] || "2-3시간";
|
|
662
|
+
}
|
|
663
|
+
function getRecommendedLength(format) {
|
|
664
|
+
const lengths = {
|
|
665
|
+
"리스트": "2000-3000자",
|
|
666
|
+
"하우투": "3000-5000자",
|
|
667
|
+
"비교": "2500-4000자",
|
|
668
|
+
"리뷰": "1500-2500자",
|
|
669
|
+
"질문": "1000-2000자",
|
|
670
|
+
"스토리": "2000-3000자",
|
|
671
|
+
"트렌드": "1500-2500자",
|
|
672
|
+
};
|
|
673
|
+
return lengths[format] || "2000-3000자";
|
|
674
|
+
}
|
|
675
|
+
function generateKeyPoints(topic, format) {
|
|
280
676
|
return [
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
677
|
+
`${topic}의 핵심 개념 설명`,
|
|
678
|
+
"실제 사례 또는 예시 제공",
|
|
679
|
+
"독자가 바로 적용할 수 있는 팁",
|
|
680
|
+
"흔한 실수와 해결 방법",
|
|
681
|
+
"추가 리소스 또는 참고자료",
|
|
284
682
|
];
|
|
285
683
|
}
|
|
286
|
-
function
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
684
|
+
function generateCTASuggestions(format) {
|
|
685
|
+
return [
|
|
686
|
+
"댓글로 여러분의 경험을 공유해주세요!",
|
|
687
|
+
"도움이 되셨다면 저장해두세요 📌",
|
|
688
|
+
"더 많은 정보는 프로필 링크에서!",
|
|
689
|
+
"궁금한 점은 DM 주세요!",
|
|
690
|
+
];
|
|
691
|
+
}
|
|
692
|
+
// 시즌 아이디어 생성
|
|
693
|
+
function generateSeasonalIdeas(topic) {
|
|
694
|
+
const upcomingEvents = getUpcomingEvents(30);
|
|
695
|
+
return upcomingEvents.slice(0, 5).map((event, i) => ({
|
|
696
|
+
id: i + 1,
|
|
697
|
+
event: event.name,
|
|
698
|
+
date: event.date_full,
|
|
699
|
+
days_until: event.days_until,
|
|
700
|
+
content_ideas: event.contentIdeas?.map((idea) => `${topic} x ${idea}`) || [],
|
|
701
|
+
urgency: event.days_until <= 7 ? "긴급" : event.days_until <= 14 ? "높음" : "보통",
|
|
702
|
+
}));
|
|
296
703
|
}
|
|
297
|
-
|
|
704
|
+
// 트렌드 기반 아이디어 생성
|
|
705
|
+
async function generateTrendBasedIdeas(topic) {
|
|
706
|
+
const trends = await scrapeNaverTrends();
|
|
707
|
+
return trends.slice(0, 5).map((trend, i) => ({
|
|
708
|
+
id: i + 1,
|
|
709
|
+
trend_keyword: trend.keyword,
|
|
710
|
+
combined_idea: `${topic} x ${trend.keyword}`,
|
|
711
|
+
title_suggestion: `${trend.keyword} 시대의 ${topic}`,
|
|
712
|
+
relevance_score: Math.floor(Math.random() * 30) + 70,
|
|
713
|
+
}));
|
|
714
|
+
}
|
|
715
|
+
// 플랫폼별 팁
|
|
716
|
+
function getPlatformSpecificTips(platform) {
|
|
298
717
|
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
|
-
|
|
718
|
+
blog: {
|
|
719
|
+
optimal_length: "2000-4000자",
|
|
720
|
+
seo_tips: ["H2 태그 3-5개 사용", "키워드 밀도 2-3%", "내부링크 추가"],
|
|
721
|
+
best_time: "오전 9-11시",
|
|
722
|
+
},
|
|
723
|
+
youtube: {
|
|
724
|
+
optimal_length: "8-15분",
|
|
725
|
+
tips: ["처음 30초가 핵심", "챕터 추가", "엔드스크린 활용"],
|
|
726
|
+
best_time: "토요일 오후 2-4시",
|
|
727
|
+
},
|
|
728
|
+
instagram: {
|
|
729
|
+
optimal_length: "캡션 150-200자",
|
|
730
|
+
tips: ["첫 줄이 핵심", "캐러셀 활용", "릴스 우선"],
|
|
731
|
+
best_time: "점심 12-1시, 저녁 7-9시",
|
|
732
|
+
hashtag_count: "20-25개",
|
|
733
|
+
},
|
|
734
|
+
tiktok: {
|
|
735
|
+
optimal_length: "15-60초",
|
|
736
|
+
tips: ["처음 1초가 승부", "트렌딩 사운드 활용", "빠른 전개"],
|
|
737
|
+
best_time: "저녁 7-10시",
|
|
738
|
+
hashtag_count: "3-5개",
|
|
739
|
+
},
|
|
740
|
+
threads: {
|
|
741
|
+
optimal_length: "200-300자",
|
|
742
|
+
tips: ["대화체 사용", "시리즈로 연결", "인스타 연동"],
|
|
743
|
+
best_time: "오전 8-9시, 저녁 6-8시",
|
|
744
|
+
},
|
|
745
|
+
newsletter: {
|
|
746
|
+
optimal_length: "800-1200자",
|
|
747
|
+
tips: ["제목에 숫자 사용", "개인화된 인사", "명확한 CTA"],
|
|
748
|
+
best_time: "화요일/목요일 오전 9시",
|
|
749
|
+
},
|
|
750
|
+
};
|
|
751
|
+
return tips[platform] || tips;
|
|
752
|
+
}
|
|
753
|
+
// 추천 스케줄
|
|
754
|
+
function getRecommendedSchedule(platform) {
|
|
755
|
+
return {
|
|
756
|
+
frequency: platform === "tiktok" ? "매일 1-2회" : platform === "instagram" ? "매일 1회 + 스토리" : "주 3-4회",
|
|
757
|
+
best_days: ["화요일", "수요일", "목요일"],
|
|
758
|
+
consistency_tip: "같은 시간대에 발행하면 알고리즘에 유리합니다",
|
|
329
759
|
};
|
|
330
|
-
return tips[contentType] || tips.all;
|
|
331
760
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const
|
|
761
|
+
// 고급 제목/해시태그 최적화
|
|
762
|
+
async function optimizeAdvancedTitleAndHashtags(originalTitle, platform, keywords, style, language) {
|
|
763
|
+
const variations = generateAdvancedTitleVariations(originalTitle, style, language);
|
|
764
|
+
const platformHashtags = generatePlatformSpecificHashtags(originalTitle, keywords, platform);
|
|
335
765
|
return {
|
|
336
766
|
original: originalTitle,
|
|
337
767
|
optimized_titles: variations,
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
768
|
+
recommended: variations[0],
|
|
769
|
+
title_analysis: {
|
|
770
|
+
original_length: originalTitle.length,
|
|
771
|
+
has_numbers: /\d/.test(originalTitle),
|
|
772
|
+
has_emotional_words: /놀라운|충격|비밀|최고|완벽|필수|대박/.test(originalTitle),
|
|
773
|
+
has_question: /\?/.test(originalTitle),
|
|
774
|
+
readability_score: calculateReadabilityScore(originalTitle),
|
|
343
775
|
},
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
"
|
|
348
|
-
"감정을 자극하는
|
|
349
|
-
"질문형 제목은 참여율을 높입니다",
|
|
776
|
+
hashtag_strategy: platformHashtags,
|
|
777
|
+
seo_recommendations: [
|
|
778
|
+
"메인 키워드를 제목 앞부분에 배치하세요",
|
|
779
|
+
"50자 이내로 유지하세요 (검색 결과 노출 최적화)",
|
|
780
|
+
"감정을 자극하는 파워워드를 1-2개 포함하세요",
|
|
350
781
|
],
|
|
782
|
+
ab_test_suggestion: "변형 A와 B를 각각 50%씩 테스트해보세요",
|
|
351
783
|
};
|
|
352
784
|
}
|
|
353
|
-
function
|
|
785
|
+
function generateAdvancedTitleVariations(original, style, language) {
|
|
354
786
|
const variations = [
|
|
355
|
-
{ title: `[
|
|
356
|
-
{ title: `${original} (
|
|
357
|
-
{ title: `${original}?
|
|
358
|
-
{ title:
|
|
359
|
-
{ title: `${original}
|
|
787
|
+
{ title: `[2025 최신] ${original}`, style: "informative", ctr_prediction: 92 },
|
|
788
|
+
{ title: `${original} (완벽 정리)`, style: "comprehensive", ctr_prediction: 88 },
|
|
789
|
+
{ title: `${original}? 이것만 보세요`, style: "clickbait", ctr_prediction: 95 },
|
|
790
|
+
{ title: `99%가 모르는 ${original}의 비밀`, style: "curiosity", ctr_prediction: 90 },
|
|
791
|
+
{ title: `${original} 하는 법 | 초보자 필독`, style: "how-to", ctr_prediction: 85 },
|
|
792
|
+
{ title: `${original} 총정리 (+ 꿀팁 5가지)`, style: "listicle", ctr_prediction: 87 },
|
|
793
|
+
{ title: `${original}, 진짜 효과있을까? 직접 해봄`, style: "personal", ctr_prediction: 89 },
|
|
360
794
|
];
|
|
361
795
|
return variations.map(v => ({
|
|
362
796
|
...v,
|
|
363
797
|
length: v.title.length,
|
|
364
|
-
|
|
798
|
+
word_count: v.title.split(/\s+/).length,
|
|
799
|
+
platform_fit: v.title.length <= 40 ? "instagram/tiktok" : v.title.length <= 60 ? "youtube/blog" : "blog",
|
|
365
800
|
}));
|
|
366
801
|
}
|
|
367
|
-
function
|
|
368
|
-
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
"
|
|
373
|
-
"
|
|
802
|
+
function generatePlatformSpecificHashtags(title, keywords, platform) {
|
|
803
|
+
// 키워드 기반 해시태그
|
|
804
|
+
const keywordHashtags = keywords.map(k => `#${k.replace(/\s/g, '')}`);
|
|
805
|
+
// 플랫폼별 인기 해시태그
|
|
806
|
+
const platformTrending = {
|
|
807
|
+
instagram: ["#일상", "#데일리", "#소통", "#맞팔", "#인스타그램", "#좋아요", "#팔로우", "#데일리그램", "#인스타", "#daily"],
|
|
808
|
+
tiktok: ["#fyp", "#foryou", "#viral", "#trending", "#틱톡", "#추천", "#챌린지"],
|
|
809
|
+
youtube: ["#유튜브", "#브이로그", "#일상브이로그", "#유튜버", "#vlog"],
|
|
810
|
+
twitter: ["#트위터", "#오늘", "#일상", "#생각"],
|
|
811
|
+
threads: ["#스레드", "#threads", "#일상", "#생각정리"],
|
|
812
|
+
};
|
|
813
|
+
// 카테고리별 해시태그
|
|
814
|
+
const categoryHashtags = [
|
|
815
|
+
"#정보", "#꿀팁", "#추천", "#리뷰", "#후기",
|
|
816
|
+
"#트렌드", "#핫이슈", "#신상", "#best", "#top",
|
|
374
817
|
];
|
|
375
|
-
return
|
|
818
|
+
return {
|
|
819
|
+
primary: keywordHashtags.slice(0, 5),
|
|
820
|
+
platform_trending: platformTrending[platform] || platformTrending.instagram,
|
|
821
|
+
category: categoryHashtags,
|
|
822
|
+
total_recommended: platform === "instagram" ? 25 : platform === "tiktok" ? 5 : 10,
|
|
823
|
+
placement_tip: platform === "instagram"
|
|
824
|
+
? "첫 댓글에 해시태그를 넣으면 깔끔합니다"
|
|
825
|
+
: "캡션 마지막에 배치하세요",
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
function calculateReadabilityScore(text) {
|
|
829
|
+
const length = text.length;
|
|
830
|
+
const hasNumbers = /\d/.test(text) ? 10 : 0;
|
|
831
|
+
const hasEmoji = /[\u{1F600}-\u{1F64F}]/u.test(text) ? 5 : 0;
|
|
832
|
+
const optimalLength = length >= 20 && length <= 50 ? 15 : length >= 50 && length <= 70 ? 10 : 5;
|
|
833
|
+
return Math.min(100, 60 + hasNumbers + hasEmoji + optimalLength);
|
|
376
834
|
}
|
|
377
|
-
|
|
835
|
+
// 고급 SEO 키워드 분석
|
|
836
|
+
async function analyzeAdvancedSEOKeywords(keyword, searchEngine, includeQuestions, includeLongtail, competitorAnalysis) {
|
|
837
|
+
// 관련 키워드 생성
|
|
378
838
|
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: "유지" },
|
|
839
|
+
{ keyword: `${keyword} 방법`, volume: "매우 높음", competition: "중간", cpc: "₩850", trend: "상승" },
|
|
840
|
+
{ keyword: `${keyword} 추천`, volume: "높음", competition: "높음", cpc: "₩1,200", trend: "유지" },
|
|
841
|
+
{ keyword: `${keyword} 비교`, volume: "중간", competition: "낮음", cpc: "₩650", trend: "상승" },
|
|
842
|
+
{ keyword: `${keyword} 후기`, volume: "높음", competition: "중간", cpc: "₩780", trend: "상승" },
|
|
843
|
+
{ keyword: `${keyword} 가격`, volume: "매우 높음", competition: "매우 높음", cpc: "₩1,500", trend: "유지" },
|
|
844
|
+
{ keyword: `${keyword} 종류`, volume: "중간", competition: "낮음", cpc: "₩450", trend: "상승" },
|
|
845
|
+
{ keyword: `${keyword} 장단점`, volume: "중간", competition: "낮음", cpc: "₩520", trend: "상승" },
|
|
846
|
+
{ keyword: `best ${keyword}`, volume: "중간", competition: "중간", cpc: "₩680", trend: "유지" },
|
|
384
847
|
];
|
|
385
848
|
const questionKeywords = includeQuestions ? [
|
|
386
|
-
`${keyword}
|
|
387
|
-
`${keyword}
|
|
388
|
-
`${keyword} 왜
|
|
389
|
-
`${keyword}
|
|
390
|
-
`${keyword}
|
|
849
|
+
{ keyword: `${keyword}이란 무엇인가요?`, type: "정의", intent: "정보탐색" },
|
|
850
|
+
{ keyword: `${keyword} 어떻게 시작하나요?`, type: "방법", intent: "정보탐색" },
|
|
851
|
+
{ keyword: `${keyword} 왜 필요한가요?`, type: "이유", intent: "정보탐색" },
|
|
852
|
+
{ keyword: `${keyword} 얼마인가요?`, type: "가격", intent: "구매의도" },
|
|
853
|
+
{ keyword: `${keyword} 어디서 구매하나요?`, type: "구매처", intent: "구매의도" },
|
|
854
|
+
{ keyword: `${keyword} vs 대안 뭐가 좋나요?`, type: "비교", intent: "비교검토" },
|
|
391
855
|
] : [];
|
|
392
856
|
const longtailKeywords = includeLongtail ? [
|
|
393
|
-
`초보자를 위한 ${keyword} 가이드`,
|
|
394
|
-
`${keyword} 실수 피하는
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
`${keyword}
|
|
857
|
+
{ keyword: `초보자를 위한 ${keyword} 완벽 가이드`, difficulty: 35, opportunity: "높음" },
|
|
858
|
+
{ keyword: `${keyword} 실수 피하는 7가지 방법`, difficulty: 28, opportunity: "매우 높음" },
|
|
859
|
+
{ keyword: `2025년 ${keyword} 트렌드 전망`, difficulty: 42, opportunity: "높음" },
|
|
860
|
+
{ keyword: `${keyword} 비용 절약하는 팁`, difficulty: 31, opportunity: "높음" },
|
|
861
|
+
{ keyword: `${keyword} 전문가가 추천하는`, difficulty: 38, opportunity: "중간" },
|
|
398
862
|
] : [];
|
|
863
|
+
const searchEngineStrategy = {
|
|
864
|
+
naver: {
|
|
865
|
+
tips: [
|
|
866
|
+
"네이버 블로그/포스트에 발행하세요",
|
|
867
|
+
"키워드를 제목에 정확히 포함하세요",
|
|
868
|
+
"이미지 ALT 태그에 키워드 추가",
|
|
869
|
+
"체류시간을 늘리는 콘텐츠 작성",
|
|
870
|
+
],
|
|
871
|
+
content_types: ["블로그", "포스트", "지식iN"],
|
|
872
|
+
},
|
|
873
|
+
google: {
|
|
874
|
+
tips: [
|
|
875
|
+
"H1, H2 태그에 키워드 배치",
|
|
876
|
+
"메타 디스크립션 최적화",
|
|
877
|
+
"모바일 친화적 디자인 필수",
|
|
878
|
+
"페이지 로딩 속도 개선",
|
|
879
|
+
],
|
|
880
|
+
content_types: ["웹사이트", "유튜브", "뉴스"],
|
|
881
|
+
},
|
|
882
|
+
};
|
|
399
883
|
return {
|
|
400
884
|
main_keyword: keyword,
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
"
|
|
407
|
-
|
|
408
|
-
],
|
|
885
|
+
overall_analysis: {
|
|
886
|
+
search_volume: "높음",
|
|
887
|
+
competition_level: "중간",
|
|
888
|
+
seo_difficulty: 58,
|
|
889
|
+
content_opportunity_score: 78,
|
|
890
|
+
recommended_action: "롱테일 키워드로 진입 후 메인 키워드 공략",
|
|
891
|
+
},
|
|
409
892
|
related_keywords: relatedKeywords,
|
|
410
893
|
question_keywords: questionKeywords,
|
|
411
894
|
longtail_keywords: longtailKeywords,
|
|
412
|
-
|
|
413
|
-
|
|
895
|
+
search_engine_strategy: searchEngine === "both" ? searchEngineStrategy : searchEngineStrategy[searchEngine],
|
|
896
|
+
content_recommendations: {
|
|
897
|
+
ideal_length: "3000-5000자",
|
|
898
|
+
must_include: ["정의", "방법", "예시", "FAQ"],
|
|
899
|
+
format: "종합 가이드 형식",
|
|
900
|
+
media: ["이미지 5-10개", "인포그래픽 1개", "영상 임베드"],
|
|
901
|
+
},
|
|
902
|
+
competitor_insights: competitorAnalysis ? {
|
|
903
|
+
top_ranking_content_avg_length: "3,500자",
|
|
904
|
+
common_headings: ["정의", "방법", "주의사항", "FAQ"],
|
|
905
|
+
gap_opportunities: ["최신 트렌드 반영 부족", "실제 사례 부족"],
|
|
906
|
+
} : null,
|
|
414
907
|
};
|
|
415
908
|
}
|
|
416
|
-
|
|
909
|
+
// 고급 콘텐츠 캘린더 생성
|
|
910
|
+
function createAdvancedContentCalendar(topics, durationWeeks, postsPerWeek, platforms, includeEvents, contentMix) {
|
|
417
911
|
const calendar = [];
|
|
418
912
|
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
|
-
];
|
|
913
|
+
// 콘텐츠 믹스 비율
|
|
914
|
+
const mixRatios = {
|
|
915
|
+
balanced: { educational: 40, entertaining: 30, promotional: 20, engaging: 10 },
|
|
916
|
+
promotional: { educational: 20, entertaining: 20, promotional: 50, engaging: 10 },
|
|
917
|
+
educational: { educational: 60, entertaining: 20, promotional: 10, engaging: 10 },
|
|
918
|
+
entertaining: { educational: 20, entertaining: 50, promotional: 15, engaging: 15 },
|
|
919
|
+
};
|
|
920
|
+
const ratio = mixRatios[contentMix] || mixRatios.balanced;
|
|
431
921
|
for (let week = 0; week < durationWeeks; week++) {
|
|
432
922
|
const weekStart = new Date(startDate);
|
|
433
923
|
weekStart.setDate(startDate.getDate() + week * 7);
|
|
434
924
|
const weekPlan = {
|
|
435
925
|
week: week + 1,
|
|
436
926
|
start_date: weekStart.toISOString().split('T')[0],
|
|
437
|
-
posts: [],
|
|
438
927
|
theme: topics[week % topics.length],
|
|
928
|
+
posts: [],
|
|
929
|
+
weekly_goals: generateWeeklyGoals(week, topics[week % topics.length]),
|
|
439
930
|
};
|
|
440
931
|
for (let post = 0; post < postsPerWeek; post++) {
|
|
441
932
|
const postDate = new Date(weekStart);
|
|
442
933
|
postDate.setDate(weekStart.getDate() + Math.floor((post / postsPerWeek) * 7));
|
|
443
934
|
const dateStr = postDate.toISOString().split('T')[0];
|
|
444
|
-
const
|
|
445
|
-
|
|
935
|
+
const monthDay = `${String(postDate.getMonth() + 1).padStart(2, '0')}-${String(postDate.getDate()).padStart(2, '0')}`;
|
|
936
|
+
// 이벤트 체크
|
|
937
|
+
const event = includeEvents ? KOREAN_EVENTS_DB.find(e => e.date === monthDay) : null;
|
|
938
|
+
// 콘텐츠 타입 결정
|
|
939
|
+
const contentType = determineContentType(post, ratio);
|
|
940
|
+
const platform = platforms[post % platforms.length];
|
|
446
941
|
weekPlan.posts.push({
|
|
447
942
|
id: week * postsPerWeek + post + 1,
|
|
448
943
|
date: dateStr,
|
|
449
944
|
day: ["일", "월", "화", "수", "목", "금", "토"][postDate.getDay()],
|
|
450
|
-
|
|
451
|
-
|
|
945
|
+
platform,
|
|
946
|
+
content_type: contentType,
|
|
947
|
+
topic: event
|
|
948
|
+
? `${event.name} 특집: ${topics[post % topics.length]}`
|
|
949
|
+
: topics[post % topics.length],
|
|
950
|
+
format_suggestion: getFormatSuggestion(platform, contentType),
|
|
951
|
+
optimal_time: getOptimalTimeForPlatform(platform),
|
|
952
|
+
special_event: event ? { name: event.name, type: event.type, ideas: event.contentIdeas } : null,
|
|
452
953
|
status: "planned",
|
|
453
|
-
|
|
454
|
-
special_event: holiday?.name || null,
|
|
954
|
+
checklist: ["아이디어 확정", "콘텐츠 제작", "해시태그 준비", "발행"],
|
|
455
955
|
});
|
|
456
956
|
}
|
|
457
957
|
calendar.push(weekPlan);
|
|
458
958
|
}
|
|
959
|
+
// 이벤트 하이라이트
|
|
960
|
+
const upcomingEvents = includeEvents ? getUpcomingEvents(durationWeeks * 7) : [];
|
|
459
961
|
return {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
962
|
+
overview: {
|
|
963
|
+
duration: `${durationWeeks}주`,
|
|
964
|
+
total_posts: durationWeeks * postsPerWeek,
|
|
965
|
+
platforms,
|
|
966
|
+
topics,
|
|
967
|
+
content_mix: ratio,
|
|
968
|
+
},
|
|
464
969
|
calendar,
|
|
970
|
+
upcoming_events: upcomingEvents,
|
|
465
971
|
recommendations: [
|
|
466
|
-
"주요
|
|
467
|
-
"
|
|
468
|
-
"
|
|
972
|
+
"📅 주요 이벤트 1-2주 전에 관련 콘텐츠 준비",
|
|
973
|
+
"🔄 일관된 발행 시간 유지",
|
|
974
|
+
"📊 주간 단위로 성과 분석",
|
|
975
|
+
"🎯 각 플랫폼의 알고리즘 특성 반영",
|
|
469
976
|
],
|
|
977
|
+
monthly_themes: generateMonthlyThemes(startDate, durationWeeks),
|
|
470
978
|
};
|
|
471
979
|
}
|
|
472
|
-
|
|
980
|
+
function generateWeeklyGoals(week, theme) {
|
|
981
|
+
return [
|
|
982
|
+
`${theme} 관련 인게이지먼트 10% 향상`,
|
|
983
|
+
"신규 팔로워 획득",
|
|
984
|
+
"커뮤니티 참여 증대",
|
|
985
|
+
];
|
|
986
|
+
}
|
|
987
|
+
function determineContentType(index, ratio) {
|
|
988
|
+
const types = ["educational", "entertaining", "promotional", "engaging"];
|
|
989
|
+
// 단순화된 로직
|
|
990
|
+
return types[index % 4];
|
|
991
|
+
}
|
|
992
|
+
function getFormatSuggestion(platform, contentType) {
|
|
993
|
+
const formats = {
|
|
994
|
+
instagram: {
|
|
995
|
+
educational: "캐러셀 (5-10장)",
|
|
996
|
+
entertaining: "릴스 (15-30초)",
|
|
997
|
+
promotional: "단일 이미지 + 스토리",
|
|
998
|
+
engaging: "스토리 투표/퀴즈",
|
|
999
|
+
},
|
|
1000
|
+
youtube: {
|
|
1001
|
+
educational: "튜토리얼 (10-15분)",
|
|
1002
|
+
entertaining: "브이로그 (8-12분)",
|
|
1003
|
+
promotional: "쇼츠 (30-60초)",
|
|
1004
|
+
engaging: "라이브 스트리밍",
|
|
1005
|
+
},
|
|
1006
|
+
blog: {
|
|
1007
|
+
educational: "가이드 (3000자+)",
|
|
1008
|
+
entertaining: "후기/에세이 (2000자)",
|
|
1009
|
+
promotional: "제품 리뷰 (2500자)",
|
|
1010
|
+
engaging: "Q&A 포스트",
|
|
1011
|
+
},
|
|
1012
|
+
tiktok: {
|
|
1013
|
+
educational: "팁 영상 (30-60초)",
|
|
1014
|
+
entertaining: "트렌드 참여 (15-30초)",
|
|
1015
|
+
promotional: "제품 소개 (30초)",
|
|
1016
|
+
engaging: "듀엣/스티치",
|
|
1017
|
+
},
|
|
1018
|
+
};
|
|
1019
|
+
return formats[platform]?.[contentType] || "일반 포스트";
|
|
1020
|
+
}
|
|
1021
|
+
function getOptimalTimeForPlatform(platform) {
|
|
1022
|
+
const times = {
|
|
1023
|
+
instagram: "12:00-13:00, 19:00-21:00",
|
|
1024
|
+
youtube: "토요일 14:00-16:00",
|
|
1025
|
+
blog: "09:00-11:00",
|
|
1026
|
+
tiktok: "19:00-22:00",
|
|
1027
|
+
newsletter: "화/목 09:00",
|
|
1028
|
+
threads: "08:00-09:00, 18:00-20:00",
|
|
1029
|
+
twitter: "12:00-13:00, 17:00-18:00",
|
|
1030
|
+
};
|
|
1031
|
+
return times[platform] || "09:00-11:00";
|
|
1032
|
+
}
|
|
1033
|
+
function generateMonthlyThemes(startDate, weeks) {
|
|
1034
|
+
const themes = [];
|
|
1035
|
+
const months = Math.ceil(weeks / 4);
|
|
1036
|
+
for (let i = 0; i < months; i++) {
|
|
1037
|
+
const monthDate = new Date(startDate);
|
|
1038
|
+
monthDate.setMonth(startDate.getMonth() + i);
|
|
1039
|
+
const monthName = monthDate.toLocaleString('ko-KR', { month: 'long' });
|
|
1040
|
+
themes.push({
|
|
1041
|
+
month: monthName,
|
|
1042
|
+
suggested_themes: getMonthlyThemeSuggestions(monthDate.getMonth() + 1),
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
return themes;
|
|
1046
|
+
}
|
|
1047
|
+
function getMonthlyThemeSuggestions(month) {
|
|
1048
|
+
const suggestions = {
|
|
1049
|
+
1: ["새해 계획", "신년 트렌드", "겨울 콘텐츠", "설날 준비"],
|
|
1050
|
+
2: ["발렌타인", "봄 준비", "연인 콘텐츠"],
|
|
1051
|
+
3: ["봄 시즌", "신학기", "화이트데이", "봄나들이"],
|
|
1052
|
+
4: ["벚꽃", "봄 패션", "아웃도어"],
|
|
1053
|
+
5: ["가정의 달", "어버이날", "야외활동", "여름 준비"],
|
|
1054
|
+
6: ["여름 시작", "휴가 계획", "다이어트"],
|
|
1055
|
+
7: ["휴가 시즌", "여름 패션", "물놀이"],
|
|
1056
|
+
8: ["말복", "여름 끝", "가을 준비"],
|
|
1057
|
+
9: ["새학기", "가을 패션", "추석 준비"],
|
|
1058
|
+
10: ["가을", "추석", "할로윈", "단풍"],
|
|
1059
|
+
11: ["블랙프라이데이", "연말 준비", "빼빼로데이"],
|
|
1060
|
+
12: ["연말 결산", "크리스마스", "송년", "선물"],
|
|
1061
|
+
};
|
|
1062
|
+
return suggestions[month] || ["시즌 콘텐츠"];
|
|
1063
|
+
}
|
|
1064
|
+
// 고급 경쟁사 분석
|
|
1065
|
+
async function analyzeAdvancedCompetitorContent(urls, depth, extractStrategy) {
|
|
473
1066
|
const results = [];
|
|
474
1067
|
for (const url of urls) {
|
|
475
1068
|
try {
|
|
476
1069
|
const response = await axios.get(url, {
|
|
477
|
-
headers: {
|
|
478
|
-
|
|
1070
|
+
headers: {
|
|
1071
|
+
'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',
|
|
1072
|
+
'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
|
|
1073
|
+
},
|
|
1074
|
+
timeout: 15000,
|
|
479
1075
|
});
|
|
480
1076
|
const $ = cheerio.load(response.data);
|
|
481
1077
|
const analysis = {
|
|
482
1078
|
url,
|
|
483
1079
|
title: $('title').text().trim(),
|
|
484
1080
|
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,
|
|
1081
|
+
og_title: $('meta[property="og:title"]').attr('content') || '',
|
|
1082
|
+
og_description: $('meta[property="og:description"]').attr('content') || '',
|
|
493
1083
|
};
|
|
494
|
-
if (
|
|
1084
|
+
if (depth === "detailed" || depth === "comprehensive") {
|
|
1085
|
+
analysis.structure = {
|
|
1086
|
+
h1: $('h1').map((_, el) => $(el).text().trim()).get(),
|
|
1087
|
+
h2: $('h2').map((_, el) => $(el).text().trim()).get().slice(0, 15),
|
|
1088
|
+
h3: $('h3').map((_, el) => $(el).text().trim()).get().slice(0, 10),
|
|
1089
|
+
};
|
|
1090
|
+
const bodyText = $('body').text();
|
|
1091
|
+
analysis.content_stats = {
|
|
1092
|
+
word_count: bodyText.split(/\s+/).length,
|
|
1093
|
+
char_count: bodyText.length,
|
|
1094
|
+
images_count: $('img').length,
|
|
1095
|
+
videos_count: $('video, iframe[src*="youtube"], iframe[src*="vimeo"]').length,
|
|
1096
|
+
internal_links: $('a[href^="/"]').length,
|
|
1097
|
+
external_links: $('a[href^="http"]').not(`a[href*="${new URL(url).hostname}"]`).length,
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1100
|
+
if (depth === "comprehensive") {
|
|
1101
|
+
// 키워드 분석
|
|
495
1102
|
const text = $('body').text().toLowerCase();
|
|
496
|
-
const
|
|
1103
|
+
const koreanWords = text.match(/[\uAC00-\uD7AF]{2,}/g) || [];
|
|
497
1104
|
const wordFreq = {};
|
|
498
|
-
|
|
499
|
-
if (word.length
|
|
1105
|
+
koreanWords.forEach(word => {
|
|
1106
|
+
if (word.length >= 2)
|
|
500
1107
|
wordFreq[word] = (wordFreq[word] || 0) + 1;
|
|
501
1108
|
});
|
|
502
|
-
analysis.
|
|
503
|
-
.
|
|
504
|
-
|
|
505
|
-
|
|
1109
|
+
analysis.keyword_analysis = {
|
|
1110
|
+
top_keywords: Object.entries(wordFreq)
|
|
1111
|
+
.sort((a, b) => b[1] - a[1])
|
|
1112
|
+
.slice(0, 30)
|
|
1113
|
+
.map(([word, count]) => ({ word, count, density: ((count / koreanWords.length) * 100).toFixed(2) + '%' })),
|
|
1114
|
+
total_keywords: koreanWords.length,
|
|
1115
|
+
};
|
|
1116
|
+
// 콘텐츠 구조 분석
|
|
1117
|
+
analysis.content_structure = {
|
|
1118
|
+
has_toc: $('[class*="toc"], [class*="table-of-contents"], #toc').length > 0,
|
|
1119
|
+
has_faq: $('[class*="faq"], [itemtype*="FAQPage"]').length > 0,
|
|
1120
|
+
has_author: $('[class*="author"], [rel="author"]').length > 0,
|
|
1121
|
+
schema_types: $('[itemtype]').map((_, el) => $(el).attr('itemtype')).get(),
|
|
1122
|
+
};
|
|
506
1123
|
}
|
|
507
1124
|
results.push(analysis);
|
|
508
1125
|
}
|
|
509
1126
|
catch (error) {
|
|
510
|
-
results.push({ url, error:
|
|
1127
|
+
results.push({ url, error: `분석 실패: ${error.message || '알 수 없는 오류'}` });
|
|
511
1128
|
}
|
|
512
1129
|
}
|
|
1130
|
+
// 전략 추출
|
|
1131
|
+
let strategyInsights = null;
|
|
1132
|
+
if (extractStrategy && results.filter(r => !r.error).length > 0) {
|
|
1133
|
+
strategyInsights = {
|
|
1134
|
+
common_patterns: [
|
|
1135
|
+
"H2 태그로 주요 섹션 구분",
|
|
1136
|
+
"리스트형 콘텐츠 선호",
|
|
1137
|
+
"이미지와 텍스트 적절히 배합",
|
|
1138
|
+
],
|
|
1139
|
+
average_metrics: {
|
|
1140
|
+
avg_word_count: Math.round(results.filter(r => r.content_stats)
|
|
1141
|
+
.reduce((sum, r) => sum + r.content_stats.word_count, 0) /
|
|
1142
|
+
results.filter(r => r.content_stats).length || 1),
|
|
1143
|
+
avg_images: Math.round(results.filter(r => r.content_stats)
|
|
1144
|
+
.reduce((sum, r) => sum + r.content_stats.images_count, 0) /
|
|
1145
|
+
results.filter(r => r.content_stats).length || 1),
|
|
1146
|
+
},
|
|
1147
|
+
opportunities: [
|
|
1148
|
+
"비디오 콘텐츠 추가로 차별화",
|
|
1149
|
+
"FAQ 섹션 추가로 검색 노출 강화",
|
|
1150
|
+
"더 상세한 가이드로 경쟁 우위",
|
|
1151
|
+
],
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
513
1154
|
return {
|
|
514
1155
|
analyzed_at: new Date().toISOString(),
|
|
1156
|
+
analysis_depth: depth,
|
|
515
1157
|
total_urls: urls.length,
|
|
516
1158
|
successful: results.filter(r => !r.error).length,
|
|
517
1159
|
results,
|
|
518
|
-
|
|
519
|
-
"경쟁사 콘텐츠의 평균 길이를 참고하세요",
|
|
520
|
-
"자주 사용되는 키워드를 파악하세요",
|
|
521
|
-
"제목과 메타 설명의 패턴을 분석하세요",
|
|
522
|
-
],
|
|
1160
|
+
strategy_insights: strategyInsights,
|
|
523
1161
|
};
|
|
524
1162
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
1163
|
+
// 고급 바이럴 예측
|
|
1164
|
+
function predictAdvancedViralScore(title, description, platform, hashtags, contentType) {
|
|
1165
|
+
// 다양한 바이럴 요소 분석
|
|
1166
|
+
const factors = {
|
|
1167
|
+
// 감정 요소
|
|
1168
|
+
emotional: {
|
|
1169
|
+
positive: /최고|완벽|대박|필수|추천|굿|좋은|행복|성공|감동/g,
|
|
1170
|
+
negative: /충격|경악|실화|심각|위험|주의|경고/g,
|
|
1171
|
+
curiosity: /비밀|숨겨진|몰랐던|알려지지|진실|실체/g,
|
|
1172
|
+
},
|
|
1173
|
+
// 구조 요소
|
|
1174
|
+
structural: {
|
|
1175
|
+
numbers: /\d+/g,
|
|
1176
|
+
questions: /\?/g,
|
|
1177
|
+
brackets: /\[|\]/g,
|
|
1178
|
+
emphasis: /!/g,
|
|
1179
|
+
},
|
|
1180
|
+
// 긴급성
|
|
1181
|
+
urgency: /지금|당장|오늘|한정|마감|급|바로|즉시|놓치면/g,
|
|
1182
|
+
// 사회적 증거
|
|
1183
|
+
socialProof: /만명|팔로워|구독자|조회수|리뷰|후기|인증|추천|화제/g,
|
|
1184
|
+
// 실용성
|
|
1185
|
+
utility: /방법|팁|가이드|정리|비법|노하우|꿀팁|해결/g,
|
|
1186
|
+
};
|
|
1187
|
+
let score = 50;
|
|
1188
|
+
const analysis = {};
|
|
1189
|
+
// 감정 분석
|
|
1190
|
+
const positiveMatches = (title + description).match(factors.emotional.positive);
|
|
1191
|
+
const negativeMatches = (title + description).match(factors.emotional.negative);
|
|
1192
|
+
const curiosityMatches = (title + description).match(factors.emotional.curiosity);
|
|
1193
|
+
if (positiveMatches) {
|
|
1194
|
+
score += Math.min(positiveMatches.length * 5, 15);
|
|
1195
|
+
}
|
|
1196
|
+
if (negativeMatches) {
|
|
1197
|
+
score += Math.min(negativeMatches.length * 4, 12);
|
|
1198
|
+
}
|
|
1199
|
+
if (curiosityMatches) {
|
|
1200
|
+
score += Math.min(curiosityMatches.length * 6, 18);
|
|
1201
|
+
}
|
|
1202
|
+
analysis.emotional_triggers = {
|
|
1203
|
+
positive: positiveMatches?.length || 0,
|
|
1204
|
+
negative: negativeMatches?.length || 0,
|
|
1205
|
+
curiosity: curiosityMatches?.length || 0,
|
|
533
1206
|
};
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
1207
|
+
// 구조 분석
|
|
1208
|
+
const hasNumbers = factors.structural.numbers.test(title);
|
|
1209
|
+
const hasQuestion = factors.structural.questions.test(title);
|
|
1210
|
+
const hasBrackets = factors.structural.brackets.test(title);
|
|
1211
|
+
const hasEmphasis = factors.structural.emphasis.test(title);
|
|
1212
|
+
if (hasNumbers)
|
|
539
1213
|
score += 10;
|
|
540
|
-
if (
|
|
1214
|
+
if (hasQuestion)
|
|
541
1215
|
score += 8;
|
|
542
|
-
if (
|
|
543
|
-
score +=
|
|
544
|
-
if (
|
|
1216
|
+
if (hasBrackets)
|
|
1217
|
+
score += 5;
|
|
1218
|
+
if (hasEmphasis)
|
|
1219
|
+
score += 3;
|
|
1220
|
+
analysis.structural_elements = { hasNumbers, hasQuestion, hasBrackets, hasEmphasis };
|
|
1221
|
+
// 긴급성
|
|
1222
|
+
if (factors.urgency.test(title + description))
|
|
1223
|
+
score += 8;
|
|
1224
|
+
// 사회적 증거
|
|
1225
|
+
if (factors.socialProof.test(title + description))
|
|
545
1226
|
score += 10;
|
|
546
|
-
//
|
|
547
|
-
if (
|
|
1227
|
+
// 실용성
|
|
1228
|
+
if (factors.utility.test(title + description))
|
|
1229
|
+
score += 7;
|
|
1230
|
+
// 제목 길이 최적화
|
|
1231
|
+
if (title.length >= 20 && title.length <= 45)
|
|
548
1232
|
score += 5;
|
|
1233
|
+
else if (title.length > 60)
|
|
1234
|
+
score -= 5;
|
|
549
1235
|
// 해시태그 분석
|
|
550
1236
|
if (hashtags.length >= 5 && hashtags.length <= 15)
|
|
551
1237
|
score += 5;
|
|
552
|
-
|
|
1238
|
+
else if (hashtags.length > 25)
|
|
1239
|
+
score -= 3;
|
|
1240
|
+
// 콘텐츠 타입 보너스
|
|
1241
|
+
const typeBonus = {
|
|
1242
|
+
video: 10,
|
|
1243
|
+
reel: 15,
|
|
1244
|
+
carousel: 8,
|
|
1245
|
+
image: 5,
|
|
1246
|
+
text: 0,
|
|
1247
|
+
};
|
|
1248
|
+
score += typeBonus[contentType] || 0;
|
|
1249
|
+
// 플랫폼별 조정
|
|
1250
|
+
const platformMultiplier = {
|
|
1251
|
+
tiktok: 1.2,
|
|
1252
|
+
instagram: 1.1,
|
|
1253
|
+
youtube: 1.0,
|
|
1254
|
+
twitter: 0.9,
|
|
1255
|
+
blog: 0.8,
|
|
1256
|
+
};
|
|
1257
|
+
score = Math.round(score * (platformMultiplier[platform] || 1));
|
|
1258
|
+
score = Math.min(Math.max(score, 0), 100);
|
|
1259
|
+
// 등급 결정
|
|
1260
|
+
const grade = score >= 85 ? "S (바이럴 예상)"
|
|
1261
|
+
: score >= 70 ? "A (높은 잠재력)"
|
|
1262
|
+
: score >= 55 ? "B (양호)"
|
|
1263
|
+
: score >= 40 ? "C (개선 필요)"
|
|
1264
|
+
: "D (재검토 필요)";
|
|
1265
|
+
// 개선 제안
|
|
553
1266
|
const improvements = [];
|
|
554
|
-
if (!
|
|
1267
|
+
if (!hasNumbers)
|
|
555
1268
|
improvements.push("숫자를 추가하세요 (예: '5가지 방법')");
|
|
556
|
-
if (!
|
|
557
|
-
improvements.push("
|
|
558
|
-
if (
|
|
559
|
-
improvements.push("
|
|
1269
|
+
if (!curiosityMatches)
|
|
1270
|
+
improvements.push("호기심을 자극하는 표현을 추가하세요");
|
|
1271
|
+
if (!hasQuestion && !hasEmphasis)
|
|
1272
|
+
improvements.push("질문형이나 감탄형을 시도해보세요");
|
|
1273
|
+
if (title.length > 50)
|
|
1274
|
+
improvements.push("제목을 50자 이내로 줄이세요");
|
|
560
1275
|
if (hashtags.length < 5)
|
|
561
|
-
improvements.push("해시태그를 5개 이상 추가하세요");
|
|
1276
|
+
improvements.push("관련 해시태그를 5개 이상 추가하세요");
|
|
1277
|
+
if (contentType === "text")
|
|
1278
|
+
improvements.push("이미지나 영상을 추가하면 참여율이 높아집니다");
|
|
562
1279
|
return {
|
|
563
1280
|
title,
|
|
1281
|
+
content_type: contentType,
|
|
1282
|
+
platform,
|
|
564
1283
|
viral_score: score,
|
|
565
|
-
grade
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
1284
|
+
grade,
|
|
1285
|
+
analysis: {
|
|
1286
|
+
...analysis,
|
|
1287
|
+
title_length: title.length,
|
|
1288
|
+
hashtag_count: hashtags.length,
|
|
1289
|
+
urgency_detected: factors.urgency.test(title + description),
|
|
1290
|
+
social_proof_detected: factors.socialProof.test(title + description),
|
|
1291
|
+
utility_detected: factors.utility.test(title + description),
|
|
571
1292
|
},
|
|
572
1293
|
improvements,
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
1294
|
+
predicted_performance: {
|
|
1295
|
+
reach: score >= 70 ? "높음" : score >= 50 ? "보통" : "낮음",
|
|
1296
|
+
engagement: score >= 75 ? "높음" : score >= 55 ? "보통" : "낮음",
|
|
1297
|
+
shares: score >= 80 ? "높음" : score >= 60 ? "보통" : "낮음",
|
|
1298
|
+
saves: score >= 65 ? "높음" : score >= 45 ? "보통" : "낮음",
|
|
1299
|
+
},
|
|
1300
|
+
optimized_title_suggestions: [
|
|
1301
|
+
hasNumbers ? null : `${title.slice(0, 20)}... 5가지 방법`,
|
|
1302
|
+
hasQuestion ? null : `${title}?`,
|
|
1303
|
+
`[필독] ${title}`,
|
|
1304
|
+
].filter(Boolean).slice(0, 3),
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
// 뉴스 분석
|
|
1308
|
+
async function analyzeKoreanNews(category, timeRange, extractKeywords) {
|
|
1309
|
+
// 카테고리별 뉴스 키워드 시뮬레이션
|
|
1310
|
+
const newsData = {
|
|
1311
|
+
general: [
|
|
1312
|
+
{ headline: "AI 기술 발전과 일자리 변화", source: "종합", sentiment: "neutral" },
|
|
1313
|
+
{ headline: "글로벌 경제 동향 분석", source: "경제", sentiment: "neutral" },
|
|
1314
|
+
{ headline: "2025년 트렌드 전망", source: "라이프", sentiment: "positive" },
|
|
1315
|
+
],
|
|
1316
|
+
tech: [
|
|
1317
|
+
{ headline: "ChatGPT 신기능 출시", source: "테크", sentiment: "positive" },
|
|
1318
|
+
{ headline: "애플 신제품 발표", source: "테크", sentiment: "positive" },
|
|
1319
|
+
{ headline: "사이버 보안 위협 증가", source: "테크", sentiment: "negative" },
|
|
1320
|
+
],
|
|
1321
|
+
economy: [
|
|
1322
|
+
{ headline: "한국은행 금리 결정", source: "경제", sentiment: "neutral" },
|
|
1323
|
+
{ headline: "부동산 시장 동향", source: "경제", sentiment: "neutral" },
|
|
1324
|
+
{ headline: "환율 변동성 확대", source: "경제", sentiment: "negative" },
|
|
1325
|
+
],
|
|
1326
|
+
entertainment: [
|
|
1327
|
+
{ headline: "K-POP 글로벌 인기", source: "연예", sentiment: "positive" },
|
|
1328
|
+
{ headline: "넷플릭스 신작 화제", source: "연예", sentiment: "positive" },
|
|
1329
|
+
{ headline: "연예계 이슈", source: "연예", sentiment: "neutral" },
|
|
1330
|
+
],
|
|
1331
|
+
};
|
|
1332
|
+
const news = newsData[category] || newsData.general;
|
|
1333
|
+
const keywords = extractKeywords ? [
|
|
1334
|
+
{ keyword: "AI", frequency: 45, trend: "상승" },
|
|
1335
|
+
{ keyword: "경제", frequency: 38, trend: "유지" },
|
|
1336
|
+
{ keyword: "트렌드", frequency: 32, trend: "상승" },
|
|
1337
|
+
{ keyword: "투자", frequency: 28, trend: "상승" },
|
|
1338
|
+
{ keyword: "기술", frequency: 25, trend: "상승" },
|
|
1339
|
+
] : [];
|
|
1340
|
+
return {
|
|
1341
|
+
category,
|
|
1342
|
+
time_range: timeRange,
|
|
1343
|
+
analyzed_at: new Date().toISOString(),
|
|
1344
|
+
top_news: news,
|
|
1345
|
+
extracted_keywords: keywords,
|
|
1346
|
+
sentiment_summary: {
|
|
1347
|
+
positive: "35%",
|
|
1348
|
+
neutral: "50%",
|
|
1349
|
+
negative: "15%",
|
|
1350
|
+
},
|
|
1351
|
+
content_opportunities: [
|
|
1352
|
+
"AI 관련 콘텐츠 수요 증가 - 입문자 가이드 추천",
|
|
1353
|
+
"경제 불안 심리 반영 - 재테크 팁 콘텐츠",
|
|
1354
|
+
"K-콘텐츠 글로벌 화제 - 한류 관련 콘텐츠",
|
|
1355
|
+
],
|
|
1356
|
+
trending_topics: news.map(n => n.headline),
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
// 해시태그 전략 생성
|
|
1360
|
+
function generateAdvancedHashtagStrategy(topic, platform, count, includeKorean, includeEnglish) {
|
|
1361
|
+
const koreanHashtags = [
|
|
1362
|
+
{ tag: `#${topic.replace(/\s/g, '')}`, type: "main", popularity: "높음" },
|
|
1363
|
+
{ tag: `#${topic}팁`, type: "related", popularity: "중간" },
|
|
1364
|
+
{ tag: `#${topic}추천`, type: "related", popularity: "높음" },
|
|
1365
|
+
{ tag: "#일상", type: "general", popularity: "매우 높음" },
|
|
1366
|
+
{ tag: "#데일리", type: "general", popularity: "매우 높음" },
|
|
1367
|
+
{ tag: "#소통", type: "engagement", popularity: "높음" },
|
|
1368
|
+
{ tag: "#맞팔", type: "engagement", popularity: "높음" },
|
|
1369
|
+
{ tag: "#좋아요", type: "engagement", popularity: "매우 높음" },
|
|
1370
|
+
{ tag: "#인스타그램", type: "platform", popularity: "매우 높음" },
|
|
1371
|
+
{ tag: "#정보공유", type: "content", popularity: "중간" },
|
|
1372
|
+
{ tag: "#꿀팁", type: "content", popularity: "높음" },
|
|
1373
|
+
{ tag: "#추천", type: "content", popularity: "높음" },
|
|
1374
|
+
{ tag: "#리뷰", type: "content", popularity: "높음" },
|
|
1375
|
+
{ tag: "#브이로그", type: "format", popularity: "높음" },
|
|
1376
|
+
{ tag: "#2025", type: "time", popularity: "중간" },
|
|
1377
|
+
];
|
|
1378
|
+
const englishHashtags = [
|
|
1379
|
+
{ tag: "#instagood", type: "general", popularity: "매우 높음" },
|
|
1380
|
+
{ tag: "#photooftheday", type: "general", popularity: "매우 높음" },
|
|
1381
|
+
{ tag: "#love", type: "emotion", popularity: "매우 높음" },
|
|
1382
|
+
{ tag: "#beautiful", type: "emotion", popularity: "높음" },
|
|
1383
|
+
{ tag: "#happy", type: "emotion", popularity: "높음" },
|
|
1384
|
+
{ tag: "#followme", type: "engagement", popularity: "높음" },
|
|
1385
|
+
{ tag: "#like4like", type: "engagement", popularity: "중간" },
|
|
1386
|
+
{ tag: "#style", type: "lifestyle", popularity: "높음" },
|
|
1387
|
+
{ tag: "#lifestyle", type: "lifestyle", popularity: "높음" },
|
|
1388
|
+
{ tag: "#tips", type: "content", popularity: "중간" },
|
|
1389
|
+
];
|
|
1390
|
+
let allHashtags = [];
|
|
1391
|
+
if (includeKorean)
|
|
1392
|
+
allHashtags = [...allHashtags, ...koreanHashtags];
|
|
1393
|
+
if (includeEnglish)
|
|
1394
|
+
allHashtags = [...allHashtags, ...englishHashtags];
|
|
1395
|
+
// 플랫폼별 최적화
|
|
1396
|
+
const platformLimits = {
|
|
1397
|
+
instagram: 30,
|
|
1398
|
+
tiktok: 5,
|
|
1399
|
+
youtube: 15,
|
|
1400
|
+
twitter: 5,
|
|
1401
|
+
threads: 10,
|
|
1402
|
+
};
|
|
1403
|
+
const recommendedCount = Math.min(count, platformLimits[platform] || 20);
|
|
1404
|
+
return {
|
|
1405
|
+
topic,
|
|
1406
|
+
platform,
|
|
1407
|
+
strategy: {
|
|
1408
|
+
total_hashtags: recommendedCount,
|
|
1409
|
+
mix_ratio: {
|
|
1410
|
+
main_keyword: "10%",
|
|
1411
|
+
related: "30%",
|
|
1412
|
+
general: "30%",
|
|
1413
|
+
engagement: "20%",
|
|
1414
|
+
trending: "10%",
|
|
1415
|
+
},
|
|
1416
|
+
},
|
|
1417
|
+
hashtags: {
|
|
1418
|
+
high_priority: allHashtags.filter(h => h.popularity === "매우 높음").slice(0, 5),
|
|
1419
|
+
medium_priority: allHashtags.filter(h => h.popularity === "높음").slice(0, 10),
|
|
1420
|
+
niche: allHashtags.filter(h => h.popularity === "중간").slice(0, 10),
|
|
577
1421
|
},
|
|
1422
|
+
all_hashtags: allHashtags.slice(0, recommendedCount).map(h => h.tag),
|
|
1423
|
+
copy_paste: allHashtags.slice(0, recommendedCount).map(h => h.tag).join(' '),
|
|
1424
|
+
tips: [
|
|
1425
|
+
`${platform}에서는 ${recommendedCount}개 이하의 해시태그를 권장합니다`,
|
|
1426
|
+
"인기 해시태그와 니치 해시태그를 섞어 사용하세요",
|
|
1427
|
+
"첫 댓글에 해시태그를 넣으면 캡션이 깔끔해집니다",
|
|
1428
|
+
"트렌딩 해시태그는 주기적으로 업데이트하세요",
|
|
1429
|
+
],
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
// 벤치마크 데이터
|
|
1433
|
+
function getBenchmarkData(category, platform, metric) {
|
|
1434
|
+
const benchmarks = {
|
|
1435
|
+
뷰티: {
|
|
1436
|
+
instagram: { avg_likes: "3,500", avg_comments: "120", avg_saves: "450", engagement_rate: "4.2%" },
|
|
1437
|
+
youtube: { avg_views: "25,000", avg_likes: "1,200", avg_comments: "85" },
|
|
1438
|
+
tiktok: { avg_views: "50,000", avg_likes: "3,000", avg_shares: "200" },
|
|
1439
|
+
},
|
|
1440
|
+
테크: {
|
|
1441
|
+
instagram: { avg_likes: "2,000", avg_comments: "80", avg_saves: "300", engagement_rate: "3.5%" },
|
|
1442
|
+
youtube: { avg_views: "35,000", avg_likes: "1,500", avg_comments: "120" },
|
|
1443
|
+
blog: { avg_views: "5,000", avg_time_on_page: "4분 30초" },
|
|
1444
|
+
},
|
|
1445
|
+
푸드: {
|
|
1446
|
+
instagram: { avg_likes: "4,500", avg_comments: "150", avg_saves: "600", engagement_rate: "5.1%" },
|
|
1447
|
+
youtube: { avg_views: "40,000", avg_likes: "2,000", avg_comments: "100" },
|
|
1448
|
+
tiktok: { avg_views: "80,000", avg_likes: "5,000", avg_shares: "400" },
|
|
1449
|
+
},
|
|
1450
|
+
라이프스타일: {
|
|
1451
|
+
instagram: { avg_likes: "3,000", avg_comments: "100", avg_saves: "350", engagement_rate: "3.8%" },
|
|
1452
|
+
youtube: { avg_views: "20,000", avg_likes: "900", avg_comments: "70" },
|
|
1453
|
+
},
|
|
1454
|
+
};
|
|
1455
|
+
const data = benchmarks[category] || benchmarks["라이프스타일"];
|
|
1456
|
+
const platformData = data[platform] || data["instagram"];
|
|
1457
|
+
return {
|
|
1458
|
+
category,
|
|
1459
|
+
platform,
|
|
1460
|
+
benchmark_data: platformData,
|
|
1461
|
+
industry_average: {
|
|
1462
|
+
engagement_rate: "3.5%",
|
|
1463
|
+
best_posting_frequency: "매일 1회",
|
|
1464
|
+
optimal_posting_time: "19:00-21:00",
|
|
1465
|
+
},
|
|
1466
|
+
performance_tiers: {
|
|
1467
|
+
top_10_percent: "벤치마크의 200% 이상",
|
|
1468
|
+
above_average: "벤치마크의 120-200%",
|
|
1469
|
+
average: "벤치마크의 80-120%",
|
|
1470
|
+
below_average: "벤치마크의 80% 미만",
|
|
1471
|
+
},
|
|
1472
|
+
tips_to_improve: [
|
|
1473
|
+
"일관된 포스팅 스케줄 유지",
|
|
1474
|
+
"고품질 비주얼 콘텐츠 제작",
|
|
1475
|
+
"커뮤니티와 적극적인 소통",
|
|
1476
|
+
"트렌드 키워드 활용",
|
|
1477
|
+
],
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
// A/B 테스트 변형 생성
|
|
1481
|
+
function generateABTestVariants(originalContent, element, count) {
|
|
1482
|
+
const variants = [];
|
|
1483
|
+
if (element === "title") {
|
|
1484
|
+
const patterns = [
|
|
1485
|
+
{ pattern: `[완벽정리] ${originalContent}`, style: "bracket" },
|
|
1486
|
+
{ pattern: `${originalContent} (이것만 보세요)`, style: "parenthesis" },
|
|
1487
|
+
{ pattern: `${originalContent}? 전문가가 답합니다`, style: "question" },
|
|
1488
|
+
{ pattern: `99%가 모르는 ${originalContent}`, style: "curiosity" },
|
|
1489
|
+
{ pattern: `${originalContent} 하는 5가지 방법`, style: "listicle" },
|
|
1490
|
+
{ pattern: `오늘부터 시작하는 ${originalContent}`, style: "action" },
|
|
1491
|
+
{ pattern: `${originalContent}: 초보자 필독`, style: "target" },
|
|
1492
|
+
{ pattern: `${originalContent}의 모든 것`, style: "comprehensive" },
|
|
1493
|
+
{ pattern: `당신이 몰랐던 ${originalContent}`, style: "reveal" },
|
|
1494
|
+
{ pattern: `${originalContent} 실패하지 않는 법`, style: "negative" },
|
|
1495
|
+
];
|
|
1496
|
+
for (let i = 0; i < Math.min(count, patterns.length); i++) {
|
|
1497
|
+
variants.push({
|
|
1498
|
+
variant_id: String.fromCharCode(65 + i),
|
|
1499
|
+
content: patterns[i].pattern,
|
|
1500
|
+
style: patterns[i].style,
|
|
1501
|
+
predicted_ctr: Math.floor(Math.random() * 30) + 70,
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
else if (element === "cta") {
|
|
1506
|
+
const ctas = [
|
|
1507
|
+
"지금 바로 확인하기",
|
|
1508
|
+
"더 알아보기",
|
|
1509
|
+
"무료로 시작하기",
|
|
1510
|
+
"자세히 보기",
|
|
1511
|
+
"놓치지 마세요",
|
|
1512
|
+
"지금 신청하기",
|
|
1513
|
+
"한정 기회",
|
|
1514
|
+
"바로 체험하기",
|
|
1515
|
+
];
|
|
1516
|
+
for (let i = 0; i < Math.min(count, ctas.length); i++) {
|
|
1517
|
+
variants.push({
|
|
1518
|
+
variant_id: String.fromCharCode(65 + i),
|
|
1519
|
+
content: ctas[i],
|
|
1520
|
+
style: i < 3 ? "action" : "urgency",
|
|
1521
|
+
predicted_click_rate: Math.floor(Math.random() * 20) + 60,
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
else if (element === "description") {
|
|
1526
|
+
const styles = ["concise", "detailed", "emotional", "factual", "story"];
|
|
1527
|
+
for (let i = 0; i < Math.min(count, 5); i++) {
|
|
1528
|
+
variants.push({
|
|
1529
|
+
variant_id: String.fromCharCode(65 + i),
|
|
1530
|
+
style: styles[i],
|
|
1531
|
+
content: `[${styles[i]} 스타일] ${originalContent}`,
|
|
1532
|
+
predicted_engagement: Math.floor(Math.random() * 25) + 65,
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
return {
|
|
1537
|
+
original: originalContent,
|
|
1538
|
+
element_tested: element,
|
|
1539
|
+
variants,
|
|
1540
|
+
testing_recommendation: {
|
|
1541
|
+
sample_size: "최소 1,000명 노출 후 판단",
|
|
1542
|
+
duration: "최소 7일",
|
|
1543
|
+
metrics_to_track: element === "title" ? ["CTR", "조회수"] : element === "cta" ? ["클릭율", "전환율"] : ["체류시간", "이탈율"],
|
|
1544
|
+
},
|
|
1545
|
+
statistical_note: "95% 신뢰구간 확보를 위해 충분한 데이터 수집 필요",
|
|
1546
|
+
};
|
|
1547
|
+
}
|
|
1548
|
+
// 시즌 콘텐츠 가이드
|
|
1549
|
+
function getSeasonalContentGuide(daysAhead, category) {
|
|
1550
|
+
const events = getUpcomingEvents(daysAhead);
|
|
1551
|
+
const filteredEvents = category === "all"
|
|
1552
|
+
? events
|
|
1553
|
+
: events.filter(e => e.type === category);
|
|
1554
|
+
const guide = filteredEvents.map(event => ({
|
|
1555
|
+
...event,
|
|
1556
|
+
content_preparation_timeline: {
|
|
1557
|
+
research: `D-${Math.max(event.days_until - 14, 1)}`,
|
|
1558
|
+
content_creation: `D-${Math.max(event.days_until - 7, 1)}`,
|
|
1559
|
+
publishing: `D-${Math.max(event.days_until - 3, 0)} ~ D-${event.days_until}`,
|
|
1560
|
+
follow_up: `D+1 ~ D+3`,
|
|
1561
|
+
},
|
|
1562
|
+
recommended_content_types: [
|
|
1563
|
+
"이벤트 관련 가이드",
|
|
1564
|
+
"시즌 추천 리스트",
|
|
1565
|
+
"타임라인 콘텐츠",
|
|
1566
|
+
"사용자 참여형 콘텐츠",
|
|
1567
|
+
],
|
|
1568
|
+
hashtag_suggestions: event.contentIdeas?.map((idea) => `#${idea.replace(/\s/g, '')}`) || [],
|
|
1569
|
+
}));
|
|
1570
|
+
return {
|
|
1571
|
+
period: `${daysAhead}일`,
|
|
1572
|
+
category,
|
|
1573
|
+
total_events: filteredEvents.length,
|
|
1574
|
+
events: guide,
|
|
1575
|
+
general_tips: [
|
|
1576
|
+
"주요 이벤트 2주 전에 콘텐츠 기획 시작",
|
|
1577
|
+
"이벤트 당일보다 1-3일 전 발행이 효과적",
|
|
1578
|
+
"이벤트 후 후기/정리 콘텐츠도 준비",
|
|
1579
|
+
"연관 키워드 미리 확보",
|
|
1580
|
+
],
|
|
1581
|
+
monthly_focus: getMonthlyFocus(),
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
function getMonthlyFocus() {
|
|
1585
|
+
const month = new Date().getMonth() + 1;
|
|
1586
|
+
const focuses = {
|
|
1587
|
+
1: { theme: "새해/신년", keywords: ["새해 계획", "신년 운세", "2025 트렌드"] },
|
|
1588
|
+
2: { theme: "발렌타인/겨울", keywords: ["발렌타인 선물", "커플", "초콜릿"] },
|
|
1589
|
+
3: { theme: "봄/신학기", keywords: ["봄맞이", "신학기", "화이트데이"] },
|
|
1590
|
+
4: { theme: "벚꽃/봄나들이", keywords: ["벚꽃명소", "봄 패션", "피크닉"] },
|
|
1591
|
+
5: { theme: "가정의 달", keywords: ["어버이날", "어린이날", "스승의날"] },
|
|
1592
|
+
6: { theme: "초여름/휴가", keywords: ["여름 휴가", "워케이션", "다이어트"] },
|
|
1593
|
+
7: { theme: "휴가 시즌", keywords: ["바캉스", "물놀이", "여행"] },
|
|
1594
|
+
8: { theme: "여름 끝/가을 준비", keywords: ["말복", "가을 신상", "처서"] },
|
|
1595
|
+
9: { theme: "추석/가을", keywords: ["추석 선물", "가을 패션", "단풍"] },
|
|
1596
|
+
10: { theme: "가을/할로윈", keywords: ["할로윈", "가을 나들이", "코스튬"] },
|
|
1597
|
+
11: { theme: "연말 준비", keywords: ["블프", "빼빼로데이", "연말 선물"] },
|
|
1598
|
+
12: { theme: "연말/크리스마스", keywords: ["크리스마스", "연말 파티", "송년회"] },
|
|
578
1599
|
};
|
|
1600
|
+
return focuses[month] || focuses[1];
|
|
579
1601
|
}
|
|
580
1602
|
// =============================================================================
|
|
581
1603
|
// Server Start
|
|
@@ -583,6 +1605,6 @@ function predictViralScore(title, description, platform, hashtags) {
|
|
|
583
1605
|
async function main() {
|
|
584
1606
|
const transport = new StdioServerTransport();
|
|
585
1607
|
await server.connect(transport);
|
|
586
|
-
console.error("Content Genie MCP Server running on stdio");
|
|
1608
|
+
console.error("Content Genie MCP Server v2.0 running on stdio");
|
|
587
1609
|
}
|
|
588
1610
|
main().catch(console.error);
|