@heripo/research-radar 2.3.1 → 2.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -8
- package/dist/index.cjs +2 -2
- package/dist/index.js +2 -2
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ An AI-powered newsletter service for Korean cultural heritage. Built on [`@llm-n
|
|
|
24
24
|
- Type-safe TypeScript with strict interfaces
|
|
25
25
|
- Provider pattern for swapping components (Crawling/Analysis/Content/Email)
|
|
26
26
|
- 66 crawling targets across heritage agencies, museums, academic societies
|
|
27
|
-
- LLM
|
|
27
|
+
- Dual LLM providers: OpenAI GPT-5 (analysis) + Google Gemini (content generation)
|
|
28
28
|
- Built-in retries, chain options, preview emails
|
|
29
29
|
|
|
30
30
|
**Links**: [Live service](https://heripo.com/research-radar/subscribe) • [Newsletter example](https://heripo.com/research-radar-newsletter-example.html) • [Core engine](https://github.com/heripo-lab/llm-newsletter-kit-core)
|
|
@@ -69,7 +69,7 @@ For academic publications:
|
|
|
69
69
|
npm install @heripo/research-radar @llm-newsletter-kit/core
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
**Requirements**: Node.js >= 22, OpenAI API key
|
|
72
|
+
**Requirements**: Node.js >= 22, OpenAI API key, Google Generative AI API key
|
|
73
73
|
|
|
74
74
|
**Note**: `@llm-newsletter-kit/core` is a peer dependency and must be installed separately.
|
|
75
75
|
|
|
@@ -80,6 +80,7 @@ import { generateNewsletter } from '@heripo/research-radar';
|
|
|
80
80
|
|
|
81
81
|
const newsletterId = await generateNewsletter({
|
|
82
82
|
openAIApiKey: process.env.OPENAI_API_KEY,
|
|
83
|
+
googleGenerativeAIApiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
|
|
83
84
|
|
|
84
85
|
// Implement these repository interfaces (see src/types/dependencies.ts)
|
|
85
86
|
taskRepository: {
|
|
@@ -104,8 +105,11 @@ const newsletterId = await generateNewsletter({
|
|
|
104
105
|
saveNewsletter: async (data) => db.newsletters.save(data),
|
|
105
106
|
},
|
|
106
107
|
|
|
107
|
-
// Optional:
|
|
108
|
+
// Optional parameters:
|
|
108
109
|
logger: console,
|
|
110
|
+
publishDate: '2026-02-20', // Override publication date (ISO format)
|
|
111
|
+
templateOptions: { /* ... */ }, // Newsletter template customization
|
|
112
|
+
customFetch: proxyFetch, // Custom fetch for proxy-based crawling
|
|
109
113
|
previewNewsletter: {
|
|
110
114
|
fetchNewsletterForPreview: async () => db.newsletters.latest(),
|
|
111
115
|
emailService: resendEmailService,
|
|
@@ -135,7 +139,7 @@ Uses the **Provider-Service pattern** from `@llm-newsletter-kit/core`. See [core
|
|
|
135
139
|
|
|
136
140
|
**Parsers** (`src/parsers/`): Custom extractors per organization
|
|
137
141
|
|
|
138
|
-
**
|
|
142
|
+
**Templates** (`src/templates/`): `newsletter-html.ts` (responsive email with light/dark mode), `welcome-html.ts` (`generateWelcomeHTML()`), `shared.ts` (shared HTML components)
|
|
139
143
|
|
|
140
144
|
## Development commands
|
|
141
145
|
|
|
@@ -158,6 +162,7 @@ A web-based tool for testing crawling parsers during development. Built with Exp
|
|
|
158
162
|
|
|
159
163
|
```bash
|
|
160
164
|
npm run dev:crawler # Start at http://localhost:3333
|
|
165
|
+
npm run dev:crawler:proxy # Start with proxy support (uses .env)
|
|
161
166
|
```
|
|
162
167
|
|
|
163
168
|
**Features**:
|
|
@@ -167,6 +172,26 @@ npm run dev:crawler # Start at http://localhost:3333
|
|
|
167
172
|
- 5-minute response cache (with skip/clear options)
|
|
168
173
|
- Timing info for fetch and parse operations
|
|
169
174
|
|
|
175
|
+
### Newsletter Preview
|
|
176
|
+
|
|
177
|
+
Preview rendered newsletter HTML with sample content.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npm run dev:newsletter-preview # Start at http://localhost:3334
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Query params: `?kras=true` (KRAS mode), `?krasNews=true` (KRAS news section), `?heripolabNews=true` (heripo lab news section)
|
|
184
|
+
|
|
185
|
+
### Welcome Email Preview
|
|
186
|
+
|
|
187
|
+
Preview rendered welcome email HTML.
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npm run dev:welcome-preview # Start at http://localhost:3335
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Query params: `?kras=true` (KRAS mode), `?name=홍길동` (subscriber name)
|
|
194
|
+
|
|
170
195
|
## 🤝 Contributing
|
|
171
196
|
|
|
172
197
|
You can use this project in two ways:
|
|
@@ -197,14 +222,14 @@ subscribeUrl: 'https://yourdomain.com/subscribe'
|
|
|
197
222
|
|
|
198
223
|
**4. Switch LLM provider** (optional):
|
|
199
224
|
|
|
200
|
-
|
|
201
|
-
- `src/newsletter-generator.ts`: Change `createOpenAI()` to your provider
|
|
225
|
+
Currently uses dual providers: **OpenAI** (analysis) + **Google Gemini** (content generation). To change:
|
|
226
|
+
- `src/newsletter-generator.ts`: Change `createOpenAI()` / `createGoogleGenerativeAI()` to your provider
|
|
202
227
|
- `src/providers/analysis.provider.ts`: Update model names (currently `gpt-5-mini`, `gpt-5.1`)
|
|
203
|
-
- `src/providers/content-generate.provider.ts`: Update model name
|
|
228
|
+
- `src/providers/content-generate.provider.ts`: Update model name (currently `gemini-3-pro-preview`)
|
|
204
229
|
|
|
205
230
|
Any [Vercel AI SDK provider](https://sdk.vercel.ai/providers) works.
|
|
206
231
|
|
|
207
|
-
**Search keywords**: `heripo`, `kimhongyeon`, `#D2691E`, `openai`, `gpt-5`
|
|
232
|
+
**Search keywords**: `heripo`, `kimhongyeon`, `#D2691E`, `openai`, `gpt-5`, `google`, `GoogleGenerativeAI`, `gemini`, `createGoogleGenerativeAI`
|
|
208
233
|
|
|
209
234
|
## Why Code-Based?
|
|
210
235
|
|
package/dist/index.cjs
CHANGED
|
@@ -2284,7 +2284,7 @@ ${options.krasNewsMarkdown}
|
|
|
2284
2284
|
fixMalformedUrls: true,
|
|
2285
2285
|
fixBoldSyntax: true,
|
|
2286
2286
|
convertStrikethrough: true,
|
|
2287
|
-
})
|
|
2287
|
+
}).replaceAll('%7B%7B%7BRESEND_UNSUBSCRIBE_URL%7D%7D%7D', '{{{RESEND_UNSUBSCRIBE_URL}}}')
|
|
2288
2288
|
: ''}
|
|
2289
2289
|
|
|
2290
2290
|
${options?.heripolabNewsMarkdown
|
|
@@ -2315,7 +2315,7 @@ ${options.heripolabNewsMarkdown}
|
|
|
2315
2315
|
</ul>
|
|
2316
2316
|
<hr style="border: 0; border-top: 2px solid #D2691E; margin: 32px 0;">
|
|
2317
2317
|
<h2 style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 24px; font-weight: bold; line-height: 1.3; color: #D2691E; margin: 0 0 16px 0; letter-spacing: -0.2px; border-left: 5px solid #D2691E; padding-left: 12px; background: none;">📅 발행 정책</h2>
|
|
2318
|
-
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.7; color: #444444; margin: 0 0 18px 0;"><strong>${options?.isKrasNewsletter ? '한국고고학회' : 'heripo 리서치 레이더'}</strong>는 매일 발행을 원칙으로 하되, 독자분들께 의미 있는 정보를 제공하기 위해 다음과 같은 발행 기준을 적용합니다:</p>
|
|
2318
|
+
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.7; color: #444444; margin: 0 0 18px 0;"><strong>${options?.isKrasNewsletter ? '한국고고학회 뉴스레터' : 'heripo 리서치 레이더'}</strong>는 매일 발행을 원칙으로 하되, 독자분들께 의미 있는 정보를 제공하기 위해 다음과 같은 발행 기준을 적용합니다:</p>
|
|
2319
2319
|
<ul style="padding-left: 24px; margin: 0 0 18px 0;">
|
|
2320
2320
|
<li style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.7; color: #444444; margin: 0 0 18px 0; margin-bottom: 8px;"><strong>정상 발행</strong>: 새로운 소식이 ${newsletterConfig.publicationCriteria.minimumArticleCountForIssue + 1}개 이상이거나, ${newsletterConfig.publicationCriteria.minimumArticleCountForIssue}개 이하여도 중요도 ${newsletterConfig.publicationCriteria.priorityArticleScoreThreshold}점 이상의 핵심 소식이 포함된 경우</li>
|
|
2321
2321
|
<li style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.7; color: #444444; margin: 0 0 18px 0; margin-bottom: 8px;"><strong>이월 발행</strong>: 새로운 소식이 ${newsletterConfig.publicationCriteria.minimumArticleCountForIssue}개 이하이면서 중요한 내용(${newsletterConfig.publicationCriteria.priorityArticleScoreThreshold}점 이상)이 없을 경우, 다음 호로 이월하여 더 풍성한 내용으로 제공</li>
|
package/dist/index.js
CHANGED
|
@@ -2263,7 +2263,7 @@ ${options.krasNewsMarkdown}
|
|
|
2263
2263
|
fixMalformedUrls: true,
|
|
2264
2264
|
fixBoldSyntax: true,
|
|
2265
2265
|
convertStrikethrough: true,
|
|
2266
|
-
})
|
|
2266
|
+
}).replaceAll('%7B%7B%7BRESEND_UNSUBSCRIBE_URL%7D%7D%7D', '{{{RESEND_UNSUBSCRIBE_URL}}}')
|
|
2267
2267
|
: ''}
|
|
2268
2268
|
|
|
2269
2269
|
${options?.heripolabNewsMarkdown
|
|
@@ -2294,7 +2294,7 @@ ${options.heripolabNewsMarkdown}
|
|
|
2294
2294
|
</ul>
|
|
2295
2295
|
<hr style="border: 0; border-top: 2px solid #D2691E; margin: 32px 0;">
|
|
2296
2296
|
<h2 style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 24px; font-weight: bold; line-height: 1.3; color: #D2691E; margin: 0 0 16px 0; letter-spacing: -0.2px; border-left: 5px solid #D2691E; padding-left: 12px; background: none;">📅 발행 정책</h2>
|
|
2297
|
-
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.7; color: #444444; margin: 0 0 18px 0;"><strong>${options?.isKrasNewsletter ? '한국고고학회' : 'heripo 리서치 레이더'}</strong>는 매일 발행을 원칙으로 하되, 독자분들께 의미 있는 정보를 제공하기 위해 다음과 같은 발행 기준을 적용합니다:</p>
|
|
2297
|
+
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.7; color: #444444; margin: 0 0 18px 0;"><strong>${options?.isKrasNewsletter ? '한국고고학회 뉴스레터' : 'heripo 리서치 레이더'}</strong>는 매일 발행을 원칙으로 하되, 독자분들께 의미 있는 정보를 제공하기 위해 다음과 같은 발행 기준을 적용합니다:</p>
|
|
2298
2298
|
<ul style="padding-left: 24px; margin: 0 0 18px 0;">
|
|
2299
2299
|
<li style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.7; color: #444444; margin: 0 0 18px 0; margin-bottom: 8px;"><strong>정상 발행</strong>: 새로운 소식이 ${newsletterConfig.publicationCriteria.minimumArticleCountForIssue + 1}개 이상이거나, ${newsletterConfig.publicationCriteria.minimumArticleCountForIssue}개 이하여도 중요도 ${newsletterConfig.publicationCriteria.priorityArticleScoreThreshold}점 이상의 핵심 소식이 포함된 경우</li>
|
|
2300
2300
|
<li style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.7; color: #444444; margin: 0 0 18px 0; margin-bottom: 8px;"><strong>이월 발행</strong>: 새로운 소식이 ${newsletterConfig.publicationCriteria.minimumArticleCountForIssue}개 이하이면서 중요한 내용(${newsletterConfig.publicationCriteria.priorityArticleScoreThreshold}점 이상)이 없을 경우, 다음 호로 이월하여 더 풍성한 내용으로 제공</li>
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@heripo/research-radar",
|
|
3
3
|
"private": false,
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "2.3.
|
|
5
|
+
"version": "2.3.3",
|
|
6
6
|
"description": "AI-driven intelligence for Korean cultural heritage. This package serves as both a ready-to-use newsletter service and a practical implementation example for the LLM-Newsletter-Kit.",
|
|
7
7
|
"main": "dist/index.cjs",
|
|
8
8
|
"module": "dist/index.js",
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
"author": "kimhongyeon",
|
|
46
46
|
"license": "Apache-2.0",
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@ai-sdk/google": "^3.0.
|
|
49
|
-
"@ai-sdk/openai": "^3.0.
|
|
48
|
+
"@ai-sdk/google": "^3.0.30",
|
|
49
|
+
"@ai-sdk/openai": "^3.0.30",
|
|
50
50
|
"cheerio": "^1.2.0",
|
|
51
51
|
"dompurify": "^3.3.1",
|
|
52
|
-
"jsdom": "^28.
|
|
52
|
+
"jsdom": "^28.1.0",
|
|
53
53
|
"juice": "^11.1.1",
|
|
54
54
|
"safe-markdown2html": "^1.0.0",
|
|
55
55
|
"turndown": "^7.2.2"
|
|
@@ -58,24 +58,24 @@
|
|
|
58
58
|
"@llm-newsletter-kit/core": "~1.3.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@eslint/js": "^
|
|
62
|
-
"@llm-newsletter-kit/core": "^1.3.
|
|
61
|
+
"@eslint/js": "^10.0.1",
|
|
62
|
+
"@llm-newsletter-kit/core": "^1.3.3",
|
|
63
63
|
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
|
64
64
|
"@types/express": "^5.0.6",
|
|
65
65
|
"@types/jsdom": "^27.0.0",
|
|
66
|
-
"@types/node": "^25.
|
|
66
|
+
"@types/node": "^25.3.0",
|
|
67
67
|
"@types/turndown": "^5.0.6",
|
|
68
|
-
"eslint": "^
|
|
68
|
+
"eslint": "^10.0.1",
|
|
69
69
|
"eslint-plugin-unused-imports": "^4.4.1",
|
|
70
70
|
"express": "^5.2.1",
|
|
71
71
|
"prettier": "^3.8.1",
|
|
72
|
-
"rimraf": "^6.1.
|
|
73
|
-
"rollup": "^4.
|
|
72
|
+
"rimraf": "^6.1.3",
|
|
73
|
+
"rollup": "^4.58.0",
|
|
74
74
|
"rollup-plugin-dts": "^6.3.0",
|
|
75
75
|
"rollup-plugin-typescript2": "^0.36.0",
|
|
76
76
|
"tsx": "^4.21.0",
|
|
77
77
|
"typescript": "^5.9.3",
|
|
78
|
-
"typescript-eslint": "^8.
|
|
78
|
+
"typescript-eslint": "^8.56.0"
|
|
79
79
|
},
|
|
80
80
|
"repository": {
|
|
81
81
|
"type": "git",
|