惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
V
Vulnerabilities – Threatpost
Security Latest
Security Latest
T
Threatpost
L
Lohrmann on Cybersecurity
Know Your Adversary
Know Your Adversary
Cyberwarzone
Cyberwarzone
S
Securelist
A
Arctic Wolf
W
WeLiveSecurity
Help Net Security
Help Net Security
Last Week in AI
Last Week in AI
H
Hacker News: Front Page
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
大猫的无限游戏
大猫的无限游戏
博客园 - 聂微东
博客园_首页
NISL@THU
NISL@THU
N
News and Events Feed by Topic
博客园 - 【当耐特】
S
Schneier on Security
阮一峰的网络日志
阮一峰的网络日志
Cloudbric
Cloudbric
P
Privacy International News Feed
小众软件
小众软件
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
宝玉的分享
宝玉的分享
Latest news
Latest news
美团技术团队
T
The Exploit Database - CXSecurity.com
S
Security Affairs
月光博客
月光博客
M
MIT News - Artificial intelligence
GbyAI
GbyAI
D
Docker
IT之家
IT之家
PCI Perspectives
PCI Perspectives
Application and Cybersecurity Blog
Application and Cybersecurity Blog
K
Kaspersky official blog
WordPress大学
WordPress大学
V2EX - 技术
V2EX - 技术
L
LINUX DO - 最新话题
P
Proofpoint News Feed
Google Online Security Blog
Google Online Security Blog
C
CERT Recently Published Vulnerability Notes
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
Cyber Attacks, Cyber Crime and Cyber Security
J
Java Code Geeks
I
InfoQ

ddadaal.me

fork subgen实现纯本地AI视频字幕生成和翻译 - ddadaal.me 把nanobot关进Docker后,如何同时保留浏览器可视化与自动化 - ddadaal.me 可划分显存 != 统一内存:AI Max+ 395 64G AI推理性能 2025年总结 - ddadaal.me 14寸16核32线程:搭载AMD AI Max+ 395的HP战99 Ultra使用感受 Node是并发性能的绊脚石吗?测试Express服务器的基准并发能力 - ddadaal.me 用大模型总结文章:效果很好,但是玄学 - ddadaal.me 2024年总结 - ddadaal.me 在西雅图,给生活换个环境 - ddadaal.me 从调库到翻源代码:给wakapi增加SQL Server支持 - ddadaal.me 增加自制博客点击量统计 - ddadaal.me 2023年总结 - ddadaal.me 博客的发展2:重写,重生 - ddadaal.me 2022年总结 - ddadaal.me 2021年总结 - ddadaal.me 我的第一个真实项目:总结和经验 - ddadaal.me 一次生产环境的文件丢失事故:复盘和教训 - ddadaal.me react-typed-i18n: 使用Template Literal Types实现强类型的i18n - ddadaal.me wslg初体验:最佳Linux发行版? - ddadaal.me 借助Docker,把VPN当作HTTP代理来用 - ddadaal.me 2020年总结 - ddadaal.me 美好的回忆和未知的未来:写在研究生开学前 - ddadaal.me 使用X11 Forwarding在WSL 2中运行GUI程序 - ddadaal.me 在小手机已经消失的时代,我选择了Galaxy S20 - ddadaal.me 使用PowerShell脚本让UWP应用使用localhost上的系统代理 - ddadaal.me 安装Arch Linux并使用N卡玩Steam游戏 - ddadaal.me 可靠性、辅助功能和多屏协同:我对智能手表的体验和看法 - ddadaal.me 从VSCode到Vim到……两个都用? - ddadaal.me 2019年总结 - ddadaal.me 入手4K显示器:LG 27UL550 - ddadaal.me 暗色模式上线 - ddadaal.me 修复gatsby-transformer-remark插件中文词数统计错误问题 - ddadaal.me 折腾Linux: 从实体机到Win10 - ddadaal.me 从viccrubs改名为ddadaal - ddadaal.me A React Form Component Performance Optimization with Profiler 博客的发展一:RSS,国内托管…… - ddadaal.me 2016至2019,和南京大学微软学生俱乐部一起成长 - ddadaal.me 北大信科 | 上交软院 | 南大软院夏令营经历 使用MVC、MVP、MVVM和FRP实现Android局域网群聊应用 - ddadaal.me 2019年春微软实习面试经验 - ddadaal.me Strongly Typed i18n with TypeScript A Kotlin DI Framework in 50 Lines and Thoughts on Kotlin 7天Hackathon,Web前端极速入门指南 - ddadaal.me An Infinite Loop Caused by Updating a Map during Iteration Simstate and Why - ddadaal.me 2018年总结 - ddadaal.me MSRA DKI组前端面经 - ddadaal.me Safety/Security and Extensibility/Scalability in Software System Design and Architecture 微软听听文档体验报告 - ddadaal.me 正则语法分析器和LALR(1)词法分析器 - ddadaal.me 新博客正式上线 - ddadaal.me 写代码要动脑子! - ddadaal.me 2017年总结 - ddadaal.me Python语言实现的符合本福特定律的十进制固定长度随机数发生器 - ddadaal.me 院自建GitLab CI配置实录 - ddadaal.me C++测例查看器 - ddadaal.me C++插件在VS2017上无法使用的分析 - ddadaal.me
博客集成AI文章总结功能 - ddadaal.me
2024-01-01 · via ddadaal.me

✨AI全文摘要

DeepSeek R1DeepSeek R1 8B

作者受朋友圈启发,为博客添加AI自动总结功能。尝试OpenAI API受阻后,转向Azure AI Studio的Language服务,利用其抽象摘要功能。通过Node.js脚本读取文章内容并调用API生成总结,结果存储为静态文件。实现中英文文章总结,但英文效果更佳,部分中文总结存在标点及逻辑问题。尽管存在不足,整体效果尚可。项目耗时约6小时,集成过程约1小时,体现开发者主动拥抱AI提升效率的实践,强调利用工具优化生产力而非被动担忧替代风险。

Azure AI部署的DeepSeek-R1模型推理

一条朋友圈的提示

当昨天的2023年总结发出后,朋友圈有人对文章做出了总结,这启发了我,何不自己用AI给文章加个总结功能呢?正好也是第一次在真实场景中实装AI功能,看看目前在真实项目中集成AI需要什么步骤,体验怎么样,能做到什么功能。

朋友圈锐总结
朋友圈锐总结

选择AI服务

确定了要做这事,下一步就开始调研应该用什么AI服务。

第一反应肯定用OpenAI API,去年某段时间注册OpenAI账号不需要手机号,趁着这个机会直接注册了一个,至少最基本的ChatGPT可以用GPT 3.5模型聊天了。而当我想去用OpenAI的API的时候,发现要获得OpenAI的API需要验证手机号,而国内手机号当然验证不了的。除了手机号,支付方式也是一个问题,虽然我有国内银行的VISA卡但是似乎仍然不能使用。

国内手机号无法验证OpenAI API
国内手机号无法验证OpenAI API

于是接下来我想到了公司的Azure OpenAI服务。虽然Azure的服务都偏贵,但是由于公司每年都给员工送150刀的Azure额度,所以一点简单的应用还是可以开发的。可是真的去注册的时候发现Azure OpenAI Service并没有完全开放给所有客户,要注册必须填个注册表,且必须以公司身份注册。

Azure OpenAI服务并未面向大众开放
Azure OpenAI服务并未面向大众开放

正当我在想“不会要去找国产服务了吧”的时候,我想到两个月前在Ignite上亮相的Azure AI Studio。仔细研究了下,发现这个功能本身只是一个集成平台,它是基于一些已经已经发布的Azure AI服务,而上面想尝试的Azure OpenAI只是这些服务内的一个。在这些服务中,有一个Language服务,正好用于处理自然语言的场景,而其中正好还自带了Summarization功能,其中的Abstractive summarization模式只要输入文本,它就能输出一段总结这段文本的文字。

一切都是正好。微软爸爸真懂我。

使用Azure AI Language Service

根据Quickstart文档,我们首先需要创建了一个Language资源,获取资源对应的endpoint以及key。

文章总结功能的一大好处是这个功能不需要实时交互。也就是说,我可以在后台把总结生成好,像文章内容本身一样作为静态资源放在仓库里。这样,我们根本不需要能够支持大量调用的AI服务,只要运行一次,就完全可以使用了。创建的资源的时候,每个subscription可以创建一个免费的资源,我们本来也就不到50篇文章,免费的资源就完全够用了。

创建好的Azure Language资源
创建好的Azure Language资源

接下来需要在项目中安装SDK来使用这个资源。我们的博客使用的是Node.js,于是我们选择Node.js继续进行下一步。使用npm install --save @azure/ai-language-text@1.1.0安装SDK后,根据指示直接在项目使用SDK即可。

由于只要内容不变,总结就没有必要更新,所以最简单最直接的做法,就是直接放在本地写个脚本,读取文章的内容,然后把文章内容的markdown直接一股脑送给服务获得内容的总结,然后把总结的内容生成到文章对应的目录下,读取文章的时候顺便读取生成的总结,然后在UI中渲染就好。

ai/summarize.mts
// 总结文本
async function summarize(text: string, languageCode: string): Promise<string[] | Error> {
  const lro = await client.beginAnalyzeBatch([
    // 使用AbstractiveSummarization模式
    { kind: "AbstractiveSummarization" },
    // 根据文章的语言指定所使用的语言,实现中文文章输出中文总结,英文文章输出英文总结
  ], [text], languageCode);
 
  // 这是个耗时操作,等待耗时操作结束
  const results = await lro.pollUntilDone();
 
  for await (const actionResult of results) {
    if (actionResult.kind !== "AbstractiveSummarization") {
      return new Error(`Expected extractive summarization results but got: ${actionResult.kind}`);
    }
    if (actionResult.error) {
      const { code, message } = actionResult.error;
      return new Error(`Unexpected error (${code}): ${message}`);
    }
 
    for (const result of actionResult.results) {
      if (result.error) {
        const { code, message } = result.error;
        return new Error(`Unexpected error (${code}): ${message}`);
      }
 
      // 返回输出的结果
      return result.summaries.map((x) => x.text);
    }
  }
 
  throw new Error("No result");
}
 
async function summarizeArticle(articleDir: string) {
  // 获取此文章的所有markdown文件
  const mdFiles = (await readdir(articleDir)).filter((x) => x.endsWith(".md"));
 
  for (const mdFile of mdFiles) {
    const mdFilePath = join(articleDir, mdFile);
 
    // 读取并解析文章内容
    const mdContent = await readFile(mdFilePath, "utf-8");
    const { data: frontMatter, content } = matter(mdContent);
 
    // 计算并更新文章Hash,如果文章内容hash没有变,之后就不要重新生成总结了
    const contentHash = hashContent(content);
 
    const summaryJsonFilePath = join(articleDir, `${frontMatter.lang}.summary.json`);
 
    if (existsSync(summaryJsonFilePath) && (await stat(summaryJsonFilePath)).isFile()) {
      const existingSummaryJson: ArticleSummary = JSON.parse(await readFile(summaryJsonFilePath, "utf-8"));
 
      existingSummaryJson.hash = contentHash;
 
      if (contentHash === existingSummaryJson.hash) {
        log("log", "Content is not changed after the last summarization. Skip summarization.");
        continue;
      }
    }
 
    // 总结文本
    const summary = await summarize(content,
      azureLanguageCodeMap[frontMatter.lang as keyof typeof azureLanguageCodeMap]);
 
    if (summary instanceof Error) {
      log("error", "Error on summarizing %s of lang %s: %s", frontMatter.id, frontMatter.lang, summary.message);
      continue;
    }
 
    // 在文章目录下生成一个[语言id].summary.json文件,存放内容hash、总结以及相关操作信息
    const summaryJson: ArticleSummary = {
      articleId: frontMatter.id,
      lang: frontMatter.lang,
      lastUpdateStartTime: startTime,
      lastUpdateEndTime: new Date().toISOString(),
      summaries: summary,
      hash: contentHash,
    };
 
    log("log", "Write summary of %s of lang %s to %s", frontMatter.id, frontMatter.lang, summaryJsonFilePath);
 
    await writeFile(summaryJsonFilePath, JSON.stringify(summaryJson, null, 2));
  }
}
 

效果

最终效果嘛,你在打开本文章的时候应该就看到了。如果一篇文章能够成功生成总结,那么文章页面的一开头,以及右侧的目录部分就会有AI总结这部分内容。

效果图
效果图

为什么说“如果可以成功生成总结”呢?在具体操作中,2020年总结这篇文章死活不能生成总结。

一篇文章无法生成总结
一篇文章无法生成总结

而对应成功生成总结的文章,总的来说英文文章的总结效果显著好于中文文章。例如,An Infinite Loop Caused by Updating a Map during Iteration这篇文章的总结包括了问题描述、问题解决过程以及最终的解决方案,语言流畅,逻辑清晰;

The author encountered a problem during the development of the 2.0 version of [simstate], where an infinite loop occurred during the iteration of a set of ' observers' stored in a ES6 Map. The problem was initially confused due to the Map having only one element and remaining unchanged between and inside loops. However, after investigation, the author discovered that the root of the problem was the call to observer, which alters the Map itself during iteration. This led to the infinite loop, even when deleting and re-adding an entry during iteration.

而同样类型的问题探究类文章一次生产环境的文件丢失事故:复盘和教训,得出的总结就过于简单,而且也没有找到问题重点,得出的文本中甚至都是英文标点。

作者通过log、数据库数据等找到了受到影响的用户,通过邮箱、电话和短信提醒他们重新上传文件。

总结

这是我第一次在实际项目中运用AI,在充分的文档帮助下,整个过程花费了6个小时左右,其中集成这个功能可能花了1个小时左右,而最终的效果不能算非常完美,但是也是是差强人意。在2023年的最后一天完成这个过程,在新年的第一天给博客实现这个新的功能,也算是一个新年礼物了吧。在AI的时代,与其害怕AI替代自己,不如主动拥抱AI提高生产效率,而这对于从业者的我们天生就有优势。