@astro-minimax/cli 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -0
- package/dist/commands/ai.d.ts +2 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +99 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/data.d.ts +2 -0
- package/dist/commands/data.d.ts.map +1 -0
- package/dist/commands/data.js +111 -0
- package/dist/commands/data.js.map +1 -0
- package/dist/commands/hooks.d.ts +2 -0
- package/dist/commands/hooks.d.ts.map +1 -0
- package/dist/commands/hooks.js +378 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +50 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/post.d.ts +2 -0
- package/dist/commands/post.d.ts.map +1 -0
- package/dist/commands/post.js +190 -0
- package/dist/commands/post.js.map +1 -0
- package/dist/commands/profile.d.ts +2 -0
- package/dist/commands/profile.d.ts.map +1 -0
- package/dist/commands/profile.js +88 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/ai-process.d.ts +20 -0
- package/dist/tools/ai-process.d.ts.map +1 -0
- package/dist/tools/ai-process.js +607 -0
- package/dist/tools/ai-process.js.map +1 -0
- package/dist/tools/build-author-context.d.ts +13 -0
- package/dist/tools/build-author-context.d.ts.map +1 -0
- package/dist/tools/build-author-context.js +313 -0
- package/dist/tools/build-author-context.js.map +1 -0
- package/dist/tools/build-voice-profile.d.ts +12 -0
- package/dist/tools/build-voice-profile.d.ts.map +1 -0
- package/dist/tools/build-voice-profile.js +270 -0
- package/dist/tools/build-voice-profile.js.map +1 -0
- package/dist/tools/eval-ai-chat.d.ts +17 -0
- package/dist/tools/eval-ai-chat.d.ts.map +1 -0
- package/dist/tools/eval-ai-chat.js +332 -0
- package/dist/tools/eval-ai-chat.js.map +1 -0
- package/dist/tools/generate-author-profile.d.ts +14 -0
- package/dist/tools/generate-author-profile.d.ts.map +1 -0
- package/dist/tools/generate-author-profile.js +289 -0
- package/dist/tools/generate-author-profile.js.map +1 -0
- package/dist/tools/generate-cover.d.ts +14 -0
- package/dist/tools/generate-cover.d.ts.map +1 -0
- package/dist/tools/generate-cover.js +95 -0
- package/dist/tools/generate-cover.js.map +1 -0
- package/dist/tools/generate-og.d.ts +3 -0
- package/dist/tools/generate-og.d.ts.map +1 -0
- package/dist/tools/generate-og.js +254 -0
- package/dist/tools/generate-og.js.map +1 -0
- package/dist/tools/generate-related.d.ts +11 -0
- package/dist/tools/generate-related.d.ts.map +1 -0
- package/dist/tools/generate-related.js +124 -0
- package/dist/tools/generate-related.js.map +1 -0
- package/dist/tools/generate-tags.d.ts +14 -0
- package/dist/tools/generate-tags.d.ts.map +1 -0
- package/dist/tools/generate-tags.js +182 -0
- package/dist/tools/generate-tags.js.map +1 -0
- package/dist/tools/lib/ai-provider.d.ts +43 -0
- package/dist/tools/lib/ai-provider.d.ts.map +1 -0
- package/dist/tools/lib/ai-provider.js +146 -0
- package/dist/tools/lib/ai-provider.js.map +1 -0
- package/dist/tools/lib/frontmatter.d.ts +11 -0
- package/dist/tools/lib/frontmatter.d.ts.map +1 -0
- package/dist/tools/lib/frontmatter.js +80 -0
- package/dist/tools/lib/frontmatter.js.map +1 -0
- package/dist/tools/lib/index.d.ts +7 -0
- package/dist/tools/lib/index.d.ts.map +1 -0
- package/{template/tools/lib/index.ts → dist/tools/lib/index.js} +1 -0
- package/dist/tools/lib/index.js.map +1 -0
- package/dist/tools/lib/markdown.d.ts +6 -0
- package/dist/tools/lib/markdown.d.ts.map +1 -0
- package/dist/tools/lib/markdown.js +34 -0
- package/dist/tools/lib/markdown.js.map +1 -0
- package/dist/tools/lib/posts.d.ts +25 -0
- package/dist/tools/lib/posts.d.ts.map +1 -0
- package/dist/tools/lib/posts.js +63 -0
- package/dist/tools/lib/posts.js.map +1 -0
- package/dist/tools/lib/utils.d.ts +18 -0
- package/dist/tools/lib/utils.d.ts.map +1 -0
- package/dist/tools/lib/utils.js +121 -0
- package/dist/tools/lib/utils.js.map +1 -0
- package/dist/tools/lib/vectors.d.ts +27 -0
- package/dist/tools/lib/vectors.d.ts.map +1 -0
- package/dist/tools/lib/vectors.js +64 -0
- package/dist/tools/lib/vectors.js.map +1 -0
- package/dist/tools/summarize.d.ts +16 -0
- package/dist/tools/summarize.d.ts.map +1 -0
- package/dist/tools/summarize.js +108 -0
- package/dist/tools/summarize.js.map +1 -0
- package/dist/tools/translate.d.ts +13 -0
- package/dist/tools/translate.d.ts.map +1 -0
- package/dist/tools/translate.js +46 -0
- package/dist/tools/translate.js.map +1 -0
- package/dist/tools/vectorize.d.ts +13 -0
- package/dist/tools/vectorize.d.ts.map +1 -0
- package/dist/tools/vectorize.js +87 -0
- package/dist/tools/vectorize.js.map +1 -0
- package/package.json +14 -9
- package/template/astro.config.ts +8 -28
- package/template/datas/ai-seo.json +8 -0
- package/template/datas/ai-skip-list.json +1 -0
- package/template/datas/author-profile-context.json +21 -0
- package/template/datas/author-profile-report.json +21 -0
- package/template/datas/eval/gold-set.json +72 -0
- package/template/functions/README.md +82 -0
- package/template/functions/api/ai-info.ts +2 -2
- package/template/functions/api/chat.ts +4 -1
- package/template/functions/api/notify/comment.ts +140 -68
- package/template/functions/api/notify/debug.ts +41 -0
- package/template/functions/api/notify/status.ts +97 -0
- package/template/functions/api/notify/test-ai-chat.ts +67 -0
- package/template/package.json +22 -25
- package/template/src/config.ts +11 -0
- package/template/src/content.config.ts +29 -16
- package/template/src/env.d.ts +0 -5
- package/index.js +0 -36
- package/template/tools/README.md +0 -169
- package/template/tools/ai-process.ts +0 -816
- package/template/tools/build-author-context.ts +0 -405
- package/template/tools/build-voice-profile.ts +0 -322
- package/template/tools/generate-author-profile.ts +0 -369
- package/template/tools/generate-cover.ts +0 -123
- package/template/tools/generate-og.ts +0 -280
- package/template/tools/generate-related.ts +0 -146
- package/template/tools/generate-tags.ts +0 -251
- package/template/tools/lib/ai-provider.ts +0 -240
- package/template/tools/lib/frontmatter.ts +0 -94
- package/template/tools/lib/markdown.ts +0 -40
- package/template/tools/lib/posts.ts +0 -89
- package/template/tools/lib/utils.ts +0 -138
- package/template/tools/lib/vectors.ts +0 -96
- package/template/tools/summarize.ts +0 -142
- package/template/tools/translate.ts +0 -60
- package/template/tools/vectorize.ts +0 -105
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vectorize.js","sourceRoot":"","sources":["../../src/tools/vectorize.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astro-minimax/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "CLI tool
|
|
5
|
+
"description": "CLI tool for astro-minimax blog — create blogs, manage content, and process data with AI.",
|
|
6
6
|
"author": "Souloss",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"astro",
|
|
10
|
-
"scaffold",
|
|
11
10
|
"cli",
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
11
|
+
"blog",
|
|
12
|
+
"scaffold",
|
|
13
|
+
"ai"
|
|
15
14
|
],
|
|
16
15
|
"homepage": "https://github.com/souloss/astro-minimax#readme",
|
|
17
16
|
"bugs": {
|
|
@@ -23,14 +22,18 @@
|
|
|
23
22
|
"directory": "packages/cli"
|
|
24
23
|
},
|
|
25
24
|
"bin": {
|
|
26
|
-
"astro-minimax": "./index.js"
|
|
25
|
+
"astro-minimax": "./dist/index.js"
|
|
27
26
|
},
|
|
28
27
|
"files": [
|
|
29
|
-
"
|
|
28
|
+
"dist/",
|
|
30
29
|
"template/"
|
|
31
30
|
],
|
|
32
|
-
"
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"tsx": "^4.21.0",
|
|
33
|
+
"undici": "^7.24.1"
|
|
34
|
+
},
|
|
33
35
|
"devDependencies": {
|
|
36
|
+
"@types/node": "^22.0.0",
|
|
34
37
|
"astro": "^5.0.0",
|
|
35
38
|
"typescript": "^5.9.3"
|
|
36
39
|
},
|
|
@@ -39,6 +42,8 @@
|
|
|
39
42
|
"pnpm": ">=9.0.0"
|
|
40
43
|
},
|
|
41
44
|
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"dev": "tsc --watch",
|
|
42
47
|
"typecheck": "tsc --noEmit"
|
|
43
48
|
}
|
|
44
49
|
}
|
package/template/astro.config.ts
CHANGED
|
@@ -5,8 +5,7 @@ import minimaxViz from "@astro-minimax/viz";
|
|
|
5
5
|
import sitemap from "@astrojs/sitemap";
|
|
6
6
|
import mdx from "@astrojs/mdx";
|
|
7
7
|
import preact from "@astrojs/preact";
|
|
8
|
-
|
|
9
|
-
import remarkCollapse from "remark-collapse";
|
|
8
|
+
|
|
10
9
|
import remarkMath from "remark-math";
|
|
11
10
|
import remarkGithubAlerts from "remark-github-alerts";
|
|
12
11
|
import remarkEmoji from "remark-emoji";
|
|
@@ -32,7 +31,8 @@ import { SITE } from "./src/config";
|
|
|
32
31
|
import { SOCIALS, SHARE_LINKS } from "./src/constants";
|
|
33
32
|
import { FRIENDS } from "./src/data/friends";
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
|
+
const asTransformer = (t: any) => t;
|
|
36
36
|
|
|
37
37
|
const shikiTransformers = [
|
|
38
38
|
asTransformer(updateStyle()),
|
|
@@ -76,13 +76,12 @@ export default defineConfig({
|
|
|
76
76
|
],
|
|
77
77
|
markdown: {
|
|
78
78
|
remarkPlugins: [
|
|
79
|
-
remarkToc,
|
|
80
|
-
[remarkCollapse, { test: "Table of contents" }],
|
|
81
79
|
remarkMath,
|
|
82
80
|
remarkGithubAlerts,
|
|
83
81
|
remarkEmoji,
|
|
84
82
|
remarkReadingTime,
|
|
85
|
-
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
84
|
+
[remarkAddZoomable as any, { className: "zoomable" }],
|
|
86
85
|
],
|
|
87
86
|
rehypePlugins: [
|
|
88
87
|
rehypeKatex,
|
|
@@ -98,28 +97,10 @@ export default defineConfig({
|
|
|
98
97
|
},
|
|
99
98
|
},
|
|
100
99
|
vite: {
|
|
101
|
-
plugins: [
|
|
102
|
-
tailwindcss() as never,
|
|
103
|
-
{
|
|
104
|
-
name: "astro-minimax-preact-singleton",
|
|
105
|
-
enforce: "pre" as const,
|
|
106
|
-
async resolveId(source, importer, options) {
|
|
107
|
-
if (source.startsWith("@/components/media")) {
|
|
108
|
-
const vizDir = new URL("../../packages/viz/src/components", import.meta.url).pathname;
|
|
109
|
-
return this.resolve(source.replace("@/components/media", vizDir), importer, { ...options, skipSelf: true });
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
],
|
|
100
|
+
plugins: [tailwindcss() as never],
|
|
114
101
|
server: {
|
|
115
102
|
fs: {
|
|
116
|
-
strict:
|
|
117
|
-
allow: [
|
|
118
|
-
new URL("../../packages", import.meta.url).pathname,
|
|
119
|
-
new URL("../../node_modules", import.meta.url).pathname,
|
|
120
|
-
"./src",
|
|
121
|
-
"./.astro",
|
|
122
|
-
],
|
|
103
|
+
strict: false,
|
|
123
104
|
},
|
|
124
105
|
proxy: {
|
|
125
106
|
"/api": {
|
|
@@ -130,8 +111,7 @@ export default defineConfig({
|
|
|
130
111
|
},
|
|
131
112
|
resolve: {
|
|
132
113
|
alias: {
|
|
133
|
-
"@/
|
|
134
|
-
"@/" : new URL("./src/", import.meta.url).pathname,
|
|
114
|
+
"@/": new URL("./src/", import.meta.url).pathname,
|
|
135
115
|
"react": "preact/compat",
|
|
136
116
|
"react-dom": "preact/compat",
|
|
137
117
|
"react/jsx-runtime": "preact/jsx-runtime",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"generatedAt": null,
|
|
3
|
+
"siteUrl": null,
|
|
4
|
+
"sourceInfo": {
|
|
5
|
+
"totalPosts": 0,
|
|
6
|
+
"zhPosts": 0,
|
|
7
|
+
"enPosts": 0,
|
|
8
|
+
"selectedPosts": 0
|
|
9
|
+
},
|
|
10
|
+
"profile": {
|
|
11
|
+
"name": "Your Name",
|
|
12
|
+
"siteUrl": null
|
|
13
|
+
},
|
|
14
|
+
"posts": [],
|
|
15
|
+
"topTags": [],
|
|
16
|
+
"topCategories": [],
|
|
17
|
+
"contentStats": {
|
|
18
|
+
"totalPosts": 0,
|
|
19
|
+
"avgPostPerMonth": 0
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"lastUpdated": null,
|
|
4
|
+
"model": "rule-based-template",
|
|
5
|
+
"generatedBy": "rule-based"
|
|
6
|
+
},
|
|
7
|
+
"report": {
|
|
8
|
+
"hero": {
|
|
9
|
+
"title": "AI 视角下的博主",
|
|
10
|
+
"summary": "一位正在持续输出高质量内容的博主。",
|
|
11
|
+
"intro": "博客正在建设中,敬请期待更多精彩内容。"
|
|
12
|
+
},
|
|
13
|
+
"identities": [],
|
|
14
|
+
"strengths": [],
|
|
15
|
+
"styles": [],
|
|
16
|
+
"proofs": {
|
|
17
|
+
"posts": []
|
|
18
|
+
},
|
|
19
|
+
"disclaimer": "该页面由 AI 归纳与规则模板联合生成,旨在帮助访客快速建立认知,可能存在概括偏差,请以原始文章信息为准。"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "eval-gold-set-v1",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"description": "AI chat evaluation golden test set. Customize these cases to match your blog content.",
|
|
5
|
+
"cases": [
|
|
6
|
+
{
|
|
7
|
+
"id": "about-001",
|
|
8
|
+
"category": "about",
|
|
9
|
+
"question": "介绍一下你自己",
|
|
10
|
+
"answerMode": "fact",
|
|
11
|
+
"expectedTopics": ["博客", "AI 助手"],
|
|
12
|
+
"forbiddenClaims": [],
|
|
13
|
+
"lang": "zh"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "about-002",
|
|
17
|
+
"category": "about",
|
|
18
|
+
"question": "What is this blog about?",
|
|
19
|
+
"answerMode": "fact",
|
|
20
|
+
"expectedTopics": ["blog", "Astro"],
|
|
21
|
+
"forbiddenClaims": [],
|
|
22
|
+
"lang": "en"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "recommend-001",
|
|
26
|
+
"category": "recommendation",
|
|
27
|
+
"question": "有哪些文章推荐?",
|
|
28
|
+
"answerMode": "list",
|
|
29
|
+
"expectedTopics": [],
|
|
30
|
+
"forbiddenClaims": [],
|
|
31
|
+
"mustHaveLinks": true,
|
|
32
|
+
"lang": "zh"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": "no-answer-001",
|
|
36
|
+
"category": "no_answer",
|
|
37
|
+
"question": "你的收入是多少?",
|
|
38
|
+
"answerMode": "unknown",
|
|
39
|
+
"expectedTopics": [],
|
|
40
|
+
"forbiddenClaims": ["具体数字", "万", "元"],
|
|
41
|
+
"lang": "zh"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "no-answer-002",
|
|
45
|
+
"category": "no_answer",
|
|
46
|
+
"question": "你住在哪里?",
|
|
47
|
+
"answerMode": "unknown",
|
|
48
|
+
"expectedTopics": [],
|
|
49
|
+
"forbiddenClaims": ["具体地址", "小区", "街道"],
|
|
50
|
+
"lang": "zh"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": "tech-001",
|
|
54
|
+
"category": "tech",
|
|
55
|
+
"question": "这个博客用了什么技术栈?",
|
|
56
|
+
"answerMode": "fact",
|
|
57
|
+
"expectedTopics": ["Astro"],
|
|
58
|
+
"forbiddenClaims": [],
|
|
59
|
+
"lang": "zh"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": "setup-001",
|
|
63
|
+
"category": "setup",
|
|
64
|
+
"question": "怎么搭建类似的博客?",
|
|
65
|
+
"answerMode": "list",
|
|
66
|
+
"expectedTopics": [],
|
|
67
|
+
"forbiddenClaims": [],
|
|
68
|
+
"mustHaveLinks": true,
|
|
69
|
+
"lang": "zh"
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Cloudflare Pages Functions
|
|
2
|
+
|
|
3
|
+
Thin adapter layer for Cloudflare Pages deployment. Core logic lives in `@astro-minimax/ai/server`.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
functions/
|
|
9
|
+
api/
|
|
10
|
+
chat.ts → AI chat endpoint
|
|
11
|
+
ai-info.ts → Provider status endpoint
|
|
12
|
+
notify/
|
|
13
|
+
comment.ts → Comment notification webhook (for Waline)
|
|
14
|
+
status.ts → Notification config status endpoint
|
|
15
|
+
test-ai-chat.ts → Test AI chat notification
|
|
16
|
+
debug.ts → Debug webhook payload
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Local Development
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm run dev
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Environment Variables
|
|
26
|
+
|
|
27
|
+
Configure in `.env` (local) or Cloudflare Dashboard (production):
|
|
28
|
+
|
|
29
|
+
### AI Configuration
|
|
30
|
+
|
|
31
|
+
| Variable | Description |
|
|
32
|
+
| ----------------- | ---------------------------------------------- |
|
|
33
|
+
| `AI_BASE_URL` | OpenAI-compatible API base URL |
|
|
34
|
+
| `AI_API_KEY` | API key |
|
|
35
|
+
| `AI_MODEL` | Model name |
|
|
36
|
+
| `AI_BINDING_NAME` | Workers AI binding name (default: `minimaxAI`) |
|
|
37
|
+
| `SITE_AUTHOR` | Author name for AI prompts |
|
|
38
|
+
| `SITE_URL` | Site URL for article links |
|
|
39
|
+
|
|
40
|
+
### Notification Configuration
|
|
41
|
+
|
|
42
|
+
| Variable | Description |
|
|
43
|
+
| --------------------------- | -------------------------------------- |
|
|
44
|
+
| `NOTIFY_TELEGRAM_BOT_TOKEN` | Telegram bot token (from @BotFather) |
|
|
45
|
+
| `NOTIFY_TELEGRAM_CHAT_ID` | Telegram chat ID (from @userinfobot) |
|
|
46
|
+
| `NOTIFY_RESEND_API_KEY` | Resend API key for email notifications |
|
|
47
|
+
| `NOTIFY_RESEND_FROM` | Email sender address |
|
|
48
|
+
| `NOTIFY_RESEND_TO` | Email recipient address |
|
|
49
|
+
| `NOTIFY_WEBHOOK_URL` | Custom webhook URL (optional) |
|
|
50
|
+
|
|
51
|
+
## Deployment
|
|
52
|
+
|
|
53
|
+
For monorepo deployment, set **Root directory** to `apps/blog` in Cloudflare Pages project settings.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pnpm run build
|
|
57
|
+
npx wrangler pages deploy dist --project-name=your-project-name
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Workers AI binding is configured in `wrangler.toml`:
|
|
61
|
+
|
|
62
|
+
```toml
|
|
63
|
+
[ai]
|
|
64
|
+
binding = "minimaxAI"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Notification Setup
|
|
68
|
+
|
|
69
|
+
### Waline Webhook
|
|
70
|
+
|
|
71
|
+
1. In Waline deployment, set `WEBHOOK` environment variable to:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
https://your-domain.com/api/notify/comment
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
2. Configure notification providers in Cloudflare Dashboard
|
|
78
|
+
|
|
79
|
+
3. Test with:
|
|
80
|
+
```bash
|
|
81
|
+
curl https://your-domain.com/api/notify/status
|
|
82
|
+
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
|
-
import {
|
|
2
|
+
import { getProviderManager, hasAnyProviderConfigured, DEFAULT_WORKERS_BINDING_NAME } from '@astro-minimax/ai';
|
|
3
3
|
import { initializeMetadata } from '@astro-minimax/ai/server';
|
|
4
4
|
import type { ChatHandlerEnv } from '@astro-minimax/ai/server';
|
|
5
5
|
import aiSummaries from '../../datas/ai-summaries.json';
|
|
@@ -17,7 +17,7 @@ export const onRequest: PagesFunction<FunctionEnv> = async (context) => {
|
|
|
17
17
|
env,
|
|
18
18
|
);
|
|
19
19
|
|
|
20
|
-
const manager =
|
|
20
|
+
const manager = getProviderManager(env, { enableMockFallback: true });
|
|
21
21
|
const providerStatus = manager.getProviderStatus();
|
|
22
22
|
const bindingName = (env.AI_BINDING_NAME as string) || DEFAULT_WORKERS_BINDING_NAME;
|
|
23
23
|
|
|
@@ -16,5 +16,8 @@ export const onRequest: PagesFunction<FunctionEnv> = async (context) => {
|
|
|
16
16
|
{ summaries: aiSummaries, authorContext, voiceProfile },
|
|
17
17
|
context.env,
|
|
18
18
|
);
|
|
19
|
-
return handleChatRequest({
|
|
19
|
+
return handleChatRequest({
|
|
20
|
+
env: context.env,
|
|
21
|
+
request: context.request,
|
|
22
|
+
});
|
|
20
23
|
};
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
|
-
import {
|
|
2
|
+
import { getNotifier } from '@astro-minimax/notify';
|
|
3
3
|
|
|
4
4
|
interface WalineComment {
|
|
5
|
-
objectId?: string;
|
|
6
|
-
url
|
|
7
|
-
nick
|
|
8
|
-
mail
|
|
5
|
+
objectId?: string | number;
|
|
6
|
+
url?: string;
|
|
7
|
+
nick?: string;
|
|
8
|
+
mail?: string;
|
|
9
9
|
link?: string;
|
|
10
|
-
comment
|
|
10
|
+
comment?: string;
|
|
11
|
+
rawComment?: string;
|
|
11
12
|
ip?: string;
|
|
12
13
|
ua?: string;
|
|
13
14
|
insertedAt?: string;
|
|
15
|
+
createdAt?: string;
|
|
16
|
+
updatedAt?: string;
|
|
14
17
|
status?: string;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
type: 'new_comment' | 'new_reply';
|
|
19
|
-
data: WalineComment;
|
|
18
|
+
type?: string;
|
|
19
|
+
user_id?: number;
|
|
20
|
+
rid?: string | number;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
interface FunctionEnv {
|
|
@@ -33,77 +34,148 @@ interface FunctionEnv {
|
|
|
33
34
|
export const onRequest: PagesFunction<FunctionEnv> = async (context) => {
|
|
34
35
|
const { env, request } = context;
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
try {
|
|
38
|
+
if (!env.NOTIFY_TELEGRAM_BOT_TOKEN && !env.NOTIFY_WEBHOOK_URL && !env.NOTIFY_RESEND_API_KEY) {
|
|
39
|
+
console.warn('[notify/comment] No providers configured');
|
|
40
|
+
return jsonError('No notification providers configured', 400);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let rawData: unknown;
|
|
44
|
+
try {
|
|
45
|
+
rawData = await request.json();
|
|
46
|
+
} catch (parseError) {
|
|
47
|
+
console.error('[notify/comment] Failed to parse JSON:', parseError);
|
|
48
|
+
return jsonError('Invalid JSON payload', 400);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log('[notify/comment] Raw payload:', JSON.stringify(rawData).slice(0, 500));
|
|
52
|
+
|
|
53
|
+
const { commentData, eventType } = parseWalinePayload(rawData);
|
|
54
|
+
|
|
55
|
+
if (!commentData) {
|
|
56
|
+
console.error('[notify/comment] Could not extract comment data from payload');
|
|
57
|
+
return jsonError('Invalid payload structure', 400);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const siteUrl = env.SITE_URL || 'https://your-blog.pages.dev';
|
|
61
|
+
const urlPath = getStringValue(commentData.url) || '';
|
|
62
|
+
const postUrl = urlPath.startsWith('http')
|
|
63
|
+
? urlPath
|
|
64
|
+
: `${siteUrl}${urlPath}`;
|
|
65
|
+
|
|
66
|
+
const author = getStringValue(commentData.nick) || '匿名用户';
|
|
67
|
+
const content = getStringValue(commentData.rawComment) || getStringValue(commentData.comment) || '';
|
|
68
|
+
const postTitle = extractPostTitle(urlPath);
|
|
69
|
+
|
|
70
|
+
console.log('[notify/comment] Processing:', { urlPath, author, postTitle });
|
|
71
|
+
|
|
72
|
+
const notifier = getNotifier({
|
|
73
|
+
telegram: env.NOTIFY_TELEGRAM_BOT_TOKEN && env.NOTIFY_TELEGRAM_CHAT_ID ? {
|
|
74
|
+
botToken: env.NOTIFY_TELEGRAM_BOT_TOKEN,
|
|
75
|
+
chatId: env.NOTIFY_TELEGRAM_CHAT_ID,
|
|
76
|
+
} : undefined,
|
|
77
|
+
webhook: env.NOTIFY_WEBHOOK_URL ? {
|
|
78
|
+
url: env.NOTIFY_WEBHOOK_URL,
|
|
79
|
+
} : undefined,
|
|
80
|
+
email: env.NOTIFY_RESEND_API_KEY && env.NOTIFY_RESEND_FROM && env.NOTIFY_RESEND_TO ? {
|
|
81
|
+
provider: 'resend',
|
|
82
|
+
apiKey: env.NOTIFY_RESEND_API_KEY,
|
|
83
|
+
from: env.NOTIFY_RESEND_FROM,
|
|
84
|
+
to: env.NOTIFY_RESEND_TO,
|
|
85
|
+
} : undefined,
|
|
40
86
|
});
|
|
41
|
-
}
|
|
42
87
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
status: 400,
|
|
49
|
-
headers: { 'Content-Type': 'application/json' },
|
|
88
|
+
const result = await notifier.comment({
|
|
89
|
+
author,
|
|
90
|
+
content,
|
|
91
|
+
postTitle,
|
|
92
|
+
postUrl,
|
|
50
93
|
});
|
|
51
|
-
}
|
|
52
94
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
95
|
+
console.log('[notify/comment] Result:', { success: result.success, channels: result.results.length });
|
|
96
|
+
|
|
97
|
+
return new Response(JSON.stringify({
|
|
98
|
+
success: result.success,
|
|
99
|
+
event: eventType,
|
|
100
|
+
channels: result.results.map(r => ({
|
|
101
|
+
channel: r.channel,
|
|
102
|
+
success: r.success,
|
|
103
|
+
})),
|
|
104
|
+
}), {
|
|
105
|
+
status: 200,
|
|
56
106
|
headers: { 'Content-Type': 'application/json' },
|
|
57
107
|
});
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error('[notify/comment] Unexpected error:', error);
|
|
110
|
+
return jsonError(
|
|
111
|
+
error instanceof Error ? error.message : 'Unknown error',
|
|
112
|
+
500
|
|
113
|
+
);
|
|
58
114
|
}
|
|
115
|
+
};
|
|
59
116
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
? data.url
|
|
65
|
-
: `${siteUrl}${data.url}`;
|
|
66
|
-
|
|
67
|
-
const notifier = createNotifier({
|
|
68
|
-
telegram: env.NOTIFY_TELEGRAM_BOT_TOKEN && env.NOTIFY_TELEGRAM_CHAT_ID ? {
|
|
69
|
-
botToken: env.NOTIFY_TELEGRAM_BOT_TOKEN,
|
|
70
|
-
chatId: env.NOTIFY_TELEGRAM_CHAT_ID,
|
|
71
|
-
} : undefined,
|
|
72
|
-
webhook: env.NOTIFY_WEBHOOK_URL ? {
|
|
73
|
-
url: env.NOTIFY_WEBHOOK_URL,
|
|
74
|
-
} : undefined,
|
|
75
|
-
email: env.NOTIFY_RESEND_API_KEY && env.NOTIFY_RESEND_FROM && env.NOTIFY_RESEND_TO ? {
|
|
76
|
-
provider: 'resend',
|
|
77
|
-
apiKey: env.NOTIFY_RESEND_API_KEY,
|
|
78
|
-
from: env.NOTIFY_RESEND_FROM,
|
|
79
|
-
to: env.NOTIFY_RESEND_TO,
|
|
80
|
-
} : undefined,
|
|
81
|
-
});
|
|
117
|
+
function parseWalinePayload(raw: unknown): { commentData: WalineComment | null; eventType: string } {
|
|
118
|
+
if (!raw || typeof raw !== 'object') {
|
|
119
|
+
return { commentData: null, eventType: 'unknown' };
|
|
120
|
+
}
|
|
82
121
|
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
122
|
+
const data = raw as Record<string, unknown>;
|
|
123
|
+
|
|
124
|
+
// Waline format: { type: 'new_comment', data: { comment: {...} } }
|
|
125
|
+
if (data.type === 'new_comment' || data.type === 'new_reply') {
|
|
126
|
+
const dataObj = data.data as Record<string, unknown> | undefined;
|
|
127
|
+
// Check if data contains a 'comment' field (Waline's nested structure)
|
|
128
|
+
if (dataObj && dataObj.comment && typeof dataObj.comment === 'object') {
|
|
129
|
+
return {
|
|
130
|
+
commentData: dataObj.comment as WalineComment,
|
|
131
|
+
eventType: data.type as string
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// Fallback: data is the comment object directly
|
|
135
|
+
return {
|
|
136
|
+
commentData: dataObj as WalineComment,
|
|
137
|
+
eventType: data.type as string
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Direct comment object format
|
|
142
|
+
if (data.url || data.nick || data.comment || data.mail) {
|
|
143
|
+
const type = data.rid ? 'new_reply' : 'new_comment';
|
|
144
|
+
return {
|
|
145
|
+
commentData: data as WalineComment,
|
|
146
|
+
eventType: type
|
|
147
|
+
};
|
|
148
|
+
}
|
|
89
149
|
|
|
90
|
-
return
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
150
|
+
return { commentData: null, eventType: 'unknown' };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function getStringValue(value: unknown): string | null {
|
|
154
|
+
if (value === null || value === undefined) return null;
|
|
155
|
+
if (typeof value === 'string') return value;
|
|
156
|
+
return String(value);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function jsonError(message: string, status: number): Response {
|
|
160
|
+
return new Response(JSON.stringify({ error: message }), {
|
|
161
|
+
status,
|
|
99
162
|
headers: { 'Content-Type': 'application/json' },
|
|
100
163
|
});
|
|
101
|
-
}
|
|
164
|
+
}
|
|
102
165
|
|
|
103
166
|
function extractPostTitle(url: string): string {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
167
|
+
if (!url || typeof url !== 'string') {
|
|
168
|
+
return '博客文章';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Match /posts/xxx, /zh/posts/xxx, or /post/xxx formats
|
|
172
|
+
const match = url.match(/\/(?:[a-z]{2}\/)?posts?\/([^/]+)/);
|
|
173
|
+
if (match && match[1]) {
|
|
174
|
+
try {
|
|
175
|
+
return decodeURIComponent(match[1].replace(/-/g, ' '));
|
|
176
|
+
} catch {
|
|
177
|
+
return match[1].replace(/-/g, ' ');
|
|
178
|
+
}
|
|
107
179
|
}
|
|
108
180
|
return '博客文章';
|
|
109
181
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/// <reference types="@cloudflare/workers-types" />
|
|
2
|
+
|
|
3
|
+
interface DebugEnv {
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const onRequest: PagesFunction<DebugEnv> = async (context) => {
|
|
8
|
+
const { request } = context;
|
|
9
|
+
|
|
10
|
+
const headers: Record<string, string> = {};
|
|
11
|
+
request.headers.forEach((value, key) => {
|
|
12
|
+
headers[key] = value;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
let body = null;
|
|
16
|
+
let bodyError = null;
|
|
17
|
+
try {
|
|
18
|
+
body = await request.json();
|
|
19
|
+
} catch (e) {
|
|
20
|
+
bodyError = e instanceof Error ? e.message : String(e);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const debug = {
|
|
24
|
+
timestamp: new Date().toISOString(),
|
|
25
|
+
method: request.method,
|
|
26
|
+
url: request.url,
|
|
27
|
+
headers,
|
|
28
|
+
body,
|
|
29
|
+
bodyError,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
console.log('[notify/debug] Request received:', JSON.stringify(debug, null, 2));
|
|
33
|
+
|
|
34
|
+
return new Response(JSON.stringify(debug, null, 2), {
|
|
35
|
+
status: 200,
|
|
36
|
+
headers: {
|
|
37
|
+
'Content-Type': 'application/json',
|
|
38
|
+
'Access-Control-Allow-Origin': '*',
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
};
|