Compare commits

..

36 Commits
4.4 ... main

Author SHA1 Message Date
GitHub Action
0575c05be3 🤖 Auto-update AI summary cache [skip ci] 2025-07-16 07:55:38 +00:00
a8ca1caa1c Update index.md 2025-07-16 15:54:59 +08:00
GitHub Action
f12ee99693 🤖 Auto-update AI summary cache [skip ci] 2025-07-15 15:54:10 +00:00
a3efc6ccb7 Merge branch 'main' of https://github.com/Wcowin/Mkdocs-Wcowin 2025-07-15 23:53:22 +08:00
9d455d6b81 Update docs and resolve merge conflicts
Resolved merge conflict markers in service_config.json and page-authors.json. Updated a link in docs/link.md and cleaned up outdated workflow instructions and formatting in 利用Mkdocs部署静态网页至GitHubpages.md.
2025-07-15 23:53:05 +08:00
GitHub Action
367b8205d4 🤖 Auto-update AI summary cache [skip ci] 2025-07-15 15:53:02 +00:00
85a392130b Update docs and resolve merge conflicts
Resolved merge conflict markers in service_config.json and page-authors.json. Updated a link in docs/link.md and cleaned up outdated workflow instructions and formatting in 利用Mkdocs部署静态网页至GitHubpages.md.
2025-07-15 23:52:09 +08:00
d7cd2e9703 Merge branch 'main' of https://github.com/Wcowin/Mkdocs-Wcowin 2025-07-15 23:51:52 +08:00
739737bd32 Add related posts feature for MkDocs pages
Introduced a new related_posts.py hook and documentation to recommend related articles on MkDocs pages. Updated navigation and hook configuration in mkdocs.yml, added supporting files, and improved CSS for link styling and navigation. This enhances user experience by surfacing relevant content and visually refining the site.
2025-07-15 23:51:46 +08:00
GitHub Action
e2465b9581 🤖 Auto-update AI summary cache [skip ci] 2025-07-12 09:53:39 +00:00
6f793041b1 Update page-authors.json 2025-07-12 17:52:52 +08:00
9f85f687fb Merge branch 'main' of https://github.com/Wcowin/Mkdocs-Wcowin 2025-07-12 17:52:49 +08:00
8c1c983ac6 Update README.md 2025-07-12 14:12:33 +08:00
GitHub Action
8612aea755 🤖 Auto-update AI summary cache [skip ci] 2025-07-10 15:28:58 +00:00
43e053bd8e Merge branch 'main' of https://github.com/Wcowin/Mkdocs-Wcowin 2025-07-10 23:28:13 +08:00
68f840e0f3 Update yuanjiaohua.md 2025-07-10 23:28:10 +08:00
GitHub Action
252c5516a0 🤖 Auto-update AI summary cache [skip ci] 2025-07-10 00:52:44 +00:00
36492898d4 Merge branch 'main' of https://github.com/Wcowin/Mkdocs-Wcowin 2025-07-10 08:52:05 +08:00
1639ed459f Update resume PDF path and AI summary config
Moved the resume PDF from docs/about to docs/assets and updated the iframe src in resume.md accordingly. Changed the default for AI_SUMMARY_LOCAL_ENABLED to 'false' in ai_summary.py. Updated .ai_cache with new summary and service config timestamp.
2025-07-10 08:51:58 +08:00
GitHub Action
60f25f8f09 🤖 Auto-update AI summary cache [skip ci] 2025-07-09 15:19:34 +00:00
1f32f608ff Add new feature to process user input
Introduced a function to handle and validate user input, improving the robustness of the input processing workflow.
2025-07-09 23:18:48 +08:00
GitHub Action
428fbe0aeb 🤖 Auto-update AI summary cache [skip ci] 2025-07-08 03:49:22 +00:00
addfa1289c Merge branch 'main' of https://github.com/Wcowin/Mkdocs-Wcowin 2025-07-08 11:48:41 +08:00
41d75cd2a8 Add new feature to process user input
Introduced a function to handle and validate user input, improving the robustness of the input processing workflow.
2025-07-08 11:47:16 +08:00
GitHub Action
d2c462b046 🤖 Auto-update AI summary cache [skip ci] 2025-07-08 03:00:26 +00:00
0dabee6a18 Merge branch 'main' of https://github.com/Wcowin/Mkdocs-Wcowin 2025-07-08 10:59:39 +08:00
62e7666ea1 Update update2025.md 2025-07-08 10:59:35 +08:00
a3758c36c7 Update linktech.md 2025-07-08 10:58:57 +08:00
GitHub Action
4628abb9f5 🤖 Auto-update AI summary cache [skip ci] 2025-07-08 02:51:56 +00:00
018fcdd60f Update index.md 2025-07-08 10:51:10 +08:00
GitHub Action
c31daf4ade 🤖 Auto-update AI summary cache [skip ci] 2025-06-26 15:31:18 +00:00
017b804ecb Merge branch 'main' of https://github.com/Wcowin/Mkdocs-Wcowin 2025-06-26 23:30:30 +08:00
59f0cddc96 Add new feature to process user input
Introduced a function to handle and validate user input, improving the robustness of the input processing workflow.
2025-06-26 23:30:24 +08:00
GitHub Action
c300e78a94 🤖 Auto-update AI summary cache [skip ci] 2025-06-26 03:12:10 +00:00
5b827b273e Merge branch 'main' of https://github.com/Wcowin/Mkdocs-Wcowin 2025-06-26 11:07:41 +08:00
ada5c410fb Update Mkdocs-AI-Summary.md 2025-06-26 11:07:39 +08:00
60 changed files with 2077 additions and 688 deletions

View File

@ -0,0 +1,7 @@
{
"summary": "本文记录了2025年网站更新包括优化流畅度、修复显示问题、设计改进和教程更新等旨在提升用户体验和网站性能。",
"service": "glm",
"page_title": "2025网站更新记录",
"timestamp": "2025-07-09T19:59:54.371013",
"language": "zh"
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
{
"summary": "MIT许可证授予用户自由使用、修改、分发软件的广泛权利仅要求保留版权声明和许可条款。该许可证明确声明软件不提供任何担保作者不对使用后果承担责任。作为宽松开源协议MIT许可证允许商业用途和二次开发适用于希望最大限度开放代码的开发者。",
"service": "deepseek",
"summary": "麻省理工学院许可证允许用户无限制使用、复制、修改和分发软件,但需保留版权声明和许可声明。软件提供“原样”,不保证适销性或无侵权性,使用风险自担。",
"service": "glm",
"page_title": "许可声明",
"timestamp": "2025-06-04T15:10:35.586724",
"timestamp": "2025-07-09T19:59:37.331858",
"language": "zh"
}

View File

@ -1,7 +1,7 @@
{
"summary": "在GitHub Pages部署mkdocs时自定义域名失效的原因是本地缺少CNAME文件导致推送后被清除。解决方法是在/docs目录下创建无后缀的CNAME文件并填入域名确保每次推送后配置信息得以保留。该方案有效解决了因文件缺失导致的域名绑定失效问题。",
"service": "deepseek",
"summary": "在Github Pages部署mkdocs时通过在/docs目录下创建无后缀的CNAME文件并填写域名可解决自定义域名失效问题。原因在于每次添加自定义域名后系统会生成新的CNAME文件但未同步到本地导致push后CNAME信息丢失。",
"service": "glm",
"page_title": "3.解决Github Pages部署mkdocs自定义域名失效的问题",
"timestamp": "2025-06-04T15:11:04.997045",
"timestamp": "2025-07-09T19:59:46.806034",
"language": "zh"
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,7 @@
{
"summary": "本文介绍了如何为Markdown文档添加阅读时间统计功能。通过配置mkdocs.yml文件和编写Python脚本实现自动计算并展示阅读时间、中文字符数和代码行数等统计信息。",
"service": "glm",
"page_title": "添加阅读信息统计",
"timestamp": "2025-07-09T20:00:07.898964",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "MkDocs AI Hooks是一款集成AI摘要和智能阅读统计功能的插件支持多AI服务自动生成80-120字摘要并提供多种配置选项提升文档智能化和用户体验。",
"service": "glm",
"page_title": "MkDocs文档AI摘要",
"timestamp": "2025-07-09T19:59:55.922690",
"language": "zh"
}

View File

@ -0,0 +1,7 @@
{
"summary": "通过简单复制代码至MD文件即可在MKdocs中添加友链。采用极简设计支持卡片样式和响应式布局适用于展示技术博客或资源分享网站。",
"service": "glm",
"page_title": "如何给MKdocs添加友链",
"timestamp": "2025-07-09T19:59:39.765402",
"language": "zh"
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,7 @@
{
"summary": "设计应简洁精炼,追求优雅美感,以用户体验为核心,注重细节,鼓励创新与情感共鸣,打造令人愉悦且富有创意的体验。",
"service": "glm",
"page_title": "我对设计的一些观点",
"timestamp": "2025-07-09T20:00:22.728567",
"language": "zh"
}

View File

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

View File

@ -0,0 +1,7 @@
{
"summary": "网站持续优化,包括流畅度提升、教程更新、修复显示问题,引入新材料设计规范和插件,提升用户体验。",
"service": "glm",
"page_title": "2025网站更新记录",
"timestamp": "2025-07-09T23:18:47.552565",
"language": "zh"
}

View File

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

View File

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

View File

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

View File

@ -1,7 +0,0 @@
{
"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

@ -1,10 +1,10 @@
{
"default_service": "deepseek",
"default_service": "glm",
"available_services": [
"deepseek",
"glm",
"openai",
"gemini"
],
"summary_language": "zh",
"check_time": "2025-06-25T03:15:30.701710"
"check_time": "2025-07-16T07:55:31.381146"
}

View File

@ -1 +1,9 @@
{"cache_date": "2025-06-16", "page_authors": {}}
<<<<<<< Updated upstream
<<<<<<< Updated upstream
{"cache_date": "2025-07-15", "page_authors": {}}
=======
{"cache_date": "2025-07-12", "page_authors": {}}
>>>>>>> Stashed changes
=======
{"cache_date": "2025-07-12", "page_authors": {}}
>>>>>>> Stashed changes

View File

@ -1,3 +1,4 @@
{
"bitoAI.codeCompletion.enableAutoCompletion": false
"bitoAI.codeCompletion.enableAutoCompletion": false,
"Codegeex.RepoIndex": true
}

View File

@ -10,6 +10,7 @@
- [Wcowin for MkDocs主题](#wcowin-for-mkdocs主题)
- [目录](#目录)
- [展示](#展示)
- [来自Claude的肯定](#来自claude的肯定)
- [如何快速使用](#如何快速使用)
- [视频教程](#视频教程)
- [Connect with me](#connect-with-me)
@ -52,6 +53,10 @@
</center>
## 来自Claude的肯定
![image](https://s1.imagehub.cc/images/2025/07/12/509bbab32399e1b22942d259c1433d09.png)
## 如何快速使用
首先,建议在虚拟环境下安装 mkdocs-material

View File

@ -6,6 +6,7 @@ hide:
- footer
- feedback
comments: false
hide_reading_time: true
---
# 首頁

View File

@ -23,8 +23,8 @@ status: new
<div class="flip-container">
<div class="image-container">
<img src="https://free.wmhua.cn/2025/05/09/681d7016db8dc.png" alt="Back Image">
<img src="https://free.wmhua.cn/2025/05/09/681d7015ed864.jpeg" alt="Front Image">
<img src="https://pic4.zhimg.com/v2-a0456a5f527c1923f096759f2926012f_1440w.jpg" alt="Back Image">
<img src="https://picx.zhimg.com/v2-fb22186d2490043435a72876950492f5_1440w.jpg" alt="Front Image">
</div>
</div>
<style>
@ -42,8 +42,8 @@ status: new
.image-container {
position: relative;
position: relative;
width: 290px;
height: 290px;
width: 280px;
height: 280px;
}
.image-container img {
position: absolute;

View File

@ -28,6 +28,6 @@ comments: false
---
<iframe src="../个人简历.pdf" width="100%" height="1250px" style="border: 1.5px solid #ccc; overflow: auto; border-radius: 18px; background: #fff;"></iframe>
<iframe src="/assets/个人简历.pdf" width="100%" height="1250px" style="border: 1.5px solid #ccc; overflow: auto; border-radius: 18px; background: #fff;"></iframe>
</div>

View File

@ -6,129 +6,143 @@ hide:
- feedback
---
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Wcowin/Wcowin.github.io@main/docs/stylesheets/link.css">
复制后在需要添加友链的.md 文件页面粘贴即可
```html hl_lines="75-110"
```html hl_lines="82-126"
<div class="post-body">
<div id="links">
<style>
/* 通用卡片样式 */
.card {
width: 320px;
height: 90px;
font-size: 1rem;
padding: 10px 20px;
border-radius: 25px;
transition: transform 0.15s, box-shadow 0.15s, background 0.15s;
margin-bottom: 1rem;
display: flex;
align-items: center;
color: #333;
}
.card:nth-child(odd) {
float: left;
}
.card:nth-child(even) {
float: right;
}
.card:hover {
transform: translateY(0px) scale(1.05);
<div id="links">
<style>
/* 友链容器样式 */
.link-navigation {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 1rem;
max-width: 100%;
}
/* 通用卡片样式 */
.card {
width: 100%;
max-width: 320px;
height: 90px;
font-size: 1rem;
padding: 10px 20px;
border-radius: 25px;
transition: transform 0.15s, box-shadow 0.15s, background 0.15s;
display: flex;
align-items: center;
color: #333;
justify-self: center;
}
.card:hover {
transform: translateY(0px) scale(1.05);
background-color: rgba(68, 138, 255, 0.1);
color: #040000;
}
.card a {
border: none;
}
.card .ava {
width: 3rem !important;
height: 3rem !important;
margin: 0 !important;
margin-right: 1em !important;
border-radius: 50%;
}
.card .card-header {
font-style: italic;
overflow: hidden;
width: auto;
}
.card .card-header a {
font-style: normal;
color: #608DBD;
font-weight: bold;
text-decoration: none;
}
.card .card-header a:hover {
color: #d480aa;
text-decoration: none;
}
.card .card-header .info {
font-style: normal;
color: #706f6f;
font-size: 14px;
min-width: 0;
overflow: visible;
white-space: normal;
}
/* 小屏优化 */
@media (max-width: 768px) {
.link-navigation {
grid-template-columns: 1fr;
gap: 0.8rem;
}
.card {
width: 100%;
max-width: 100%;
height: auto;
min-height: 80px;
}
.card:hover {
background-color: rgba(68, 138, 255, 0.1);
color: #040000;
}
.card a {
border: none;
}
.card .ava {
width: 3rem !important;
height: 3rem !important;
margin: 0 !important;
margin-right: 1em !important;
border-radius: 50%;
}
.card .card-header {
font-style: italic;
overflow: hidden;
width: auto;
}
.card .card-header a {
font-style: normal;
color: #608DBD;
font-weight: bold;
text-decoration: none;
}
.card .card-header a:hover {
color: #d480aa;
text-decoration: none;
}
.card .card-header .info {
font-style: normal;
color: #706f6f;
font-size: 14px;
min-width: 0;
overflow: visible;
white-space: normal;
}
/* 小屏优化 */
@media (max-width: 768px) {
.card {
width: 100%;
height: auto;
float: none;
}
.card:hover {
background-color: rgba(68, 138, 255, 0.1);
}
}
</style>
<div class="links-content">
<div class="link-navigation">
<div class="card">
<img class="ava" src="https://i.stardots.io/wcowin/1750089315509.png" />
<div class="card-header">
}
}
</style>
<div class="links-content">
<div class="link-navigation">
<div class="card">
<img class="ava" src="https://avatars.githubusercontent.com/jaywhj" />
<div class="card-header">
<div>
<a href="https://wcowin.work/" target="_blank">Wcowins blog</a>
<a href="https://jaywhj.netlify.app/" target="_blank">极简主义</a>
</div>
<div class="info">这是一个分享技术的小站。</div>
</div>
<div class="info">文档即产品</div>
</div>
<div class="card">
<img class="ava" src="https://i.loli.net/2020/05/14/5VyHPQqR6LWF39a.png" />
<div class="card-header">
<div>
<a href="https://twitter.com/" target="_blank">Twitter</a>
</div>
<div class="info">社交分享平台</div>
</div>
</div>
<div class="card">
<img class="ava" src="https://i.stardots.io/wcowin/1750220860750.jpg" />
<div class="card-header">
<div>
<a href="https://macapp.org.cn" target="_blank">Macapp</a>
</div>
<div class="info">一个专注于分享Mac资源的频道</div>
</div>
</div>
<div class="card">
<img class="ava" src="https://i.stardots.io/wcowin/1750221795613.jpeg" />
<div class="card-header">
<div>
<a href="{link}" target="_blank">{name}</a>
</div>
<div class="info">{description}</div>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<img class="ava" src="https://i.stardots.io/wcowin/1750089315509.png" />
<div class="card-header">
<div>
<a href="https://wcowin.work/" target="_blank">Wcowins blog</a>
</div>
<div class="info">这是一个分享技术的小站。</div>
</div>
</div>
<div class="card">
<img class="ava" src="https://i.loli.net/2020/05/14/5VyHPQqR6LWF39a.png" />
<div class="card-header">
<div>
<a href="https://twitter.com/" target="_blank">Twitter</a>
</div>
<div class="info">社交分享平台</div>
</div>
</div>
<div class="card">
<img class="ava" src="https://i.stardots.io/wcowin/1750220860750.jpg" />
<div class="card-header">
<div>
<a href="https://macapp.org.cn" target="_blank">Macapp</a>
</div>
<div class="info">一个专注于分享Mac资源的频道</div>
</div>
</div>
<div class="card">
<img class="ava" src="https://i.stardots.io/wcowin/1750221795613.jpeg" />
<div class="card-header">
<div>
<a href="{link}" target="_blank">{name}</a>
</div>
<div class="info">{description}</div>
</div>
</div>
</div>
</div>
</div>
</div>
```
## 如何加入友链
```html
@ -164,109 +178,133 @@ hide:
<div class="post-body">
<div id="links">
<style>
/* 通用卡片样式 */
.card {
width: 320px;
height: 90px;
font-size: 1rem;
padding: 10px 20px;
border-radius: 25px;
transition: transform 0.15s, box-shadow 0.15s, background 0.15s;
margin-bottom: 1rem;
display: flex;
align-items: center;
color: #333;
}
.card:nth-child(odd) {
float: left;
}
.card:nth-child(even) {
float: right;
}
.card:hover {
transform: translateY(0px) scale(1.05);
<div id="links">
<style>
/* 友链容器样式 */
.link-navigation {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 1rem;
max-width: 100%;
}
/* 通用卡片样式 */
.card {
width: 100%;
max-width: 320px;
height: 90px;
font-size: 1rem;
padding: 10px 20px;
border-radius: 25px;
transition: transform 0.15s, box-shadow 0.15s, background 0.15s;
display: flex;
align-items: center;
color: #333;
justify-self: center;
}
.card:hover {
transform: translateY(0px) scale(1.05);
background-color: rgba(68, 138, 255, 0.1);
color: #040000;
}
.card a {
border: none;
}
.card .ava {
width: 3rem !important;
height: 3rem !important;
margin: 0 !important;
margin-right: 1em !important;
border-radius: 50%;
}
.card .card-header {
font-style: italic;
overflow: hidden;
width: auto;
}
.card .card-header a {
font-style: normal;
color: #608DBD;
font-weight: bold;
text-decoration: none;
}
.card .card-header a:hover {
color: #d480aa;
text-decoration: none;
}
.card .card-header .info {
font-style: normal;
color: #706f6f;
font-size: 14px;
min-width: 0;
overflow: visible;
white-space: normal;
}
/* 小屏优化 */
@media (max-width: 768px) {
.link-navigation {
grid-template-columns: 1fr;
gap: 0.8rem;
}
.card {
width: 100%;
max-width: 100%;
height: auto;
min-height: 80px;
}
.card:hover {
background-color: rgba(68, 138, 255, 0.1);
color: #040000;
}
.card a {
border: none;
}
.card .ava {
width: 3rem !important;
height: 3rem !important;
margin: 0 !important;
margin-right: 1em !important;
border-radius: 50%;
}
.card .card-header {
font-style: italic;
overflow: hidden;
width: auto;
}
.card .card-header a {
font-style: normal;
color: #608DBD;
font-weight: bold;
text-decoration: none;
}
.card .card-header a:hover {
color: #d480aa;
text-decoration: none;
}
.card .card-header .info {
font-style: normal;
color: #706f6f;
font-size: 14px;
min-width: 0;
overflow: visible;
white-space: normal;
}
/* 小屏优化 */
@media (max-width: 768px) {
.card {
width: 100%;
height: auto;
float: none;
}
.card:hover {
background-color: rgba(68, 138, 255, 0.1);
}
}
</style>
<div class="links-content">
<div class="link-navigation">
<div class="card">
<img class="ava" src="https://i.stardots.io/wcowin/1750089315509.png" />
<div class="card-header">
}
}
</style>
<div class="links-content">
<div class="link-navigation">
<div class="card">
<img class="ava" src="https://avatars.githubusercontent.com/jaywhj" />
<div class="card-header">
<div>
<a href="https://wcowin.work/" target="_blank">Wcowins blog</a>
<a href="https://jaywhj.netlify.app/" target="_blank">极简主义</a>
</div>
<div class="info">这是一个分享技术的小站。</div>
</div>
<div class="info">文档即产品</div>
</div>
<div class="card">
<img class="ava" src="https://i.loli.net/2020/05/14/5VyHPQqR6LWF39a.png" />
<div class="card-header">
<div>
<a href="https://twitter.com/" target="_blank">Twitter</a>
</div>
<div class="info">社交分享平台</div>
</div>
</div>
<div class="card">
<img class="ava" src="https://i.stardots.io/wcowin/1750221795613.jpeg" />
<div class="card-header">
<div>
<a href="{link}" target="_blank">{name}</a>
</div>
<div class="info">{description}</div>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<img class="ava" src="https://i.stardots.io/wcowin/1750089315509.png" />
<div class="card-header">
<div>
<a href="https://wcowin.work/" target="_blank">Wcowins blog</a>
</div>
<div class="info">这是一个分享技术的小站。</div>
</div>
</div>
<div class="card">
<img class="ava" src="https://i.loli.net/2020/05/14/5VyHPQqR6LWF39a.png" />
<div class="card-header">
<div>
<a href="https://twitter.com/" target="_blank">Twitter</a>
</div>
<div class="info">社交分享平台</div>
</div>
</div>
<div class="card">
<img class="ava" src="https://i.stardots.io/wcowin/1750220860750.jpg" />
<div class="card-header">
<div>
<a href="https://macapp.org.cn" target="_blank">Macapp</a>
</div>
<div class="info">一个专注于分享Mac资源的频道</div>
</div>
</div>
<div class="card">
<img class="ava" src="https://i.stardots.io/wcowin/1750221795613.jpeg" />
<div class="card-header">
<div>
<a href="{link}" target="_blank">{name}</a>
</div>
<div class="info">{description}</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -7,6 +7,20 @@ categories:
readtime: 2
hide_reading_time: true
---
## </p><h1 id="01" name="01"><strong>2025-07-08</strong></h1><p>
* 优化网站流畅度(玄学)
* AI摘要全局更换为智谱清言GLM
## </p><h1 id="01" name="01"><strong>2025-07-08</strong></h1><p>
* 优化网站流畅度(玄学)
* 修复[友链教程](../Mkdocs/linktech.md)的一些显示问题(感谢[Arron](https://github.com/jaywhj)
* 重新设计了页脚样式
## </p><h1 id="01" name="01"><strong>2025-06-15</strong></h1><p>
* 优化网站流畅度(玄学)
* 优化CDN配置
* 引入全局圆角化设计,参考[Material Design](https://material.io/design)设计规范
## </p><h1 id="01" name="01"><strong>2025-04-30</strong></h1><p>
* 优化网站流畅度(玄学)
* 修复[关于](../../about/geren.md)页面的显示问题

View File

@ -10,7 +10,7 @@ status: new
![logo 2](https://s1.imagehub.cc/images/2025/06/06/ee327dc2912fd2f31d38ee8a16a1e1ff.png){.img1}
仓库地址:[https://github.com/Wcowin/Mkdocs-AI-Summary](https://github.com/Wcowin/Mkdocs-AI-Summary)
🌐 **在线演示**:[https://wcowin.work/Mkdocs-AI-Summary/](https://wcowin.work/Mkdocs-AI-Summary/)
🌐 **在线演示**:[https://wcowin.work/Mkdocs-AI-Summary-Plus/](https://wcowin.work/Mkdocs-AI-Summary-Plus/)
<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

@ -0,0 +1,534 @@
---
title: 为MKdocs页面添加相关文章推荐
tags:
- Mkdocs
status: new
---
# 为MKdocs页面添加相关文章推荐
## 步骤
`mkdocs.yml`中需要覆写文件夹overrides(没有的话新建一个)
```yaml
theme:
name: material
custom_dir: docs/overrides
```
在docs/overrides/hooks/下新建一个`related_posts.py`文件即可,内容如下:
具体配置根据自己仓库情况自行修改
```python
import os
import re
from collections import Counter, defaultdict
from textwrap import dedent
import hashlib
import yaml
from urllib.parse import urlparse
# 存储所有文章的信息和索引
article_index = {}
category_index = defaultdict(list)
keyword_index = defaultdict(set)
# 配置:需要索引的目录
INDEXED_DIRECTORIES = ['blog/', 'develop/']
# 配置:排除推荐的页面列表(支持精确匹配和模式匹配)
EXCLUDED_PAGES = {
# 精确路径匹配
'blog/index.md',
'develop/index.md',
# 可以添加更多排除的页面
# 'blog/special-page.md',
}
# 配置:排除推荐的页面模式(支持通配符)
EXCLUDED_PATTERNS = [
r'.*\/index\.md$', # 排除所有 index.md 文件
r'.*\/archive\.md$', # 排除所有 archive.md 文件
r'blog\/posts?\/.*', # 排除 blog/post/ 和 blog/posts/ 目录下的所有文章
# 可以添加更多模式
# r'blog\/draft\/.*', # 排除草稿目录
]
# 配置:相似度阈值和权重
SIMILARITY_CONFIG = {
'min_threshold': 0.15, # 提高最低相似度阈值
'weights': {
'keywords': 0.35, # 关键词权重
'tags': 0.30, # 标签权重
'categories': 0.20, # 分类权重
'path': 0.10, # 路径分类权重
'source_dir': 0.05 # 源目录权重
},
'title_similarity': 0.25 # 标题相似度权重
}
def is_page_excluded(file_path):
"""检查页面是否应该排除推荐"""
# 精确匹配检查
if file_path in EXCLUDED_PAGES:
return True
# 模式匹配检查
for pattern in EXCLUDED_PATTERNS:
if re.match(pattern, file_path):
return True
return False
def should_index_file(file_path):
"""检查文件是否应该被索引"""
if not file_path.endswith('.md'):
return False
# 先检查是否被排除
if is_page_excluded(file_path):
return False
# 检查是否在指定目录下
for directory in INDEXED_DIRECTORIES:
if file_path.startswith(directory):
return True
return False
def extract_keywords(content, title):
"""提取文章中的关键词,改进算法"""
# 移除YAML front matter
content = re.sub(r'^---\s*\n.*?\n---\s*\n', '', content, flags=re.DOTALL | re.MULTILINE)
# 移除代码块
content = re.sub(r'```.*?```', '', content, flags=re.DOTALL)
# 移除HTML标签
content = re.sub(r'<.*?>', '', content)
# 移除链接
content = re.sub(r'\[.*?\]\(.*?\)', '', content)
# 移除标题标记
content = re.sub(r'^#+\s+', '', content, flags=re.MULTILINE)
# 合并标题和内容,标题权重更高
title_words = re.findall(r'\b\w+\b', title.lower()) * 4 # 增加标题权重
content_words = re.findall(r'\b\w+\b', content.lower())
all_words = title_words + content_words
# 扩展停用词列表(包含中英文)
stopwords = {
# 英文停用词
'the', 'a', 'an', 'in', 'on', 'at', 'to', 'for', 'of', 'and', 'or', 'is', 'are', 'was', 'were',
'be', 'been', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should',
'this', 'that', 'these', 'those', 'with', 'from', 'by', 'as', 'can', 'but', 'not', 'if', 'it',
'they', 'them', 'their', 'you', 'your', 'we', 'our', 'my', 'me', 'i', 'he', 'she', 'him', 'her',
# 常见无意义词
'about', 'above', 'after', 'again', 'all', 'also', 'any', 'because', 'before', 'between',
'both', 'each', 'few', 'first', 'get', 'how', 'into', 'just', 'last', 'made', 'make', 'may',
'most', 'new', 'now', 'old', 'only', 'other', 'over', 'said', 'same', 'see', 'some', 'such',
'take', 'than', 'then', 'time', 'two', 'use', 'very', 'way', 'well', 'where', 'when', 'which',
'while', 'who', 'why', 'work', 'world', 'year', 'years',
# 中文停用词
'的', '了', '和', '是', '就', '都', '而', '及', '与', '这', '那', '有', '在', '中', '为', '对', '等',
'能', '会', '可以', '没有', '什么', '一个', '自己', '这个', '那个', '这些', '那些', '如果', '因为', '所以'
}
# 过滤单词:长度>=2不在停用词中不是纯数字
words = [w for w in all_words
if len(w) >= 2 and w not in stopwords and not w.isdigit()]
# 返回词频最高的15个词
return Counter(words).most_common(15)
def extract_metadata(content):
"""提取文章元数据支持YAML front matter"""
metadata = {
'title': "未命名",
'description': "",
'tags': [],
'categories': [],
'disable_related': False # 新增:是否禁用相关推荐
}
# 尝试解析YAML front matter
yaml_match = re.match(r'^---\s*\n(.*?)\n---\s*\n', content, re.DOTALL)
if yaml_match:
try:
yaml_content = yaml_match.group(1)
yaml_data = yaml.safe_load(yaml_content)
if yaml_data:
metadata['title'] = str(yaml_data.get('title', '未命名')).strip('"\'')
metadata['description'] = str(yaml_data.get('description', '')).strip('"\'')
metadata['disable_related'] = yaml_data.get('disable_related', False)
# 处理tags
tags = yaml_data.get('tags', [])
if isinstance(tags, list):
metadata['tags'] = [str(tag).strip() for tag in tags]
elif isinstance(tags, str):
metadata['tags'] = [tag.strip() for tag in tags.split(',') if tag.strip()]
# 处理categories
categories = yaml_data.get('categories', [])
if isinstance(categories, list):
metadata['categories'] = [str(cat).strip() for cat in categories]
elif isinstance(categories, str):
metadata['categories'] = [cat.strip() for cat in categories.split(',') if cat.strip()]
except yaml.YAMLError:
pass # 如果YAML解析失败使用默认值
# 如果YAML解析失败回退到正则表达式
if metadata['title'] == "未命名":
title_match = re.search(r'^title:\s*(.+)$', content, re.MULTILINE)
if title_match:
metadata['title'] = title_match.group(1).strip('"\'')
return metadata
def get_category_from_path(file_path):
"""从文件路径提取分类"""
parts = file_path.split('/')
if len(parts) > 2:
return parts[1] # blog/category/file.md 或 develop/category/file.md格式
elif len(parts) > 1:
return parts[0] # blog 或 develop
return "未分类"
def calculate_content_hash(content):
"""计算内容哈希,用于检测内容变化"""
return hashlib.md5(content.encode('utf-8')).hexdigest()
def on_files(files, config):
"""预处理所有文章,建立索引"""
global article_index, category_index, keyword_index
# 清空索引
article_index.clear()
category_index.clear()
keyword_index.clear()
processed_count = 0
excluded_count = 0
for file in files:
if should_index_file(file.src_path):
try:
with open(file.abs_src_path, 'r', encoding='utf-8') as f:
content = f.read()
# 提取元数据
metadata = extract_metadata(content)
# 检查是否禁用相关推荐
if metadata.get('disable_related', False):
excluded_count += 1
continue
# 再次检查是否在排除列表中(双重检查)
if is_page_excluded(file.src_path):
excluded_count += 1
continue
# 提取关键词
keywords = extract_keywords(content, metadata['title'])
# 获取分类
path_category = get_category_from_path(file.src_path)
# 构建文章信息
article_info = {
'title': metadata['title'],
'description': metadata['description'],
'tags': metadata['tags'],
'categories': metadata['categories'],
'path_category': path_category,
'keywords': keywords,
'url': file.url,
'path': file.src_path,
'content_hash': calculate_content_hash(content),
'source_dir': file.src_path.split('/')[0] # blog 或 develop
}
# 添加到主索引
article_index[file.src_path] = article_info
# 添加到分类索引
category_index[path_category].append(file.src_path)
for category in metadata['categories']:
if category: # 确保分类不为空
category_index[category].append(file.src_path)
# 添加到关键词索引
for keyword, _ in keywords:
keyword_index[keyword].add(file.src_path)
for tag in metadata['tags']:
if tag: # 确保标签不为空
keyword_index[tag.lower()].add(file.src_path)
processed_count += 1
except Exception as e:
print(f"❌ 处理文件 {file.src_path} 时出错: {e}")
print(f"✅ 已索引 {processed_count} 篇文章 (blog + develop)")
if excluded_count > 0:
print(f"📝 排除 {excluded_count} 篇禁用推荐或在排除列表中的文章")
print(f"📊 分类数量: {len(category_index)}")
print(f"🔤 关键词数量: {len(keyword_index)}")
return files
def on_page_markdown(markdown, **kwargs):
"""为每篇文章添加相关推荐"""
page = kwargs['page']
config = kwargs['config']
# 检查是否应该处理这个页面
if not should_index_file(page.file.src_path):
return markdown
# 检查是否被排除
if is_page_excluded(page.file.src_path):
return markdown
# 检查文章元数据是否禁用推荐
try:
with open(page.file.abs_src_path, 'r', encoding='utf-8') as f:
content = f.read()
metadata = extract_metadata(content)
if metadata.get('disable_related', False):
return markdown
except Exception:
pass # 如果读取失败,继续处理
# 获取相关文章
related_articles = get_related_articles(page.file.src_path, max_count=5)
if not related_articles:
return markdown
# 从 config 中获取 site_url 并解析出基本路径
site_url = config.get('site_url', '')
base_path = urlparse(site_url).path if site_url else '/'
if not base_path.endswith('/'):
base_path += '/'
# 构建推荐HTML - 针对Safari浏览器优化
recommendation_html = "\n"
# 添加CSS样式特别针对Safari浏览器优化
recommendation_html += """<style>
.related-posts {
margin-top: 1.5rem;
padding-top: 0.75rem;
border-top: 1px solid rgba(0,0,0,0.1);
max-height: none !important; /* 防止Safari错误计算高度 */
overflow: visible !important; /* 防止内容被截断 */
}
.related-posts h3 {
margin-top: 0;
margin-bottom: 0.5rem;
font-size: 1.2rem;
font-weight: 500;
line-height: 1.3;
}
.related-posts ul {
margin: 0 0 0.5rem 0 !important; /* 强制覆盖可能的冲突样式 */
padding-left: 1.5rem;
list-style-position: outside;
}
.related-posts li {
margin-bottom: 0.25rem;
line-height: 1.4;
}
/* 暗色模式适配 */
[data-md-color-scheme="slate"] .related-posts {
border-top-color: rgba(255,255,255,0.1);
}
/* Safari特定修复 */
@supports (-webkit-hyphens:none) {
.related-posts {
display: block;
position: relative;
height: auto !important;
}
.related-posts ul {
position: static;
}
}
</style>
"""
# 简化且兼容的HTML结构
recommendation_html += '<div class="related-posts">\n'
recommendation_html += '<h3>📚 相关文章推荐</h3>\n'
recommendation_html += '<ul>\n'
for score, article_info in related_articles:
title = article_info['title']
relative_url = article_info['url']
# 拼接基本路径和文章相对URL并确保路径分隔符正确
full_url = (base_path + relative_url).replace('//', '/')
recommendation_html += f'<li><a href="{full_url}">{title}</a></li>\n'
recommendation_html += '</ul>\n'
recommendation_html += '</div>\n'
# 确保没有多余的空行
return markdown.rstrip() + recommendation_html
def get_related_articles(current_path, max_count=5):
"""获取相关文章,使用改进的算法"""
if current_path not in article_index:
return []
current_article = article_index[current_path]
similarities = []
# 获取当前文章的关键信息
current_title = current_article['title'].lower()
current_tags = set(tag.lower() for tag in current_article['tags'] if tag)
current_categories = set(cat.lower() for cat in current_article['categories'] if cat)
for path, article_info in article_index.items():
if path == current_path:
continue
# 过滤掉标题为"未命名"的文章
if article_info['title'] == "未命名" or not article_info['title'].strip():
continue
# 再次检查是否在排除列表中(双重检查)
if is_page_excluded(path):
continue
# 计算相似度
score = calculate_similarity(current_article, article_info)
# 标题相似度加权
title_similarity = calculate_title_similarity(current_title, article_info['title'].lower())
if title_similarity > 0.3: # 标题有一定相似度
score += title_similarity * SIMILARITY_CONFIG['title_similarity']
# 应用最低阈值
if score > SIMILARITY_CONFIG['min_threshold']:
similarities.append((score, article_info))
# 按相似度排序
similarities.sort(key=lambda x: x[0], reverse=True)
# 多样性优化:确保不同分类的文章都有机会被推荐
if len(similarities) > max_count * 2:
# 按分类分组
category_groups = defaultdict(list)
for score, article in similarities:
for category in article['categories']:
if category:
category_groups[category.lower()].append((score, article))
# 从每个分类中选取最相关的文章
diverse_results = []
used_paths = set()
# 首先添加最相关的文章
if similarities:
top_score, top_article = similarities[0]
diverse_results.append((top_score, top_article))
used_paths.add(top_article['path'])
# 然后从每个分类中添加最相关的文章
for category in sorted(category_groups.keys()):
if len(diverse_results) >= max_count:
break
for score, article in category_groups[category]:
if article['path'] not in used_paths:
diverse_results.append((score, article))
used_paths.add(article['path'])
break
# 如果还有空位,从剩余的高分文章中填充
if len(diverse_results) < max_count:
for score, article in similarities:
if article['path'] not in used_paths and len(diverse_results) < max_count:
diverse_results.append((score, article))
used_paths.add(article['path'])
# 重新按相似度排序
diverse_results.sort(key=lambda x: x[0], reverse=True)
return diverse_results[:max_count]
return similarities[:max_count]
def calculate_title_similarity(title1, title2):
"""计算两个标题的相似度"""
# 分词
words1 = set(re.findall(r'\b\w+\b', title1))
words2 = set(re.findall(r'\b\w+\b', title2))
if not words1 or not words2:
return 0
# 计算Jaccard相似度
intersection = len(words1.intersection(words2))
union = len(words1.union(words2))
if union == 0:
return 0
return intersection / union
def calculate_similarity(article1, article2):
"""计算两篇文章的相似度"""
score = 0
weights = SIMILARITY_CONFIG['weights']
# 1. 关键词相似度
keywords1 = dict(article1['keywords'])
keywords2 = dict(article2['keywords'])
common_keywords = set(keywords1.keys()) & set(keywords2.keys())
if common_keywords:
# 考虑关键词的频率和重要性
keyword_score = sum(min(keywords1[kw], keywords2[kw]) for kw in common_keywords)
# 关键词匹配数量的奖励
keyword_count_bonus = len(common_keywords) / max(len(keywords1), 1) * 0.5
score += (keyword_score + keyword_count_bonus) * weights['keywords']
# 2. 标签相似度
tags1 = set(tag.lower() for tag in article1['tags'] if tag)
tags2 = set(tag.lower() for tag in article2['tags'] if tag)
if tags1 and tags2: # 确保两篇文章都有标签
tag_overlap = len(tags1 & tags2)
tag_ratio = tag_overlap / max(len(tags1), 1) # 相对重叠比例
tag_score = tag_overlap * 8 * (1 + tag_ratio) # 增加重叠比例奖励
score += tag_score * weights['tags']
# 3. 分类相似度
categories1 = set(cat.lower() for cat in article1['categories'] if cat)
categories2 = set(cat.lower() for cat in article2['categories'] if cat)
if categories1 and categories2: # 确保两篇文章都有分类
category_overlap = len(categories1 & categories2)
category_ratio = category_overlap / max(len(categories1), 1)
category_score = category_overlap * 12 * (1 + category_ratio)
score += category_score * weights['categories']
# 4. 路径分类相似度
if article1['path_category'] == article2['path_category']:
score += 3 * weights['path']
# 5. 同源目录加分
if article1.get('source_dir') == article2.get('source_dir'):
score += 2 * weights['source_dir']
return score
```
## 效果如下

View File

@ -20,59 +20,26 @@ comments: false
```css
:root {
--admonition-border-left-width: 0.2rem;
--base-border-radius: 0.5rem;
--base-border-radius: 1rem;
/* --card-hover-shadow: 0 0 0.2rem #ffffff40; */
}
/* Change font family of filename present on top of code block. */
/* .highlight span.filename {
border-bottom: none;
border-radius: var(--base-border-radius);
display: inline;
font-family: var(--md-code-font-family);
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
margin-bottom: 5px;
text-align: center;
}
.highlight span.filename + pre > code {
border-radius: var(--base-border-radius);
border-top-left-radius: 0;
}
.md-typeset pre > code {
border-radius: var(--base-border-radius);
} */
/* Customize admonition layout */
/* .md-typeset .admonition {
border-width: 0px;
border-left-width: var(--admonition-border-left-width);
}
[dir="ltr"] .md-typeset blockquote {
border-radius: 0.2rem;
border-left-width: var(--admonition-border-left-width);
} */
/* Grid Cards */
.md-typeset .grid.cards > ul > li {
/* 卡片圆角与悬浮阴影 */
.md-typeset .grid.cards > ul > li,
.md-typeset .md-button,
.md-typeset table:not([class]) {
border-radius: var(--base-border-radius);
}
.md-typeset .grid.cards > ul > li:hover {
box-shadow: 0 0 0.2rem #ffffff40;
box-shadow: var(--card-hover-shadow);
}
/* Markdown Button */
.md-typeset .md-button {
border-radius: var(--base-border-radius);
}
/* Footer: Social Links */
/* 页脚社交图标高度 */
.md-social__link svg {
max-height: 1rem;
}
/* Forms */
/* 搜索框及下拉结果圆角 */
.md-search__form {
border-radius: var(--base-border-radius);
}
@ -87,185 +54,57 @@ comments: false
border-bottom-left-radius: var(--base-border-radius);
}
/* Blog - index.md */
/* div.md-content header {
display: none;
/* 可选:如需恢复代码块、警告框等样式,取消注释即可 */
/*
.highlight span.filename {
border-bottom: none;
border-radius: var(--base-border-radius);
display: inline;
font-family: var(--md-code-font-family);
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
margin-bottom: 5px;
text-align: center;
}
.highlight span.filename + pre > code,
.md-typeset pre > code {
border-radius: var(--base-border-radius);
border-top-left-radius: 0;
}
.md-typeset .admonition {
border-width: 0px;
border-left-width: var(--admonition-border-left-width);
}
[dir="ltr"] .md-typeset blockquote {
border-radius: 0.2rem;
border-left-width: var(--admonition-border-left-width);
}
*/
.md-post--excerpt {
background-color: var(--md-accent-fg-color--transparent);
box-shadow: 0 0 0 1rem var(--md-accent-fg-color--transparent);
/* 可选:博客相关样式,按需启用 */
/* .md-post--excerpt {
background-color: rgba(68,138,255,.1);
box-shadow: 0 0 0 1rem rgba(68,138,255,.1);
border-radius: var(--base-border-radius);
}
.md-post--excerpt .md-post__header {
justify-content: center;
justify-content: left;
}
.md-post--excerpt .md-post__content > h2,
.md-post__action {
text-align: center;
text-align: left;
} */
/* Table */
.md-typeset table:not([class]) {
border-radius: var(--base-border-radius);
}
.carousel {
width: 60%;
height: 100%;
border-radius: 0.4rem;
/* 让所有admonition包括!!! tip圆角化且更自然 */
.md-typeset .admonition,
.md-typeset details {
border-radius: 1.5em;
box-shadow: 0 2px 12px 0 rgba(60,60,60,0.07);
transition: border-radius 0.4s cubic-bezier(.4,2,.6,1), box-shadow 0.3s;
overflow: hidden;
position: relative;
/* 居中 */
margin-left: auto;
margin-right: auto;
border: 0.075rem solid #7b7b7b7a;
box-shadow: var(--md-shadow-z1);
}
.carousel-container {
width: 100%;
height: 100%;
position: relative;
left: 0;
display: flex;
/* 过渡动画 1s */
transition: all 1s;
}
.carousel-hover {
height: 100%;
width: 10%;
position: absolute;
top: 0;
/* 子元素垂直居中 */
display: flex;
flex-flow: column nowrap;
align-items: center;
justify-content: center;
}
.carousel-hover.left {
left: 0;
}
.carousel-hover.right {
right: 0;
}
.carousel-hover button {
background-color: var(--md-accent-fg-color);
border-radius: 50%;
cursor: pointer;
opacity: 0;
transition: opacity 0.3s;
}
.carousel-hover button::after {
display: block;
height: 1.5rem;
width: 1.5rem;
background-color: white;
content: "";
mask-position: center;
-webkit-mask-position: center;
}
.carousel-hover.left button::after {
mask-image: var(--md-tabbed-icon--prev);
-webkit-mask-image: var(--md-tabbed-icon--prev);
}
.carousel-hover.right button::after {
mask-image: var(--md-tabbed-icon--next);
-webkit-mask-image: var(--md-tabbed-icon--next);
}
/* hover 外层 */
.carousel-hover:hover button {
opacity: 0.5;
transition: opacity 0.3s;
}
/* hover 内层 */
.carousel-hover button:hover {
opacity: 0.8;
transition: opacity 0.3s;
}
.carousel-container a {
width: 100%;
height: 100%;
flex-shrink: 0;
}
.carousel-container img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.carousel-bottom {
position: absolute;
/* 宽度等同于内容宽度 */
width: 100%;
padding: 20px;
bottom: 0;
display: flex;
justify-content: center;
/* 指示器间距 */
gap: 10px;
opacity: 0;
transition: opacity 0.3s;
}
.carousel-bottom:hover {
opacity: 0.8;
transition: opacity 0.3s;
}
.carousel-bottom .indicator {
height: 5px;
width: 20px;
background-color: var(--md-accent-fg-color);
opacity: 0.5;
cursor: pointer;
}
.carousel:hover .bottom .indicator {
opacity: 1;
}
.carousel:hover .shift .btn {
opacity: 1;
}
@media screen and (max-width: 600px) {
.carousel {
width: 100%;
}
.carousel-hover button {
opacity: 1;
}
}
```
## 图片圆角化

View File

@ -7,6 +7,7 @@ hide:
comments: false
---
<!--
____ __ ____ ______ ______ ____ __ ____ __ .__ __.
\ \ / \ / / / | / __ \ \ \ / \ / / | | | \ | |
@ -170,7 +171,7 @@ ____ __ ____ ______ ______ ____ __ ____ __ .__ __.
[^Knowing-that-loving-you-has-no-ending]:太阳总是能温暖向日葵
[^see-how-much-I-love-you]:All-problems-in-computer-science-can-be-solved-by-another-level-of-indirection
<body>
<!-- <body>
<font color="#B9B9B9">
<p style="text-align: center; ">
<span>本站已经运行</span>
@ -197,7 +198,7 @@ ____ __ ____ ______ ______ ____ __ ____ __ .__ __.
},1000)
</script>
</font>
</body>
</body> -->
<!-- <script src="//code.tidio.co/6jmawe9m5wy4ahvlhub2riyrnujz7xxi.js" async></script> -->
@ -238,9 +239,8 @@ body::before {
}
</style>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2327435979273742"
<!-- <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2327435979273742"
crossorigin="anonymous"></script>
<!-- AD1 -->
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-2327435979273742"
@ -249,4 +249,4 @@ body::before {
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</script> -->

View File

@ -48,7 +48,7 @@ t.parentNode.insertBefore(e,t)}})();
<img class="ava" src="https://s1.imagehub.cc/images/2025/06/03/526b59b6a2e478f2ffa1629320e3e2ce.png" />
<div class="card-header">
<div>
<a href="https://wcowin.work/Mkdocs-AI-Summary/MkDocs-AI-Summary/">MkDocs AI Summary</a>
<a href="https://wcowin.work/Mkdocs-AI-Summary-Plus/MkDocs-AI-Summary/">MkDocs AI Summary</a>
</div>
<div class="info">
AI驱动的摘要生成

View File

@ -59,7 +59,7 @@ comments: false
width: 180px;
color: #999;
border-radius: 25px;
border: 2px solid #608DBD;
border: 2px solid #1F2635;
padding: 12px 24px;
text-align: center;
text-decoration: none;
@ -77,9 +77,9 @@ comments: false
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.buttonxuan.active {
background-color: #608DBD;
background-color: #1F2635;
color: white;
border-color: #3498db;
border-color: #1F2635;
}
@media (max-width: 768px) {
.button-container {

View File

@ -44,11 +44,11 @@ class AISummaryGenerator:
# 🤖 多AI服务配置
self.ai_services = {
'deepseek': {
'url': 'https://api.deepseek.com/v1/chat/completions',
'model': 'deepseek-chat',
'api_key': os.getenv('DEEPSEEK_API_KEY', ),
'max_tokens': 150,
'glm': {
'url': 'https://open.bigmodel.cn/api/paas/v4/chat/completions',
'model': 'glm-4-flash', # 或 'glm-4-plus', 'glm-4-air'
'api_key': os.getenv('GLM_API_KEY', ),
'max_tokens': 300,
'temperature': 0.3
},
'openai': {
@ -75,10 +75,10 @@ class AISummaryGenerator:
}
# 默认使用的AI服务
self.default_service = 'deepseek'
self.default_service = 'glm'
# 服务优先级(按顺序尝试)
self.service_fallback_order = ['openai', 'deepseek', 'claude', 'gemini']
self.service_fallback_order = ['glm', 'openai', 'claude', 'gemini']
# 📂 可自定义的文件夹配置
self.enabled_folders = [
@ -212,7 +212,7 @@ class AISummaryGenerator:
配置AI服务
Args:
service_name: 服务名称 ('deepseek', 'openai', 'azure_openai', 'claude', 'gemini')
service_name: 服务名称 ('glm', 'openai', 'azure_openai', 'claude', 'gemini')
config: 服务配置字典
"""
old_service = self.default_service
@ -382,7 +382,7 @@ class AISummaryGenerator:
# Google API使用URL参数
pass
else:
# OpenAI和DeepSeek使用Bearer token
# OpenAI和GLM使用Bearer token
headers['Authorization'] = f"Bearer {service_config['api_key']}"
# 添加额外的头部
@ -491,7 +491,7 @@ Please generate bilingual summary:"""
}
}
else:
# OpenAI格式 (OpenAI, DeepSeek, Azure OpenAI)
# OpenAI格式 (OpenAI, GLM, Azure OpenAI)
system_content = {
'zh': "你是一个专业的技术文档摘要专家,擅长提取文章核心要点并生成简洁准确的中文摘要。",
'en': "You are a professional technical documentation summary expert, skilled at extracting core points from articles and generating concise and accurate English summaries.",
@ -920,7 +920,7 @@ Please generate bilingual summary:"""
# 根据语言设置显示不同的标题
service_names = {
'zh': {
'deepseek': 'AI智能摘要 (DeepSeek)',
'glm': 'AI智能摘要 (智谱清言)',
'openai': 'AI智能摘要 (ChatGPT)',
'azure_openai': 'AI智能摘要 (Azure OpenAI)',
'claude': 'AI智能摘要 (Claude)',
@ -930,7 +930,7 @@ Please generate bilingual summary:"""
'ci_cache_only': 'AI智能摘要 (缓存)'
},
'en': {
'deepseek': 'AI Summary (DeepSeek)',
'glm': 'AI Summary (GLM)',
'openai': 'AI Summary (ChatGPT)',
'azure_openai': 'AI Summary (Azure OpenAI)',
'claude': 'AI Summary (Claude)',
@ -940,7 +940,7 @@ Please generate bilingual summary:"""
'ci_cache_only': 'AI Summary (Cached)'
},
'both': {
'deepseek': 'AI智能摘要 / AI Summary (DeepSeek)',
'glm': 'AI智能摘要 / AI Summary (GLM)',
'openai': 'AI智能摘要 / AI Summary (ChatGPT)',
'azure_openai': 'AI智能摘要 / AI Summary (Azure OpenAI)',
'claude': 'AI智能摘要 / AI Summary (Claude)',
@ -977,7 +977,7 @@ def configure_ai_summary(enabled_folders=None, exclude_patterns=None, exclude_fi
enabled_folders: 启用AI摘要的文件夹列表
exclude_patterns: 排除的模式列表
exclude_files: 排除的特定文件列表
ai_service: 使用的AI服务 ('deepseek', 'openai', 'claude', 'gemini')
ai_service: 使用的AI服务 ('glm', 'openai', 'claude', 'gemini')
service_config: AI服务配置
language: 摘要语言 ('zh': 中文, 'en': 英文, 'both': 双语)
ci_enabled: 是否在 CI 环境中启用

View File

@ -0,0 +1,503 @@
import os
import re
from collections import Counter, defaultdict
from textwrap import dedent
import hashlib
import yaml
from urllib.parse import urlparse
# 存储所有文章的信息和索引
article_index = {}
category_index = defaultdict(list)
keyword_index = defaultdict(set)
# 配置:需要索引的目录
INDEXED_DIRECTORIES = ['blog/', 'develop/']
# 配置:排除推荐的页面列表(支持精确匹配和模式匹配)
EXCLUDED_PAGES = {
# 精确路径匹配
'blog/index.md',
'develop/index.md',
# 可以添加更多排除的页面
# 'blog/special-page.md',
}
# 配置:排除推荐的页面模式(支持通配符)
EXCLUDED_PATTERNS = [
r'.*\/index\.md$', # 排除所有 index.md 文件
r'.*\/archive\.md$', # 排除所有 archive.md 文件
r'blog\/posts?\/.*', # 排除 blog/post/ 和 blog/posts/ 目录下的所有文章
# 可以添加更多模式
# r'blog\/draft\/.*', # 排除草稿目录
]
# 配置:相似度阈值和权重
SIMILARITY_CONFIG = {
'min_threshold': 0.15, # 提高最低相似度阈值
'weights': {
'keywords': 0.35, # 关键词权重
'tags': 0.30, # 标签权重
'categories': 0.20, # 分类权重
'path': 0.10, # 路径分类权重
'source_dir': 0.05 # 源目录权重
},
'title_similarity': 0.25 # 标题相似度权重
}
def is_page_excluded(file_path):
"""检查页面是否应该排除推荐"""
# 精确匹配检查
if file_path in EXCLUDED_PAGES:
return True
# 模式匹配检查
for pattern in EXCLUDED_PATTERNS:
if re.match(pattern, file_path):
return True
return False
def should_index_file(file_path):
"""检查文件是否应该被索引"""
if not file_path.endswith('.md'):
return False
# 先检查是否被排除
if is_page_excluded(file_path):
return False
# 检查是否在指定目录下
for directory in INDEXED_DIRECTORIES:
if file_path.startswith(directory):
return True
return False
def extract_keywords(content, title):
"""提取文章中的关键词,改进算法"""
# 移除YAML front matter
content = re.sub(r'^---\s*\n.*?\n---\s*\n', '', content, flags=re.DOTALL | re.MULTILINE)
# 移除代码块
content = re.sub(r'```.*?```', '', content, flags=re.DOTALL)
# 移除HTML标签
content = re.sub(r'<.*?>', '', content)
# 移除链接
content = re.sub(r'\[.*?\]\(.*?\)', '', content)
# 移除标题标记
content = re.sub(r'^#+\s+', '', content, flags=re.MULTILINE)
# 合并标题和内容,标题权重更高
title_words = re.findall(r'\b\w+\b', title.lower()) * 4 # 增加标题权重
content_words = re.findall(r'\b\w+\b', content.lower())
all_words = title_words + content_words
# 扩展停用词列表(包含中英文)
stopwords = {
# 英文停用词
'the', 'a', 'an', 'in', 'on', 'at', 'to', 'for', 'of', 'and', 'or', 'is', 'are', 'was', 'were',
'be', 'been', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should',
'this', 'that', 'these', 'those', 'with', 'from', 'by', 'as', 'can', 'but', 'not', 'if', 'it',
'they', 'them', 'their', 'you', 'your', 'we', 'our', 'my', 'me', 'i', 'he', 'she', 'him', 'her',
# 常见无意义词
'about', 'above', 'after', 'again', 'all', 'also', 'any', 'because', 'before', 'between',
'both', 'each', 'few', 'first', 'get', 'how', 'into', 'just', 'last', 'made', 'make', 'may',
'most', 'new', 'now', 'old', 'only', 'other', 'over', 'said', 'same', 'see', 'some', 'such',
'take', 'than', 'then', 'time', 'two', 'use', 'very', 'way', 'well', 'where', 'when', 'which',
'while', 'who', 'why', 'work', 'world', 'year', 'years',
# 中文停用词
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '可以', '没有', '什么', '一个', '自己', '这个', '那个', '这些', '那些', '如果', '因为', '所以'
}
# 过滤单词:长度>=2不在停用词中不是纯数字
words = [w for w in all_words
if len(w) >= 2 and w not in stopwords and not w.isdigit()]
# 返回词频最高的15个词
return Counter(words).most_common(15)
def extract_metadata(content):
"""提取文章元数据支持YAML front matter"""
metadata = {
'title': "未命名",
'description': "",
'tags': [],
'categories': [],
'disable_related': False # 新增:是否禁用相关推荐
}
# 尝试解析YAML front matter
yaml_match = re.match(r'^---\s*\n(.*?)\n---\s*\n', content, re.DOTALL)
if yaml_match:
try:
yaml_content = yaml_match.group(1)
yaml_data = yaml.safe_load(yaml_content)
if yaml_data:
metadata['title'] = str(yaml_data.get('title', '未命名')).strip('"\'')
metadata['description'] = str(yaml_data.get('description', '')).strip('"\'')
metadata['disable_related'] = yaml_data.get('disable_related', False)
# 处理tags
tags = yaml_data.get('tags', [])
if isinstance(tags, list):
metadata['tags'] = [str(tag).strip() for tag in tags]
elif isinstance(tags, str):
metadata['tags'] = [tag.strip() for tag in tags.split(',') if tag.strip()]
# 处理categories
categories = yaml_data.get('categories', [])
if isinstance(categories, list):
metadata['categories'] = [str(cat).strip() for cat in categories]
elif isinstance(categories, str):
metadata['categories'] = [cat.strip() for cat in categories.split(',') if cat.strip()]
except yaml.YAMLError:
pass # 如果YAML解析失败使用默认值
# 如果YAML解析失败回退到正则表达式
if metadata['title'] == "未命名":
title_match = re.search(r'^title:\s*(.+)$', content, re.MULTILINE)
if title_match:
metadata['title'] = title_match.group(1).strip('"\'')
return metadata
def get_category_from_path(file_path):
"""从文件路径提取分类"""
parts = file_path.split('/')
if len(parts) > 2:
return parts[1] # blog/category/file.md 或 develop/category/file.md格式
elif len(parts) > 1:
return parts[0] # blog 或 develop
return "未分类"
def calculate_content_hash(content):
"""计算内容哈希,用于检测内容变化"""
return hashlib.md5(content.encode('utf-8')).hexdigest()
def on_files(files, config):
"""预处理所有文章,建立索引"""
global article_index, category_index, keyword_index
# 清空索引
article_index.clear()
category_index.clear()
keyword_index.clear()
processed_count = 0
excluded_count = 0
for file in files:
if should_index_file(file.src_path):
try:
with open(file.abs_src_path, 'r', encoding='utf-8') as f:
content = f.read()
# 提取元数据
metadata = extract_metadata(content)
# 检查是否禁用相关推荐
if metadata.get('disable_related', False):
excluded_count += 1
continue
# 再次检查是否在排除列表中(双重检查)
if is_page_excluded(file.src_path):
excluded_count += 1
continue
# 提取关键词
keywords = extract_keywords(content, metadata['title'])
# 获取分类
path_category = get_category_from_path(file.src_path)
# 构建文章信息
article_info = {
'title': metadata['title'],
'description': metadata['description'],
'tags': metadata['tags'],
'categories': metadata['categories'],
'path_category': path_category,
'keywords': keywords,
'url': file.url,
'path': file.src_path,
'content_hash': calculate_content_hash(content),
'source_dir': file.src_path.split('/')[0] # blog 或 develop
}
# 添加到主索引
article_index[file.src_path] = article_info
# 添加到分类索引
category_index[path_category].append(file.src_path)
for category in metadata['categories']:
if category: # 确保分类不为空
category_index[category].append(file.src_path)
# 添加到关键词索引
for keyword, _ in keywords:
keyword_index[keyword].add(file.src_path)
for tag in metadata['tags']:
if tag: # 确保标签不为空
keyword_index[tag.lower()].add(file.src_path)
processed_count += 1
except Exception as e:
print(f"❌ 处理文件 {file.src_path} 时出错: {e}")
print(f"✅ 已索引 {processed_count} 篇文章 (blog + develop)")
if excluded_count > 0:
print(f"📝 排除 {excluded_count} 篇禁用推荐或在排除列表中的文章")
print(f"📊 分类数量: {len(category_index)}")
print(f"🔤 关键词数量: {len(keyword_index)}")
return files
def on_page_markdown(markdown, **kwargs):
"""为每篇文章添加相关推荐"""
page = kwargs['page']
config = kwargs['config']
# 检查是否应该处理这个页面
if not should_index_file(page.file.src_path):
return markdown
# 检查是否被排除
if is_page_excluded(page.file.src_path):
return markdown
# 检查文章元数据是否禁用推荐
try:
with open(page.file.abs_src_path, 'r', encoding='utf-8') as f:
content = f.read()
metadata = extract_metadata(content)
if metadata.get('disable_related', False):
return markdown
except Exception:
pass # 如果读取失败,继续处理
# 获取相关文章
related_articles = get_related_articles(page.file.src_path, max_count=5)
if not related_articles:
return markdown
# 从 config 中获取 site_url 并解析出基本路径
site_url = config.get('site_url', '')
base_path = urlparse(site_url).path if site_url else '/'
if not base_path.endswith('/'):
base_path += '/'
# 构建推荐HTML - 针对Safari浏览器优化
recommendation_html = "\n"
# 添加CSS样式特别针对Safari浏览器优化
recommendation_html += """<style>
.related-posts {
margin-top: 1.5rem;
padding-top: 0.75rem;
border-top: 1px solid rgba(0,0,0,0.1);
max-height: none !important; /* 防止Safari错误计算高度 */
overflow: visible !important; /* 防止内容被截断 */
}
.related-posts h3 {
margin-top: 0;
margin-bottom: 0.5rem;
font-size: 1.2rem;
font-weight: 500;
line-height: 1.3;
}
.related-posts ul {
margin: 0 0 0.5rem 0 !important; /* 强制覆盖可能的冲突样式 */
padding-left: 1.5rem;
list-style-position: outside;
}
.related-posts li {
margin-bottom: 0.25rem;
line-height: 1.4;
}
/* 暗色模式适配 */
[data-md-color-scheme="slate"] .related-posts {
border-top-color: rgba(255,255,255,0.1);
}
/* Safari特定修复 */
@supports (-webkit-hyphens:none) {
.related-posts {
display: block;
position: relative;
height: auto !important;
}
.related-posts ul {
position: static;
}
}
</style>
"""
# 简化且兼容的HTML结构
recommendation_html += '<div class="related-posts">\n'
recommendation_html += '<h3>📚 相关文章推荐</h3>\n'
recommendation_html += '<ul>\n'
for score, article_info in related_articles:
title = article_info['title']
relative_url = article_info['url']
# 拼接基本路径和文章相对URL并确保路径分隔符正确
full_url = (base_path + relative_url).replace('//', '/')
recommendation_html += f'<li><a href="{full_url}">{title}</a></li>\n'
recommendation_html += '</ul>\n'
recommendation_html += '</div>\n'
# 确保没有多余的空行
return markdown.rstrip() + recommendation_html
def get_related_articles(current_path, max_count=5):
"""获取相关文章,使用改进的算法"""
if current_path not in article_index:
return []
current_article = article_index[current_path]
similarities = []
# 获取当前文章的关键信息
current_title = current_article['title'].lower()
current_tags = set(tag.lower() for tag in current_article['tags'] if tag)
current_categories = set(cat.lower() for cat in current_article['categories'] if cat)
for path, article_info in article_index.items():
if path == current_path:
continue
# 过滤掉标题为"未命名"的文章
if article_info['title'] == "未命名" or not article_info['title'].strip():
continue
# 再次检查是否在排除列表中(双重检查)
if is_page_excluded(path):
continue
# 计算相似度
score = calculate_similarity(current_article, article_info)
# 标题相似度加权
title_similarity = calculate_title_similarity(current_title, article_info['title'].lower())
if title_similarity > 0.3: # 标题有一定相似度
score += title_similarity * SIMILARITY_CONFIG['title_similarity']
# 应用最低阈值
if score > SIMILARITY_CONFIG['min_threshold']:
similarities.append((score, article_info))
# 按相似度排序
similarities.sort(key=lambda x: x[0], reverse=True)
# 多样性优化:确保不同分类的文章都有机会被推荐
if len(similarities) > max_count * 2:
# 按分类分组
category_groups = defaultdict(list)
for score, article in similarities:
for category in article['categories']:
if category:
category_groups[category.lower()].append((score, article))
# 从每个分类中选取最相关的文章
diverse_results = []
used_paths = set()
# 首先添加最相关的文章
if similarities:
top_score, top_article = similarities[0]
diverse_results.append((top_score, top_article))
used_paths.add(top_article['path'])
# 然后从每个分类中添加最相关的文章
for category in sorted(category_groups.keys()):
if len(diverse_results) >= max_count:
break
for score, article in category_groups[category]:
if article['path'] not in used_paths:
diverse_results.append((score, article))
used_paths.add(article['path'])
break
# 如果还有空位,从剩余的高分文章中填充
if len(diverse_results) < max_count:
for score, article in similarities:
if article['path'] not in used_paths and len(diverse_results) < max_count:
diverse_results.append((score, article))
used_paths.add(article['path'])
# 重新按相似度排序
diverse_results.sort(key=lambda x: x[0], reverse=True)
return diverse_results[:max_count]
return similarities[:max_count]
def calculate_title_similarity(title1, title2):
"""计算两个标题的相似度"""
# 分词
words1 = set(re.findall(r'\b\w+\b', title1))
words2 = set(re.findall(r'\b\w+\b', title2))
if not words1 or not words2:
return 0
# 计算Jaccard相似度
intersection = len(words1.intersection(words2))
union = len(words1.union(words2))
if union == 0:
return 0
return intersection / union
def calculate_similarity(article1, article2):
"""计算两篇文章的相似度"""
score = 0
weights = SIMILARITY_CONFIG['weights']
# 1. 关键词相似度
keywords1 = dict(article1['keywords'])
keywords2 = dict(article2['keywords'])
common_keywords = set(keywords1.keys()) & set(keywords2.keys())
if common_keywords:
# 考虑关键词的频率和重要性
keyword_score = sum(min(keywords1[kw], keywords2[kw]) for kw in common_keywords)
# 关键词匹配数量的奖励
keyword_count_bonus = len(common_keywords) / max(len(keywords1), 1) * 0.5
score += (keyword_score + keyword_count_bonus) * weights['keywords']
# 2. 标签相似度
tags1 = set(tag.lower() for tag in article1['tags'] if tag)
tags2 = set(tag.lower() for tag in article2['tags'] if tag)
if tags1 and tags2: # 确保两篇文章都有标签
tag_overlap = len(tags1 & tags2)
tag_ratio = tag_overlap / max(len(tags1), 1) # 相对重叠比例
tag_score = tag_overlap * 8 * (1 + tag_ratio) # 增加重叠比例奖励
score += tag_score * weights['tags']
# 3. 分类相似度
categories1 = set(cat.lower() for cat in article1['categories'] if cat)
categories2 = set(cat.lower() for cat in article2['categories'] if cat)
if categories1 and categories2: # 确保两篇文章都有分类
category_overlap = len(categories1 & categories2)
category_ratio = category_overlap / max(len(categories1), 1)
category_score = category_overlap * 12 * (1 + category_ratio)
score += category_score * weights['categories']
# 4. 路径分类相似度
if article1['path_category'] == article2['path_category']:
score += 3 * weights['path']
# 5. 同源目录加分
if article1.get('source_dir') == article2.get('source_dir'):
score += 2 * weights['source_dir']
return score

View File

@ -1,92 +1,532 @@
<!-- Footer -->
<footer class="md-footer">
<!-- Link to previous and/or next page -->
{% if "navigation.footer" in features %}
{% if page.previous_page or page.next_page %}
{% if page.meta and page.meta.hide %}
{% set hidden = "hidden" if "footer" in page.meta.hide %}
{% endif %}
<nav
class="md-footer__inner md-grid"
aria-label="{{ lang.t('footer') }}"
{{ hidden }}
>
<!-- Link to previous page -->
{% if page.previous_page %}
{% set direction = lang.t("footer.previous") %}
<a
href="{{ page.previous_page.url | url }}"
class="md-footer__link md-footer__link--prev"
aria-label="{{ direction }}: {{ page.previous_page.title | e }}"
>
<div class="md-footer__button md-icon">
{% set icon = config.theme.icon.previous or "material/arrow-left" %}
{% include ".icons/" ~ icon ~ ".svg" %}
</div>
<div class="md-footer__title">
<span class="md-footer__direction">
{{ direction }}
</span>
<div class="md-ellipsis">
{{ page.previous_page.title }}
</div>
</div>
</a>
{% endif %}
<!-- Link to next page -->
{% if page.next_page %}
{% set direction = lang.t("footer.next") %}
<a
href="{{ page.next_page.url | url }}"
class="md-footer__link md-footer__link--next"
aria-label="{{ direction }}: {{ page.next_page.title | e }}"
>
<div class="md-footer__title">
<span class="md-footer__direction">
{{ direction }}
</span>
<div class="md-ellipsis">
{{ page.next_page.title }}
</div>
</div>
<div class="md-footer__button md-icon">
{% set icon = config.theme.icon.next or "material/arrow-right" %}
{% include ".icons/" ~ icon ~ ".svg" %}
</div>
</a>
{% endif %}
</nav>
<!-- Link to previous and/or next page - 移到最上面 -->
{% if "navigation.footer" in features %} {% if page.previous_page or
page.next_page %} {% if page.meta and page.meta.hide %} {% set hidden =
"hidden" if "footer" in page.meta.hide %} {% endif %}
<nav
class="md-footer__inner md-grid"
aria-label="{{ lang.t('footer') }}"
{{ hidden }}
>
<!-- Link to previous page -->
{% if page.previous_page %} {% set direction = lang.t("footer.previous") %}
<a
href="{{ page.previous_page.url | url }}"
class="md-footer__link md-footer__link--prev"
aria-label="{{ direction }}: {{ page.previous_page.title | e }}"
>
<div class="md-footer__button md-icon">
{% set icon = config.theme.icon.previous or "material/arrow-left" %} {%
include ".icons/" ~ icon ~ ".svg" %}
</div>
<div class="md-footer__title">
<span class="md-footer__direction"> {{ direction }} </span>
<div class="md-ellipsis">{{ page.previous_page.title }}</div>
</div>
</a>
{% endif %}
{% endif %}
<!-- Link to next page -->
{% if page.next_page %} {% set direction = lang.t("footer.next") %}
<a
href="{{ page.next_page.url | url }}"
class="md-footer__link md-footer__link--next"
aria-label="{{ direction }}: {{ page.next_page.title | e }}"
>
<div class="md-footer__title">
<span class="md-footer__direction"> {{ direction }} </span>
<div class="md-ellipsis">{{ page.next_page.title }}</div>
</div>
<div class="md-footer__button md-icon">
{% set icon = config.theme.icon.next or "material/arrow-right" %} {%
include ".icons/" ~ icon ~ ".svg" %}
</div>
</a>
{% endif %}
</nav>
{% endif %} {% endif %}
<!-- Further information -->
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
{% include "partials/copyright.html" %}
<font color="#B9B9B9">
<div class="footer-visit-count" style="display: flex; justify-content: center; align-items: center;">
本站访问量:<script async src="//finicounter.eu.org/finicounter.js"></script>
<span id="finicount_views"></span> &nbsp;|&nbsp;
<footer>
<a href="https://icp.gov.moe/?keyword=20230640" target="_blank">萌ICP备20230640号</a>
</footer>
</div>
</font>
<div class="footer-wrapper">
<!-- 访问统计区域 -->
<div class="footer-content">
<div class="footer-visit-count">
<div class="footer-item">
<!-- <span class="footer-icon">👀</span> -->
<span>本站访问量:</span>
<span id="finicount_views" class="footer-highlight"></span>
</div>
<div class="footer-item">
<!-- <span class="footer-icon">📝</span> -->
<a
href="https://icp.gov.moe/?keyword=20230640"
target="_blank"
rel="noopener noreferrer"
class="icp-link"
>萌ICP备20230640号</a>
</div>
<div class="footer-item runtime-info">
<!-- <span class="footer-icon">⏱️</span> -->
<span>本站已经运行</span>
<span id="box1" class="footer-highlight"></span>
</div>
</div>
</div>
<!-- 移动端简洁布局 (仿 footercopy.html) -->
<div class="footer-visit-count-mobile">
<span>本站访问量:</span>
<span id="finicount_views_mobile" class="footer-highlight"></span>
|
<a
href="https://icp.gov.moe/?keyword=20230640"
target="_blank"
rel="noopener noreferrer"
class="icp-link"
>萌ICP备20230640号</a>
<!-- |&nbsp; -->
<span class="runtime-info">
<span>本站已经运行</span>
<span id="box1_mobile"></span>
</span>
</div>
<!-- 版权信息和社交媒体水平布局 -->
<div class="footer-bottom-section">
<div class="md-footer-copyright">
<p>Copyright © 2022-2025 Wcowin</p>
<p>Made with <a href="https://squidfunk.github.io/mkdocs-material/" style="color: #518FC1; text-decoration: none;">Material for MkDocs</a></p>
</div>
{% if config.extra.social %}
<div class="footer-social">
{% include "partials/social.html" %}
</div>
{% endif %}
</div>
</div>
<script>
(function() {
// 避免变量冲突,将所有代码包装在立即执行函数中
function timingTime() {
const start = "2023-10-14T00:00:00";
const startTime = new Date(start).getTime();
const now = Date.now();
let diff = Math.floor((now - startTime) / 1000);
const days = Math.floor(diff / 86400);
diff %= 86400;
const hours = Math.floor(diff / 3600);
diff %= 3600;
const minutes = Math.floor(diff / 60);
const seconds = diff % 60;
return `${days}天${hours}时${minutes}分${seconds}秒`;
}
// 简化的计时器更新函数
function updateTime() {
const el = document.getElementById("box1");
const elMobile = document.getElementById("box1_mobile");
const time = timingTime();
if (el) el.textContent = time;
if (elMobile) elMobile.textContent = time;
}
// 加载访问量计数器
async function loadVisitCounter() {
try {
const script = document.createElement('script');
script.src = '//finicounter.eu.org/finicounter.js';
script.async = true;
script.onerror = function() {
console.log('访问量计数器加载失败,使用备用显示');
const desktop = document.getElementById("finicount_views");
const mobile = document.getElementById("finicount_views_mobile");
if (desktop) desktop.textContent = '统计中...';
if (mobile) mobile.textContent = '统计中...';
};
document.head.appendChild(script);
} catch (e) {
console.log('访问量计数器初始化失败:', e);
}
}
// 同步访问量显示
function syncVisitCount() {
const desktop = document.getElementById("finicount_views");
const mobile = document.getElementById("finicount_views_mobile");
if (desktop && mobile && desktop.textContent && desktop.textContent !== '加载中...') {
mobile.textContent = desktop.textContent;
}
}
// 监听访问量更新
function setupVisitCountObserver() {
try {
const observer = new MutationObserver(syncVisitCount);
const visitCountTarget = document.getElementById("finicount_views");
if (visitCountTarget) {
observer.observe(visitCountTarget, { childList: true, subtree: true });
}
} catch (e) {
console.log('访问量监听器设置失败:', e);
}
}
// 初始化所有功能
function init() {
// 启动计时器
updateTime();
setInterval(updateTime, 1000);
// 加载访问量计数器
loadVisitCounter();
// 设置访问量同步
setupVisitCountObserver();
// 调试信息
console.log('页脚功能已启动');
console.log('当前时间:', timingTime());
}
// 确保DOM加载完成后再初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
</script>
<style>
.footer-visit-count {
height: fit-content;
min-height: 55px; /* 根据实际情况调整此高度 */
/* 页脚背景配色方案 - 可根据喜好选择 */
/* 方案1: 现代深蓝灰色调 (当前使用) */
.md-footer {
background: linear-gradient(135deg, #1e293b 0%, #334155 100%);
}
</style>
{% if config.extra.social %}
{% include "partials/social.html" %}
{% endif %}
.md-footer-meta {
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
}
/* 方案2: 优雅紫色调 (取消注释使用)
.md-footer {
background: linear-gradient(135deg, #2d1b69 0%, #4c1d95 100%);
}
.md-footer-meta {
background: linear-gradient(135deg, #1e1b4b 0%, #2d1b69 100%);
}
*/
/* 方案3: 温暖深绿色调 (取消注释使用)
.md-footer {
background: linear-gradient(135deg, #14532d 0%, #166534 100%);
}
.md-footer-meta {
background: linear-gradient(135deg, #052e16 0%, #14532d 100%);
}
*/
/* 方案4: 经典深灰色调 (取消注释使用)
.md-footer {
background: linear-gradient(135deg, #374151 0%, #4b5563 100%);
}
.md-footer-meta {
background: linear-gradient(135deg, #1f2937 0%, #374151 100%);
}
*/
/* 整体页脚容器 */
.footer-wrapper {
width: 100%;
padding: 0.2rem 0;
text-align: center;
}
/* 版权信息和社交媒体水平布局 */
.footer-bottom-section {
max-width: 900px;
margin: 0.4rem auto 0;
padding: 0.4rem 1rem;
border-top: 1px solid rgba(255, 255, 255, 0.15);
display: flex;
justify-content: space-between;
align-items: center;
}
/* 版权信息 */
.md-footer-copyright {
text-align: left;
font-size: 0.75rem;
opacity: 0.8;
line-height: 1.2;
}
/* 社交媒体图标 */
.footer-social {
display: -webkit-flex;
display: flex;
gap: 0.3rem;
-webkit-align-items: center;
align-items: center;
}
/* Safari兼容性修复 */
.footer-social .md-social__link svg {
-webkit-transform: translateZ(0);
transform: translateZ(0);
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
opacity: 1 !important;
visibility: visible !important;
pointer-events: auto;
}
/* 强制Safari显示SVG图标 */
.footer-social .md-social__link {
opacity: 1 !important;
visibility: visible !important;
}
/* 内容区域样式 */
.footer-content {
max-width: 900px;
margin: 0 auto;
padding: 0.4rem 0 0;
}
.footer-visit-count {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.3rem;
font-size: 0.75rem;
color: var(--md-footer-fg-color--light);
}
.footer-item {
display: flex;
align-items: center;
justify-content: center;
padding: 0.4rem 0.8rem;
border-radius: 16px;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.15);
backdrop-filter: blur(10px);
min-width: 160px;
font-size: 0.8rem;
transition: all 0.2s ease;
}
.footer-item:hover {
background: rgba(255, 255, 255, 0.15);
border-color: rgba(81, 143, 193, 0.4);
transform: translateY(-1px);
}
.footer-icon {
margin-right: 0.5rem;
font-size: 1rem;
}
.footer-highlight {
color: #939ba2;
font-weight: 600;
margin-left: 0.3rem;
}
.icp-link {
color: inherit;
text-decoration: none;
}
.icp-link:hover {
color: #518FC1;
}
/* 社交媒体图标样式 - 仅桌面端 */
@media (min-width: 76.1875em) {
.footer-social .md-social__link {
padding: 0.3rem;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.1);
width: 2rem;
height: 2rem;
display: -webkit-inline-flex;
display: inline-flex;
-webkit-align-items: center;
align-items: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-transition: all 0.2s ease;
transition: all 0.2s ease;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.footer-social .md-social__link svg {
width: 1.2rem;
height: 1.2rem;
fill: currentColor;
-webkit-flex-shrink: 0;
flex-shrink: 0;
}
.footer-social .md-social__link:hover {
background: rgba(81, 143, 193, 0.2);
border-color: rgba(81, 143, 193, 0.4);
}
}
/* 移动端社交媒体图标样式 - 恢复默认样式 */
@media (max-width: 76.1875em) {
.footer-social .md-social__link {
padding: 0.4rem;
background: transparent;
border: none;
width: auto;
height: auto;
display: inline-block;
border-radius: 0;
-webkit-transition: color 0.2s ease;
transition: color 0.2s ease;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.footer-social .md-social__link:hover {
background: transparent;
border: none;
color: var(--md-accent-fg-color);
}
.footer-social .md-social__link svg {
width: 1.6rem;
height: 1.6rem;
fill: currentColor;
-webkit-flex-shrink: 0;
flex-shrink: 0;
display: block;
}
}
/* 导航链接样式 */
.md-footer__link {
transition: opacity 0.2s ease;
}
.md-footer__link:hover {
opacity: 1;
}
/* 移动端响应式 - 使用 footercopy.html 样式 */
@media (max-width: 76.1875em) {
/* 隐藏桌面端的卡片式布局 */
.footer-visit-count {
display: none;
}
.footer-bottom-section {
flex-direction: column;
gap: 0.6rem;
text-align: center;
}
.md-footer-copyright {
text-align: center;
font-size: 0.75rem;
}
.footer-social .md-social__link {
width: 1.8rem;
height: 1.8rem;
}
/* 显示移动端的简洁布局 */
.footer-visit-count-mobile {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
gap: 0.4em 0.8em;
padding: 0.2em 0;
font-size: 0.75rem;
color: var(--md-footer-fg-color--light);
text-align: center;
}
.footer-visit-count-mobile > * {
white-space: nowrap;
}
.footer-visit-count-mobile .icp-link {
color: var(--md-footer-fg-color--light);
text-decoration: none;
}
.footer-visit-count-mobile .icp-link:hover {
color: #596875;
text-decoration: underline;
}
/* .runtime-info {
display: none; 移动端隐藏运行时间
} */
}
/* 桌面端隐藏移动端布局 */
@media (min-width: 76.1875em) {
.footer-visit-count-mobile {
display: none;
}
}
@media (min-width: 768px) {
.footer-visit-count {
flex-direction: row;
justify-content: center;
gap: 2rem;
}
}
/* 深色模式适配 */
[data-md-color-scheme="slate"] .md-footer {
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
}
[data-md-color-scheme="slate"] .md-footer-meta {
background: linear-gradient(135deg, #020617 0%, #0f172a 100%);
}
[data-md-color-scheme="slate"] .footer-item {
background: rgba(255, 255, 255, 0.08);
border-color: rgba(255, 255, 255, 0.12);
}
[data-md-color-scheme="slate"] .footer-item:hover {
background: rgba(255, 255, 255, 0.12);
border-color: rgba(81, 143, 193, 0.3);
}
[data-md-color-scheme="slate"] .footer-social .md-social__link {
background: rgba(255, 255, 255, 0.08);
border-color: rgba(255, 255, 255, 0.12);
}
</style>
</div>
</div>
</footer>
</footer>

View File

@ -1,7 +1,7 @@
:root > * {
--md-primary-fg-color: #4c94cb;
--md-primary-fg-color--light:#4c94cb;
--md-primary-fg-color--dark: #4c94cb;
--md-primary-fg-color: #1D2636;
--md-primary-fg-color--light:#1D2636;
--md-primary-fg-color--dark: #1D2636;
}
/* 给所有元素加上边框 */
@ -15,7 +15,7 @@ button.md-top {
font-family: LXGW WenKai; /* 修改字体 */
font-size: 16px; /* 修改字体大小 */
font-weight: lighter;/* 修改字体粗细 */
color: #518FC1; /* 修改字体颜色 */
/* color: #1D2636; 修改字体颜色 */
}
:root {
@ -604,3 +604,27 @@ filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
height: 30rem;
}
/* 仅针对文本链接设置红色 */
.md-typeset p a:not(.md-button):not([class*="md-"]):not([style*="background"]),
.md-typeset li a:not(.md-button):not([class*="md-"]):not([style*="background"]),
.md-typeset td a:not(.md-button):not([class*="md-"]):not([style*="background"]),
.md-typeset blockquote a:not(.md-button):not([class*="md-"]):not([style*="background"]) {
color: #5688F7 !important; /* 红色文本链接 */
text-decoration: none;
}
.md-typeset p a:not(.md-button):not([class*="md-"]):not([style*="background"]):hover,
.md-typeset li a:not(.md-button):not([class*="md-"]):not([style*="background"]):hover,
.md-typeset td a:not(.md-button):not([class*="md-"]):not([style*="background"]):hover,
.md-typeset blockquote a:not(.md-button):not([class*="md-"]):not([style*="background"]):hover {
color: #43d2e8 !important; /* 悬停时深红色 */
text-decoration: underline;
}
/* 访问过的文本链接 */
/* .md-typeset p a:not(.md-button):not([class*="md-"]):not([style*="background"]):visited,
.md-typeset li a:not(.md-button):not([class*="md-"]):not([style*="background"]):visited,
.md-typeset td a:not(.md-button):not([class*="md-"]):not([style*="background"]):visited,
.md-typeset blockquote a:not(.md-button):not([class*="md-"]):not([style*="background"]):visited {
color: #b83280 !important;
} */

View File

@ -40,4 +40,9 @@
padding: 0.25rem 0.5rem;
border-radius: 4px;
cursor: pointer;
}
/* 目录导航的缩进参考线 */
nav.md-nav--secondary ul {
border-left: 1px solid lightblue;
}

View File

@ -76,6 +76,7 @@ nav:
- 3.解决Github Pages部署mkdocs自定义域名失效的问题: blog/Mkdocs/mkdocs3.md
- Mkdocs美化/补充:
- MkDocs文档AI摘要: blog/websitebeauty/Mkdocs-AI-Summary.md
- 添加相关推荐文章: blog/websitebeauty/recommend.md
- 添加阅读信息统计: blog/websitebeauty/reading_time.md
- 添加Mkdocs博客: blog/Mkdocs/mkdocsblog.md
- 如何给MKdocs添加友链: blog/Mkdocs/linktech.md
@ -116,7 +117,8 @@ nav:
- 支持作者: about/zcw.md
- 功能测试: about/test.md
- 个人博客: https://wcowin.work
- 个人简介: https://wcowin.work/Personal-Profile/#
# - 个人简介: https://wcowin.work/Personal-Profile/#
# https://personal-story-web-display.lovable.app/
- 使用本主题: https://github.com/new?template_name=Mkdocs-Wcowin&template_owner=Wcowin
copyright: Copyright &copy; 2022~2025 Wcowin # 左下角的版权声明
@ -317,4 +319,5 @@ extra_css:
hooks:
- docs/overrides/hooks/socialmedia.py
- docs/overrides/hooks/reading_time.py
- docs/overrides/hooks/ai_summary.py
- docs/overrides/hooks/ai_summary.py
- docs/overrides/hooks/related_posts.py

View File

@ -1,16 +1,6 @@
---
title: 利用Mkdocs部署静态网页至GitHubpages
tags:
- Mkdocs
---
!!! info
Material for MkDocs官方网站: [Material for MkDocs](https://www.mkdocs.org/)
MkDocs中文文档: [MkDocs中文文档](https://hellowac.github.io/mkdocs-docs-zh/)
---
推荐看下这个视频:
:fontawesome-brands-bilibili:{ style="color: #EE98A7" }
__[How to set up Material for MkDocs]__ by @Wcowin :octicons-clock-24:
__[How to set up Material for MkDocs]__ by @Wcowin
10m 用MKdocs构建一个博客网站.
[How to set up Material for MkDocs]: https://space.bilibili.com/1407028951/lists/4566631?type=series
@ -61,42 +51,6 @@ mkdocs new mkdocs-site
执行下面的代码添加一个GitHub Workflow
***
???note "过时的PublishMySite.yml"
(执行下面的代码添加一个GitHub Workflow(**已经过时但是仍然能用最新方法见下方ci.yml**)
```
mkdir .github
cd .github
mkdir workflows
cd workflows
vim PublishMySite.yml
```
在PublishMySite.yml里面输入以下内容
```yaml
name: publish site
on: # 在什么时候触发工作流
push: # 在从本地main分支被push到GitHub仓库时
branches:
- main
pull_request: # 在main分支合并别人提的pr时
branches:
- main
jobs: # 工作流的具体内容
deploy:
runs-on: ubuntu-latest # 创建一个新的云端虚拟机 使用最新Ubuntu系统
steps:
- uses: actions/checkout@v2 # 先checkout到main分支
- uses: actions/setup-python@v2 # 再安装Python3和相关环境
with:
python-version: 3.x
- run: pip install mkdocs-material # 使用pip包管理工具安装mkdocs-material
- run: mkdocs gh-deploy --force # 使用mkdocs-material部署gh-pages分支
```
)
***
```
mkdir .github
@ -155,8 +109,7 @@ Wcowin.github.io
└── mkdocs.yml
```
!!!重点来了
**重点来了**
Github仓库setings/Actions/General 勾选这两项
![](https://s1.imagehub.cc/images/2024/02/02/02fd4e77eb52d4ce18c227f0e29b2c6d.png)
@ -177,7 +130,7 @@ theme:
详细mkdocs.yml配置见[Changing the colors - Material for MkDocs](https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/)
[下次](https://blog.csdn.net/m0_63203517/article/details/127444446?spm=1001.2014.3001.5502)我会具体谈谈这个问题
***
在下方终端运行可以在浏览器看到实时网站
```