feat(blog): add comprehensive blog review and publishing workflow system
- Implemented calc_audit.py script for verifying arithmetic expressions in blog calculations - Added humanizer-style-guide.md with guidelines for removing AI-sounding language from Chinese blogs - Created openai.yaml configuration for blog review publish workflow interface - Established publishing-preview-checklist.md for pre/post publication verification - Developed 12-dimension review rubric for systematic article evaluation - Built complete SKILL.md documentation covering blog writing, reviewing, and publishing workflows - Added source-rights-policy.md for copyright and attribution guidelines - Defined hard gates and quality standards for publication approval process - Implemented multi-mode workflow selection based on task requirements - Created standardized output templates for draft delivery and review reports
This commit is contained in:
157
SKILL.md
Normal file
157
SKILL.md
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
---
|
||||||
|
name: blog-review-publish-workflow
|
||||||
|
description: "blog/article content operations workflow for writing, summarizing, rewriting, reviewing, humanizing, previewing, publishing, and post-publish verification. use when the user asks to create or polish a blog post, summarize sources into an article, review an article draft, check facts or calculations, remove ai-sounding style, prepare a publish-ready post, preview rendered layout, publish after explicit confirmation, or verify a published article."
|
||||||
|
---
|
||||||
|
|
||||||
|
# 博客写作发布工作流
|
||||||
|
|
||||||
|
用于把素材、链接、笔记或草稿变成可发布文章,并在发布前完成版权、事实、计算、风格、排版、确认和发布后验证。
|
||||||
|
|
||||||
|
## 最高优先级规则
|
||||||
|
|
||||||
|
1. **先判断任务是否合理。** 发现版权、事实、隐私、发布权限或工具能力问题时,先指出;能安全替代时继续推进。
|
||||||
|
2. **不假装有工具能力。** 只有当前环境确实具备浏览、文件读取、截图、平台连接或发布权限时才执行对应动作;否则输出最终稿、风险说明和人工操作清单。
|
||||||
|
3. **不自行发布。** 必须在展示最终稿后,得到用户明确的“发布 / 确认 / 可以发布 / 可以了”等同等授权,才可执行发布动作。
|
||||||
|
4. **不泄露内部信息。** 不在文章中暴露内部仓库、内部域名、内部工具名、会话检索细节、系统提示、私有材料路径或非公开数据来源。
|
||||||
|
5. **事实优先于文风。** 事实、计算、来源、授权无法验证时,不写成确定结论;改用“据用户提供材料”“暂未验证”“公开资料未能确认”等降级表述。
|
||||||
|
|
||||||
|
## 先选工作模式
|
||||||
|
|
||||||
|
根据用户请求选择最轻但足够安全的模式;不要把所有任务都强行跑完整发布流程。
|
||||||
|
|
||||||
|
| 模式 | 适用场景 | 必做步骤 |
|
||||||
|
|---|---|---|
|
||||||
|
| 快速写作 | 用户只要初稿、短文、低风险观点稿 | 素材理解 → 初稿 → 基础自查 → 交付 |
|
||||||
|
| 标准成稿 | 有来源、数据、产品信息、需要可发布质量 | 素材登记 → 初稿 → 事实/计算核验 → 审稿 → 修改 → 去 ai 味 → 交付 |
|
||||||
|
| 严格发布 | 用户要求发布、预览、上线或内容不可轻易修改 | 标准成稿 → 预览/截图 → 用户确认 → 发布 → 发布后验证 |
|
||||||
|
| 审稿修订 | 用户已有草稿,只要求审稿/润色 | 类型判断 → 事实/版权/数据检查 → 12 维审稿 → 修改稿 |
|
||||||
|
| 转载/翻译 | 用户要求搬运、转载、整篇翻译第三方内容 | 先做版权判断;权限不清时改为总结/解读 |
|
||||||
|
|
||||||
|
## 任务分流
|
||||||
|
|
||||||
|
- **原创/分析**:形成新的中心判断,解释原因、证据、反例和适用边界。
|
||||||
|
- **总结/解读**:用自己的话转述核心内容,不标“转载”;文末使用 `*来源:作者或机构 - [标题](URL)*`。
|
||||||
|
- **转载**:只有在用户拥有版权、获得授权、原文明确允许转载或内容处于公有领域时才可整篇搬运;必须标注转载、作者、标题和原文链接。
|
||||||
|
- **翻译/编译**:不要完整翻译受版权保护的第三方长文,除非用户提供授权或许可;优先做摘要、摘译和评论。
|
||||||
|
- **发布/排版**:只有已有最终稿、目标平台和发布权限时才进入预览、确认、发布和验证。
|
||||||
|
|
||||||
|
版权和来源细则见 `references/source-rights-policy.md`。
|
||||||
|
|
||||||
|
## 硬性发布闸门
|
||||||
|
|
||||||
|
以下任一项不通过,不得进入发布;可以交付草稿或说明风险。
|
||||||
|
|
||||||
|
| 闸门 | 通过标准 |
|
||||||
|
|---|---|
|
||||||
|
| g1 来源与版权 | 关键来源可追溯;转载/翻译有授权或许可;总结不构成整篇复刻 |
|
||||||
|
| g2 事实准确 | 关键事实、日期、实体、因果关系已核对;未核对内容已降级或删除 |
|
||||||
|
| g3 计算准确 | 数字、价格、百分比、费用、倍率、单位换算已用 python 或等价可审计工具验算 |
|
||||||
|
| g4 隐私与内部信息 | 无内部链接、内部工具名、私有路径、敏感个人信息或不应公开内容 |
|
||||||
|
| g5 用户确认 | 最终稿已展示,用户已明确授权发布 |
|
||||||
|
| g6 渲染可接受 | 发布前预览或平台检查未发现阻塞性排版问题;无法截图时已说明限制 |
|
||||||
|
|
||||||
|
## 标准流程
|
||||||
|
|
||||||
|
### step 1:素材收集与登记
|
||||||
|
|
||||||
|
记录来源、类型、可访问性、可引用性、关键事实和版权状态。外部信息优先使用官方文档、原始公告、论文、监管文件、公司博客、项目仓库、价格页等一手来源。无法访问来源时要求用户提供正文、截图或摘录;在此之前不要把未读内容写成事实。
|
||||||
|
|
||||||
|
### step 2:写初稿
|
||||||
|
|
||||||
|
按文章类型写作。初稿必须有中心判断或清晰信息结构,不做材料堆砌。短文默认不加 h2;长文、教程、报告型内容可使用 h2 和目录。避免“本文将”“随着技术发展”“总而言之”等模板句。
|
||||||
|
|
||||||
|
### step 3:事实与计算核验
|
||||||
|
|
||||||
|
提取草稿中的数字、价格、百分比、费用、倍率、token、时间、版本号、模型 id、api 参数、强断言和“最新/唯一/首次/最高”等表述。使用 python 或 `scripts/calc_audit.py` 对计算逐条验算;价格、模型 id、版本状态等对照官方来源。输出验算报告,记录公式、输入、结果和处理动作。
|
||||||
|
|
||||||
|
### step 4:12 维审稿
|
||||||
|
|
||||||
|
使用 `references/review-rubric.md`。将“可发布/不可发布”由硬性闸门决定,将“写得好不好”由 12 维评分决定。10 分代表最好;不要使用“ai 味”作为正向分数,改用“自然度/人味”。
|
||||||
|
|
||||||
|
严格发布模式下,硬性闸门必须全部通过;事实准确、计算准确、版权来源、隐私安全不得有阻塞问题;其他评分原则上不低于 8 分。
|
||||||
|
|
||||||
|
### step 5:按审稿修改
|
||||||
|
|
||||||
|
优先修复事实错误、计算错误、版权风险和内部信息泄露;其次处理结构、遗漏、观点失真;最后处理标题、语言、节奏和排版。新增事实或数字后必须回到 step 3。
|
||||||
|
|
||||||
|
### step 6:去 ai 味与风格统一
|
||||||
|
|
||||||
|
使用 `references/humanizer-style-guide.md`。重点删除模板起手、过密排比、口号化结尾、过度加粗、虚高形容词和整齐但空泛的段落。保留明确判断、具体例子、限制条件和自然节奏。
|
||||||
|
|
||||||
|
### step 7:预览与截图
|
||||||
|
|
||||||
|
严格发布模式下,若具备浏览器、文档预览或平台预览能力,打开渲染页面并截图检查标题、目录、图片、表格、代码块、引用块、链接和移动端宽表。若无法截图,明确说明限制,并提供人工预览清单。预览细则见 `references/publishing-preview-checklist.md`。
|
||||||
|
|
||||||
|
### step 8:用户确认
|
||||||
|
|
||||||
|
向用户展示最终稿和发布摘要:标题、目标平台、可见性、外链、图片/表格/代码块、未验证风险。未确认前不得发布。用户要求修改时回到 step 5;新增事实或数字时回到 step 3。
|
||||||
|
|
||||||
|
### step 9:发布与发布后验证
|
||||||
|
|
||||||
|
只有在确认、权限和工具能力均满足时发布。发布后打开公开或预览 url,检查标题、正文、图片、表格、代码块、链接、标签、作者和日期。能截图时提供截图;不能截图时说明限制和人工核对项。
|
||||||
|
|
||||||
|
## 输出模板
|
||||||
|
|
||||||
|
### 成稿交付
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 最终稿
|
||||||
|
[文章正文]
|
||||||
|
|
||||||
|
## 验证摘要
|
||||||
|
- 来源:已核对 / 部分未核对 / 用户提供材料
|
||||||
|
- 版权:可总结 / 可转载 / 权限不清已改写 / 存在风险
|
||||||
|
- 事实:通过 / 有未验证项 / 已降级处理
|
||||||
|
- 计算:无计算 / 已验算 / 已修正
|
||||||
|
- 发布风险:无明显阻塞 / 风险列表
|
||||||
|
```
|
||||||
|
|
||||||
|
### 审稿报告
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 发布闸门
|
||||||
|
| 闸门 | 结论 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| 来源与版权 | pass/fail | ... |
|
||||||
|
| 事实准确 | pass/fail | ... |
|
||||||
|
| 计算准确 | pass/fail/na | ... |
|
||||||
|
| 隐私与内部信息 | pass/fail | ... |
|
||||||
|
| 用户确认 | pending/pass | ... |
|
||||||
|
| 渲染检查 | pending/pass/fail/na | ... |
|
||||||
|
|
||||||
|
## 12 维评分
|
||||||
|
| 维度 | 分数 | 问题 | 修改动作 |
|
||||||
|
|---|---:|---|---|
|
||||||
|
| 目标与读者匹配 | 8 | ... | ... |
|
||||||
|
```
|
||||||
|
|
||||||
|
### 发布前确认
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 待确认发布稿
|
||||||
|
标题:[标题]
|
||||||
|
目标平台:[平台]
|
||||||
|
可见性:[公开/私密/草稿/未知]
|
||||||
|
|
||||||
|
[文章正文]
|
||||||
|
|
||||||
|
确认后才会发布;未确认前不会发布。
|
||||||
|
```
|
||||||
|
|
||||||
|
### 发布后验证
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 发布结果
|
||||||
|
- url:[链接]
|
||||||
|
- 状态:已发布 / 已保存草稿 / 发布失败
|
||||||
|
- 验证:标题、正文、链接、图片、表格、代码块、标签、日期
|
||||||
|
- 问题:无 / 问题列表与修复建议
|
||||||
|
```
|
||||||
|
|
||||||
|
## 资源使用
|
||||||
|
|
||||||
|
- 需要判断版权、转载、来源可信度时,读取 `references/source-rights-policy.md`。
|
||||||
|
- 需要审稿或发布前质检时,读取 `references/review-rubric.md`。
|
||||||
|
- 需要去 ai 味、统一语气或改写文风时,读取 `references/humanizer-style-guide.md`。
|
||||||
|
- 需要预览、截图、发布、发布后验证时,读取 `references/publishing-preview-checklist.md`。
|
||||||
|
- 需要批量验算算式时,可运行 `scripts/calc_audit.py`。
|
||||||
3
agents/openai.yaml
Normal file
3
agents/openai.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Blog Review Publish Workflow"
|
||||||
|
short_description: "End-to-end blog writing, review, humanizing, preview, publish, and verification workflow."
|
||||||
47
references/humanizer-style-guide.md
Normal file
47
references/humanizer-style-guide.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# 去 ai 味与中文博客风格指南
|
||||||
|
|
||||||
|
## 总体目标
|
||||||
|
|
||||||
|
文章应该像一个清醒的旁观者或分析师写的:有判断,但不过度代入;有信息密度,但不端着;有结构,但不露模板。
|
||||||
|
|
||||||
|
## 必删或慎用
|
||||||
|
|
||||||
|
- 模板起手:本文将、在当今时代、随着技术不断发展、总而言之、综上所述。
|
||||||
|
- 过度排比:不是……而是……、不仅……更……、一方面……另一方面……连续出现。
|
||||||
|
- 营销空词:赋能、破局、闭环、生态、颠覆、重塑、抓手、底层逻辑、护城河、范式革命。
|
||||||
|
- 假深刻连接:大量破折号、冒号、加粗句制造结论感。
|
||||||
|
- 口号化结尾:未来已来、值得每个人关注、这只是开始。
|
||||||
|
|
||||||
|
## 保留或增加
|
||||||
|
|
||||||
|
- 具体判断:这件事真正值得关注的是……
|
||||||
|
- 适用边界:这个结论只适用于……
|
||||||
|
- 反例或限制:但这不意味着……
|
||||||
|
- 读者视角:如果读者关心的是成本/稳定性/落地难度,重点不一样。
|
||||||
|
- 信息节奏:长段后接短句;密集信息后接一句解释。
|
||||||
|
|
||||||
|
## 改写动作
|
||||||
|
|
||||||
|
1. 删除文章自我介绍句,直接进入事件、问题或判断。
|
||||||
|
2. 把整齐排比拆成自然句,保留最关键的一组对照即可。
|
||||||
|
3. 把泛泛形容词换成具体证据、场景或限制。
|
||||||
|
4. 每 3-5 段检查一次节奏:是否需要短句、例子、反问、边界或小结。
|
||||||
|
5. 结尾用具体信息收束:适用范围、下一步、风险提醒、未解决问题。
|
||||||
|
|
||||||
|
## 示例
|
||||||
|
|
||||||
|
差:
|
||||||
|
|
||||||
|
> 这不仅是一次产品升级,更是对行业生态的重塑。
|
||||||
|
|
||||||
|
好:
|
||||||
|
|
||||||
|
> 更实际的变化是,开发者需要重新计算调用成本和迁移风险。产品升级本身不难,难的是它会不会改变现有架构的默认选择。
|
||||||
|
|
||||||
|
差:
|
||||||
|
|
||||||
|
> 总而言之,这一变化值得所有人关注。
|
||||||
|
|
||||||
|
好:
|
||||||
|
|
||||||
|
> 如果只是轻量试用,影响可能不大;真正需要重新评估的是高频调用、长上下文和多模型切换的场景。
|
||||||
45
references/publishing-preview-checklist.md
Normal file
45
references/publishing-preview-checklist.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# 预览、发布与发布后验证清单
|
||||||
|
|
||||||
|
## 发布前预览
|
||||||
|
|
||||||
|
能使用浏览器、文档预览或平台预览时,必须实际查看渲染结果。不能截图或不能访问平台时,明确说明限制,不要声称已预览。
|
||||||
|
|
||||||
|
检查项:
|
||||||
|
|
||||||
|
- 标题、摘要、封面图、作者、标签、slug、可见性。
|
||||||
|
- h2/h3 层级、目录、段落间距、列表缩进。
|
||||||
|
- 图片是否加载,是否需要说明文字,是否有版权风险。
|
||||||
|
- 表格是否过宽,移动端是否挤压;必要时改为分组列表。
|
||||||
|
- 代码块语言、缩进、换行、复制体验。
|
||||||
|
- 引用块、脚注、链接文本是否正常。
|
||||||
|
- 外链是否指向公开地址,不含内部域名或私有路径。
|
||||||
|
- markdown 是否被目标平台错误解析。
|
||||||
|
|
||||||
|
## 用户确认
|
||||||
|
|
||||||
|
发布前给出:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
标题:...
|
||||||
|
目标平台:...
|
||||||
|
可见性:公开/私密/草稿/未知
|
||||||
|
包含:外链/图片/表格/代码块
|
||||||
|
未验证风险:无/列表
|
||||||
|
```
|
||||||
|
|
||||||
|
只有用户明确授权后才能发布。
|
||||||
|
|
||||||
|
## 发布动作
|
||||||
|
|
||||||
|
发布前再次确认目标平台、账号/空间、标题、slug、标签、可见性、发布时间和是否允许发布后编辑。如果发布后编辑受限,必须提醒用户。
|
||||||
|
|
||||||
|
## 发布后验证
|
||||||
|
|
||||||
|
发布后打开公开或预览 url,检查:
|
||||||
|
|
||||||
|
- 标题、正文、摘要、作者、发布日期。
|
||||||
|
- 图片、表格、代码块、引用、目录、链接。
|
||||||
|
- 标签、分类、可见性、分享卡片。
|
||||||
|
- 是否存在内部链接、错别字、渲染错位或缺失段落。
|
||||||
|
|
||||||
|
发现问题时列出影响范围和修复建议。只有在用户授权且平台允许编辑时才修复。
|
||||||
63
references/review-rubric.md
Normal file
63
references/review-rubric.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# 12 维审稿标准
|
||||||
|
|
||||||
|
## 为什么不是单纯 9 维
|
||||||
|
|
||||||
|
原 9 维覆盖了自然度、结构、深度、可读性、事实、完整性、价值、语气和计算,适合做文章质量检查,但有三个问题:
|
||||||
|
|
||||||
|
1. “ai 味”“可读性”“语气一致性”有重叠,且“ai 味”作为 1-10 分方向不清。
|
||||||
|
2. 缺少读者目标、标题分发、版权来源、隐私安全、平台排版等发布前关键项。
|
||||||
|
3. 把硬性风险和文风评分混在一起,容易出现“文章写得不错但不该发布”的情况。
|
||||||
|
|
||||||
|
建议使用“硬性闸门 + 12 维评分”。闸门决定能不能发布;评分决定文章质量。
|
||||||
|
|
||||||
|
## 硬性闸门
|
||||||
|
|
||||||
|
| 闸门 | fail 条件 |
|
||||||
|
|---|---|
|
||||||
|
| 来源与版权 | 转载/翻译无授权;来源不可追溯;大段复刻第三方内容 |
|
||||||
|
| 事实准确 | 关键事实无法核实却写成确定结论;原文观点被误读 |
|
||||||
|
| 计算准确 | 价格、百分比、倍率、费用、单位换算未验算或结果错误 |
|
||||||
|
| 隐私与内部信息 | 暴露内部链接、内部工具、私有路径、敏感个人信息 |
|
||||||
|
| 用户确认 | 发布前未展示最终稿,或用户未明确授权发布 |
|
||||||
|
| 渲染检查 | 严格发布场景下存在阻塞性排版错误,或无法确认关键渲染 |
|
||||||
|
|
||||||
|
## 12 维评分
|
||||||
|
|
||||||
|
每项 1-10 分,10 分最好。严格发布模式原则上每项不低于 8 分;事实、计算、版权、隐私以闸门为准。
|
||||||
|
|
||||||
|
| # | 维度 | 10 分标准 | 常见问题 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 目标与读者匹配 | 明确知道写给谁、解决什么问题、读者读完能得到什么 | 对象模糊;像内部备忘录;读者收益不清 |
|
||||||
|
| 2 | 中心论点与角度 | 有一句话可概括的核心判断,角度不散 | 只是罗列信息;没有判断;标题和正文重点不一致 |
|
||||||
|
| 3 | 结构与叙事推进 | 开头有钩子,中段有递进,结尾有具体收束 | 段落可随意调换;跳跃;重复;过渡模板化 |
|
||||||
|
| 4 | 信息完整性 | 重要事实、限制、背景和反例没有遗漏 | 只写亮点;遗漏限制条件;断章取义 |
|
||||||
|
| 5 | 事实忠实度 | 准确区分原文事实、作者观点和本文判断 | 误读来源;把推测写成事实;因果倒置 |
|
||||||
|
| 6 | 数据与计算完整性 | 数字来源清楚,公式可复查,单位和口径一致 | 心算;口径混乱;价格/模型/版本过期 |
|
||||||
|
| 7 | 来源、版权与引用 | 来源格式清楚,转载/翻译边界合规 | 版权不明;来源缺失;引用过长;链接不可追溯 |
|
||||||
|
| 8 | 洞察与价值增量 | 相比原文,多出解释、判断、适用边界或读者行动建议 | 纯复述;没有 why;没有取舍 |
|
||||||
|
| 9 | 可读性与节奏 | 句长有变化,信息密度有起伏,读起来不累 | 每段同样密;长句堆叠;术语无解释 |
|
||||||
|
| 10 | 自然度与人味 | 像真实作者写作,有具体判断和自然转折 | 排比堆砌;口号化;过度加粗;模板起承转合 |
|
||||||
|
| 11 | 标题、摘要与分发适配 | 标题准确、有吸引力不过度营销,适合目标平台 | 标题党;太泛;seo/平台摘要缺失 |
|
||||||
|
| 12 | 排版、可访问性与平台适配 | 表格、代码块、图片、引用、链接适合平台和移动端 | 宽表挤压;代码不可读;图片无说明;链接文本含糊 |
|
||||||
|
|
||||||
|
## 审稿输出格式
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 发布闸门
|
||||||
|
| 闸门 | 结论 | 说明 | 必要动作 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 来源与版权 | pass/fail | ... | ... |
|
||||||
|
|
||||||
|
## 12 维评分
|
||||||
|
| 维度 | 分数 | 问题 | 修改动作 |
|
||||||
|
|---|---:|---|---|
|
||||||
|
| 目标与读者匹配 | 8 | ... | ... |
|
||||||
|
|
||||||
|
## 结论
|
||||||
|
- 可发布:0 阻塞意见。
|
||||||
|
- 或不可发布:列出阻塞项和需要用户补充的信息。
|
||||||
|
```
|
||||||
|
|
||||||
|
## 多轮规则
|
||||||
|
|
||||||
|
第一轮全面审稿,第二轮只检查遗留问题和新引入问题。三轮后仍存在阻塞项时,不继续空转;说明剩余风险和需要补充的材料。
|
||||||
46
references/source-rights-policy.md
Normal file
46
references/source-rights-policy.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# 来源、版权与转载策略
|
||||||
|
|
||||||
|
## 来源优先级
|
||||||
|
|
||||||
|
优先级从高到低:
|
||||||
|
|
||||||
|
1. 官方文档、价格页、产品公告、监管文件、论文、项目仓库、公司博客。
|
||||||
|
2. 权威媒体、行业报告、数据库、标准组织。
|
||||||
|
3. 作者博客、访谈、播客、会议演讲。
|
||||||
|
4. 社交媒体、论坛、二手转载、聚合页面。
|
||||||
|
|
||||||
|
涉及价格、模型 id、api 参数、法规、版本状态、发布日期、人物职务、公司状态等可能变化的信息,必须尽量核对一手来源。无法核对时不要写成确定结论。
|
||||||
|
|
||||||
|
## 总结、转载、翻译的边界
|
||||||
|
|
||||||
|
- **总结/解读**:重组结构、用自己的话表达、加入判断和边界;文末标来源。不要连续大段保留原文表达。
|
||||||
|
- **转载**:保留原文主体内容。只有授权、许可、公有领域或用户拥有版权时才可做。必须标“转载”和原文链接。
|
||||||
|
- **翻译**:完整翻译第三方长文通常等同于复制表达。权限不清时改为摘要、摘译、评论或要点解读。
|
||||||
|
- **编译**:多个来源整合时,分别记录来源,避免把不同来源观点混成一个确定事实。
|
||||||
|
|
||||||
|
## 文章中的来源格式
|
||||||
|
|
||||||
|
总结类单一来源:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
*来源:作者或机构 - [标题](URL)*
|
||||||
|
```
|
||||||
|
|
||||||
|
多来源分析:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 参考资料
|
||||||
|
- 作者或机构:[标题](URL)
|
||||||
|
- 作者或机构:[标题](URL)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 风险处理
|
||||||
|
|
||||||
|
| 情况 | 处理 |
|
||||||
|
|---|---|
|
||||||
|
| 原文禁止转载 | 不转载;改成短摘要和评论 |
|
||||||
|
| 权限不明但用户要求整篇搬运 | 拒绝整篇搬运;提供总结/解读版本 |
|
||||||
|
| 无法访问链接 | 要求用户提供正文或截图;不要编造来源内容 |
|
||||||
|
| 来源互相矛盾 | 标出分歧,优先一手来源,不强行合并 |
|
||||||
|
| 用户提供内部材料 | 只提取必要信息;不暴露材料路径、内部链接、工具名 |
|
||||||
|
| 高风险领域 | 使用保守表述,避免给出未经验证的专业建议 |
|
||||||
115
scripts/calc_audit.py
Normal file
115
scripts/calc_audit.py
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Evaluate arithmetic expressions for blog calculation audits.
|
||||||
|
|
||||||
|
Input JSON format:
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"claim": "monthly cost is 12.50",
|
||||||
|
"expression": "0.25 * 50",
|
||||||
|
"expected": 12.5,
|
||||||
|
"tolerance": 0.000001,
|
||||||
|
"note": "unit: usd/month"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
The script intentionally supports arithmetic only, not arbitrary Python code.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import ast
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
import operator
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
ALLOWED_BINOPS = {
|
||||||
|
ast.Add: operator.add,
|
||||||
|
ast.Sub: operator.sub,
|
||||||
|
ast.Mult: operator.mul,
|
||||||
|
ast.Div: operator.truediv,
|
||||||
|
ast.FloorDiv: operator.floordiv,
|
||||||
|
ast.Mod: operator.mod,
|
||||||
|
ast.Pow: operator.pow,
|
||||||
|
}
|
||||||
|
ALLOWED_UNARYOPS = {ast.UAdd: operator.pos, ast.USub: operator.neg}
|
||||||
|
|
||||||
|
|
||||||
|
def eval_expr(expr: str) -> float:
|
||||||
|
node = ast.parse(expr, mode="eval")
|
||||||
|
|
||||||
|
def walk(n: ast.AST) -> float:
|
||||||
|
if isinstance(n, ast.Expression):
|
||||||
|
return walk(n.body)
|
||||||
|
if isinstance(n, ast.Constant) and isinstance(n.value, (int, float)):
|
||||||
|
return float(n.value)
|
||||||
|
if isinstance(n, ast.BinOp) and type(n.op) in ALLOWED_BINOPS:
|
||||||
|
return float(ALLOWED_BINOPS[type(n.op)](walk(n.left), walk(n.right)))
|
||||||
|
if isinstance(n, ast.UnaryOp) and type(n.op) in ALLOWED_UNARYOPS:
|
||||||
|
return float(ALLOWED_UNARYOPS[type(n.op)](walk(n.operand)))
|
||||||
|
raise ValueError(f"unsupported expression element: {ast.dump(n)}")
|
||||||
|
|
||||||
|
return walk(node)
|
||||||
|
|
||||||
|
|
||||||
|
def fmt(value: Any) -> str:
|
||||||
|
if value is None:
|
||||||
|
return ""
|
||||||
|
if isinstance(value, float):
|
||||||
|
if math.isfinite(value):
|
||||||
|
return f"{value:.12g}"
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print("usage: calc_audit.py calculations.json", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
path = Path(sys.argv[1])
|
||||||
|
items = json.loads(path.read_text(encoding="utf-8"))
|
||||||
|
if not isinstance(items, list):
|
||||||
|
print("input must be a json list", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for item in items:
|
||||||
|
if not isinstance(item, dict):
|
||||||
|
raise ValueError("each item must be an object")
|
||||||
|
result = eval_expr(str(item["expression"]))
|
||||||
|
expected = item.get("expected")
|
||||||
|
tolerance = float(item.get("tolerance", 1e-9))
|
||||||
|
if expected is None:
|
||||||
|
status = "computed"
|
||||||
|
delta = None
|
||||||
|
else:
|
||||||
|
expected_float = float(expected)
|
||||||
|
delta = result - expected_float
|
||||||
|
status = "pass" if abs(delta) <= tolerance else "fail"
|
||||||
|
rows.append(
|
||||||
|
[
|
||||||
|
str(item.get("id", "")),
|
||||||
|
str(item.get("claim", "")),
|
||||||
|
str(item.get("expression", "")),
|
||||||
|
fmt(result),
|
||||||
|
fmt(expected),
|
||||||
|
fmt(delta),
|
||||||
|
status,
|
||||||
|
str(item.get("note", "")),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
headers = ["id", "claim", "expression", "result", "expected", "delta", "status", "note"]
|
||||||
|
print("| " + " | ".join(headers) + " |")
|
||||||
|
print("|" + "|".join(["---"] * len(headers)) + "|")
|
||||||
|
for row in rows:
|
||||||
|
safe = [cell.replace("|", "\\|").replace("\n", " ") for cell in row]
|
||||||
|
print("| " + " | ".join(safe) + " |")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user