Skip to content

Commit 85b76e9

Browse files
committed
feat: add SummaryAI.vue
1 parent 43a1c0d commit 85b76e9

File tree

7 files changed

+235
-25
lines changed

7 files changed

+235
-25
lines changed

.vitepress/theme/ThemeLayout.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
<script setup lang="ts">
22
import { useData } from 'vitepress'
33
import DefaultTheme from 'vitepress/theme'
4+
import themeConfig from './config'
45
import Home from './components/Home.vue'
56
import PostHeader from './components/PostHeader.vue'
67
import PostFooter from './components/PostFooter.vue'
78
import Comments from './components/Comments.vue'
9+
import SummaryAI from './components/SummaryAI.vue'
810
911
const { page } = useData()
1012
const { Layout } = DefaultTheme
@@ -17,6 +19,7 @@ const { Layout } = DefaultTheme
1719
</template>
1820
<template #doc-before>
1921
<PostHeader />
22+
<SummaryAI v-show='themeConfig.cloudflareApi'/>
2023
</template>
2124
<template #doc-after>
2225
<PostFooter />
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<script setup lang='ts'>
2+
import { ref } from 'vue'
3+
import themeConfig from '../config'
4+
5+
const summary = ref('')
6+
const loading = ref(false)
7+
8+
async function summarizer(input: object) {
9+
const response = await fetch(
10+
themeConfig.cloudflareApi,
11+
{
12+
headers: {'Content-Type':'application/json'},
13+
method: 'POST',
14+
body: JSON.stringify(input)
15+
}
16+
);
17+
const result = await response.json()
18+
return result
19+
}
20+
21+
function htmlFilter(html: HTMLElement) {
22+
// clone for editing
23+
const tempElement = html.cloneNode(true) as HTMLElement;
24+
// remove class language-* elements
25+
const langElements = tempElement.querySelectorAll("[class^='language-']")
26+
langElements.forEach(el => el.parentNode?.removeChild(el))
27+
28+
// remove class footnotes elements
29+
const footnotes = tempElement.querySelectorAll('.footnotes')
30+
footnotes.forEach(el => el.parentNode?.removeChild(el))
31+
32+
// remove class footnote elements
33+
const footnote = tempElement.querySelectorAll('.footnote')
34+
footnote.forEach(el => el.parentNode?.removeChild(el))
35+
36+
return tempElement.innerText
37+
}
38+
39+
function run(){
40+
const articleElement = document.querySelector('.vp-doc') as HTMLElement;
41+
if (!articleElement) return
42+
43+
loading.value = true
44+
const articleText = htmlFilter(articleElement)
45+
summarizer({message: articleText}).then((res) => {
46+
summary.value = '🤖 AI Summary : ' + res['response']['result']['response']
47+
loading.value = false
48+
})
49+
}
50+
</script>
51+
52+
<template>
53+
<div class='theme-summary'>
54+
<button v-if='!summary' @click='run' class='theme-summary-button' :disabled='loading'>
55+
<template v-if='loading'>
56+
<span class='inline-flex space-x-2 ml-1 h-4 items-end'>
57+
<span class='theme-summary-dot animate-bounce [animation-delay:-0.3s]'></span>
58+
<span class='theme-summary-dot animate-bounce [animation-delay:-0.15s]'></span>
59+
<span class='theme-summary-dot animate-bounce'></span>
60+
</span>
61+
</template>
62+
<template v-else>
63+
🤖 AI Summary
64+
</template>
65+
</button>
66+
<p v-else>{{ summary }}</p>
67+
</div>
68+
</template>

.vitepress/theme/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ const themeConfig = {
5858
issueTerm: 'title',
5959
light: 'github-light',
6060
dark: 'gruvbox-dark'
61-
}
61+
},
62+
cloudflareApi: ''
6263
}
6364

6465
export default themeConfig

.vitepress/theme/style.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@
2424
rounded-md ring-1 ring-cyan-500 animate-pulse;
2525
}
2626

27+
.theme-summary {
28+
@apply border-2 border-dashed border-gray-400 dark:border-gray-600
29+
p-4 min-h-[120px] flex items-center justify-center text-gray-700 dark:text-gray-300;
30+
}
31+
32+
.theme-summary-button {
33+
@apply bg-yellow-500 text-black text-black font-bold py-2 px-4 rounded-lg;
34+
}
35+
36+
.theme-summary-dot {
37+
@apply w-2 h-2 bg-current rounded-full
38+
}
39+
2740
.theme-pagination {
2841
@apply flex items-center justify-center px-3 h-8 leading-tight cursor-pointer
2942
text-cyan-700 border border-gray-300 sm:hover:bg-gray-300 sm:hover:text-cyan-500

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# 2025-04-15
2+
3+
### Features
4+
- add SummaryAI.vue
5+
16
# 2025-02-22
27

38
### Features

README.md

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,85 @@ If there has any problem please feel free to create issue.
2121
Detailed changes are documented in the [CHANGELOG](./CHANGELOG.md).
2222

2323
## Features
24-
- create new post with CLI
25-
- add JSON-LD for SEO on post pages
26-
- style with Tailwind CSS (RWD)
27-
- style for light / dark mode
28-
- pagination with History API
29-
- [built-in sitemap generation](https://vitepress.dev/guide/sitemap-generation#sitemap-generation)
30-
- common use config integration
31-
- [utterances](https://utteranc.es) for blog comments
32-
- sync light / dark mode for utterances
33-
- [MathJax style optimization for mobile](https://github.com/vuejs/vitepress/issues/3914#issuecomment-2138527325)
34-
- prev / next links without fontmatter setting
35-
- support footnote by [markdown-it-footnote](https://github.com/markdown-it/markdown-it-footnote)
24+
- 🖋️ **Generate new posts via CLI** – Scaffold articles instantly with a single command
25+
- 🤖 **AI-powered summary** – Real-time article overview powered by AI
26+
- 📈 **SEO-ready with JSON-LD** – Auto-injected schema data on every post page
27+
- 🎨 **Style with Tailwind CSS** – Responsive design that looks great in both light/dark mode
28+
- 📚 **Pagination powered by History API** – Smooth navigation between post lists
29+
- 🗺️ [**Automatic sitemap generation**](https://vitepress.dev/guide/sitemap-generation#sitemap-generation) – Boost your site's visibility in search engines
30+
- 🧩 **Modular config integration** – Centralized control for site and theme settings
31+
- 💬 [**Utterances for comments**](https://utteranc.es) – GitHub-powered commenting system
32+
- 🔄 **Theme-aware Utterances** – Auto-sync comment box with light/dark mode
33+
- 📐 [**Optimized MathJax rendering**](https://github.com/vuejs/vitepress/issues/3914#issuecomment-2138527325) – Clean, responsive math formulas on mobile
34+
- ⏭️ **Prev/Next post links** – Auto-generated without extra frontmatter
35+
- 🦶 **Footnote support** – Powered by [markdown-it-footnote](https://github.com/markdown-it/markdown-it-footnote) for scholarly notes
3636

3737
## Prerequisite
3838
- [Node.js](https://nodejs.org) version 18 or higher.
3939

4040
## Usage
4141
- Clone the project.
4242
- Edit [theme config](/.vitepress/theme/config.ts) and [public files](/public/) for custom.
43+
- To enable the AI-powered realtime summary, you need to sign up for [Cloudflare](https://www.cloudflare.com), create your own AI Worker (free), and configure the Worker API in the theme config.
44+
```
45+
# worker.js
46+
const corsHeaders = {
47+
'Access-Control-Allow-Origin': 'YOUR_HOST',
48+
'Access-Control-Allow-Methods': 'POST, OPTIONS',
49+
'Access-Control-Allow-Headers': 'Content-Type',
50+
'Content-Type': 'application/json'
51+
};
52+
53+
const sendErrorResponse = (message, status = 500) => {
54+
return new Response(JSON.stringify({ error: message }), {
55+
status,
56+
headers: corsHeaders
57+
});
58+
};
59+
60+
export default {
61+
async fetch(request, env) {
62+
if (request.method === 'OPTIONS') {
63+
return new Response(null, { headers: corsHeaders });
64+
}
65+
66+
if (request.method !== 'POST') {
67+
return sendErrorResponse('Only POST requests are allowed', 405);
68+
}
69+
70+
try {
71+
const { message } = await request.json();
72+
if (!message) {
73+
return sendErrorResponse('Missing message in request body', 400);
74+
}
75+
const model = '@cf/meta/llama-3.1-8b-instruct';
76+
const userID = 'YOUR_USER_ID';
77+
const gateway = `https://gateway.ai.cloudflare.com/v1/${userID}/ai-gateway/workers-ai/${model}`;
78+
const prompt = `You are a professional summarization assistant. Based on the content I provide, generate a summary no longer than 60 characters, and return only the summary—no additional text: ${message}`;
79+
const apiResponse = await fetch(
80+
gateway,
81+
{
82+
method: 'POST',
83+
headers: {
84+
'Content-Type': 'application/json',
85+
'Authorization': `${env.key}`
86+
},
87+
body: JSON.stringify({'prompt': prompt})
88+
}
89+
);
90+
91+
if (!apiResponse.ok) {
92+
throw new Error(`Cloudflare Workers AI error: ${apiResponse.statusText}`);
93+
}
94+
95+
const response = await apiResponse.json();
96+
return new Response(JSON.stringify({ response }), { headers: corsHeaders });
97+
} catch (error) {
98+
return sendErrorResponse(error.message);
99+
}
100+
}
101+
};
102+
```
43103
- Launch terminal and execute commands as follows :
44104
```shell
45105
# install devDependencies

README_CH.md

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,85 @@
2020
有關更新的細節都紀錄在 [CHANGELOG](./CHANGELOG.md)
2121

2222
## 主題特色
23-
- 透過終端機指令建立新文章
24-
- 文章頁面使用 JSON-LD 改進 SEO
25-
- Tailwind CSS (響應式)
26-
- 淺色 / 深色主題切換
27-
- 文章列表分頁使用 History API
28-
- [內建網站地圖(sitemap)生成](https://vitepress.dev/guide/sitemap-generation#sitemap-generation)
29-
- 整合常用網站 / 主題設定
30-
- 使用 [utterances](https://utteranc.es) 留言系統
31-
- utterances 同步切換淺色 / 深色主題
32-
- [針對行動裝置瀏覽改善 MathJax 樣式](https://github.com/vuejs/vitepress/issues/3914#issuecomment-2138527325)
33-
- 自動產生上一篇 / 下一篇連結(無需手動設定)
34-
- 整合 [markdown-it-footnote](https://github.com/markdown-it/markdown-it-footnote) 腳註支援
23+
- 🖋️ 使用 CLI 快速建立新文章 – 一行指令即可生成文章模板
24+
- 🤖 AI 即時摘要 – 即時生成文章重點摘要,讓讀者快速掌握內容
25+
- 📈 SEO 強化(支援 JSON-LD)– 自動在每篇文章注入結構化資料
26+
- 🎨 採用 Tailwind CSS 設計 – 響應式頁面,支援明暗主題切換
27+
- 📚 分頁功能(使用 History API)– 流暢切換文章列表,無需重新載入
28+
- 🗺️ [自動生成 Sitemap](https://vitepress.dev/guide/sitemap-generation#sitemap-generation) – 提升部落格在搜尋引擎中的能見度
29+
- 🧩 模組化設定整合 – 將框架與主題設定集中管理,易於維護與擴充
30+
- 💬 [Utterances 留言系統](https://utteranc.es) – 基於 GitHub Issues 的輕量化留言功能
31+
- 🔄 留言區主題同步 – Utterances 會自動配合網站明暗模式切換
32+
- 📐 [針對行動裝置瀏覽改善 MathJax 樣式]((https://github.com/vuejs/vitepress/issues/3914#issuecomment-2138527325)) – 易讀的數學公式呈現
33+
- ⏭️ 上/下一篇自動連結 – 無需額外設定 frontmatter
34+
- 🦶 支援腳註 – 使用 [markdown-it-footnote](https://github.com/markdown-it/markdown-it-footnote) 呈現專業註解說明
3535

3636
## 先決條件
3737
- [Node.js](https://nodejs.org) 版本最低需求為 18.0.0
3838

3939
## 如何使用
4040
- 複製或下載本主題
4141
- 根據個人需求編輯 [theme config](/.vitepress/theme/config.ts)[public 資料夾](/public/)中的檔案
42+
- 若要啟用AI即時摘要,必須註冊[Cloudflare](https://www.cloudflare.com)並建立你的AI Worker (提供免費額度),再將Worker API填入主題設定
43+
```
44+
# worker.js
45+
const corsHeaders = {
46+
'Access-Control-Allow-Origin': 'YOUR_HOST',
47+
'Access-Control-Allow-Methods': 'POST, OPTIONS',
48+
'Access-Control-Allow-Headers': 'Content-Type',
49+
'Content-Type': 'application/json'
50+
};
51+
52+
const sendErrorResponse = (message, status = 500) => {
53+
return new Response(JSON.stringify({ error: message }), {
54+
status,
55+
headers: corsHeaders
56+
});
57+
};
58+
59+
export default {
60+
async fetch(request, env) {
61+
if (request.method === 'OPTIONS') {
62+
return new Response(null, { headers: corsHeaders });
63+
}
64+
65+
if (request.method !== 'POST') {
66+
return sendErrorResponse('Only POST requests are allowed', 405);
67+
}
68+
69+
try {
70+
const { message } = await request.json();
71+
if (!message) {
72+
return sendErrorResponse('Missing message in request body', 400);
73+
}
74+
const model = '@cf/meta/llama-3.1-8b-instruct';
75+
const userID = 'YOUR_USER_ID';
76+
const gateway = `https://gateway.ai.cloudflare.com/v1/${userID}/ai-gateway/workers-ai/${model}`;
77+
const prompt = `你是一個專業的摘要助手,請根據我提供的內容,生成不超過60字的繁體中文摘要,並且只回傳摘要,不得包含其他內容: ${message}`;
78+
const apiResponse = await fetch(
79+
gateway,
80+
{
81+
method: 'POST',
82+
headers: {
83+
'Content-Type': 'application/json',
84+
'Authorization': `${env.key}`
85+
},
86+
body: JSON.stringify({'prompt': prompt})
87+
}
88+
);
89+
90+
if (!apiResponse.ok) {
91+
throw new Error(`Cloudflare Workers AI error: ${apiResponse.statusText}`);
92+
}
93+
94+
const response = await apiResponse.json();
95+
return new Response(JSON.stringify({ response }), { headers: corsHeaders });
96+
} catch (error) {
97+
return sendErrorResponse(error.message);
98+
}
99+
}
100+
};
101+
```
42102
- 啟動終端機執行以下指令 :
43103
```shell
44104
# 安裝依賴套件

0 commit comments

Comments
 (0)