eallion

大大的小蜗牛

机会总是垂青于有准备的人!
mastodon
github
twitter
steam
telegram
keybase
email

博客 AI 摘要及優化

為何需要 AI 摘要#

記不太清了,印象中在中學時代學過一篇課文,是講如何讀報紙的。
我在閱讀時一直保持了當時文中介紹的習慣。
對於不需要精讀的內容可以跳讀。
現在 ChatGPT 爆火後出現了大量的應用,其中 AI 摘要插件對我的幫忙很大。
信息過剩後,我們被很多低價值的信息轟炸,這類插件可以讓我快速的辨別一篇文章是否值得細讀。
通過多方對比後,我選擇了「ChatGPT 總結助手 - Chrome 應用商店」作為我瀏覽網頁時的首選插件。
它的使用效果如圖:

chatgpt_summary

必須要 AI 摘要嗎#

不必要!

我集成 AI 摘要只是為了方便跟我有一樣閱讀習慣的人。
我的個人博客在於記錄生活和寫一些備忘錄,對於別人來說全是一些低價值的數據。

我現在在博客上集成了 AI 摘要功能,是因為我使用了 TianliGPT
我當時因為出於 “支持獨立開發者” 的情結,購買了 TianliGPT 的服務。
發現購買的 Key 很快就消耗完了,又買了一個 Key,發現還是不夠,再買了一個 Key。
即便如此,我的博客中也只有不到三分之二的文章有 AI 摘要。
這樣下去,感覺像個無底洞。
這個時候的 AI 摘要功能就變成了一個歷史包袱。
如果取消 AI 摘要功能,那前面花的那些小錢就變成了沉沒成本了。

有情懷不代表需要妥協 Geek 精神。
所以決定自己動手改造一下 AI 摘要。
這也符合當初換到 Hugo 靜態博客的初衷,儘量把數據都靜態化。
儘量讓頁面數據 SSG(Static-Site Generation)/ SSR(Server-Side Rendering)。

怎麼優化 AI 摘要#

推薦:https://github.com/Moraxyc/ai-summary-hugo 輔助生成 summary.json 的 Python 腳本

1. 方式#

把 AI 摘要放在本地有 2 個思路:

  1. data 目錄下用 .json 文件保存數據

data_summary_json

  1. 把摘要結果放在文章 .md 文件的 Front Matter 裡

summary_frontmatter

2. 數據格式#

我選擇的是方式 1 ,把所有 AI 摘要放在 .json 文件中,這樣方便後期維護,也不破壞現有文章。
數據來源:

  • TianliGPT 已經生成的摘要
  • 通過腳本從 ChatGPT 和 Claude2 獲取的摘要

我現在用了好幾個腳本來獲取摘要,沒有一個完美的腳本能勝任這一工作,所以就不貼腳本了。
TianliGPT 的摘要,可以在網頁上按 F12 打開 DevTools 找到:

tianligpt_response

把多種方式獲取到的 AI 摘要集中起來後,生成一個 summary.json 文件。
data 目錄新建 data/summary/summary.json 文件, 所有數據複製到其中,數據格式:

{
  "summaries": [
    {
      "title": "2010 年 12 月 15 日 雪景",
      "slug": "snows",
      "generated": true,
      "summary": "文章描述了作者在 2010 年 12 月 15 日所經歷的雪景。作者提到,下雪之前天空只有幾點零星的白天,沒人預料到會下這麼大的雪。作者認為家鄉可能下得更大。文章還提到了關於地址設定和程序錯誤的問題,並以數字花園用愛發電作為結尾。"
    },
    {
      "title": "2011 向左,2010 向右",
      "slug": "goodbye2010",
      "generated": true,
      "summary": "文章講述了作者對 2010 年的回顧和對 2011 年的期望。他認為自己在過去一年中太過於為別人而活,失去了自我。他希望新的一年能更加積極陽光,並將經歷和感悟當成財富。最後,他表示不再傻逼地訴說苦難,祝大家新年快樂。"
    }
    ]
}

其中 generated 是我自用的一個判斷詞,可有可無,titleslug 是用於對應文章的錨點。

3. 渲染 AI 摘要#

summary.json 文件中的 AI 摘要渲染到每篇文章的開頭,修改一下 Hugo 文章的模板文件即可。
不同主題的模板文件可能不太一樣,不過也差不離。
一般名叫 single.html ,位於主題的 layouts 或 Hugo 根目錄的 layouts 下。
比如 DoIt 的模板位於 themes/DoIt/layouts/posts/single.html
我把它複製到根目錄 layouts/posts/single.html 了,同名模板優先渲染根目錄
在文章模板 single.html{{ .Content }} 之前,插入以下代碼:

<!-- 其他代碼 -->

<!-- 獲取數據 -->
{{ $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>

<!-- 渲染文檔正文 -->
{{ .Content }}

<!-- 其他代碼 -->

不需要打字機效果,上面的內容已經可用了。

如果需要打字機效果,需要取消 <div id="ai-explanation" class="ai-explanation"></div> 的註釋。
需要給 <div class="ai-explanation-content" style="display: none;"> 添加 display: none 隱藏掉,它的作用僅給 Typeit 插件賦值。
添加 JS :

<script src="https://unpkg.com/[email protected]/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: 50,
        lifeLike: true,
        waitUntilVisible: true,
    }).go();
});
</script>
4. 簡單的 CSS#
.post-ai {
    background: #f5f5f5;
    border-radius: 0.5rem;
    padding: 0.5rem;
    line-height: 1.3;
    border: 1px solid #cfe6f3;
    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: 0.25rem;
    line-height: 1;
}

.ai-explanation {
    margin-top: 1rem;
    padding: 0.5rem 1rem;
    background: #fff;
    border-radius: 0.5rem;
    border: 1px solid #cfe6f3;
    font-size: 0.95rem;
    line-height: 1.4;
    display: inline-block;
    width: 100%;
}

.ai-explanation span {
    margin-left: 0.5rem;
}

/* .ai-explanation-content {
    display: none !important;
} */
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。