Compare commits

..

7 Commits

Author SHA1 Message Date
GitHub Action
63de83f68e 🤖 Auto-update AI summary cache [skip ci] 2025-06-04 08:00:45 +00:00
1082654942 2564 2025-06-04 16:00:07 +08:00
94628b57c3 Update ci.yml 2025-06-04 15:58:32 +08:00
c4540d868e Merge branch 'main' of https://github.com/Wcowin/Mkdocs-Wcowin 2025-06-04 15:55:28 +08:00
ae13ab78f4 2564 2025-06-04 15:55:26 +08:00
GitHub Action
9e8af81916 🤖 Auto-update AI summary cache [skip ci] 2025-06-04 07:22:54 +00:00
74812525a2 Update ai_summary.py 2025-06-04 15:22:07 +08:00
35 changed files with 1542 additions and 298 deletions

View File

@ -0,0 +1,7 @@
{
"summary": "本文介绍了Git版本控制系统的核心操作与实用技巧涵盖仓库创建、分支管理、冲突解决等基础功能重点讲解了stash暂存、rebase/merge策略选择、cherry-pick等高效工作方法。通过具体代码示例和场景说明帮助开发者掌握提交修改、撤销变更、生成补丁等关键操作提升团队协作和代码管理效率。",
"service": "deepseek",
"page_title": "Git 实用技巧",
"timestamp": "2025-06-04T15:14:01.936057",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "MkDocs允许通过自定义HTML文件实现页脚个性化配置。用户需在docs/overrides/partials目录下创建或修改footer.html文件插入特定代码片段即可完成页脚定制。该功能适用于需要品牌展示、版权声明或导航链接等场景通过覆盖默认模板实现灵活布局。操作仅需基础HTML知识无需编译过程。",
"service": "deepseek",
"page_title": "页脚设置",
"timestamp": "2025-06-04T15:12:53.237431",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "Tidio提供免费、无需梯子的在线聊天解决方案适用于网站集成。用户只需注册账号从设置中获取专属JavaScript代码将其嵌入网站指定位置即可完成部署。该工具安装简便仅需单行代码即可实现实时聊天功能适合快速为网站添加客服系统。",
"service": "deepseek",
"page_title": "添加在线聊天",
"timestamp": "2025-06-04T15:13:43.957414",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "本文介绍了网页圆角化设计的实现方法重点讲解通过CSS样式文件实现图片和边框的圆角效果。具体包括在mkdocs.yml中引入CSS文件、编写圆角样式代码以及在Markdown文件中应用的方法同时展示了按钮和卡片组件的圆角化实现示例。该技术可提升网页视觉美感适用于文档网站和UI组件开发。",
"service": "deepseek",
"page_title": "网页圆角化设计",
"timestamp": "2025-06-04T15:13:52.101323",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "该技术方案通过git-revision-date-localized插件为MKdocs文档系统添加文章修订时间戳功能。核心实现包括在CI工作流中配置智能渲染策略既避免了本地渲染时全量检查git历史导致的性能损耗又能确保发布时准确显示最后更新时间。该方法显著提升了文档系统的维护性和用户体验特别适合需要展示内容时效性的技术文档场景。",
"service": "deepseek",
"page_title": "为MKdocs添加文章修订时间戳",
"timestamp": "2025-06-04T15:13:36.305003",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "MIT许可证授予用户自由使用、修改、分发软件的广泛权利仅要求保留版权声明和许可条款。该许可证明确声明软件不提供任何担保作者不对使用后果承担责任。作为宽松开源协议MIT许可证允许商业用途和二次开发适用于希望最大限度开放代码的开发者。",
"service": "deepseek",
"page_title": "许可声明",
"timestamp": "2025-06-04T15:10:35.586724",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "在GitHub Pages部署mkdocs时自定义域名失效的原因是本地缺少CNAME文件导致推送后被清除。解决方法是在/docs目录下创建无后缀的CNAME文件并填入域名确保每次推送后配置信息得以保留。该方案有效解决了因文件缺失导致的域名绑定失效问题。",
"service": "deepseek",
"page_title": "3.解决Github Pages部署mkdocs自定义域名失效的问题",
"timestamp": "2025-06-04T15:11:04.997045",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "本文总结了MkDocs文档系统中相对地址引用的常见问题与解决方案重点阐述了图片、PDF、跨页面及静态资源的正确引用方式。核心要点包括以docs目录为根路径进行相对定位保持路径大小写一致统一资源目录结构。针对本地与线上环境差异提供了确保资源可访问性的实用技巧如路径检查、文件压缩等为MkDocs项目的资源管理提供了系统化指导。",
"service": "deepseek",
"page_title": "相对地址的一些问题",
"timestamp": "2025-06-04T15:12:22.532085",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "唐·诺曼提出的情感设计三层次理论包括本能层、行为层和反思层。本能层关注产品外观引发的即时情感反应;行为层强调使用过程中的功能性和效率体验;反思层涉及用户对产品的理性认知和自我形象关联。这三个层次相互影响,共同塑造用户对产品的整体体验。该理论为设计实践提供了系统框架,解释了为何某些产品即使存在功能缺陷仍能获得市场成功。",
"service": "deepseek",
"page_title": "唐·诺曼—情感设计的三个层次",
"timestamp": "2025-06-04T15:14:41.148887",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "Mkdocs内置博客插件可快速搭建技术博客只需在mkdocs.yml中添加简单配置即可启用。支持通过docs/blog/.authors.yml文件管理作者信息无需额外创建文件。该方案适合文档站点集成博客功能具有配置简单、维护便捷的特点适用于技术团队分享文章或项目动态。",
"service": "deepseek",
"page_title": "添加Mkdocs博客",
"timestamp": "2025-06-04T15:11:12.460937",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "本次网站更新主要围绕性能优化和功能完善展开包括持续优化网站流畅度、修复Markdown解析异常、改进友链统计准确性等核心改进。技术层面涉及代码重构、插件调整如取消glightbox及界面交互优化留言板按钮切换。同时更新了教程内容以适配官方最新版本并解决了图片显示、评论区定位等具体问题。更新记录显示开发者兼顾性能提升与用户体验改善的双重目标。",
"service": "deepseek",
"page_title": "2025网站更新记录",
"timestamp": "2025-06-04T15:12:05.048968",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "本文介绍了开源中文字体\"霞鹜文楷\"的技术特点与应用。该字体基于日本FONTWORKS公司的Klee One衍生开发包含多个版本屏幕阅读版、轻便版、GB/TC版等支持简繁中文及谚文。文章详细说明了字体的开发背景、补字计划、获取方式及使用注意事项特别强调了其开源特性SIL授权和针对不同场景的优化设计适合网站嵌入和移动设备显示。",
"service": "deepseek",
"page_title": "修改网站字体",
"timestamp": "2025-06-04T15:13:20.429334",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "该技术文档介绍了三种网页背景特效的实现方法雪花、樱花和粒子效果。核心是通过JavaScript动态加载特效脚本并利用LocalStorage存储用户偏好设置来控制特效显示。代码示例展示了如何通过DOM操作插入外部脚本实现可配置的动态背景效果适用于增强网页视觉体验。",
"service": "deepseek",
"page_title": "背景特效",
"timestamp": "2025-06-04T15:12:42.871226",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "本文详细介绍了使用MkDocs框架部署静态网页到GitHub Pages的完整流程。重点讲解了从创建GitHub仓库、本地环境配置、MkDocs初始化到最终部署的关键步骤包括目录结构调整、workflow配置和页面发布设置。教程采用Material for MkDocs主题提供了基础yml配置示例并强调通过GitHub Desktop实现代码同步。该方法适合快速搭建技术文档网站或个人博客具备版本控制优势。",
"service": "deepseek",
"page_title": "1.利用Mkdocs部署静态网页",
"timestamp": "2025-06-04T15:10:46.691272",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "MWeb Pro是一款专为macOS设计的专业Markdown写作与笔记应用支持GFM语法扩展包括表格、LaTeX、代码块及多种图表库。提供便捷的图片插入、表格编辑和文档导出功能支持多种格式输出及主流博客平台发布。内置强大的笔记管理系统支持分类树、标签管理和快速搜索适合个人知识整理与静态网站生成。原生优化界面简洁高效兼顾功能全面与易用性。",
"service": "deepseek",
"page_title": "MWeb Pro",
"timestamp": "2025-06-04T15:14:21.266829",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "本文介绍如何在文档站点中添加顶部公告栏,通过修改`docs/overrides/main.html`文件实现自定义公告内容。操作步骤包括创建该HTML文件并编辑其代码结构用户可根据需求灵活调整公告栏样式和内容。该方法适用于需要突出显示重要通知的技术文档网站实现简单且无需改动核心框架。",
"service": "deepseek",
"page_title": "添加顶部公告栏",
"timestamp": "2025-06-04T15:13:00.936276",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "本文介绍了MkDocs文档工具的学习资源和使用指南包括官方教程、Material主题、插件列表以及作者提供的中文教程语雀、CSDN、知乎。内容涵盖快速部署静态网页到GitHub Pages、配置mkdocs.yml文件以及添加博客功能并附有视频教程。最后请求使用者注明教程来源并支持友链申请。",
"service": "deepseek",
"page_title": "0.Mkdocs教程前言",
"timestamp": "2025-06-04T15:11:20.593701",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "本文介绍了使用MkDocs构建网站时的性能优化方案包括采用WebP等高效图片格式压缩资源、利用CDN加速静态文件分发以及通过合理配置git插件提升本地渲染效率。重点阐述了开发环境与生产环境的差异化配置策略并推荐使用Lighthouse工具进行性能测试验证优化效果。这些措施能有效降低页面加载延迟提升用户体验。",
"service": "deepseek",
"page_title": "加速网站访问的一些心得",
"timestamp": "2025-06-04T15:12:34.767613",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "Markdown是一种轻量级标记语言支持纯文本编写并转换为多种格式如HTML/PDF。本文介绍了其核心语法标题分级、文本样式斜体/粗体)、列表(有序/无序)、表格、链接/图片插入、代码块及特殊字符处理。同时推荐了各平台常用编辑工具如MacDown、Dillinger适用于快速创建结构化文档。语法简洁易学适合技术文档编写与日常笔记整理。",
"service": "deepseek",
"page_title": "Markdown指南",
"timestamp": "2025-06-04T15:14:32.352182",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "该文介绍了通过JavaScript和CSS自定义网页鼠标样式的实现方法重点说明了关键参数配置包括鼠标尺寸、颜色支持RGB值和颜色名称以及圆形跟随效果。提供了具体的代码示例和配置路径并强调需在mkdocs.yml中引入相关文件。适用于需要个性化鼠标交互效果的网页开发场景。",
"service": "deepseek",
"page_title": "JS实现鼠标样式",
"timestamp": "2025-06-04T15:13:28.158803",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "2024年网站持续优化重点提升流畅度和访问速度包括启用CDN加速、删除冗余代码、优化UI显示效果。技术改进涉及JS/CSS代码精简、MKdocs主题更新、图片迁移至SMMS平台并引入自动新标签页打开功能。网站被百度/谷歌收录友链扩展至16个同时完善了文档版本管理插件。",
"service": "deepseek",
"page_title": "2024网站更新记录",
"timestamp": "2025-06-04T15:11:53.050478",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "本文阐述了设计的核心原则与实践要点,强调简洁性、美感和用户体验的重要性。作者提出优秀设计应去除冗余元素,注重视觉平衡与细节把控,同时以用户需求为中心构建直观交互。创新思维和情感共鸣被列为关键要素,通过故事性设计传递品牌价值。全文突出了设计在功能性与艺术性之间的平衡,以及细节处理对产品质感的提升作用。",
"service": "deepseek",
"page_title": "我对设计的一些观点",
"timestamp": "2025-06-04T15:14:49.241260",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "本文详细介绍了Mkdocs配置文件mkdocs.yml的核心配置项包括站点基本信息、主题配色方案、导航功能设置和搜索优化等。重点讲解了如何通过palette配置实现明暗模式切换以及通过features启用目录跟踪、标签页、代码复制等实用功能。此外还涉及多语言支持、图标自定义、标签系统实现方法并提供了扩展Markdown语法和添加自定义CSS/JS的配置指导。该配置文件可帮助用户快速搭建功能完善、界面美观的文档网站。",
"service": "deepseek",
"page_title": "2.Mkdocs配置说明(mkdocs.yml)",
"timestamp": "2025-06-04T15:10:56.177242",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "Lighthouse是谷歌开发的网站性能测试工具可评估页面加载速度、可访问性等关键指标。通过浏览器开发者工具F12即可快速启动测试适用于各类网站的性能优化。该工具提供直观的评分和详细改进建议帮助开发者定位性能瓶颈提升用户体验。测试过程简单无需额外安装支持主流Chromium内核浏览器。",
"service": "deepseek",
"page_title": "利用Lighthouse测试网站性能",
"timestamp": "2025-06-04T15:14:10.415296",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "2022年网站建设过程包括10月建立Github仓库并正式建站取消cookie确认简化访问流程新增首页反馈功能6月确定采用MKdocs框架搭建10月完成独立域名wcowin.work的注册。主要优化了用户体验和隐私保护技术方案选择轻量级文档框架。",
"service": "deepseek",
"page_title": "2022网站更新记录",
"timestamp": "2025-06-04T15:11:29.885224",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "giscus是一款基于GitHub Discussions的开源评论系统无需数据库且完全免费。它支持多语言、自定义主题和高可配置性数据自动同步GitHub Discussions。相比传统方案giscus无需维护服务器无跟踪和广告适合技术博客和文档网站集成。通过简单配置即可实现评论功能同时保留自建服务的灵活性。",
"service": "deepseek",
"page_title": "添加评论系统(giscus为例)",
"timestamp": "2025-06-04T15:13:09.054845",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "2023年网站主要更新包括引入AI问答机器人25条/月限制、多语言支持含台湾地区、国内镜像站点和Mkdocs-Wcowin主题。技术优化涉及图片懒加载、移动端适配、LaTeX渲染修复及网页流畅度提升。新增功能有留言板集成giscus、友链模块和博客板块同时改进了搜索功能与界面设计。全年持续进行性能优化和用户体验改进。",
"service": "deepseek",
"page_title": "2023网站更新记录",
"timestamp": "2025-06-04T15:11:39.818678",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "该插件为MkDocs文档系统提供AI驱动的智能摘要和阅读统计功能支持OpenAI、DeepSeek等多API服务。核心特性包括自动生成80-120字多语言摘要、智能内容清理、高效缓存系统以及精准的中文阅读时间估算。通过灵活的配置选项用户可实现文件夹或页面级别的精确控制并自定义API服务和提示词。安装简便支持直接下载或Git克隆适合技术文档和博客的自动化摘要需求。",
"service": "deepseek",
"page_title": "MkDocs文档AI摘要",
"timestamp": "2025-06-04T15:12:14.050558",
"language": "zh"
}

View File

@ -0,0 +1,10 @@
{
"default_service": "deepseek",
"available_services": [
"deepseek",
"openai",
"gemini"
],
"summary_language": "zh",
"check_time": "2025-06-04T08:00:39.286309"
}

View File

@ -4,6 +4,10 @@ on:
branches:
- master
- main
# 禁止从 fork 仓库访问 secrets
pull_request:
types: [closed]
branches: [main, master]
permissions:
contents: write
jobs:
@ -13,37 +17,60 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0
sparse-checkout: |
docs
includes
.ai_cache
- uses: actions/setup-python@v4
with:
python-version: 3.x
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- name: Set cache ID
run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@v3
with:
key: mkdocs-material-${ env.cache_id }
key: mkdocs-material-${{ github.run_number }}
path: .cache
restore-keys: |
mkdocs-material-
- run: pip install mkdocs-git-revision-date-localized-plugin
- run: pip install mkdocs-git-authors-plugin
- run: pip install mkdocs-git-committers-plugin-2
- run: pip install markdown-callouts
- run: pip install mkdocs-rss-plugin
# - run: pip install jieba
- run: pip install mkdocs-markdownextradata-plugin
# - run: pip install mkdocs-glightbox
# - run: pip install "mkdocs-material[imaging]"
# - run: pip install mkdocs-statistics-plugin
# - run: pip install mkdocs-rss-plugin
- run: pip install requests>=2.25.0
- run: pip install python-dateutil>=2.8.0
- run: pip install cachetools>=4.2.0
- run: pip install python-dotenv>=0.19.0
- run: pip install pymdown-extensions
- run: pip install mkdocs-material
- run: pip install --upgrade --force-reinstall mkdocs-material
- run: pip install requests
- run: mkdocs gh-deploy --force
- name: Deploy with AI Summary
env:
# AI摘要配置
AI_SUMMARY_CI_ENABLED: true # CI环境启用AI摘要
AI_SUMMARY_LOCAL_ENABLED: false # 本地环境禁用AI摘要
AI_SUMMARY_CI_ONLY_CACHE: false # CI环境允许生成新摘要
AI_SUMMARY_CI_FALLBACK: true # CI环境启用备用摘要
# API密钥取消注释以启用真实AI服务
# AI摘要开关控制
AI_SUMMARY_CI_ENABLED: 'true' # CI部署环境启用AI摘要 (true=在CI中为文章生成AI摘要)
AI_SUMMARY_CI_ONLY_CACHE: 'true' # CI部署不生成新摘要 (true=使用本地部署过的摘要缓存不再重复调用API)
AI_SUMMARY_CI_FALLBACK: 'true' # CI部署启用备用摘要 (true=API失败时生成离线基础摘要)
# AI_SUMMARY_LOCAL_ENABLED: 'false' # 本地部署环境禁用AI摘要 (true=本地开发时也生成摘要)(不需要管这条)
# AI_SUMMARY_CACHE_ENABLED: 'true' # 本地启用缓存功能 (true=缓存摘要避免重复生成)(不需要管这条)
# API密钥配置
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: mkdocs gh-deploy --force
# 自动提交新生成的AI缓存文件
- name: Auto-commit AI cache (if any new files)
run: |
if [ -d ".ai_cache" ] && [ "$(ls -A .ai_cache 2>/dev/null)" ]; then
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add .ai_cache/
if ! git diff --cached --quiet; then
git commit -m "🤖 Auto-update AI summary cache [skip ci]"
git push
echo "✅ 自动提交了新的 AI 缓存文件"
else
echo " 没有新的缓存文件需要提交"
fi
else
echo " 没有找到缓存目录或缓存为空"
fi

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
# 环境变量文件(敏感信息)
.env
.env.local
.env.*.local
*.key
# MkDocs 构建输出目录
site/
# AI 摘要缓存目录(项目根目录)- 需要被提交
!.ai_cache/

View File

@ -7,7 +7,9 @@ status: new
# MkDocs AI Hooks
仓库地址https://github.com/Wcowin/mkdocs-ai-hooks
仓库地址https://github.com/Wcowin/mkdocs-ai-hooks
在线预览https://wcowin.work/mkdocs-ai-hooks/
<p align="center">
<img src="https://img.shields.io/badge/MkDocs-Hooks-526CFE?style=for-the-badge&logo=MaterialForMkDocs&logoColor=white" alt="MkDocs Hooks">

View File

@ -1,3 +1,6 @@
from dotenv import load_dotenv
load_dotenv() # 自动加载 .env 文件
import re
import json
import hashlib
@ -9,18 +12,33 @@ import shutil
class AISummaryGenerator:
def __init__(self):
self.cache_dir = Path("site/.ai_cache")
# 🗂️ 统一缓存路径策略 - 本地和CI环境都使用项目根目录
# 这样避免了CI构建时被清理也简化了路径管理
self.cache_dir = Path(".ai_cache")
self.cache_dir.mkdir(parents=True, exist_ok=True)
# 🚀 CI 环境配置 - 默认只在 CI 环境中启用
# AI摘要环境配置
self.ci_config = {
'enabled_in_ci': os.getenv('AI_SUMMARY_CI_ENABLED', 'true').lower() == 'true', # 默认 CI 中启用
'enabled_in_local': os.getenv('AI_SUMMARY_LOCAL_ENABLED', 'false').lower() == 'true', # 默认本地禁用
# 'enabled_in_local': os.getenv('AI_SUMMARY_LOCAL_ENABLED', 'true').lower() == 'true', # 默认本地启用
'ci_only_cache': os.getenv('AI_SUMMARY_CI_ONLY_CACHE', 'false').lower() == 'true', # CI 中也允许生成新摘要
'ci_fallback_enabled': os.getenv('AI_SUMMARY_CI_FALLBACK', 'true').lower() == 'true'
# CI部署环境开关 (true=CI中启用AI摘要生成)
'enabled_in_ci': os.getenv('AI_SUMMARY_CI_ENABLED', 'true').lower() == 'true',
# 本地部署环境开关 (true=本地开发时启用AI摘要)
'enabled_in_local': os.getenv('AI_SUMMARY_LOCAL_ENABLED', 'false').lower() == 'true',
# CI部署仅缓存模式 (true=仅使用缓存不调用API, false=允许生成新摘要)
'ci_only_cache': os.getenv('AI_SUMMARY_CI_ONLY_CACHE', 'false').lower() == 'true',
# 本地部署缓存功能开关 (true=启用缓存避免重复生成, false=总是生成新摘要)
'cache_enabled': os.getenv('AI_SUMMARY_CACHE_ENABLED', 'true').lower() == 'true',
# CI部署备用摘要开关 (true=API失败时生成基础摘要, false=失败时不显示摘要)
'ci_fallback_enabled': os.getenv('AI_SUMMARY_CI_FALLBACK', 'true').lower() == 'true',
}
# 🔄 自动缓存迁移逻辑(一次性迁移旧缓存) - 移到ci_config初始化之后
self._auto_migrate_cache()
# 添加服务配置文件,用于跟踪当前使用的服务
self.service_config_file = self.cache_dir / "service_config.json"
@ -47,17 +65,17 @@ class AISummaryGenerator:
# 'max_tokens': 150,
# 'temperature': 0.3
# },
# 'gemini': {
# 'url': 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent',
# 'model': 'gemini-pro',
# 'api_key': os.getenv('GOOGLE_API_KEY', 'your-claude-api-key'),
# 'max_tokens': 150,
# 'temperature': 0.3
# }
'gemini': {
'url': 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent',
'model': 'gemini-pro',
'api_key': os.getenv('GOOGLE_API_KEY', 'AIzaSyDwWgffCCyVFZVsRasX3B3arWFaCT1PzNI'),
'max_tokens': 150,
'temperature': 0.3
}
}
# 默认使用的AI服务
self.default_service = 'deepseek' # 默认使用 DeepSeek
self.default_service = 'deepseek'
# 服务优先级(按顺序尝试)
self.service_fallback_order = ['openai', 'deepseek', 'claude', 'gemini']
@ -66,44 +84,29 @@ class AISummaryGenerator:
self.enabled_folders = [
'blog/', # blog文件夹
'develop/', # develop文件夹
# 'about/', # about文件夹
# 在这里添加您想要启用AI摘要的文件夹
# 'posts/', # posts文件夹
# 'trip/', # trip文件夹
# 'about/', # about文件夹
]
# 📋 Excluded files and folders
# 📋 排除的文件和文件夹
self.exclude_patterns = [
'404.md', 'tag.md', 'tags.md',
'waline.md', 'link.md', '404.md', 'tag.md', 'tags.md',
'/about/', '/search/', '/sitemap', '/admin/',
'index.md', # 根目录index.md
]
# 📋 Excluded specific files
# 📋 排除的特定文件
self.exclude_files = [
'blog/index.md',
'blog/indexblog.md',
'docs/index.md',
'develop/index.md',
]
# 🌍 语言配置/Language Configuration
self.summary_language = 'zh' # 默认中文,可选 'zh'、'en'、'both'
# 初始化阅读统计相关的正则表达式
self.chinese_chars_pattern = re.compile(r'[\u4e00-\u9fff\u3400-\u4dbf]')
self.code_block_pattern = re.compile(r'```.*?```', re.DOTALL)
self.inline_code_pattern = re.compile(r'`[^`]+`')
self.yaml_front_pattern = re.compile(r'^---.*?---\s*', re.DOTALL)
self.html_tag_pattern = re.compile(r'<[^>]+>')
self.image_pattern = re.compile(r'!\[.*?\]\([^)]+\)')
self.link_pattern = re.compile(r'\[([^\]]+)\]\([^)]+\)')
# 支持的编程语言
self.programming_languages = frozenset({
'python', 'py', 'javascript', 'js', 'typescript', 'ts', 'java', 'cpp', 'c',
'go', 'rust', 'php', 'ruby', 'swift', 'kotlin', 'csharp', 'cs',
'bash', 'sh', 'powershell', 'ps1', 'zsh', 'fish', 'bat', 'cmd',
'html', 'css', 'scss', 'sass', 'less', 'yaml', 'yml', 'json', 'xml',
'toml', 'ini', 'conf', 'dockerfile', 'makefile',
'sql', 'mysql', 'postgresql', 'sqlite', 'mongodb',
'r', 'matlab', 'scala', 'perl', 'lua', 'dart', 'tex', 'latex',
'csv', 'properties', ''
})
# 在初始化时就进行环境检查
self._check_environment()
@ -133,6 +136,10 @@ class AISummaryGenerator:
def _check_service_change(self):
"""检查AI服务是否发生变更如有变更则自动清理缓存"""
# 如果禁用了缓存功能,跳过服务变更检查
if not self.ci_config['cache_enabled']:
return
current_config = {
'default_service': self.default_service,
'available_services': list(self.ai_services.keys()),
@ -284,6 +291,10 @@ class AISummaryGenerator:
def get_cached_summary(self, content_hash):
"""获取缓存的摘要"""
# 如果禁用了缓存功能直接返回None
if not self.ci_config['cache_enabled']:
return None
cache_file = self.cache_dir / f"{content_hash}.json"
if cache_file.exists():
try:
@ -299,6 +310,10 @@ class AISummaryGenerator:
def save_summary_cache(self, content_hash, summary_data):
"""保存摘要到缓存"""
# 如果禁用了缓存功能,不保存缓存
if not self.ci_config['cache_enabled']:
return
cache_file = self.cache_dir / f"{content_hash}.json"
try:
summary_data['timestamp'] = datetime.now().isoformat()
@ -573,7 +588,7 @@ Please generate bilingual summary:"""
# 如果在 CI 环境中且配置为只使用缓存
if is_ci and self.ci_config['ci_only_cache']:
print(f"📦 CI 环仅使用缓存模式")
print(f"📦 CI 环 environment仅使用缓存模式")
return None, 'ci_cache_only'
# 按优先级尝试不同服务
@ -624,18 +639,18 @@ Please generate bilingual summary:"""
priority_sentences.append(sentence)
else:
normal_sentences.append(sentence)
# 组合摘要
selected_sentences = []
total_length = 0
# 优先使用关键句子
for sentence in priority_sentences:
if total_length + len(sentence) > 100:
break
selected_sentences.append(sentence)
total_length += len(sentence)
# 如果还有空间,添加普通句子
if total_length < 80:
for sentence in normal_sentences:
@ -643,7 +658,7 @@ Please generate bilingual summary:"""
break
selected_sentences.append(sentence)
total_length += len(sentence)
if selected_sentences:
summary = '.'.join(selected_sentences) + '.'
# 简化冗长的摘要
@ -672,119 +687,34 @@ Please generate bilingual summary:"""
def _generate_chinese_fallback(self, page_title=""):
"""生成中文备用摘要"""
if any(keyword in page_title for keyword in ['教程', '指南', 'Tutorial']):
return '本文提供了详细的教程指南,通过实例演示帮助读者掌握相关技术要点。'
elif any(keyword in page_title for keyword in ['配置', '设置', '安装', 'Config']):
return '本文介绍了系统配置的方法和步骤,提供实用的设置建议和最佳实践。'
elif any(keyword in page_title for keyword in ['开发', '编程', 'Development']):
return '本文分享了开发经验和技术实践,提供了实用的代码示例和解决方案。'
if page_title:
# 根据标题生成通用摘要
if any(keyword in page_title for keyword in ['教程', '指南', '配置', '安装']):
return f"本文介绍了{page_title}的相关内容,包括具体的操作步骤和注意事项,为读者提供实用的技术指导。"
elif any(keyword in page_title for keyword in ['分析', '研究', '探讨', '原理']):
return f"本文深入分析了{page_title}的核心概念和技术原理,为读者提供详细的理论解析和实践见解。"
elif any(keyword in page_title for keyword in ['开发', '构建', '实现', '设计']):
return f"本文详细讲解了{page_title}的开发过程和实现方法,分享了实际的开发经验和技术方案。"
else:
return f"本文围绕{page_title}展开讨论,介绍了相关的技术概念、应用场景和实践方法。"
else:
return '本文深入探讨了相关技术内容,提供了实用的方法和解决方案。'
return "本文介绍了相关的技术概念和实践方法,为读者提供有价值的参考信息。"
def _generate_english_fallback(self, page_title=""):
"""生成英文备用摘要"""
if any(keyword in page_title.lower() for keyword in ['tutorial', 'guide', '教程', '指南']):
return 'This article provides a detailed tutorial guide with practical examples to help readers master relevant technical points.'
elif any(keyword in page_title.lower() for keyword in ['config', 'setup', 'install', '配置', '设置', '安装']):
return 'This article introduces system configuration methods and procedures, providing practical setup suggestions and best practices.'
elif any(keyword in page_title.lower() for keyword in ['develop', 'programming', 'code', '开发', '编程']):
return 'This article shares development experience and technical practices, providing practical code examples and solutions.'
if page_title:
# 根据标题生成通用摘要
if any(keyword in page_title.lower() for keyword in ['tutorial', 'guide', 'setup', 'install', 'config']):
return f"This article provides a comprehensive guide on {page_title}, including step-by-step instructions and important considerations for practical implementation."
elif any(keyword in page_title.lower() for keyword in ['analysis', 'research', 'study', 'principle']):
return f"This article presents an in-depth analysis of {page_title}, exploring core concepts and technical principles with detailed theoretical insights."
elif any(keyword in page_title.lower() for keyword in ['develop', 'build', 'implement', 'design']):
return f"This article explains the development process and implementation methods for {page_title}, sharing practical development experience and technical solutions."
else:
return f"This article discusses {page_title}, covering relevant technical concepts, application scenarios, and practical methods."
else:
return 'This article explores relevant technical content in depth, providing practical methods and solutions.'
def calculate_reading_stats(self, markdown):
"""计算中文字符数和代码行数"""
# 清理内容用于中文字符统计
content = markdown
content = self.yaml_front_pattern.sub('', content)
content = self.html_tag_pattern.sub('', content)
content = self.image_pattern.sub('', content)
content = self.link_pattern.sub(r'\1', content)
content = self.code_block_pattern.sub('', content)
content = self.inline_code_pattern.sub('', content)
chinese_chars = len(self.chinese_chars_pattern.findall(content))
# 统计代码行数
code_lines = self.count_code_lines(markdown)
# 计算阅读时间中文400字/分钟)
reading_time = max(1, round(chinese_chars / 400))
return reading_time, chinese_chars, code_lines
def count_code_lines(self, markdown):
"""统计代码行数"""
code_blocks = self.code_block_pattern.findall(markdown)
total_code_lines = 0
for block in code_blocks:
# 提取语言标识
lang_match = re.match(r'^```(\w*)', block)
language = lang_match.group(1).lower() if lang_match else ''
# 移除开头的语言标识和结尾的```
code_content = re.sub(r'^```\w*\n?', '', block)
code_content = re.sub(r'\n?```$', '', code_content)
# 过滤空代码块
if not code_content.strip():
continue
# 计算有效行数
lines = [line for line in code_content.split('\n') if line.strip()]
line_count = len(lines)
# 如果有明确的编程语言标识,直接统计
if language and language in self.programming_languages:
total_code_lines += line_count
continue
# 检测是否为代码内容
if self.is_code_content(code_content):
total_code_lines += line_count
return total_code_lines
def is_code_content(self, content):
"""判断内容是否为代码"""
# 命令行检测
command_indicators = [
'sudo ', 'npm ', 'pip ', 'git ', 'cd ', 'ls ', 'mkdir ', 'rm ', 'cp ', 'mv ',
'chmod ', 'chown ', 'grep ', 'find ', 'ps ', 'kill ', 'top ', 'cat ', 'echo ',
'wget ', 'curl ', 'tar ', 'zip ', 'unzip ', 'ssh ', 'scp ', 'rsync ',
'$ ', '# ', '% ', '> ', 'C:\\>', 'PS>', '#!/',
'/Applications/', '/usr/', '/etc/', '/var/', '/home/', '~/',
]
if any(indicator in content for indicator in command_indicators):
return True
# 编程语法检测
programming_indicators = [
'def ', 'class ', 'import ', 'from ', 'return ', 'function', 'var ', 'let ', 'const ',
'public ', 'private ', 'protected ', 'static ', 'void ', 'int ', 'string ',
'==', '!=', '<=', '>=', '&&', '||', '++', '--', '+=', '-=',
'while ', 'for ', 'if ', 'else:', 'switch ', 'case ',
'<!DOCTYPE', '<html', '<div', '<span', 'display:', 'color:', 'background:',
]
if any(indicator in content for indicator in programming_indicators):
return True
# 结构化检测
lines = content.split('\n')
if len(lines) > 1 and any(line.startswith(' ') or line.startswith('\t') for line in lines):
return True
if '<' in content and '>' in content:
return True
if any(char in content for char in ['{', '}', '(', ')', '[', ']']) and ('=' in content or ':' in content):
return True
return False
return "This article introduces relevant technical concepts and practical methods, providing valuable reference information for readers."
def is_ci_environment(self):
"""检测是否在 CI 环境中运行"""
# 常见的 CI 环境变量
@ -839,83 +769,115 @@ Please generate bilingual summary:"""
else:
return 'Unknown CI'
def _auto_migrate_cache(self):
"""自动迁移缓存文件(仅在需要时执行一次)"""
# 如果禁用了缓存功能,跳过缓存迁移
if not self.ci_config.get('cache_enabled', True):
return
old_cache_dir = Path("site/.ai_cache")
new_cache_dir = Path(".ai_cache")
# 检查是否需要迁移
if old_cache_dir.exists() and not new_cache_dir.exists():
print("🔄 检测到旧缓存目录,开始自动迁移...")
try:
# 创建新目录
new_cache_dir.mkdir(exist_ok=True)
# 复制文件
cache_files = list(old_cache_dir.glob("*.json"))
copied_count = 0
for cache_file in cache_files:
target_file = new_cache_dir / cache_file.name
try:
shutil.copy2(cache_file, target_file)
copied_count += 1
except Exception as e:
print(f"⚠️ 复制缓存文件失败 {cache_file.name}: {e}")
if copied_count > 0:
print(f"✅ 自动迁移完成!共迁移 {copied_count} 个缓存文件")
print("💡 提示:请将 .ai_cache 目录提交到 Git 仓库")
else:
print(" 没有缓存文件需要迁移")
except Exception as e:
print(f"❌ 自动迁移失败: {e}")
elif new_cache_dir.exists():
# 新缓存目录已存在,检查是否有文件
cache_files = list(new_cache_dir.glob("*.json"))
if cache_files:
is_ci = self.is_ci_environment()
env_desc = '(CI)' if is_ci else '(本地)'
print(f"📦 发现根目录缓存 {env_desc},共 {len(cache_files)} 个缓存文件")
def process_page(self, markdown, page, config):
"""处理页面生成AI摘要和阅读统计支持CI环境检测"""
"""处理页面生成AI摘要支持CI环境检测"""
# 检查是否应该在当前环境运行
if not self.should_run_in_current_environment():
return markdown
# 检查是否需要显示阅读信息
show_reading_info = self.should_show_reading_info(page, markdown)
# 检查是否需要生成AI摘要
should_generate_ai_summary = self.should_generate_summary(page, markdown)
# 如果两者都不需要,直接返回原内容
if not show_reading_info and not should_generate_ai_summary:
if not self.should_generate_summary(page, markdown):
return markdown
# 计算阅读统计
reading_time, chinese_chars, code_lines = self.calculate_reading_stats(markdown)
clean_content = self.clean_content_for_ai(markdown)
result_blocks = []
# 内容长度检查
if len(clean_content) < 100:
print(f"📄 内容太短,跳过摘要生成: {page.file.src_path}")
return markdown
# 处理AI摘要
if should_generate_ai_summary:
clean_content = self.clean_content_for_ai(markdown)
content_hash = self.get_content_hash(clean_content)
page_title = getattr(page, 'title', '')
is_ci = self.is_ci_environment()
# 检查缓存
cached_summary = self.get_cached_summary(content_hash)
if cached_summary:
summary = cached_summary.get('summary', '')
ai_service = cached_summary.get('service', 'cached')
env_desc = '(CI)' if is_ci else '(本地)'
print(f"✅ 使用缓存摘要 {env_desc}: {page.file.src_path}")
else:
# 如果在 CI 环境中且配置为只使用缓存,直接跳过摘要生成
if is_ci and self.ci_config['ci_only_cache']:
print(f"📦 CI 环境仅使用缓存模式,无缓存可用,跳过摘要生成: {page.file.src_path}")
return markdown
# 内容长度检查
if len(clean_content) >= 100:
content_hash = self.get_content_hash(clean_content)
page_title = getattr(page, 'title', '')
is_ci = self.is_ci_environment()
# 检查缓存
cached_summary = self.get_cached_summary(content_hash)
if cached_summary:
summary = cached_summary.get('summary', '')
ai_service = cached_summary.get('service', 'cached')
env_desc = '(CI)' if is_ci else '(本地)'
print(f"✅ 使用缓存摘要 {env_desc}: {page.file.src_path}")
else:
# 生成新摘要
lang_desc = {'zh': '中文', 'en': '英文', 'both': '双语'}
env_desc = '(CI)' if is_ci else '(本地)'
print(f"🤖 正在生成{lang_desc.get(self.summary_language, '中文')}AI摘要 {env_desc}: {page.file.src_path}")
summary, ai_service = self.generate_ai_summary(clean_content, page_title)
if not summary:
# 尝试生成备用摘要
summary = self.generate_fallback_summary(clean_content, page_title)
if summary:
ai_service = 'fallback'
print(f"📝 使用备用摘要 {env_desc}: {page.file.src_path}")
else:
print(f"❌ 无法生成摘要 {env_desc}: {page.file.src_path}")
else:
print(f"✅ AI摘要生成成功 ({ai_service}) {env_desc}: {page.file.src_path}")
# 保存到缓存
if summary:
self.save_summary_cache(content_hash, {
'summary': summary,
'service': ai_service,
'page_title': page_title
})
# 添加AI摘要块
# 生成新摘要
lang_desc = {'zh': '中文', 'en': '英文', 'both': '双语'}
env_desc = '(CI)' if is_ci else '(本地)'
print(f"🤖 正在生成{lang_desc.get(self.summary_language, '中文')}AI摘要 {env_desc}: {page.file.src_path}")
summary, ai_service = self.generate_ai_summary(clean_content, page_title)
if not summary:
# 尝试生成备用摘要
summary = self.generate_fallback_summary(clean_content, page_title)
if summary:
ai_summary_block = self.format_summary(summary, ai_service)
result_blocks.append(ai_summary_block)
ai_service = 'fallback'
print(f"📝 使用备用摘要 {env_desc}: {page.file.src_path}")
else:
print(f"❌ 无法生成摘要 {env_desc}: {page.file.src_path}")
return markdown
else:
print(f"✅ AI摘要生成成功 ({ai_service}) {env_desc}: {page.file.src_path}")
# 保存到缓存
if summary:
self.save_summary_cache(content_hash, {
'summary': summary,
'service': ai_service,
'page_title': page_title
})
# 添加阅读信息块
if show_reading_info:
reading_info_block = self.format_reading_info(reading_time, chinese_chars, code_lines)
result_blocks.append(reading_info_block)
# 合并所有块并返回
if result_blocks:
return '\n'.join(result_blocks) + '\n\n' + markdown
# 添加摘要到页面最上面
if summary:
summary_html = self.format_summary(summary, ai_service)
return summary_html + '\n\n' + markdown
else:
return markdown
@ -953,52 +915,6 @@ Please generate bilingual summary:"""
# 默认不生成摘要
return False
def should_show_reading_info(self, page, markdown):
"""判断是否应该显示阅读信息"""
# 检查页面元数据
if hasattr(page, 'meta') and page.meta.get('hide_reading_time', False):
return False
# 获取文件路径
src_path = page.file.src_path.replace('\\', '/')
# 使用现有的排除模式检查
exclude_patterns = [
r'^index\.md$', r'^about/', r'^trip/index\.md$', r'^relax/index\.md$',
r'^blog/indexblog\.md$', r'^blog/posts\.md$', r'^develop/index\.md$',
r'waline\.md$', r'link\.md$', r'404\.md$'
]
for pattern in exclude_patterns:
if re.match(pattern, src_path):
return False
# 检查页面类型
if hasattr(page, 'meta'):
page_type = page.meta.get('type', '')
if page_type in {'landing', 'special', 'widget'}:
return False
# 内容长度检查
if len(markdown) < 300:
return False
# 计算中文字符数
_, chinese_chars, _ = self.calculate_reading_stats(markdown)
if chinese_chars < 50:
return False
return True
def format_reading_info(self, reading_time, chinese_chars, code_lines):
"""格式化阅读信息显示"""
if code_lines > 0:
return f'''!!! info "📖 阅读信息"
阅读时间**{reading_time}** 分钟 | 中文字符**{chinese_chars}** | 有效代码行数**{code_lines}**'''
else:
return f'''!!! info "📖 阅读信息"
阅读时间**{reading_time}** 分钟 | 中文字符**{chinese_chars}**'''
def format_summary(self, summary, ai_service):
"""格式化摘要显示包含CI环境标识"""
# 根据语言设置显示不同的标题
@ -1053,7 +969,7 @@ ai_summary_generator = AISummaryGenerator()
# 🔧 配置函数
def configure_ai_summary(enabled_folders=None, exclude_patterns=None, exclude_files=None,
ai_service=None, service_config=None, language='zh',
ci_enabled=None, local_enabled=None, ci_only_cache=None, ci_fallback=None):
ci_enabled=None, local_enabled=None, ci_only_cache=None, ci_fallback=None, cache_enabled=None):
"""
配置AI摘要功能支持CI和本地环境分别配置
@ -1068,24 +984,33 @@ def configure_ai_summary(enabled_folders=None, exclude_patterns=None, exclude_fi
local_enabled: 是否在本地环境中启用
ci_only_cache: CI 环境是否仅使用缓存
ci_fallback: CI 环境是否启用备用摘要
cache_enabled: 是否启用缓存功能
Example:
# 推荐配置:只在 CI 中启用,本地禁用
# 本地开发时禁用缓存,总是生成新摘要
configure_ai_summary(
enabled_folders=['blog/', 'docs/'],
language='zh',
ci_enabled=True, # CI 中启用
local_enabled=False, # 本地禁用
ci_only_cache=False, # CI 中允许生成新摘要
ci_fallback=True # CI 中启用备用摘要
local_enabled=True,
cache_enabled=False # 禁用缓存
)
# CI中启用缓存本地禁用缓存
configure_ai_summary(
enabled_folders=['blog/', 'docs/'],
language='zh',
ci_enabled=True,
local_enabled=True,
ci_only_cache=True, # CI仅使用缓存
cache_enabled=True # 启用缓存功能
)
"""
ai_summary_generator.configure_folders(enabled_folders, exclude_patterns, exclude_files)
ai_summary_generator.configure_language(language)
# 配置环境行为
if any(x is not None for x in [ci_enabled, local_enabled, ci_only_cache, ci_fallback]):
configure_ci_behavior(ci_enabled, local_enabled, ci_only_cache, ci_fallback)
if any(x is not None for x in [ci_enabled, local_enabled, ci_only_cache, ci_fallback, cache_enabled]):
configure_ci_behavior(ci_enabled, local_enabled, ci_only_cache, ci_fallback, cache_enabled)
if ai_service:
if service_config:
@ -1097,7 +1022,7 @@ def configure_ai_summary(enabled_folders=None, exclude_patterns=None, exclude_fi
ai_summary_generator.configure_ai_service(ai_service)
# 🔧 新增 CI 配置函数
def configure_ci_behavior(enabled_in_ci=None, enabled_in_local=None, ci_only_cache=None, ci_fallback_enabled=None):
def configure_ci_behavior(enabled_in_ci=None, enabled_in_local=None, ci_only_cache=None, ci_fallback_enabled=None, cache_enabled=None):
"""
配置 CI 和本地环境行为
@ -1106,16 +1031,17 @@ def configure_ci_behavior(enabled_in_ci=None, enabled_in_local=None, ci_only_cac
enabled_in_local: 是否在本地环境中启用 AI 摘要
ci_only_cache: CI 环境是否仅使用缓存
ci_fallback_enabled: CI 环境是否启用备用摘要
cache_enabled: 是否启用缓存功能默认True
Example:
# 只在 CI 中启用,本地禁用(推荐配置)
configure_ci_behavior(enabled_in_ci=True, enabled_in_local=False)
# 完全禁用缓存
configure_ci_behavior(cache_enabled=False)
# 本地和 CI 都启用
configure_ci_behavior(enabled_in_ci=True, enabled_in_local=True)
# 本地开发时禁用缓存,总是生成新摘要
configure_ci_behavior(enabled_in_local=True, cache_enabled=False)
# 只在本地启用,CI 中禁用
configure_ci_behavior(enabled_in_ci=False, enabled_in_local=True)
# CI中使用缓存,本地禁用缓存
configure_ci_behavior(enabled_in_ci=True, enabled_in_local=True, ci_only_cache=True, cache_enabled=True)
"""
if enabled_in_ci is not None:
ai_summary_generator.ci_config['enabled_in_ci'] = enabled_in_ci
@ -1132,6 +1058,10 @@ def configure_ci_behavior(enabled_in_ci=None, enabled_in_local=None, ci_only_cac
if ci_fallback_enabled is not None:
ai_summary_generator.ci_config['ci_fallback_enabled'] = ci_fallback_enabled
print(f"✅ CI 环境备用摘要: {'启用' if ci_fallback_enabled else '禁用'}")
if cache_enabled is not None:
ai_summary_generator.ci_config['cache_enabled'] = cache_enabled
print(f"✅ 缓存功能: {'启用' if cache_enabled else '禁用'}")
def on_page_markdown(markdown, page, config, files):
"""MkDocs hook入口点"""

File diff suppressed because it is too large Load Diff