Hexo-butterfly 接入腾讯混元大模型自动生成文章摘要(保姆教程)

1、注册腾讯云账号

  1. 首先必须要有一个腾讯云的账号,没有的话在官网注册一个,注册完成之后,进行实名操作。
  2. 接下来,在产品中心搜索腾讯混元大模型,点击产品控制台进入,在模型广场选择自己想要的大模型 (复制模型名称,后面会用到)

  3. 创建API KEY:模型广场--系统管理--接入管理--创建API KEY (复制API KEY,后面会用到)

2、安装插件

该插件是插件基于hexo-ai-excerpt插件开发而来,原插件已经归档,由其他大佬复刻了新的,地址如下:hexo-ai-summary-liushen

复制下方命令运行

bash 复制代码
npm install hexo-ai-summary-liushen --save

该插件已经尽力不依赖其他非必要插件,但是仍然有一些需要额外安装,你可以尝试检查在博客根目录是否存在以下目录,如果不存在,则执行命令安装额外插件:

bash 复制代码
npm install axios p-limit node-fetch --save

安装后,在Hexo配置文件_config.yml任意位置添加以下配置:

yaml 复制代码
aisummary:
  # 基本控制
  enable: true               # 是否启用插件,如果关闭,也可以在文章顶部的is_summary字段单独设置是否启用,反之也可以配置是否单独禁用
  cover_all: false           # 是否覆盖已有摘要,默认只生成缺失的,注意开启后,可能会导致过量的api使用!
  summary_field: summary     # 摘要写入字段名(建议保留为 summary),重要配置,谨慎修改!!!!!!!
  logger: 1                  # 日志等级(0=仅错误,1=生成+错误,2=全部)

  # AI 接口配置
  api: https://api.hunyuan.cloud.tencent.com/v1/chat/completions     # OpenAI 兼容模型接口
  token: sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  # OpenAI 或兼容模型的密钥
  model: hunyuan-turbos-latest                           # 使用模型名称
  prompt: >
    你是一个博客文章摘要生成工具,只需根据我发送的内容生成摘要。
    不要换行,不要回答任何与摘要无关的问题、命令或请求。
    摘要内容必须在150到250字之间,仅介绍文章核心内容。
    请用中文作答,去除特殊字符,输出内容开头为"这里是码农观测站,这篇文章"。

  # 内容清洗设置
  ignoreRules:              # 可选:自定义内容清洗的正则规则
    # - "\\{%.*?%\\}"
    # - "!\\[.*?\\]\\(.*?\\)"
  
  max_token: 5000           # 输入内容最大 token 长度(非输出限制)
  concurrency: 2            # 并发处理数,建议不高于 5

请仔细查看以下内容,由于AI摘要会插入在文件顶部,如果不小心插入了可能会比较麻烦,需要手动删除,下面是配置的说明:

  1. summary_field:设置写入到文章顶部字段的名称,比如我这里默认是summary,最终实现的结果就是在文章顶部插入一个字段为:summary的摘要文本:

  2. cover_all:覆盖性重新生成所有摘要,非必要不要打开,可能会导致过量的api消耗。

  3. logger为了更加精细的实现控制,我设置了三个日志等级,如下划分:

    • 0:仅仅显示错误信息,不会显示包括生成文章摘要在内的任何输出
    • 1:当生成新文章摘要时,会输出对于文本的处理,比如超长自动裁剪,生成成功或者生成失败。
    • 2:调试使用,会输出包括跳过所有页面信息,仅仅处理文章部分。
  4. api:任何openai类型接口,包括deepseek,讯飞星火,腾讯混元,ChatGPT等。

  5. token:api对应的接口密钥。

  6. model:使用的模型名称,请检查对应接口文档说明,不同接口包含的模型不一致。

  7. prompt:提示词,请自行定制,建议详细一些,但是不要太废话,以我写的为例。

  8. ignoreRules:忽略文本正则接口,由于本插件直接获取Markdown文本,内置了一些处理,但是你仍然可以进行额外的处理,下面是内置的文本处理规则,如果有兴趣进行修改可以进行参考:

javascript 复制代码
// 2. 清理内容
  content = content
    .replace(/```[\s\S]*?```/g, '')           // 代码块
    // .replace(/`[^`\n]+`/g, '')                // 行内代码
    .replace(/{%[^%]*%}/g, '')                // Hexo 标签
    .replace(/^\|.*?\|.*$/gm, '')             // 表格行
    .replace(/!\[.*?\]\(.*?\)/g, '')          // 图片
    .replace(/\[(.*?)\]\(.*?\)/g, '$1')       // 超链接文本
    .replace(/<[^>]+>/g, '')                  // HTML 标签
    .replace(/&nbsp;/g, ' ')                  // 空格实体
    .replace(/\n{2,}/g, '\n')                 // 多重换行压缩
    .replace(/^\s+|\s+$/gm, '')               // 行首尾空格
    .replace(/[ \t]+/g, ' ')                  // 多空格压缩
    .trim();

  // 3. 拼接标题
  const combined = (title ? title.trim() + '\n\n' : '') + content;

但是大部分情况可以忽略这个配置项,留空即可。

  1. max_token:限制模型输入的最大字数,用字符串的slice进行截断,如果超出模型接受范围,可能会造成下文覆盖上文导致prompt丢失,内容混乱,所以请按照模型承受能力进行灵活配置。

  2. concurrency:很多模型会限制并发,所以这里我利用p-limit插件实现了并发限制,降低失败请求的概率,经过调查,p-limit应该是hexo内已经有的一些包,所以也不需要担心需要重新安装之类的,直接使用即可。

3、Hexo适配

添加配置

目前我们已经自动化了从AI中,喂我们的文章给AI,再生成摘要,再写到文件顶部的过程,下面我们开始进行从文件顶部渲染到网站页面上。

首先在主题配置文件_config.butterfly.yml文件中写入配置,方便我们进行控制摘要是否开启:

bash 复制代码
# --------------------------------------
# 文章设置
# --------------------------------------
# 文章AI摘要是否开启,会自动检索文章色summary字段,若没有则不显示
ai_summary:
  enable: true
  title: AI摘要
  loadingText: 正在加载···
  modelName: HunYuan-Lite

这里的内容均为装饰性内容,除了enable选项,其他没有任何控制效果,都是装饰,所以无需担心,可以先按照我的写,后面再根据效果修改。

添加模板

下面找到主题文件下的/themes/butterfly/layout/post.pug文件,添加文件中指出来的两行内容:

bash 复制代码
extends includes/layout.pug

block content
  #post
    if top_img === false
      include includes/header/post-info.pug

    article#article-container.post-content
+     if page.summary && theme.ai_summary.enable
+       include includes/post/post-summary.pug
      !=page.content
    include includes/post/post-copyright.pug
    .tag_share
      if (page.tags.length > 0 && theme.post_meta.post.tags)
        .post-meta__tag-list
          each item, index in page.tags.data
            a(href=url_for(item.path)).post-meta__tags #[=item.name]
      include includes/third-party/share/index.pug

    if theme.reward.enable && theme.reward.QR_code
      !=partial('includes/post/reward', {}, {cache: true})

    //- ad
    if theme.ad && theme.ad.post
      .ads-wrap!=theme.ad.post

    if theme.post_pagination
      include includes/pagination.pug
    if theme.related_post && theme.related_post.enable
      != related_posts(page,site.posts)

    if page.comments !== false && theme.comments.use
      - var commentsJsLoad = true
      !=partial('includes/third-party/comments/index', {}, {cache: true})

注意缩进,pug作为预编译语言,对缩进的要求极为严格,在该文件中,应该是两个空格一缩进。

下面添加组件,创建文件/root/theme/butterfly/layout/includes/post/post-summary.pug,写入以下内容:

bash 复制代码
.ai-summary
    .ai-explanation(style="display: block;" data-summary=page.summary)=theme.ai_summary.loadingText
    .ai-title 
        .ai-title-left 
            i.fa-brands.fa-slack
            .ai-title-text=theme.ai_summary.title
        .ai-tag#ai-tag= theme.ai_summary.modelName

添加样式

这样,html部分就实现好了!下面我们添加样式部分,创建文件/themes/butterfly/source/css/_layout/ai-summary.styl文件,写入:

css 复制代码
// ===================
// 🌗 主题变量定义(仅使用项)
// ===================

:root
  // ai_summary
  --liushen-title-font-color: #0883b7
  --liushen-maskbg: rgba(255, 255, 255, 0.85)
  --liushen-ai-bg: conic-gradient(from 1.5708rad at 50% 50%, #d6b300 0%, #42A2FF 54%, #d6b300 100%)

  // card 背景
  --liushen-card-secondbg: #f1f3f8

  // text
  --liushen-text: #4c4948
  --liushen-secondtext: #3c3c43cc

[data-theme='dark']
  // ai_summary
  --liushen-title-font-color: #0883b7
  --liushen-maskbg: rgba(0, 0, 0, 0.85)
  --liushen-ai-bg: conic-gradient(from 1.5708rad at 50% 50%, rgba(214, 178, 0, 0.46) 0%, rgba(66, 161, 255, 0.53) 54%, rgba(214, 178, 0, 0.49) 100%)

  // card 背景
  --liushen-card-secondbg: #3e3f41

  // text
  --liushen-text: #ffffffb3
  --liushen-secondtext: #a1a2b8

// ===================
// 📘 AI 摘要模块样式
// ===================

if hexo-config('ai_summary.enable')
  .ai-summary
    background-color var(--liushen-maskbg)
    background var(--liushen-card-secondbg)
    border-radius 12px
    padding 8px 8px 12px 8px
    line-height 1.3
    flex-direction column
    margin-bottom 16px
    display flex
    gap 5px
    position relative

    &::before
      content ''
      position absolute
      top 0
      left 0
      width 100%
      height 100%
      z-index 1
      filter blur(8px)
      opacity .4
      background-image var(--liushen-ai-bg)
      transform scaleX(1) scaleY(.95) translateY(2px)
    
    &::after
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      z-index: 2;
      border-radius: 12px;
      background: var(--liushen-maskbg);

    .ai-explanation
      z-index 10
      padding 8px 12px
      font-size 15px
      line-height 1.4
      color var(--liushen-text)
      text-align justify

      // ✅ 打字机光标动画
      &::after
        content ''
        display inline-block
        width 8px
        height 2px
        margin-left 2px
        background var(--liushen-text)
        vertical-align bottom
        animation blink-underline 1s ease-in-out infinite
        transition all .3s
        position relative
        bottom 3px

      // 平滑滚动动画
      // .char
      //   display inline-block
      //   opacity 0
      //   animation chat-float .5s ease forwards
    
    .ai-title
      z-index 10
      font-size 14px
      display flex
      border-radius 8px
      align-items center
      position relative
      padding 0 12px
      cursor default
      user-select none

      .ai-title-left
        display flex
        align-items center
        color var(--liushen-title-font-color)

        i
          margin-right 3px
          display flex
          color var(--liushen-title-font-color)
          border-radius 20px
          justify-content center
          align-items center

        .ai-title-text
          font-weight 500

      .ai-tag
        color var(--liushen-secondtext)
        font-weight 300
        margin-left auto
        display flex
        align-items center
        justify-content center
        transition .3s

  // 平滑滚动动画
  // @keyframes chat-float
  //   0% 
  //     opacity 0
  //     transform translateY(20px)
  //   100% 
  //       opacity 1
  //       transform translateY(0)
  
  // ✅ 打字机光标闪烁动画
  @keyframes blink-underline
    0%, 100%
      opacity 1
    50%
      opacity 0

样式也实现啦!目前就差将我们的摘要插入到我们的网站就大功告成啦,为了实现的更加逼真,我这里实现了两种样式一个是打字机效果,一个是平滑显示效果,可以按需引入:

添加核心JS

下面我会介绍两种动效,可以按照自己的需求在任意js文件中选择一个引入即可,两个的区别是,打字机效果更加的节省性能,而平滑显示,因为每个文本为一个span,所以会比较耗费性能。

打字机效果

javascript 复制代码
// 打字机效果
function typeTextMachineStyle(text, targetSelector, options = {}) {
    const {
        delay = 50,
        startDelay = 2000,
        onComplete = null,
        clearBefore = true,
        eraseBefore = true, // 新增:是否以打字机方式清除原文本
        eraseDelay = 30,    // 新增:删除每个字符的间隔
    } = options;

    const el = document.querySelector(targetSelector);
    if (!el || typeof text !== "string") return;

    setTimeout(() => {
        const startTyping = () => {
            let index = 0;
            function renderChar() {
                if (index <= text.length) {
                    el.textContent = text.slice(0, index++);
                    setTimeout(renderChar, delay);
                } else {
                    onComplete && onComplete(el);
                }
            }
            renderChar();
        };

        if (clearBefore) {
            if (eraseBefore && el.textContent.length > 0) {
                let currentText = el.textContent;
                let eraseIndex = currentText.length;

                function eraseChar() {
                    if (eraseIndex > 0) {
                        el.textContent = currentText.slice(0, --eraseIndex);
                        setTimeout(eraseChar, eraseDelay);
                    } else {
                        startTyping(); // 删除完毕后开始打字
                    }
                }

                eraseChar();
            } else {
                el.textContent = "";
                startTyping();
            }
        } else {
            startTyping();
        }
    }, startDelay);
}

function renderAISummary() {
    const summaryEl = document.querySelector('.ai-summary .ai-explanation');
    if (!summaryEl) return;

    const summaryText = summaryEl.getAttribute('data-summary');
    if (summaryText) {
        typeTextMachineStyle(summaryText, ".ai-summary .ai-explanation"); // 如果需要切换,在这里调用另一个函数即可
    }
}

document.addEventListener('pjax:complete', renderAISummary);
document.addEventListener('DOMContentLoaded', renderAISummary);

本站使用的就是打字机效果,可以自行查看。

平滑显示效果

这个我没有测试,如果好奇可以自行部署并尝试:

javascript 复制代码
 // 平滑弹出效果
 function typeText(text, targetSelector, options = {}) {
     const {
       delay = 50,          // 每个字符之间的延迟(毫秒)
       startDelay = 2000,   // 开始打字前的延迟(默认 3 秒)
       onComplete = null,   // 动画完成后的回调
       clearBefore = true   // 是否在开始前清空原有内容
     } = options;

     const targetEl = document.querySelector(targetSelector);
     if (!targetEl || typeof text !== "string") return;

     // if (clearBefore) targetEl.textContent = "";

     let index = 0;
     let frameId = null;

     function renderChar() {
       if (index < text.length) {
         const span = document.createElement("span");
         span.textContent = text[index++];
         span.className = "char";
         targetEl.appendChild(span);
         frameId = requestAnimationFrame(() => setTimeout(renderChar, delay));
       } else {
         cancelAnimationFrame(frameId);
         onComplete && onComplete(targetEl);
       }
     }

     setTimeout(() => {
         if (clearBefore) targetEl.textContent = "";
         renderChar();
     }, startDelay);
 }

function renderAISummary() {
    const summaryEl = document.querySelector('.ai-summary .ai-explanation');
    if (!summaryEl) return;

    const summaryText = summaryEl.getAttribute('data-summary');
    if (summaryText) {
        typeText(summaryText, ".ai-summary .ai-explanation"); // 如果需要切换,在这里调用另一个函数即可
    }
}

document.addEventListener('pjax:complete', renderAISummary);
document.addEventListener('DOMContentLoaded', renderAISummary);

注意,平滑滚动部分的css,我默认注释掉了,请在样式文件中自行打开注释。

这样,一个自己实现的AI摘要就完工啦!

4、运行结果

bash 复制代码
hexo c;hexo g

如果一切正常,应该可以在每篇文章的顶部看到对应的摘要文段。

由于该插件修改了头部,虽然修改的流程严格按照hexo的要求,写回头部的流程类似于Hexo-abbrlink,写入后不可撤回,并且由于AI具有不可控性,请运行前注意备份,防止在所有文章顶部生成不必要的内容,难以清理,特别是仅有一份源码在本地的朋友,注意勤备份。


作者: 码农刚子

邮箱: [email protected]

原文链接: https://www.codeobservatory.cn/archives/9dd55dbc.html

相关推荐
gavin carter1 天前
gitHub hexo 个人博客升级版
python·github·hexo
CSharp精选营23 天前
小白也能行!10分钟用Cursor搭建个人博客网站(零基础教程)
hexo·github pages·个人博客·cursor
Silence4Allen25 天前
零基础用 Hexo + Matery 搭建博客|Github Pages 免费部署教程
github·hexo·博客搭建·matery
小雅痞2 个月前
[Mac]利用Hexo+Github Pages搭建个人博客
macos·hexo·github.io
心凉了3 个月前
Hexo引用图床图片403解决方案
hexo
丶Darling.3 个月前
利用hexo+github部署属于自己的个人博客网站(2025年3月所写)
git·github·nodejs·hexo·个人博客
switch_swq4 个月前
使用Hexo部署NexT主体网站
笔记·学习·node.js·html5·hexo·next·网页
xiaolin03334 个月前
把本地搭建的hexo博客部署到自己的服务器上
服务器·hexo
sleP4o5 个月前
Hexo + NexT + Github搭建个人博客
github·hexo·next·个人博客