@heripo/research-radar 1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,346 @@
1
+ import { UrlString, ParsedTarget, CrawlingTargetGroup, CrawlingTarget, UnscoredArticle, ArticleForUpdateByAnalysis, ArticleForGenerateContent, Newsletter, AppLogger, EmailService, EmailMessage, DateService as DateService$1, IsoDateString, TaskService as TaskService$1, AnalysisProvider as AnalysisProvider$1, ContentGenerateProvider as ContentGenerateProvider$1, HtmlTemplate, CrawlingProvider as CrawlingProvider$1 } from '@llm-newsletter-kit/core';
2
+ import { OpenAIProvider } from '@ai-sdk/openai';
3
+
4
+ /**
5
+ * Repository interface for task management
6
+ */
7
+ interface TaskRepository {
8
+ /**
9
+ * Create and save a new task
10
+ * @returns Created task ID
11
+ */
12
+ createTask(): Promise<number>;
13
+ /**
14
+ * Complete a task
15
+ * @param taskId Task ID to complete
16
+ */
17
+ completeTask(taskId: number): Promise<void>;
18
+ }
19
+ /**
20
+ * Repository interface for article management
21
+ */
22
+ interface ArticleRepository {
23
+ /**
24
+ * Find existing articles by URLs
25
+ * @param urls URLs to query
26
+ * @returns Previously saved articles
27
+ */
28
+ findByUrls(urls: UrlString[]): Promise<ParsedTarget[]>;
29
+ /**
30
+ * Save crawled articles
31
+ * @param articles Articles to save
32
+ * @param context Task context information
33
+ * @returns Number of saved articles
34
+ */
35
+ saveCrawledArticles<TaskId>(articles: ParsedTarget[], context: {
36
+ taskId: TaskId;
37
+ targetGroup: Omit<CrawlingTargetGroup, 'targets'>;
38
+ target: CrawlingTarget;
39
+ }): Promise<number>;
40
+ /**
41
+ * Find unscored articles (targets for analysis)
42
+ * @returns Articles without scores
43
+ */
44
+ findUnscoredArticles(): Promise<UnscoredArticle[]>;
45
+ /**
46
+ * Update article with analysis results
47
+ * @param article Article information to update
48
+ */
49
+ updateAnalysis(article: ArticleForUpdateByAnalysis): Promise<void>;
50
+ /**
51
+ * Find candidate articles for newsletter generation
52
+ * @returns Candidate articles
53
+ */
54
+ findCandidatesForNewsletter(): Promise<ArticleForGenerateContent[]>;
55
+ }
56
+ /**
57
+ * Repository interface for tag management
58
+ */
59
+ interface TagRepository {
60
+ /**
61
+ * Find all existing tags
62
+ * @returns Tag name list
63
+ */
64
+ findAllTags(): Promise<string[]>;
65
+ }
66
+ /**
67
+ * Repository interface for newsletter management
68
+ */
69
+ interface NewsletterRepository {
70
+ /**
71
+ * Get the next issue order number
72
+ * @returns Next issue order
73
+ */
74
+ getNextIssueOrder(): Promise<number>;
75
+ /**
76
+ * Save newsletter
77
+ * @param input - Input parameters
78
+ * @param input.newsletter - Newsletter data
79
+ * @param input.usedArticles - List of used articles
80
+ * @returns Saved newsletter ID
81
+ */
82
+ saveNewsletter(input: {
83
+ newsletter: Newsletter;
84
+ usedArticles: ArticleForGenerateContent[];
85
+ }): Promise<{
86
+ id: string | number;
87
+ }>;
88
+ }
89
+
90
+ /**
91
+ * This implementation is currently hardcoded to use OpenAI.
92
+ * To use a different LLM provider, you need to modify:
93
+ * - This file: Change `createOpenAI` import and initialization
94
+ * - src/providers/analysis.provider.ts: Change OpenAIProvider type and model names
95
+ * - src/providers/content-generate.provider.ts: Change OpenAIProvider type and model name
96
+ *
97
+ * For details on switching providers, see README.md section:
98
+ * "⚠️ Fork하여 나만의 뉴스레터 만들기 > 4. LLM 프로바이더 변경"
99
+ */
100
+
101
+ /**
102
+ * Preview newsletter configuration options
103
+ */
104
+ interface PreviewNewsletterOptions {
105
+ /** Function to fetch newsletter for preview */
106
+ fetchNewsletterForPreview: () => Promise<Newsletter>;
107
+ /** Email sending service */
108
+ emailService: EmailService;
109
+ /** Email message configuration (subject, html, text are auto-generated) */
110
+ emailMessage: Omit<EmailMessage, 'subject' | 'html' | 'text'>;
111
+ }
112
+ /**
113
+ * Newsletter generator dependencies interface
114
+ */
115
+ interface NewsletterGeneratorDependencies {
116
+ /** OpenAI API key */
117
+ openAIApiKey: string;
118
+ /** Task management repository */
119
+ taskRepository: TaskRepository;
120
+ /** Article management repository */
121
+ articleRepository: ArticleRepository;
122
+ /** Tag management repository */
123
+ tagRepository: TagRepository;
124
+ /** Newsletter management repository */
125
+ newsletterRepository: NewsletterRepository;
126
+ /** Logger (optional) */
127
+ logger?: AppLogger;
128
+ /** Preview email configuration (optional) */
129
+ previewNewsletter?: PreviewNewsletterOptions;
130
+ }
131
+ /**
132
+ * Newsletter generation execution function
133
+ *
134
+ * @param dependencies - Repository implementations and options
135
+ * @returns Generated newsletter ID
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * const newsletterId = await generateNewsletter({
140
+ * openAIApiKey: process.env.OPENAI_API_KEY,
141
+ * taskRepository: new PrismaTaskRepository(prisma),
142
+ * articleRepository: new PrismaArticleRepository(prisma),
143
+ * tagRepository: new PrismaTagRepository(prisma),
144
+ * newsletterRepository: new PrismaNewsletterRepository(prisma),
145
+ * });
146
+ * ```
147
+ */
148
+ declare function generateNewsletter(dependencies: NewsletterGeneratorDependencies): Promise<string | number | null>;
149
+
150
+ /**
151
+ * Date service implementation
152
+ * - Provides current date and display date strings
153
+ */
154
+ declare class DateService implements DateService$1 {
155
+ /**
156
+ * Get current date in ISO format (YYYY-MM-DD)
157
+ * @returns ISO date string (e.g., "2024-10-15")
158
+ */
159
+ getCurrentISODateString(): IsoDateString;
160
+ /**
161
+ * Get formatted display date string
162
+ * @returns Korean formatted date (e.g., "2024년 10월 15일")
163
+ */
164
+ getDisplayDateString(): string;
165
+ }
166
+
167
+ /**
168
+ * Task service implementation
169
+ * - Manages newsletter generation task lifecycle (start/end)
170
+ * - Prevents duplicate execution
171
+ */
172
+ declare class TaskService implements TaskService$1<number> {
173
+ private readonly taskRepository;
174
+ private currentTaskId;
175
+ constructor(taskRepository: TaskRepository);
176
+ /**
177
+ * Start a new task
178
+ * @throws Error if a task is already running
179
+ * @returns Task ID
180
+ */
181
+ start(): Promise<number>;
182
+ /**
183
+ * End the current task
184
+ * @throws Error if no task is running
185
+ */
186
+ end(): Promise<void>;
187
+ }
188
+
189
+ /**
190
+ * Analysis provider implementation
191
+ * - LLM-based article analysis
192
+ * - Tag classification, image analysis, importance scoring
193
+ */
194
+ declare class AnalysisProvider implements AnalysisProvider$1 {
195
+ private readonly openai;
196
+ private readonly articleRepository;
197
+ private readonly tagRepository;
198
+ classifyTagOptions: {
199
+ model: ReturnType<OpenAIProvider>;
200
+ };
201
+ analyzeImagesOptions: {
202
+ model: ReturnType<OpenAIProvider>;
203
+ };
204
+ determineScoreOptions: {
205
+ model: ReturnType<OpenAIProvider>;
206
+ minimumImportanceScoreRules: Array<{
207
+ targetUrl: string;
208
+ minScore: number;
209
+ }>;
210
+ };
211
+ constructor(openai: OpenAIProvider, articleRepository: ArticleRepository, tagRepository: TagRepository);
212
+ /**
213
+ * Fetch articles that haven't been scored yet
214
+ * @returns Unscored articles awaiting analysis
215
+ */
216
+ fetchUnscoredArticles(): Promise<UnscoredArticle[]>;
217
+ /**
218
+ * Fetch all existing tags for classification
219
+ * @returns List of tag names
220
+ */
221
+ fetchTags(): Promise<string[]>;
222
+ /**
223
+ * Update article with analysis results (tags, image analysis, importance score)
224
+ * @param article - Article with analysis data
225
+ */
226
+ update(article: ArticleForUpdateByAnalysis): Promise<void>;
227
+ }
228
+
229
+ /**
230
+ * Content generation provider implementation
231
+ * - LLM-based newsletter content generation
232
+ * - HTML template provisioning
233
+ * - Newsletter persistence
234
+ */
235
+ declare class ContentGenerateProvider implements ContentGenerateProvider$1 {
236
+ private readonly openai;
237
+ private readonly articleRepository;
238
+ private readonly newsletterRepository;
239
+ private _issueOrder;
240
+ model: ReturnType<OpenAIProvider>;
241
+ constructor(openai: OpenAIProvider, articleRepository: ArticleRepository, newsletterRepository: NewsletterRepository);
242
+ /** LLM temperature setting for content generation */
243
+ temperature: number;
244
+ /** Newsletter brand name */
245
+ newsletterBrandName: string;
246
+ /** Subscribe page URL */
247
+ subscribePageUrl: UrlString;
248
+ /** Publication criteria (minimum article count, priority score threshold) */
249
+ publicationCriteria: {
250
+ minimumArticleCountForIssue: number;
251
+ priorityArticleScoreThreshold: number;
252
+ };
253
+ /**
254
+ * Get current issue order
255
+ * @throws Error if issue order not initialized
256
+ */
257
+ get issueOrder(): number;
258
+ /**
259
+ * Initialize issue order before newsletter generation
260
+ */
261
+ initializeIssueOrder(): Promise<void>;
262
+ /**
263
+ * Fetch candidate articles for newsletter generation
264
+ * @returns Articles eligible for inclusion in the newsletter
265
+ */
266
+ fetchArticleCandidates(): Promise<ArticleForGenerateContent[]>;
267
+ /** HTML template with markers for title and content injection */
268
+ htmlTemplate: HtmlTemplate;
269
+ /**
270
+ * Save generated newsletter to the repository
271
+ * @param input - Newsletter data and used articles
272
+ * @returns Saved newsletter ID
273
+ */
274
+ saveNewsletter(input: {
275
+ newsletter: Newsletter;
276
+ usedArticles: ArticleForGenerateContent[];
277
+ }): Promise<{
278
+ id: string | number;
279
+ }>;
280
+ }
281
+
282
+ /**
283
+ * Crawling provider implementation
284
+ * - Defines crawling targets
285
+ * - Saves crawling results
286
+ * - Fetches existing articles
287
+ */
288
+ declare class CrawlingProvider implements CrawlingProvider$1 {
289
+ private readonly articleRepository;
290
+ /** Maximum number of concurrent crawling operations */
291
+ maxConcurrency: number;
292
+ constructor(articleRepository: ArticleRepository);
293
+ /** Crawling target groups configuration */
294
+ crawlingTargetGroups: CrawlingTargetGroup[];
295
+ /**
296
+ * Fetch existing articles by URLs to avoid duplicate crawling
297
+ * @param articleUrls - URLs to check
298
+ * @returns Existing articles
299
+ */
300
+ fetchExistingArticlesByUrls(articleUrls: UrlString[]): Promise<ParsedTarget[]>;
301
+ /**
302
+ * Save crawled articles to the repository
303
+ * @param articles - Articles to save
304
+ * @param context - Task context (task ID, target group, target)
305
+ * @returns Number of saved articles
306
+ */
307
+ saveCrawledArticles<TaskId>(articles: ParsedTarget[], context: {
308
+ taskId: TaskId;
309
+ targetGroup: Omit<CrawlingTargetGroup, 'targets'>;
310
+ target: CrawlingTarget;
311
+ }): Promise<number>;
312
+ }
313
+
314
+ declare const crawlingTargetGroups: CrawlingTargetGroup[];
315
+
316
+ /**
317
+ * Newsletter content configuration
318
+ */
319
+ declare const contentOptions: {
320
+ outputLanguage: string;
321
+ expertField: string[];
322
+ };
323
+ /**
324
+ * Newsletter brand configuration
325
+ */
326
+ declare const newsletterConfig: {
327
+ brandName: string;
328
+ subscribePageUrl: string;
329
+ publicationCriteria: {
330
+ minimumArticleCountForIssue: number;
331
+ priorityArticleScoreThreshold: number;
332
+ };
333
+ };
334
+ /**
335
+ * LLM configuration
336
+ */
337
+ declare const llmConfig: {
338
+ maxRetries: number;
339
+ chainStopAfterAttempt: number;
340
+ generation: {
341
+ temperature: number;
342
+ };
343
+ };
344
+
345
+ export { AnalysisProvider, ContentGenerateProvider, CrawlingProvider, DateService, TaskService, contentOptions, crawlingTargetGroups, generateNewsletter, llmConfig, newsletterConfig };
346
+ export type { ArticleRepository, NewsletterGeneratorDependencies, NewsletterRepository, PreviewNewsletterOptions, TagRepository, TaskRepository };