mirror of
https://github.com/Ad-closeNN/blog-fuwari.git
synced 2026-05-31 02:00:05 -04:00
feat(aiSummary): AI 文章总结
This commit is contained in:
@@ -8,6 +8,8 @@ category: 杂项
|
||||
draft: false
|
||||
showcover: false
|
||||
customcover: /public/pic/cloudflare-turnstile-verify-error.png
|
||||
aiSummary: "本文介绍了多种验证码实现与集成要点,涵盖 Google reCaptcha、Cloudflare Turnstile、hCaptcha 及 Arkose Labs 的使用场景、 key 配置与前端嵌入方式,帮助开发者快速了解并对比不同方案的适用性与实现流程。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
<head>
|
||||
<!-- Google reCaptcha v2-->
|
||||
|
||||
@@ -8,8 +8,9 @@ showcover: false
|
||||
customcover: /public/pic/chrome-ext-force-custom-font.png
|
||||
category: 教程
|
||||
draft: false
|
||||
aiSummary: "本文介绍了 Chrome 已停止对 Manifest V2 的支持及其时间线,给出通过开启 flags、添加启动参数或切换浏览器(如 Firefox)等临时解决方案与注意事项。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
# 前言
|
||||
|
||||
:::tip[提示]
|
||||
|
||||
@@ -7,8 +7,9 @@ image: /public/pic/discord-bot-cln-bot-profile.png
|
||||
customcover: /public/pic/discord-bot-cln-bot-profile-wide.png
|
||||
showcover: false
|
||||
category: 教程
|
||||
aiSummary: "本文介绍了如何在 Cloudflare Workers 上实现 Discord 与 Telegram 机器人,包括创建机器人、获取必要信息、配置秘密、上传并部署 Worker、设置端点 URL 以及注册命令,强调安全保存密钥并可直接复制粘贴配置,实现快速部署与未来扩展。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
:::tip[提示]
|
||||
~~赛博菩萨~~ Cloudflare Workers 不仅能运行 Discord 机器人,还能运行 Telegram 机器人。
|
||||
:::
|
||||
|
||||
@@ -8,6 +8,8 @@ customcover: /public/pic/codex-warp-banner.png
|
||||
tags: ["Codex", "Warp", "注册机", "AI"]
|
||||
category: '教程'
|
||||
outdated: true
|
||||
aiSummary: "本文介绍了通过注册机注册 OpenAI 免费模型的风险、被封禁现状,以及利用 Cloudflare Warp 提高注册成功率的做法与具体使用方法,以及相关注意事项与测试IP示例。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
# 前言
|
||||
|
||||
|
||||
@@ -7,8 +7,9 @@ image: "/public/pic/custom-frontmatter-cover.svg"
|
||||
category: 教程
|
||||
showcover: false
|
||||
customcover: /public/pic/custom-frontmatter-customcover.svg
|
||||
aiSummary: "本文介绍了在 Astro/Fuwari 博客中,通过在 Markdown 顶部自定义前置参数(如 draft、image、customcover、showcover 等)来灵活控制文章头图的显示与替换,并给出在前端模板中按条件渲染头图的实现方法、示例代码及配置要点,帮助提升博客主页与文章内页头图的可控性与个性化展示。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
# 前言
|
||||
如果你用的博客是 [Astro](https://astro.build) 或以它为架构的 [Fuwari](https://github.com/saicaca/fuwari),那么这篇文章或许适合。
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ description: 2025/8/8 早上,Telegram 竟可在国内被访问,不过现在
|
||||
image: /public/pic/telegram-devices-panel-china.jpg
|
||||
category: 记录
|
||||
draft: false
|
||||
aiSummary: "本文介绍了 Telegram DC5 部分地区直连的尝试与 GFW 窗口变化,以及 Cloudflare Warp 的国内直连可能性与相关定位误差。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
# Telegram 能直连了?
|
||||
### 目前已被墙
|
||||
[t.me/zaihuapd/34943](https://t.me/zaihuapd/34943)
|
||||
|
||||
@@ -6,8 +6,9 @@ description: 通过阿里云免费企业邮箱获得一个类似于 admin@github
|
||||
image: /public/pic/aliyun-email-mxcheck.png
|
||||
category: 教程
|
||||
draft: false
|
||||
aiSummary: "本文介绍了如何利用阿里云免费企业邮箱,用自有域名收发邮件的流程与注意事项,以及从域名解析到管理员设置、MX/DKIM验证等前置配置的要点和实际使用路径。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
# 前言
|
||||
自从你上网冲浪接触邮箱以来,你或多或少都会见过这种邮箱:
|
||||
- noreply@github.com
|
||||
|
||||
@@ -6,8 +6,9 @@ description: Folo(Follow)是一个 RSS 订阅源合集软件,用它可以
|
||||
image: /public/pic/folo-rss-verify-panel.png
|
||||
category: 教程
|
||||
draft: false
|
||||
aiSummary: "本文介绍了通过纯文本、描述和 RSS 标签三种方式,将订阅源与 Folo 账户绑定并完成认证的具体步骤与示例。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
# 前言
|
||||
:::tip[提示]
|
||||
Folo 也就是之前的 Follow,只不过改名成了 Folo。
|
||||
|
||||
@@ -7,8 +7,9 @@ image: /public/pic/giscus-preview.png
|
||||
customcover: /public/pic/giscus-no-content.png
|
||||
showcover: false
|
||||
category: 教程
|
||||
aiSummary: "本文介绍了如何在博客��接入 Giscus 评论区,包含在博客仓库或专用仓库存放、获取并粘贴 JS 代码、将评论区嵌入特定页面与页面模板中的具体实现,以及 origin 配置与简单的反垃圾思路。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
# 前言
|
||||
如果你的静态博客没有评论区,又不想自己搭建一个评论系统,那么 Giscus 就是一个不错的选择。
|
||||
接下来就手把手教你添加这个[插](https://giscus.app/client.js)件并配置它。
|
||||
|
||||
@@ -5,8 +5,9 @@ tags: ["网站", "验证"]
|
||||
description: 一次出3个 hCaptcha?瞧瞧你干的好事!
|
||||
image: /public/pic/hCaptcha-localhost-errkey.png
|
||||
category: 记录
|
||||
aiSummary: "本文介绍了在同时使用 Google reCaptcha 与 hCaptcha 时,hCaptcha 会尝试兼容导致界面混乱的情况,并给出通过将脚本 URL 加上 recaptchacompat=off 关闭兼容化的简单解决方法。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
# 强兼 Google reCaptcha 失败?
|
||||
如你所见,这是 hCaptcha 无法验证的样子。当然,如果你在一个页面同时放上 [Google reCaptcha](https://developers.google.com/recaptcha?hl=zh-cn)(我的是 v2)和 [hCaptcha](https://www.hcaptcha.com),那么聪明的 hCaptcha 会 [开始兼容它](https://docs.hcaptcha.com/configuration) 。
|
||||

|
||||
|
||||
@@ -7,8 +7,9 @@ customcover: /public/pic/kugou-music-nodejs-api-self-hosting-menu.png
|
||||
showcover: false
|
||||
tags: ["酷狗音乐", "狠活"]
|
||||
category: '教程'
|
||||
aiSummary: "本文介绍了通过开源酷狗API解析音乐URL的后端搭建、登录领取概念版VIP及通过FileHash下载高音质音乐的关键步骤与注意事项。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
# 前言
|
||||
:::caution[警告]
|
||||
1. 本教程仅供学习交流,下载的音乐文件请于24小时内删除。
|
||||
|
||||
@@ -7,8 +7,9 @@ description: 获得了一个新域名 *这使我充满了决心
|
||||
image: /public/pic/domain-inlist-adclosenn.top.png
|
||||
category: 记录
|
||||
draft: false
|
||||
aiSummary: "本文介绍了作者通过购买 .top 域名并搭建博客的过程,比较不同域名注册商和支付体验,分享域名被 XYZ 服务器暂停、解封的经历以及教训与使用场景。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
# .dev 域名
|
||||
:::note[感谢]
|
||||
感谢 [MC_Kero blog](https://blog.mckero.com) 的站长 [MC_Kero](https://github.com/MCKero6423) 提供的 [GitHub Student Developer Pack](https://education.github.com/pack) 免费**一年域名**福利!~~都给我去 Follow 他~~
|
||||
|
||||
@@ -7,8 +7,9 @@ image: /public/pic/newtab-link-npm-plugin-info-1.png
|
||||
customcover: /public/pic/newtab-link-npm-plugin-info-2.png
|
||||
showcover: false
|
||||
category: 教程
|
||||
aiSummary: "本文介绍了如何使用 rehype-external-links 插件,在 Astro 项目中将文章内外部链接统一设置为在新标签页打开,包含安装与在配置中的具体实现要点与示例。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
# 前言
|
||||
看标题可能不明白在说什么。但是如果我放出这两个链接让你点,你应该知道是什么意思。
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ description: 在 PCL 启动器上面询问大模型?当然可以~
|
||||
image: /public/pic/pcl-gemini-mixed.png
|
||||
category: 教程
|
||||
draft: false
|
||||
aiSummary: "本文介绍了多 API Key 模式的原理、适用场景及如何在 Google Gemini API 的速率限制下通过多钥匙并用来提升请求量。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
<!-- 小破站防盗链?Referrer 为 localhost 的时候 403 Forbidden -->
|
||||
<meta name="referrer" content="no-referrer">
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ description: Umami 是一个精美的网站统计分析工具,我们可以自
|
||||
image: /public/pic/umami-screenshot.png
|
||||
category: 教程
|
||||
draft: false
|
||||
aiSummary: "本文介绍了自托管 Umami 的整体思路、所需条件、以 Neon/Netlify 为例的具体部署步骤,以及登录与注意事项,帮助搭建独立的网站统计工具。"
|
||||
aiSummaryModel: "gpt-5-nano"
|
||||
---
|
||||
|
||||
# 自行托管 Umami
|
||||
|
||||
## 什么是 Umami
|
||||
|
||||
@@ -34,6 +34,61 @@ const lastUpdatedAt = entry.data.updated ?? entry.data.published;
|
||||
const lastUpdatedLabel = formatDateToYYYYMMDD(lastUpdatedAt);
|
||||
const lastUpdatedTimestamp = lastUpdatedAt.getTime();
|
||||
|
||||
const postSources = import.meta.glob("../../content/posts/**/*.{md,mdx}", {
|
||||
query: "?raw",
|
||||
import: "default",
|
||||
eager: true,
|
||||
}) as Record<string, string>;
|
||||
const normalizedPostSources = Object.fromEntries(
|
||||
Object.entries(postSources).map(([key, source]) => [key.toLowerCase(), source]),
|
||||
);
|
||||
|
||||
function parseAiSummaryValue(value: string) {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return "";
|
||||
if (trimmed.startsWith('"')) {
|
||||
try {
|
||||
return JSON.parse(trimmed);
|
||||
} catch {
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
function extractFrontmatterValue(frontmatter: string, key: string) {
|
||||
const valueMatch = frontmatter.match(new RegExp(`^${key}:[ \\t]*(.*)$`, "m"));
|
||||
if (!valueMatch) return "";
|
||||
|
||||
const inlineValue = valueMatch[1].trim();
|
||||
if (inlineValue !== ">" && inlineValue !== "|") {
|
||||
return parseAiSummaryValue(inlineValue);
|
||||
}
|
||||
|
||||
const afterValue = frontmatter.slice(valueMatch.index! + valueMatch[0].length);
|
||||
const lines = afterValue.split(/\r?\n/);
|
||||
const blockLines = [];
|
||||
for (const line of lines) {
|
||||
if (!line.startsWith(" ") && line.trim()) break;
|
||||
blockLines.push(line.replace(/^ {1,2}/, ""));
|
||||
}
|
||||
return blockLines.join("\n").trim();
|
||||
}
|
||||
|
||||
function getAiSummaryMeta(entryId: string) {
|
||||
const source =
|
||||
normalizedPostSources[`../../content/posts/${entryId}`.toLowerCase()] ??
|
||||
normalizedPostSources[`../../content/posts/${entryId}.md`.toLowerCase()] ??
|
||||
normalizedPostSources[`../../content/posts/${entryId}.mdx`.toLowerCase()];
|
||||
const frontmatter = source?.match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1];
|
||||
return {
|
||||
summary: frontmatter ? extractFrontmatterValue(frontmatter, "aiSummary") : "",
|
||||
model: frontmatter ? extractFrontmatterValue(frontmatter, "aiSummaryModel") : "",
|
||||
};
|
||||
}
|
||||
|
||||
const aiSummaryMeta = getAiSummaryMeta(entry.id);
|
||||
|
||||
const jsonLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
@@ -177,6 +232,22 @@ const isOutdated = entry.data.outdated;
|
||||
{!entry.data.image && <div class="border-[var(--line-divider)] border-dashed border-b-[1px] mb-5"></div>}
|
||||
</div>
|
||||
|
||||
{aiSummaryMeta.summary && (
|
||||
<div class="mb-4 rounded-xl p-4 bg-gradient-to-r from-violet-500/10 to-indigo-500/10 dark:from-violet-500/15 dark:to-indigo-500/15 border border-violet-500/20 onload-animation">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="shrink-0 w-8 h-8 rounded-lg bg-violet-500/20 dark:bg-violet-500/30 flex items-center justify-center">
|
||||
<Icon name="material-symbols:info-outline-rounded" class="text-violet-600 dark:text-violet-400 text-lg"></Icon>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="text-sm font-medium text-violet-700 dark:text-violet-300 mb-1 select-none pointer-events-none">
|
||||
AI 摘要{aiSummaryMeta.model && <span class="text-violet-600/70 dark:text-violet-300/70"> · {aiSummaryMeta.model}</span>}
|
||||
</div>
|
||||
<div class="text-sm text-black/70 dark:text-white/70 leading-relaxed">{aiSummaryMeta.summary}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<!-- always show cover as long as it has one -->
|
||||
<!-- 使用自制 showcover 控制器控制头图的出现 -->
|
||||
{showcover && entry.data.image &&
|
||||
|
||||
Reference in New Issue
Block a user