Generate summary with ai
1 views
Loading...
一直想在我的 Blog 中添加点 AI 的的能力,没想要加啥。前几天看到几个博客都有 AI摘要 的模块,利用 AI 生成一个简短的摘要,可以更好的帮助浏览文章的读者更好的理解文章内容,也不需要自己去总结了,每次总结还是挺痛苦的。
实现方案
- 新增一个
Summary摘要组件 - 生成内容摘要
- 通过数据库来实现缓存效果,避免每次都生成消耗
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> )}摘要这里的逻辑比较简单,就是获取摘要内容然后展示就好。我这里是屏蔽掉了 weekly 和 ph-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() || '';}
// 这里把相关的标签也删除掉了,只保留了文章的文字内容,这样可以节省一些 tokenasync 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 });}整体思路如代码所示,然后就是将页面内容优化的美观一点就好,这里用到了新的