Generate summary with ai

1 views

Generate summary with ai
Loading...

一直想在我的 Blog 中添加点 AI 的的能力,没想要加啥。前几天看到几个博客都有 AI摘要 的模块,利用 AI 生成一个简短的摘要,可以更好的帮助浏览文章的读者更好的理解文章内容,也不需要自己去总结了,每次总结还是挺痛苦的。

实现方案

  1. 新增一个 Summary 摘要组件
  2. 生成内容摘要
  3. 通过数据库来实现缓存效果,避免每次都生成消耗 Token

Summary 组件

const getPostSummary = async (slug: string) => {
if (!isProd) {
return {
error: 'Development environment'
};
}
const data = await fetch(`${HOST}/summary/${slug}`);
const result = await data.json();
return result;
};
export default function Summary({ slug }: { slug: string }) {
const [summary, setSummary] = useState('');
useEffect(() => {
if (slug.includes('weekly') || slug.includes('ph-daily')) {
return;
}
const init = async () => {
if (!slug) return;
const result = await getPostSummary(slug);
setSummary(result.summary || '');
};
init();
}, []);
return (
<div>
AI 摘要: {summary}
</div>
)
}

摘要这里的逻辑比较简单,就是获取摘要内容然后展示就好。我这里是屏蔽掉了 weeklyph-daily 相关的内容,由于这两个栏目的内容整体来说 段落性内容分隔 还是比较清晰的,所以没必要再去通过 AI 去梳理。

生成摘要内容

// 通过 getBlogContent 来获取文章的内容
const html = await getBlogContent(`${DOMAIN}/${path}`);
// 通过 gpt-4o-mini 的模型来生成摘要
const summary = await generateSummary(html, 'OPEN AI KEY');
// 我们提前给一些 prompt 来帮助我们生成更好的结果
async function generateSummary(html: string, apiKey: string) {
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content:
'你是一个摘要生成工具,你需要解释我发送给你的内容,不要换行,不要超过200字,只需要介绍文章的内容,不需要提出建议和缺少的东西。请用中文回答,输出的内容开头为“这篇文章介绍了”',
},
{
role: 'user',
content: `请为以下文章内容生成摘要: ${html}`,
},
],
temperature: 0.7,
max_tokens: 200,
}),
});
const data = (await response.json()) as any;
return data?.choices?.[0].message.content.trim() || '';
}
// 这里把相关的标签也删除掉了,只保留了文章的文字内容,这样可以节省一些 token
async function getBlogContent(url: string) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const html = await response.text();
const result = html.replace(/<[^>]+>/g, '');
return result || '';
} catch (error) {
return `Error fetching the blog content: ${error}`;
}
}

这块的内容我实在 Cloudflare 的 Worker 中实现的,没有通过前端直接调用 API 的考虑主要有两点:

  • 避免 OPEN AI 的 KEY 暴露
  • 由于后续需要一些数据库的操作,所以直接就集成到 Worker 中了

解释下我在生成 html 内容的时候通过正则把标签和 class 相关的内容评标的原因?

主要目的就是减少内容的 token 数,这些标签和样式名对生成摘要没啥作用,而且这个时候使用 Tailwindcss 的一个劣势也出来了,当你的布局相对复杂的时候,你的样式就是一大坨 💩 。

数据库来实现缓存效

这算个优化的过程,避免每次都通过 API 来请求,这边可以在第一次请求为完将摘要内容存到数据库,后续再请求的时候可以优先从数据库中读取。

try {
const result = await env.DB.prepare(`SELECT Summary FROM PageView WHERE Path = ?`).bind(path).first();
if (result?.Summary) {
return new Response(JSON.stringify({ summary: result.Summary }), {
headers: { 'Content-Type': 'application/json', ...HEADERS },
});
} else {
const html = await getBlogContent(`${DOMAIN}/${path}`);
// 如果摘要为空,调用 OpenAI API 生成摘要
const summary = await generateSummary(html, 'OPEN KEY');
// // 将生成的摘要保存到数据库
await env.DB.prepare(`UPDATE PageView SET Summary = ? WHERE Path = ?`).bind(summary, path).run();
return new Response(JSON.stringify({ summary }), {
headers: { 'Content-Type': 'application/json', ...HEADERS },
});
}
} catch (error: any) {
console.error('Failed to fetch or generate summary:', error);
return new Response(`Failed to fetch or generate summary: ${error.message}`, { status: 500 });
}

整体思路如代码所示,然后就是将页面内容优化的美观一点就好,这里用到了新的 ,里边有很多比较好看的效果。