又又又来折腾博客了,看不少博友都加上了 AI 总结文章的功能,也想自己整一个。本文借鉴了大大的小蜗牛并进行了部分修改。
获取摘要数据
AI 生成总结
方式有三种:
- 接入 TianliGPT,自动在访问时生成(需要购买 Key)
- 通过脚本从 ChatGPT 或 Claude 获取
- 手动把文章内容喂给 ChatGPT 或 Claude 获取
我自己用的是第三种。因为我博客也就三十几篇文章,TianliGPT 9 块钱能生成至少 50 篇文章的摘要,而且目前博客访问的人也不多,能省就省省😅。脚本虽然很方便,但貌似我还不太会使用,搞不出来。正好之前部署过 NextChat 且有一个免费的 GPT-3.5 的 API Key,所以就手动喂给 GPT 了。
数据存在哪
有两种方式:
- 在
/data
目录下用json
文件保存 - 把摘要结果放在文章 Front Matter 的
summary
下
方式 1 显然要比方式 2 方便维护。
在 /data
新建 summary.json
, 数据格式如下:
{
"summaries": [
{
"title": "",
"slug": "",
"generated": true,
"summary": ""
}
]
}
渲染 AI 摘要
修改模板文件
Hugo 可以直接修改位于 /layouts
的页面模板文件,大大的小蜗牛直接把代码加在 single.html
里了,我为了单个文件不要太长难看懂,单独将 AI 摘要部分放在一个文件里。如果同样是 Stack 主题,可以直接跟着下文操作,其他主题也大差不差。
在 /layouts/partial/article/components
创建 aisummary.html
(getJSON
仅适用于 Hugo 0.134.3 及以下,新版的 resource.Get
我搞不明白):
<!-- 获取数据 -->
{{ $summary := getJSON "data/summary/summary.json" }}
<!-- 以 slug 作为锚点来对应文章与摘要 -->
{{ $currentSlug := .Params.slug }}
{{ $matchingSummary := index (where $summary.summaries "slug" $currentSlug) 0 }}
<div class="post-ai">
<div class="ai-title">
<i class="fas fa-robot ai-title-icon"></i>
<div class="ai-title-text">AI 摘要</div>
</div>
<!-- Typeit 打字机效果,不需要则注释掉下面这行代码 -->
<div id="ai-explanation" class="ai-explanation"></div>
<div class="ai-explanation ai-explanation-content">
{{ if $matchingSummary.summary }}
{{ $matchingSummary.summary }}
{{ else }}
AI 摘要接口暂时失联……
{{ end }}
</div>
</div>
<!-- 打字机效果的 JS 不需要则注释掉 -->
<script src="https://npm.elemecdn.com/typeit@8.7.1/dist/index.umd.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
// 从 .ai-explanation-content 取值
const matchingSummary = document.querySelector(".ai-explanation-content").textContent;
new TypeIt("#ai-explanation", {
strings: matchingSummary,
speed: 10,
lifeLike: true,
waitUntilVisible: true,
}).go();
});
</script>
<i class="fas fa-robot ai-title-icon"></i>
中的 fas fa-robot
需要更改为你自己的图标 CSS 里的名称(生成 CSS 可用 Fontello)
如不需要打字机效果,需要将 <div id="ai-explanation" class="ai-explanation"></div>
和 JS 部分注释掉。
这里的修改是把 unpkg 换成了国内的饿了么 npm 镜像,并且调快了打字机速度(原来感觉有点太慢了,如果还觉得慢可以把 speed
数值继续调小)
然后把摘要引入文章的模板文件。在 /layouts/partial/article/article.html
的 header
和 content
中间加上 {{ partial "article/components/aisummary" . }}
添加 CSS
为了方便管理我单独创建了 ai.scss
。在 /assets/scss
下的合适位置(我是 /assets/scss/custom
)创建 ai.scss
:
.post-ai {
background: #f5f5f5;
border-radius: 2rem;
padding: 1rem;
line-height: 1.5;
border: 10px solid #ffffff;
margin: 1rem 0;
}
.ai-title {
display: flex;
color: #2d96bd;
border-radius: 0.5rem;
align-items: center;
padding: 0 0.25rem;
cursor: default;
user-select: none;
}
.ai-title-icon {
width: 20px;
height: auto;
margin-right: 0.25rem;
}
.ai-title-text {
font-weight: bold;
margin-left: 1rem;
line-height: 1;
}
.ai-explanation {
margin-top: 1rem;
padding: 0.5rem 1rem;
background: #fff;
border-radius: 0.5rem;
border: 1px solid #cfe6f3;
font-size: 1.5rem;
line-height: 1.7;
display: inline-block;
width: 100%;
}
.ai-explanation span {
margin-left: 0.5rem;
}
// 打字机效果,不需要则注释掉
.ai-explanation-content {
display: none !important;
}
部分参数可以自行根据喜好更改。
如不需要打字机效果,也要把最后一项 ai-explanation-content
的 CSS 注释掉。
然后在 /assets/scss/custom.scss
中引入(@import "custom/ai.scss";
)。
单篇文章禁用摘要
这是我自己添加的功能。有些文章代码太多,总字符数很大,导致喂给 GPT 会超出最大字符数,无法生成摘要。并且一些文章并不需要 AI 摘要,比如我的 Hugo-theme-Stack 魔改美化 和 博客魔改美化(通用) 这两篇文章,几乎都是代码片段,右侧的目录本身就是总结。所以禁用单篇文章摘要的功能来了。受到 article.html
里面 {{ if or .Params.math .Site.Params.article.math }}{{ partialCached "article/components/math.html" . }}{{ end }}
的启发,可以通过调用 Hugo 的函数方式实现。
询问 ChatGPT 后得知,上面的代码意思是:
这段代码是在Hugo模板中使用的条件语句,用于根据条件来决定是否插入数学公式。让我们逐步解释这段代码的含义:
{{ if ... }} ... {{ end }}
:这是 Hugo 模板中的条件语句,表示如果条件为真,则执行条件语句块中的内容。
or .Params.math .Site.Params.article.math
:这部分是条件语句的条件部分。它使用了逻辑运算符or
来判断两个条件中只要有一个为真即为真。具体解释如下:
.Params.math
:这是访问当前页面(文章)的 Front Matter 参数中的math
字段的值。通常,这个字段用于标识该文章是否包含数学公式。.Site.Params.article.math
:这是访问网站全局参数中的article.math
字段的值。这个字段可能用于设置整个网站是否启用数学公式显示。
{{ partialCached "article/components/math.html" . }}
:如果条件为真,将会调用名为article/components/math.html
的部分模板。这个部分模板可能包含用于显示数学公式的相关代码。综合起来,这段代码的意思是:如果当前页面的 Front Matter 中包含
math
字段,或者网站全局参数中的article.math
字段为真,那么就会插入数学公式相关的内容,可能是通过调用特定的部分模板来实现数学公式的显示。
那么我们一葫芦画瓢,写一个“除非当前页面的 Front Matter 中的 ai
字段为 false
,那么就插入文章摘要”的条件语句。
翻了下 Hugo 写得很复杂的文档后找到了一个 ne
函数,它的作用是判断两个值是否不相等,如果不相等,则返回 true
,否则返回 false
。
那么我们需要的代码就是 {{ if ne .Params.ai false }}{{ end }}
。
现在仅实现了在单篇文章的 Front Matter 中禁用,如果要能够统一禁用所有的 AI 摘要,就需要在网站全局参数中设置一个字段,如 article.ai
字段。
修改一下,使用 and
函数来要求两个条件同时为真才执行条件语句中的内容。只有当 Front Matter 中的 ai
字段和网站全局参数中的 article.ai
字段的值都不为 false
时,才会执行条件语句块中的内容:{{ if and (ne .Params.ai false) (ne .Site.Params.article.ai false) }}{{ end }}
现在将最终的代码片段加在 /layouts/partial/article/article.html
的 header
和 content
中间:
{{ if and (ne .Params.ai false) (ne .Site.Params.article.ai false) }}
{{ partial "article/components/aisummary" . }}
{{ end }}
再在 hugo.yaml
或 config.yaml
中加一个 article.ai
字段并设为 true
,想要禁用单篇文章摘要在 Front Matter 中加上 ai: false
即可。
Enjoy~