@astro-minimax/cli 0.5.0 → 0.7.1

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.
Files changed (174) hide show
  1. package/README.md +69 -0
  2. package/dist/commands/ai.d.ts +2 -0
  3. package/dist/commands/ai.d.ts.map +1 -0
  4. package/dist/commands/ai.js +99 -0
  5. package/dist/commands/ai.js.map +1 -0
  6. package/dist/commands/data.d.ts +2 -0
  7. package/dist/commands/data.d.ts.map +1 -0
  8. package/dist/commands/data.js +111 -0
  9. package/dist/commands/data.js.map +1 -0
  10. package/dist/commands/hooks.d.ts +2 -0
  11. package/dist/commands/hooks.d.ts.map +1 -0
  12. package/dist/commands/hooks.js +378 -0
  13. package/dist/commands/hooks.js.map +1 -0
  14. package/dist/commands/init.d.ts +2 -0
  15. package/dist/commands/init.d.ts.map +1 -0
  16. package/dist/commands/init.js +50 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/commands/podcast.d.ts +2 -0
  19. package/dist/commands/podcast.d.ts.map +1 -0
  20. package/dist/commands/podcast.js +89 -0
  21. package/dist/commands/podcast.js.map +1 -0
  22. package/dist/commands/post.d.ts +2 -0
  23. package/dist/commands/post.d.ts.map +1 -0
  24. package/dist/commands/post.js +190 -0
  25. package/dist/commands/post.js.map +1 -0
  26. package/dist/commands/profile.d.ts +2 -0
  27. package/dist/commands/profile.d.ts.map +1 -0
  28. package/dist/commands/profile.js +88 -0
  29. package/dist/commands/profile.js.map +1 -0
  30. package/dist/index.d.ts +3 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +81 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/tools/ai-process.d.ts +20 -0
  35. package/dist/tools/ai-process.d.ts.map +1 -0
  36. package/dist/tools/ai-process.js +607 -0
  37. package/dist/tools/ai-process.js.map +1 -0
  38. package/dist/tools/build-author-context.d.ts +13 -0
  39. package/dist/tools/build-author-context.d.ts.map +1 -0
  40. package/dist/tools/build-author-context.js +313 -0
  41. package/dist/tools/build-author-context.js.map +1 -0
  42. package/dist/tools/build-voice-profile.d.ts +12 -0
  43. package/dist/tools/build-voice-profile.d.ts.map +1 -0
  44. package/dist/tools/build-voice-profile.js +270 -0
  45. package/dist/tools/build-voice-profile.js.map +1 -0
  46. package/dist/tools/eval-ai-chat.d.ts +17 -0
  47. package/dist/tools/eval-ai-chat.d.ts.map +1 -0
  48. package/dist/tools/eval-ai-chat.js +362 -0
  49. package/dist/tools/eval-ai-chat.js.map +1 -0
  50. package/dist/tools/generate-author-profile.d.ts +14 -0
  51. package/dist/tools/generate-author-profile.d.ts.map +1 -0
  52. package/dist/tools/generate-author-profile.js +289 -0
  53. package/dist/tools/generate-author-profile.js.map +1 -0
  54. package/dist/tools/generate-cover.d.ts +14 -0
  55. package/dist/tools/generate-cover.d.ts.map +1 -0
  56. package/dist/tools/generate-cover.js +95 -0
  57. package/dist/tools/generate-cover.js.map +1 -0
  58. package/dist/tools/generate-og.d.ts +3 -0
  59. package/dist/tools/generate-og.d.ts.map +1 -0
  60. package/dist/tools/generate-og.js +254 -0
  61. package/dist/tools/generate-og.js.map +1 -0
  62. package/dist/tools/generate-related.d.ts +11 -0
  63. package/dist/tools/generate-related.d.ts.map +1 -0
  64. package/dist/tools/generate-related.js +124 -0
  65. package/dist/tools/generate-related.js.map +1 -0
  66. package/dist/tools/generate-tags.d.ts +14 -0
  67. package/dist/tools/generate-tags.d.ts.map +1 -0
  68. package/dist/tools/generate-tags.js +182 -0
  69. package/dist/tools/generate-tags.js.map +1 -0
  70. package/dist/tools/lib/ai-provider.d.ts +43 -0
  71. package/dist/tools/lib/ai-provider.d.ts.map +1 -0
  72. package/dist/tools/lib/ai-provider.js +146 -0
  73. package/dist/tools/lib/ai-provider.js.map +1 -0
  74. package/dist/tools/lib/audio-processor.d.ts +46 -0
  75. package/dist/tools/lib/audio-processor.d.ts.map +1 -0
  76. package/dist/tools/lib/audio-processor.js +188 -0
  77. package/dist/tools/lib/audio-processor.js.map +1 -0
  78. package/dist/tools/lib/frontmatter.d.ts +11 -0
  79. package/dist/tools/lib/frontmatter.d.ts.map +1 -0
  80. package/dist/tools/lib/frontmatter.js +80 -0
  81. package/dist/tools/lib/frontmatter.js.map +1 -0
  82. package/dist/tools/lib/index.d.ts +7 -0
  83. package/dist/tools/lib/index.d.ts.map +1 -0
  84. package/{template/tools/lib/index.ts → dist/tools/lib/index.js} +1 -0
  85. package/dist/tools/lib/index.js.map +1 -0
  86. package/dist/tools/lib/markdown.d.ts +6 -0
  87. package/dist/tools/lib/markdown.d.ts.map +1 -0
  88. package/dist/tools/lib/markdown.js +34 -0
  89. package/dist/tools/lib/markdown.js.map +1 -0
  90. package/dist/tools/lib/posts.d.ts +25 -0
  91. package/dist/tools/lib/posts.d.ts.map +1 -0
  92. package/dist/tools/lib/posts.js +63 -0
  93. package/dist/tools/lib/posts.js.map +1 -0
  94. package/dist/tools/lib/script-generator.d.ts +61 -0
  95. package/dist/tools/lib/script-generator.d.ts.map +1 -0
  96. package/dist/tools/lib/script-generator.js +182 -0
  97. package/dist/tools/lib/script-generator.js.map +1 -0
  98. package/dist/tools/lib/tts-provider.d.ts +65 -0
  99. package/dist/tools/lib/tts-provider.d.ts.map +1 -0
  100. package/dist/tools/lib/tts-provider.js +116 -0
  101. package/dist/tools/lib/tts-provider.js.map +1 -0
  102. package/dist/tools/lib/types.d.ts +129 -0
  103. package/dist/tools/lib/types.d.ts.map +1 -0
  104. package/dist/tools/lib/types.js +64 -0
  105. package/dist/tools/lib/types.js.map +1 -0
  106. package/dist/tools/lib/utils.d.ts +18 -0
  107. package/dist/tools/lib/utils.d.ts.map +1 -0
  108. package/dist/tools/lib/utils.js +121 -0
  109. package/dist/tools/lib/utils.js.map +1 -0
  110. package/dist/tools/lib/vectors.d.ts +27 -0
  111. package/dist/tools/lib/vectors.d.ts.map +1 -0
  112. package/dist/tools/lib/vectors.js +64 -0
  113. package/dist/tools/lib/vectors.js.map +1 -0
  114. package/dist/tools/podcast-feed.d.ts +6 -0
  115. package/dist/tools/podcast-feed.d.ts.map +1 -0
  116. package/dist/tools/podcast-feed.js +121 -0
  117. package/dist/tools/podcast-feed.js.map +1 -0
  118. package/dist/tools/podcast-generate.d.ts +15 -0
  119. package/dist/tools/podcast-generate.d.ts.map +1 -0
  120. package/dist/tools/podcast-generate.js +318 -0
  121. package/dist/tools/podcast-generate.js.map +1 -0
  122. package/dist/tools/podcast-list.d.ts +6 -0
  123. package/dist/tools/podcast-list.d.ts.map +1 -0
  124. package/dist/tools/podcast-list.js +66 -0
  125. package/dist/tools/podcast-list.js.map +1 -0
  126. package/dist/tools/summarize.d.ts +16 -0
  127. package/dist/tools/summarize.d.ts.map +1 -0
  128. package/dist/tools/summarize.js +108 -0
  129. package/dist/tools/summarize.js.map +1 -0
  130. package/dist/tools/translate.d.ts +13 -0
  131. package/dist/tools/translate.d.ts.map +1 -0
  132. package/dist/tools/translate.js +46 -0
  133. package/dist/tools/translate.js.map +1 -0
  134. package/dist/tools/vectorize.d.ts +13 -0
  135. package/dist/tools/vectorize.d.ts.map +1 -0
  136. package/dist/tools/vectorize.js +87 -0
  137. package/dist/tools/vectorize.js.map +1 -0
  138. package/package.json +14 -9
  139. package/template/astro.config.ts +8 -28
  140. package/template/datas/ai-seo.json +8 -0
  141. package/template/datas/ai-skip-list.json +1 -0
  142. package/template/datas/author-profile-context.json +21 -0
  143. package/template/datas/author-profile-report.json +21 -0
  144. package/template/datas/eval/gold-set.json +72 -0
  145. package/template/functions/README.md +82 -0
  146. package/template/functions/api/ai-info.ts +2 -2
  147. package/template/functions/api/chat.ts +4 -1
  148. package/template/functions/api/notify/comment.ts +140 -68
  149. package/template/functions/api/notify/debug.ts +41 -0
  150. package/template/functions/api/notify/status.ts +97 -0
  151. package/template/functions/api/notify/test-ai-chat.ts +67 -0
  152. package/template/package.json +22 -25
  153. package/template/src/config.ts +11 -0
  154. package/template/src/content.config.ts +29 -16
  155. package/template/src/env.d.ts +0 -5
  156. package/index.js +0 -36
  157. package/template/tools/README.md +0 -169
  158. package/template/tools/ai-process.ts +0 -816
  159. package/template/tools/build-author-context.ts +0 -405
  160. package/template/tools/build-voice-profile.ts +0 -322
  161. package/template/tools/generate-author-profile.ts +0 -369
  162. package/template/tools/generate-cover.ts +0 -123
  163. package/template/tools/generate-og.ts +0 -280
  164. package/template/tools/generate-related.ts +0 -146
  165. package/template/tools/generate-tags.ts +0 -251
  166. package/template/tools/lib/ai-provider.ts +0 -240
  167. package/template/tools/lib/frontmatter.ts +0 -94
  168. package/template/tools/lib/markdown.ts +0 -40
  169. package/template/tools/lib/posts.ts +0 -89
  170. package/template/tools/lib/utils.ts +0 -138
  171. package/template/tools/lib/vectors.ts +0 -96
  172. package/template/tools/summarize.ts +0 -142
  173. package/template/tools/translate.ts +0 -60
  174. package/template/tools/vectorize.ts +0 -105
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * 博客内容向量化与索引生成
4
+ *
5
+ * 用法:
6
+ * pnpm run tools:vectorize # TF-IDF 模式(无需 API Key)
7
+ * pnpm run tools:vectorize --openai # OpenAI Embeddings 模式
8
+ *
9
+ * 环境变量:
10
+ * AI_API_KEY / OPENAI_API_KEY(仅 --openai 模式需要)
11
+ */
12
+ import { writeFile, mkdir } from "node:fs/promises";
13
+ import { join } from "node:path";
14
+ import { chunkText } from "./lib/markdown.js";
15
+ import { getAllPosts } from "./lib/posts.js";
16
+ import { generateEmbeddings } from "./lib/ai-provider.js";
17
+ import { generateTfIdfVectors, } from "./lib/vectors.js";
18
+ const OUTPUT_DIR = join(process.cwd(), "src/data/vectors");
19
+ const OUTPUT_FILE = join(OUTPUT_DIR, "index.json");
20
+ const CHUNK_SIZE = 500;
21
+ const CHUNK_OVERLAP = 50;
22
+ async function main() {
23
+ const useOpenAI = process.argv.includes("--openai");
24
+ const method = useOpenAI ? "openai" : "tfidf";
25
+ console.log(`📚 读取博客文章...`);
26
+ const posts = await getAllPosts();
27
+ console.log(` 找到 ${posts.length} 篇文章\n`);
28
+ console.log(`📝 分割内容块...`);
29
+ const chunks = [];
30
+ for (const post of posts) {
31
+ const fullText = `${post.title}\n${post.description}\n${post.body}`;
32
+ const textChunks = chunkText(fullText, CHUNK_SIZE, CHUNK_OVERLAP);
33
+ for (let i = 0; i < textChunks.length; i++) {
34
+ chunks.push({
35
+ postId: post.id,
36
+ title: post.title,
37
+ lang: post.lang,
38
+ chunkIndex: i,
39
+ text: textChunks[i],
40
+ });
41
+ }
42
+ }
43
+ console.log(` 生成 ${chunks.length} 个内容块\n`);
44
+ if (method === "openai") {
45
+ console.log(`🧠 使用 OpenAI Embeddings 生成向量...`);
46
+ const texts = chunks.map(c => c.text);
47
+ const vectors = await generateEmbeddings(texts);
48
+ chunks.forEach((c, i) => {
49
+ c.vector = vectors[i];
50
+ });
51
+ const index = {
52
+ version: 1,
53
+ method: "openai",
54
+ createdAt: new Date().toISOString(),
55
+ chunks,
56
+ };
57
+ await mkdir(OUTPUT_DIR, { recursive: true });
58
+ await writeFile(OUTPUT_FILE, JSON.stringify(index, null, 0), "utf-8");
59
+ const fileSize = (JSON.stringify(index).length / 1024).toFixed(1);
60
+ console.log(`\n✅ 索引已生成: ${OUTPUT_FILE}`);
61
+ console.log(` 文件大小: ${fileSize} KB`);
62
+ console.log(` 内容块: ${chunks.length}`);
63
+ }
64
+ else {
65
+ console.log(`🔢 使用 TF-IDF 生成向量...`);
66
+ const { vocabulary, vectors } = generateTfIdfVectors(chunks);
67
+ chunks.forEach((c, i) => {
68
+ c.vector = vectors[i];
69
+ });
70
+ const index = {
71
+ version: 1,
72
+ method: "tfidf",
73
+ createdAt: new Date().toISOString(),
74
+ vocabulary,
75
+ chunks,
76
+ };
77
+ await mkdir(OUTPUT_DIR, { recursive: true });
78
+ await writeFile(OUTPUT_FILE, JSON.stringify(index, null, 0), "utf-8");
79
+ const fileSize = (JSON.stringify(index).length / 1024).toFixed(1);
80
+ console.log(`\n✅ 索引已生成: ${OUTPUT_FILE}`);
81
+ console.log(` 文件大小: ${fileSize} KB`);
82
+ console.log(` 词汇量: ${vocabulary.length}`);
83
+ console.log(` 内容块: ${chunks.length}`);
84
+ }
85
+ }
86
+ main().catch(console.error);
87
+ //# sourceMappingURL=vectorize.js.map
@@ -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.5.0",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
- "description": "CLI tool to create a new astro-minimax blog project a minimalist, fast, and modern Astro blog theme with AI-powered features.",
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
- "template",
13
- "blog-starter",
14
- "create-app"
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
- "index.js",
28
+ "dist/",
30
29
  "template/"
31
30
  ],
32
- "sideEffects": false,
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
  }
@@ -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
- import remarkToc from "remark-toc";
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
- const asTransformer = (t: unknown) => t;
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
- [remarkAddZoomable, { className: "zoomable" }],
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: true,
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
- "@/components/media": new URL("../../packages/viz/src/components", import.meta.url).pathname,
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,8 @@
1
+ {
2
+ "meta": {
3
+ "lastUpdated": null,
4
+ "model": null,
5
+ "totalProcessed": 0
6
+ },
7
+ "articles": {}
8
+ }
@@ -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 { ProviderManager, hasAnyProviderConfigured, DEFAULT_WORKERS_BINDING_NAME } from '@astro-minimax/ai';
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 = new ProviderManager(env, { enableMockFallback: true });
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({ env: context.env, request: context.request });
19
+ return handleChatRequest({
20
+ env: context.env,
21
+ request: context.request,
22
+ });
20
23
  };